desug.ml 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. open Ast
  2. open Util
  3. let rec var_init = function
  4. (* Move global initialisations to __init function *)
  5. | Program (decls, loc) ->
  6. let decls = flatten_blocks (List.map var_init decls) in
  7. let rec trav assigns = function
  8. | [] -> (assigns, [])
  9. | (Assign _ as h) :: t -> trav (assigns @ [h]) t
  10. | h :: t ->
  11. let (assigns, decls) = trav assigns t in
  12. (assigns, (h :: decls))
  13. in
  14. let (assigns, decls) = trav [] decls in (
  15. match assigns with
  16. | [] -> Program (decls, loc)
  17. | assigns ->
  18. let init_func = FunDef (true, Void, "__init", [], Block assigns, noloc) in
  19. Program (init_func :: decls, loc)
  20. )
  21. (* Move global variable initialisations to exported __init function *)
  22. | GlobalDef (export, ctype, name, Some init, loc) ->
  23. Block [GlobalDef (export, ctype, name, None, loc);
  24. Assign (name, None, init, locof init)]
  25. (* Split local variable initialisations in declaration and assignment *)
  26. | FunDef (export, ret_type, name, params, Block body, loc) ->
  27. let move_inits body =
  28. let rec trav inits node = match node with
  29. (* translate scalar array initialisation to ArrayScalar node,
  30. * for easy replacement later on *)
  31. | VarDec (ArrayDef _ as vtype, name,
  32. Some (BoolConst _ as v), loc) :: t
  33. | VarDec (ArrayDef _ as vtype, name,
  34. Some (FloatConst _ as v), loc) :: t
  35. | VarDec (ArrayDef _ as vtype, name,
  36. Some (IntConst _ as v), loc) :: t ->
  37. trav inits (VarDec (vtype, name, Some (ArrayScalar (v, vtype)), loc) :: t)
  38. | VarDec (ctype, name, init, loc) as dec :: tl ->
  39. (* array definition: create __allocate statement *)
  40. let alloc = match ctype with
  41. | ArrayDef (_, dims) -> [Allocate (name, dims, dec, loc)]
  42. | _ -> []
  43. in
  44. (* initialisation: create assign statement *)
  45. let add = match init with
  46. | Some value -> alloc @ [Assign (name, None, value, loc)]
  47. | None -> alloc
  48. in
  49. VarDec (ctype, name, None, loc) :: (trav (inits @ add) tl)
  50. (* initialisations need to be placed after local functions *)
  51. | (FunDef (_, _, _, _, _, _) as h) :: t ->
  52. (var_init h) :: (trav inits t)
  53. (* rest of function body: recurse *)
  54. | rest -> inits @ (List.map var_init rest)
  55. in
  56. flatten_blocks (trav [] body)
  57. in
  58. let params = flatten_blocks (List.map var_init params) in
  59. FunDef (export, ret_type, name, params, Block (move_inits body), loc)
  60. | node -> transform_children var_init node
  61. let rec replace_var var replacement node =
  62. let trav = (replace_var var replacement) in
  63. match node with
  64. | Var (name, loc) when name = var ->
  65. Var (replacement, loc)
  66. | For (counter, start, stop, step, body, loc) when counter = var ->
  67. For (replacement, trav start, trav stop, trav step, trav body, loc)
  68. | node ->
  69. transform_children trav node
  70. let for_to_while node =
  71. let rec traverse new_vars = function
  72. | FunDef (export, ret_type, name, params, body, loc) ->
  73. let new_vars = ref [] in
  74. let body = traverse new_vars body in
  75. let create_vardec name = VarDec (Int, name, None, noloc) in
  76. let new_vardecs = List.map create_vardec !new_vars in
  77. let _body = new_vardecs @ (flatten_blocks (block_body body)) in
  78. FunDef (export, ret_type, name, params, Block _body, loc)
  79. (* Transform for-loops to while-loops *)
  80. | For (counter, start, stop, step, body, loc) ->
  81. let _i = fresh_var counter in
  82. let _stop = fresh_var "stop" in
  83. let _step = fresh_var "step" in
  84. new_vars := !new_vars @ [_i; _stop; _step];
  85. let vi = Var (_i, noloc) in
  86. let vstop = Var (_stop, locof stop) in
  87. let vstep = Var (_step, locof step) in
  88. let cond = Cond (
  89. Binop (Gt, vstep, IntConst (0, noloc), noloc),
  90. Binop (Lt, vi, vstop, noloc),
  91. Binop (Gt, vi, vstop, noloc),
  92. noloc
  93. ) in
  94. Block [
  95. Assign (_i, None, start, locof start);
  96. Assign (_stop, None, stop, locof stop);
  97. Assign (_step, None, step, locof step);
  98. While (cond, traverse new_vars (Block (
  99. (* TODO: check for illegal assigments of counter in body *)
  100. block_body (replace_var counter _i body) @
  101. [Assign (_i, None, Binop (Add, vi, vstep, noloc), noloc)]
  102. )), loc);
  103. ]
  104. | node -> transform_children (traverse new_vars) node
  105. in
  106. traverse (ref []) node
  107. let rec array_init = function
  108. (* Transform scalar assignment into nested for-loops *)
  109. | Assign (name, None, ArrayScalar (value, ArrayDef (_, dims)), loc) ->
  110. let rec add_loop indices = function
  111. | [] ->
  112. Assign (name, Some indices, value, loc)
  113. | dim :: rest ->
  114. let counter = fresh_var "i" in
  115. let body = Block [add_loop (indices @ [Var (counter, noloc)]) rest] in
  116. For (counter, IntConst (0, noloc), dim, IntConst (1, noloc), body, noloc)
  117. in
  118. add_loop [] dims
  119. (* TODO *)
  120. | Assign (name, None, ArrayConst (dims, _), _) ->
  121. Block []
  122. | node -> transform_children array_init node
  123. let rec phase input =
  124. prerr_endline "- Desugaring";
  125. match input with
  126. | Ast (node, args) ->
  127. Ast (for_to_while (array_init (var_init node)), args)
  128. | _ -> raise (InvalidInput "desugar")