desug.ml 7.4 KB

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