desug.ml 7.2 KB

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