desug.ml 5.8 KB

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