desug.ml 5.6 KB

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