extern_vars.ml 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. open Ast
  2. open Util
  3. (* Remove Type nodes temporarily for easy traversal *)
  4. let rec prune_types = function
  5. | Type (node, _) -> prune_types node
  6. | node -> transform_children prune_types node
  7. let create_param ctype name =
  8. let param = Param (ctype, name, noloc) in
  9. let value = VarUse (Var (name, noloc), ctype, 0) in
  10. (param, value)
  11. let call node args depth = match node with
  12. | FunDec (ctype, name, _, _) as def ->
  13. Type (FunUse (FunCall (name, args, noloc), def, depth), ctype)
  14. | _ -> raise InvalidNode
  15. let process globals = function
  16. | GlobalDef (true, Array (ctype, dims), name, None, loc) ->
  17. (* Getters for array variable: crate getter for given index Note that
  18. * getters and setters for dimensions are automatically generated,
  19. * because they have been put into new global variables during the
  20. * desugarin phase *)
  21. let (param, index) = create_param Int (fresh_var "index") in
  22. let var = Deref (name, [index], noloc) in
  23. let body = Block [Return (var, noloc)] in
  24. let getter = FunDef (true, ctype, name ^ "$get", [param], body, noloc) in
  25. (* Setters for array variable: create setter for given index *)
  26. let (param1, index) = create_param Int (fresh_var "index") in
  27. let (param2, value) = create_param ctype (fresh_var "value") in
  28. let body = Block [VarLet (Assign (name, Some [index], value, noloc), ctype, 1)] in
  29. let setter = FunDef (true, Void, name ^ "$set", [param1; param2], body, noloc) in
  30. [getter; setter]
  31. | GlobalDef (true, ctype, name, None, loc) ->
  32. (* Getter for basic variable type: return the variable *)
  33. let var = VarUse (Var (name, noloc), ctype, 1) in
  34. let body = [Return (var, noloc)] in
  35. let getter = FunDef (true, ctype, name ^ "$get", [], Block body, noloc) in
  36. (* Setter for basic variable type: assign the variable *)
  37. let (param, value) = create_param ctype (fresh_var "value") in
  38. let body = [VarLet (Assign (name, None, value, noloc), ctype, 1)] in
  39. let setter = FunDef (true, Void, name ^ "$set", [param], Block body, noloc) in
  40. [getter; setter]
  41. | GlobalDec (Array (ctype, dims), name, loc) ->
  42. (* Getters for external array variable: create getter for a given index *)
  43. (* Setters for external array variable:
  44. * - define setter for a given index
  45. * - define setter for each dimension*)
  46. let (param, _) = create_param Int "index" in
  47. let rec process_dims i = function
  48. | [] -> []
  49. | Dim (oldname, _) :: tl ->
  50. let dimname = name ^ "$" ^ string_of_int i in
  51. let getter = FunDec (Void, dimname ^ "$get", [], noloc) in
  52. let (param, _) = create_param ctype "value" in
  53. let setter = FunDec (Void, dimname ^ "$set", [param], noloc) in
  54. Hashtbl.add globals oldname (call getter, call setter);
  55. getter :: setter :: (process_dims (i + 1) tl)
  56. | _ -> raise InvalidNode
  57. in
  58. let getter = FunDec (ctype, name ^ "$get", [param], noloc) in
  59. let (param1, index) = create_param Int "index" in
  60. let (param2, value) = create_param ctype "value" in
  61. let setter = FunDec (Void, name ^ "$set", [param1; param2], noloc) in
  62. Hashtbl.add globals name (call getter, call setter);
  63. getter :: setter :: (process_dims 1 dims)
  64. (* Getter for basic variable type: return the variable *)
  65. | GlobalDec (ctype, name, loc) ->
  66. let getter = FunDec (ctype, name ^ "$get", [], noloc) in
  67. let (param, _) = create_param ctype "value" in
  68. let setter = FunDec (Void, name ^ "$set", [param], noloc) in
  69. Hashtbl.add globals name (call getter, call setter);
  70. [getter; setter]
  71. | _ -> raise InvalidNode
  72. let rec create_funcs globals = function
  73. | Program (decls, loc) ->
  74. let decls = List.map (create_funcs globals) decls in
  75. Program (flatten_blocks (List.map (create_funcs globals) decls), loc)
  76. | GlobalDef (true, ctype, name, None, loc) as node ->
  77. Block (GlobalDef (false, ctype, name, None, loc) ::
  78. (process globals node))
  79. | GlobalDec (ctype, name, loc) as node ->
  80. Block (process globals node)
  81. | node -> transform_children (create_funcs globals) node
  82. let rec replace_vars scope depth = function
  83. | (VarDec (_, name, _, _) as node)
  84. | (Param (_, name, _) as node)
  85. when Hashtbl.mem scope name ->
  86. Hashtbl.remove scope name;
  87. node
  88. | FunDef (export, ret_type, name, params, body, loc) ->
  89. let local_scope = Hashtbl.copy scope in
  90. let trav = replace_vars local_scope (depth + 1) in
  91. let params = List.map trav params in
  92. FunDef (export, ret_type, name, params, trav body, loc)
  93. | VarUse (Var (name, loc), _, _) as node when Hashtbl.mem scope name ->
  94. let (get, _) = Hashtbl.find scope name in
  95. get [] depth
  96. | VarLet (Assign (name, None, value, _), _, _) when Hashtbl.mem scope name ->
  97. let (_, set) = Hashtbl.find scope name in
  98. Expr (set [replace_vars scope depth value] depth)
  99. | VarLet (Assign (name, Some dims, value, _), _, _) when Hashtbl.mem scope name ->
  100. let dims = List.map (replace_vars scope depth) dims in
  101. let (_, set) = Hashtbl.find scope name in
  102. Expr (set (dims @ [replace_vars scope depth value]) depth)
  103. | node -> transform_children (replace_vars scope depth) node
  104. let rec phase input =
  105. prerr_endline "- Create getters and setters for extern variables";
  106. match input with
  107. | Ast node ->
  108. let globals = Hashtbl.create 20 in
  109. let node = create_funcs globals (prune_types node) in
  110. Ast (replace_vars globals 0 node)
  111. | _ -> raise (InvalidInput "extern vars")