desug.ml 5.8 KB

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