extern.ml 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. open Types
  2. open Util
  3. let create_param ctype name =
  4. let param = Param (ctype, name, [Depth 1]) in
  5. let value = VarUse (param, None, [Type ctype; Depth 1]) in
  6. (param, value)
  7. let call node args depth =
  8. match node with
  9. | FunDec (ctype, name, _, _) as dec ->
  10. FunUse (dec, args, [Type ctype; Depth depth])
  11. | _ -> raise InvalidNode
  12. let generate_name name postfix = "_" ^ name ^ "_" ^ postfix
  13. let getname name = generate_name name "get"
  14. let setname name = generate_name name "set"
  15. let create_getset globals = function
  16. | GlobalDef (true, ArrayDims (ctype, _), name, None, ann) as dec ->
  17. (* Getters for array variable: create 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. * desugaring phase *)
  21. let (param, index) = create_param Int (fresh_id "index") in
  22. let var = VarUse (dec, Some [index], [Type ctype; Depth 1]) in
  23. let body = Block [Return (var, [])] in
  24. let getter = FunDef (true, ctype, getname name, [param], body, []) in
  25. (* Setters for array variable: create setter for given index *)
  26. let (param1, index) = create_param Int (fresh_id "index") in
  27. let (param2, value) = create_param ctype (fresh_id "value") in
  28. let params = [param1; param2] in
  29. let body = Block [VarLet (dec, Some [index], value, [])] in
  30. let setter = FunDef (true, Void, setname name, params, body, []) in
  31. [getter; setter]
  32. | GlobalDef (true, ctype, name, None, ann) as dec ->
  33. (* Getter for basic variable type: return the variable *)
  34. let var = VarUse (dec, None, [Type ctype; Depth 1]) in
  35. let body = [Return (var, [])] in
  36. let getter = FunDef (true, ctype, getname name, [], Block body, []) in
  37. (* Setter for basic variable type: assign the variable *)
  38. let (param, value) = create_param ctype (fresh_id "value") in
  39. let body = [VarLet (dec, None, value, [])] in
  40. let setter = FunDef (true, Void, setname name, [param], Block body, []) in
  41. [getter; setter]
  42. | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
  43. (* External array variable: create getter and setter for a given index. Now
  44. * we also need to generate functions for dimensions since they are NOT
  45. * added as new variables during desugaring. *)
  46. let rec add_dims i = function
  47. | [] -> []
  48. | Dim (dimname, ann) :: tl ->
  49. let newname = generate_id name i in
  50. let getter = FunDec (ctype, getname newname, [], []) in
  51. let (param, _) = create_param ctype "value" in
  52. let setter = FunDec (Void, setname newname, [param], []) in
  53. Hashtbl.add globals dimname (call getter, call setter);
  54. getter :: setter :: (add_dims (i + 1) tl)
  55. | _ -> raise InvalidNode
  56. in
  57. let dimfuncs = add_dims 1 dims in
  58. let (param, _) = create_param Int "index" in
  59. let getter = FunDec (ctype, getname name, [param], []) in
  60. let (param1, index) = create_param Int "index" in
  61. let (param2, value) = create_param ctype "value" in
  62. let setter = FunDec (Void, setname name, [param1; param2], []) in
  63. Hashtbl.add globals name (call getter, call setter);
  64. getter :: setter :: dimfuncs
  65. (* Getter for basic variable type: return the variable *)
  66. | GlobalDec (ctype, name, ann) ->
  67. let getter = FunDec (ctype, getname name, [], []) in
  68. let (param, _) = create_param ctype "value" in
  69. let setter = FunDec (Void, setname name, [param], []) in
  70. Hashtbl.add globals name (call getter, call setter);
  71. [getter; setter]
  72. | _ -> raise InvalidNode
  73. (* Create getter/setter functions for exported/imported variables *)
  74. let rec create_funcs globals = function
  75. | Program (decls, ann) ->
  76. let decls = List.map (create_funcs globals) decls in
  77. Program (flatten_blocks (List.map (create_funcs globals) decls), ann)
  78. | GlobalDef (true, ctype, name, None, ann) as node ->
  79. Block (GlobalDef (false, ctype, name, None, ann) ::
  80. (create_getset globals node))
  81. | GlobalDec (ctype, name, ann) as node ->
  82. Block (create_getset globals node)
  83. | node -> transform_children (create_funcs globals) node
  84. (* Replace uses for imported/exported variabels with getter/setter functions *)
  85. let rec replace_vars scope depth = function
  86. (* Variable names may be redefined in function scopes *)
  87. | (VarDec (_, name, _, _) as node)
  88. | (Param (_, name, _) as node) when Hashtbl.mem scope name ->
  89. Hashtbl.remove scope name;
  90. node
  91. (* Copy scope when traversing into function,, and restore afterwards *)
  92. | FunDef (export, ret_type, name, params, body, ann) ->
  93. let local_scope = Hashtbl.copy scope in
  94. let trav = replace_vars local_scope (depth + 1) in
  95. let params = List.map trav params in
  96. FunDef (export, ret_type, name, params, trav body, ann)
  97. (* Use of regular external variable *)
  98. | VarUse (dec, None, _) when Hashtbl.mem scope (nameof dec) ->
  99. let (get, _) = Hashtbl.find scope (nameof dec) in
  100. get [] depth
  101. (* Dereference of external array *)
  102. | VarUse (dec, Some indices, _) when Hashtbl.mem scope (nameof dec) ->
  103. let (get, _) = Hashtbl.find scope (nameof dec) in
  104. get indices depth
  105. | VarLet (dec, dims, value, _) when Hashtbl.mem scope (nameof dec) ->
  106. let dims = optmapl (replace_vars scope depth) dims in
  107. let (_, set) = Hashtbl.find scope (nameof dec) in
  108. Expr (set (dims @ [replace_vars scope depth value]) depth)
  109. | node -> transform_children (replace_vars scope depth) node
  110. let phase = function
  111. | Ast node ->
  112. let globals = Hashtbl.create 20 in
  113. let node = create_funcs globals node in
  114. Ast (replace_vars globals 0 node)
  115. | _ -> raise (InvalidInput "extern vars")