desug.ml 5.7 KB

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