context.ml 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. open Printf
  2. open Types
  3. open Util
  4. let rec add_depth depth node =
  5. match node with
  6. | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
  7. (* XXX: traversal should traverse into Dim nodes *)
  8. let dims = List.map (add_depth depth) dims in
  9. GlobalDec (ArrayDims (ctype, dims), name, Depth depth :: ann)
  10. | Param (ArrayDims (ctype, dims), name, ann) ->
  11. let dims = List.map (add_depth depth) dims in
  12. Param (ArrayDims (ctype, dims), name, Depth depth :: ann)
  13. | GlobalDec _
  14. | GlobalDef _
  15. | Param _
  16. | Dim _
  17. | VarDec _
  18. | Var _
  19. | FunCall _
  20. | Assign _
  21. | For _
  22. | VarUse _
  23. | FunUse _
  24. | VarLet _ ->
  25. annotate (Depth depth) node |> traverse_unit (add_depth depth)
  26. | FunDec _ ->
  27. annotate (Depth depth) node
  28. | FunDef (export, ret_type, name, params, body, ann) ->
  29. let params = List.map (add_depth (depth + 1)) params in
  30. let body = add_depth (depth + 1) body in
  31. FunDef (export, ret_type, name, params, body, Depth depth :: ann)
  32. | _ ->
  33. traverse_unit (add_depth depth) node
  34. type identifier_type = Funcname | Varname
  35. let typename = function Varname -> "variable" | Funcname -> "function"
  36. let tblfind tbl name = try Some (Hashtbl.find tbl name) with Not_found -> None
  37. let add_to_scope scope name dec namety err =
  38. match tblfind scope name with
  39. | Some orig when depthof orig >= depthof dec ->
  40. err := NodeMsg (orig, "\rPreviously declared here:") ::
  41. NodeMsg (dec, sprintf "Error: cannot redeclare %s \"%s\""
  42. (typename namety) name) :: !err
  43. | Some _ ->
  44. Hashtbl.replace scope name dec
  45. | None ->
  46. Hashtbl.add scope name dec
  47. let check_in_scope scope name errnode namety err =
  48. match tblfind scope name with
  49. | Some dec -> dec
  50. | None ->
  51. let msg = sprintf "undefined %s \"%s\"" (typename namety) name in
  52. err := NodeMsg (errnode, msg) :: !err;
  53. DummyNode
  54. let prt_vars vars =
  55. let prt name dec = prerr_string (name ^ ", ") in
  56. Hashtbl.iter prt vars;
  57. prerr_endline "(end)"
  58. let analyse do_rename program =
  59. let err = ref [] in
  60. (* Add functions at the current depth to the function scope, do not traverse
  61. * into nested functions *)
  62. let rec collect_funs funs node =
  63. match node with
  64. | FunDec (_, name, _, _)
  65. | FunDef (_, _, name, _, _, _) ->
  66. (* TODO: don't copy function body to save memory *)
  67. add_to_scope funs name node Funcname err;
  68. node
  69. | _ -> traverse_unit (collect_funs funs) node
  70. in
  71. (* Traverse through statements in the current scope, checking and replacing
  72. * variable occurrences. Add newly declared variables to the variable scope
  73. * on-the-fly. *)
  74. let rec traverse scope node =
  75. let trav = traverse scope in
  76. let trav_dims = function
  77. | ArrayDims (ctype, dims) ->
  78. ArrayDims (ctype, List.map trav dims)
  79. | ctype -> ctype
  80. in
  81. let vars, funs, repl = scope in
  82. let check_rename node rename =
  83. let name = nameof node in
  84. let shadows_higher_scope =
  85. do_rename && (Hashtbl.mem vars name || Hashtbl.mem repl name)
  86. in
  87. (* Trigger duplication error and make sure following duplication errors
  88. * will refer to a non-generated variable name *)
  89. add_to_scope vars name node Varname err;
  90. if shadows_higher_scope then begin
  91. let newname = fresh_id name in
  92. Hashtbl.replace repl name newname;
  93. let newnode = rename newname in
  94. add_to_scope vars newname newnode Varname err;
  95. newnode
  96. end else
  97. node
  98. in
  99. let add_dims = function
  100. | ArrayDims (ctype, dims) ->
  101. let rec add = function
  102. | [] -> []
  103. | (Dim (name, ann) as dim) :: tl ->
  104. check_rename dim (fun name -> Dim (name, ann)) :: add tl
  105. | _ -> raise InvalidNode
  106. in
  107. ArrayDims (ctype, add dims)
  108. | ctype -> ctype
  109. in
  110. match node with
  111. | Program (decls, ann) ->
  112. Program (Block decls |> trav |> trav_funs scope |> block_body, ann)
  113. | FunDec _ | FunDef _ -> node
  114. | GlobalDef (export, ctype, name, init, ann) ->
  115. let node = GlobalDef (export, trav_dims ctype, name, optdo trav init, ann) in
  116. add_to_scope vars name node Varname err;
  117. node
  118. | VarDec (ctype, name, init, ann) ->
  119. let ctype = trav_dims ctype in
  120. let init = optdo trav init in
  121. let node = VarDec (ctype, name, init, ann) in
  122. check_rename node (fun name -> VarDec (ctype, name, init, ann))
  123. | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
  124. let rec replace_dims i = function
  125. | [] -> []
  126. | Dim (dimname, ann) :: tl ->
  127. let newname = generate_array_dim name i in
  128. Hashtbl.add repl dimname newname;
  129. Dim (newname, ann) :: replace_dims (i + 1) tl
  130. | _ -> raise InvalidNode
  131. in
  132. let ctype = ArrayDims (ctype, replace_dims 0 dims) in
  133. let node = GlobalDec (add_dims ctype, name, ann) in
  134. add_to_scope vars name node Varname err;
  135. node
  136. | GlobalDec (ctype, name, ann) ->
  137. add_to_scope vars name node Varname err;
  138. node
  139. | Param (ctype, name, ann) ->
  140. let ctype = add_dims ctype in
  141. let node = Param (ctype, name, ann) in
  142. check_rename node (fun name -> Param (ctype, name, ann))
  143. | For (name, start, stop, step, body, ann) ->
  144. let start, stop, step = trav start, trav stop, trav step in
  145. (* For-loops are a special case: the loop counter defines a new scope
  146. * which is allowed to shadow existing local variables, and allows for
  147. * nested loops with the same induction variables. Replace the loop
  148. * counter with a fresh variable to enforce this behaviour, and avoid
  149. * having to replace variables during desigaring. *)
  150. (* FIXME: only create new variable if necessary *)
  151. let newname = fresh_id name in
  152. let node = For (newname, start, stop, step, body, ann) in
  153. Hashtbl.add vars name node;
  154. Hashtbl.add vars newname node;
  155. Hashtbl.add repl name newname;
  156. let node = For (newname, start, stop, step, trav body, ann) in
  157. Hashtbl.remove repl name;
  158. Hashtbl.remove vars newname;
  159. Hashtbl.remove vars name;
  160. node
  161. (* Perform renaming *)
  162. | Var (name, dims, ann) when Hashtbl.mem repl name ->
  163. trav (Var (Hashtbl.find repl name, dims, ann))
  164. | Assign (name, dims, value, ann) when Hashtbl.mem repl name ->
  165. trav (Assign (Hashtbl.find repl name, dims, value, ann) )
  166. (* Replace variables or function calls with use-nodes which contain the
  167. * entire declaration *)
  168. | Var (name, dims, ann) ->
  169. let dec = check_in_scope vars name node Varname err in
  170. VarUse (dec, optmap trav dims, ann)
  171. | FunCall (name, args, ann) ->
  172. let dec = check_in_scope funs name node Funcname err in
  173. FunUse (dec, List.map trav args, ann)
  174. (* Assign statements are replaced with VarLet nodes, which stores the
  175. * declaration of the assigned variable *)
  176. | Assign (name, dims, value, ann) ->
  177. begin
  178. match check_in_scope vars name node Varname err with
  179. | For _ ->
  180. err := NodeMsg (node, "cannot assign to induction variable") :: !err;
  181. node
  182. | dec ->
  183. VarLet (dec, optmap trav dims, trav value, ann)
  184. end
  185. (* Also support intermediary nodes because context analysis is re-run later
  186. * on to propagate new declaration properties *)
  187. | VarUse (dec, dims, ann) ->
  188. VarUse (Hashtbl.find vars (nameof dec), optmap trav dims, ann)
  189. | FunUse (dec, args, ann) ->
  190. FunUse (Hashtbl.find funs (nameof dec), List.map trav args, ann)
  191. | VarLet (dec, dims, value, ann) ->
  192. VarLet (Hashtbl.find vars (nameof dec), optmap trav dims, trav value, ann)
  193. | Allocate (dec, dims, ann) ->
  194. Allocate (Hashtbl.find vars (nameof dec), List.map trav dims, ann)
  195. (* Do not traverse into external function declarations, since their
  196. * parameters must not be added to the namespace *)
  197. | FunDec _ -> node
  198. | _ -> traverse_unit trav node
  199. and trav_funs scope = function
  200. (* Copy scope when entering a function body *)
  201. | FunDef (export, ret_type, name, params, body, ann) ->
  202. let vars, funs, repl = scope in
  203. let locfuns = Hashtbl.copy funs in
  204. let locscope = (Hashtbl.copy vars, locfuns, Hashtbl.copy repl) in
  205. let params = List.map (traverse locscope) params in
  206. let body =
  207. collect_funs locfuns body |> traverse locscope |> trav_funs locscope
  208. in
  209. FunDef (export, ret_type, name, params, body, ann)
  210. | node -> traverse_unit (trav_funs scope) node
  211. in
  212. let vars = Hashtbl.create 32 in
  213. let funs = Hashtbl.create 16 in
  214. let repl = Hashtbl.create 16 in
  215. add_depth 0 program |>
  216. collect_funs funs |>
  217. traverse (vars, funs, repl) |>
  218. quit_on_error (List.rev !err)
  219. let phase = function
  220. | Ast node -> Ast (analyse true node)
  221. | _ -> raise InvalidInput