-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypify.ml
275 lines (248 loc) · 8.45 KB
/
typify.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
open Typ
open Syntax
open Error
type typenv = (string, typ) Hashtbl.t list (* ("x", IntT); ("y", VarT("'y")); ... *)
type typsubst = (string * typ) list (* ("'y", IntT); ("'z", VarT("'y")); ... *)
let builtin_optypes = [
("print", FunT(VarT("'__print"), UnitT) );
("+", FunT(IntT, FunT(IntT, IntT)) );
("-", FunT(IntT, FunT(IntT, IntT)) );
("__neg", FunT(IntT, IntT) );
("*", FunT(IntT, FunT(IntT, IntT)) );
("/", FunT(IntT, FunT(IntT, IntT)) );
("==", FunT(IntT, FunT(IntT, BoolT)) );
("!=", FunT(IntT, FunT(IntT, BoolT)) );
("<", FunT(IntT, FunT(IntT, BoolT)) );
(">", FunT(IntT, FunT(IntT, BoolT)) );
("<=", FunT(IntT, FunT(IntT, BoolT)) );
(">=", FunT(IntT, FunT(IntT, BoolT)) );
]
let builtin_types = [
("I32", IntT);
("Bool", BoolT);
]
let rec string_of_typenv typenv =
match typenv with
|typtbl::xs ->
let s = Hashtbl.fold (fun k t s -> s^k^":"^(string_of_type t)^", ") typtbl "" in
s^"\n"^(string_of_typenv xs)
|[] -> ""
let type_of_name name =
match List.assoc_opt name builtin_types with
|Some(t) -> t
|None -> raise (SilkError ("Undefined type:" ^ name))
let type_of_name_opt name =
match name with
|Some(name) -> Some(type_of_name name)
|_ -> None
(* add var with type into current scope *)
let add_var name typ typenv =
match typenv with
|typtbl::xs -> begin
let typtbl = Hashtbl.copy typtbl in
Hashtbl.add typtbl name typ;
typtbl::xs
end
|[] -> begin
let typtbl = Hashtbl.create 10 in
Hashtbl.add typtbl name typ;
[typtbl]
end
let lookup_scope name typenv =
match Hashtbl.find_opt (List.hd typenv) name with
|Some(typ) -> Some(typ)
|None -> None
let rec lookup name typenv =
match typenv with
|typtbl::xs -> begin
match Hashtbl.find_opt typtbl name with
|Some(typ) -> Some(typ)
|None -> lookup name xs
end
|[] -> None
let rec newtypevar name typenv =
match lookup name typenv with
|Some(_) -> newtypevar ("'"^name) typenv
|None -> VarT(name)
let rec occurs var_name typ =
if var_name = typ then true
else
match typ with
|FunT(argt, rett) -> (occurs var_name argt) || (occurs var_name rett)
|_ -> false
(* replace t with ty *)
let rec replace_type (t: typ) name (ty: typ): typ =
match t with
|VarT(name') -> if name = name' then ty else t
|FunT(argt, rett) -> FunT(replace_type argt name ty, replace_type rett name ty)
|_ -> t
let apply_substs (t: typ) (s: typsubst): typ =
List.fold_right (fun (name, ty) t -> replace_type t name ty) s t
let rec unify_one (t1: typ) (t2: typ): typsubst =
match (t1, t2) with
|(VarT(name1), VarT(name2)) ->
if name1 = name2 then []
else [(name2, t1)]
|(VarT(name), _) ->
if occurs t1 t2 then raise (TypeError "not unifiable")
else [(name, t2)]
|(_, VarT(name)) ->
if occurs t2 t1 then raise (TypeError "not unifiable")
else [(name, t1)]
|(FunT(argt1, rett1), FunT(argt2, rett2)) ->
unify [(argt1, argt2); (rett1, rett2)]
|(_, _) ->
if t1 = t2 then []
else raise (TypeError ("type mismatched:"^(string_of_type t1)^", "^(string_of_type t2)))
and unify typs =
match typs with
|(t1, t2)::xs ->
let substs = unify xs in
let subst = unify_one (apply_substs t1 substs) (apply_substs t2 substs) in
subst @ substs (* list concatenation *)
|[] -> []
let subst_typenv (typenv:typenv) (subst:typsubst) :typenv =
List.map
(fun typtbl ->
Hashtbl.filter_map_inplace
(fun name t ->
let t = (apply_substs t subst) in
Some(t))
typtbl;
typtbl)
typenv
let rec typify_expr exp typenv =
match exp with
|Unit -> (TUnit(UnitT), typenv)
|Int(v) -> (TInt(v, IntT), typenv)
|Bool(v) -> (TBool(v, BoolT), typenv)
|Call(name, args) ->
let f =
match List.assoc_opt name builtin_optypes with
|Some(f') -> f' (* builtin *)
|None -> begin
match lookup name typenv with
|Some(f') when is_funt f' -> f' (* user defined *)
|_ -> begin
print_string (string_of_typenv typenv);
raise (SilkError ("Undefined function: " ^ name))
end
end
in
(* unifying argument types and return ret_t *)
let rec typify_call args f typenv subst =
match args with
|arg::xs ->
let t = arg_type f in
let arg_t, typenv = typify_expr arg typenv in
let subst = subst @ (unify [(t, typeof arg_t)]) in
let argts, r_t, typenv = typify_call xs (ret_type f) typenv subst in
(arg_t::argts, apply_substs r_t subst, typenv)
|[] -> ([], f, typenv)
in
let args =
match args with
|[] -> [Unit]
|_ -> args
in
let argts, rett, typenv = typify_call args f typenv [] in
(TCall(name, argts, rett), typenv)
|If(cond, then_exp, else_exp) ->
let cond_t, typenv = typify_expr cond typenv in
let typenv = subst_typenv typenv (unify [(BoolT, typeof cond_t)]) in
let then_t, typenv = typify_expr then_exp typenv in
let else_t, typenv = typify_expr else_exp typenv in
let typenv = subst_typenv typenv (unify [(typeof then_t, typeof else_t)]) in
let then_t, typenv = typify_expr then_exp typenv in
(TIf(cond_t, then_t, else_t, typeof then_t), typenv)
|Var(name) -> begin
match lookup name typenv with
|Some(t) -> (TVar(name, t), typenv)
|None -> raise (SilkError ("variable is undefined:"^name))
end
|Assign(name, t_specifier, exp) -> begin
let expt, typenv = typify_expr exp typenv in
let typenv =
match (lookup_scope name typenv, type_of_name_opt t_specifier) with
|(Some(t), None) -> (* reassign (should have same type) *)
subst_typenv typenv (unify [(t, typeof expt)])
|(Some(t), Some(t')) when t = t' -> (* reassign (same type) *)
subst_typenv typenv (unify [(t, typeof expt)])
|(None, Some(t)) -> (* new assign with type specifier *)
let typenv = subst_typenv typenv (unify [(t, typeof expt)]) in
add_var name t typenv
|(None, None) -> (* new assign without type specifier *)
add_var name (typeof expt) typenv
|(Some(t), Some(t_specifier)) -> (* reassign (different type) *)
raise (SilkError ("type of variable "^name^" is "^(string_of_type t)))
in
(TAssign(name, expt, typeof expt), typenv)
end
|MultiExpr(exprs) -> begin
let typenv = (Hashtbl.create 10)::typenv in
let rec typify_exprs exprs typenv =
match exprs with
|e::xs -> begin
let e_t, typenv = typify_expr e typenv in
match xs with
|[] -> ([e_t], typeof e_t, typenv)
|_ ->
let e_ts, r_t, typenv = typify_exprs xs typenv in
(e_t::e_ts, r_t, typenv)
end
|[] -> ([], UnitT, typenv)
in
let exprs_t, r_t, typenv = typify_exprs exprs typenv in
let typenv = List.tl typenv in
(TMultiExpr(exprs_t, r_t), typenv)
end
|Defun(name, args, rett, body) -> begin
(* function scope *)
let scopeenv = (Hashtbl.create 10) in
let recursible = ref true in
let argnames = List.map (fun (argname, argtype) ->
let _ =
match argtype with
|Some(t) ->
Hashtbl.add scopeenv argname (type_of_name t)
|None -> begin
let tyvar = newtypevar argname typenv in
Hashtbl.add scopeenv argname tyvar;
recursible := false
end
in
argname) args
in
let rett, recursible =
match rett with
|Some(rett) -> (type_of_name rett), !recursible
|None -> UnitT, false
in
if recursible then begin
let argtypes = List.map (fun (_, argtype) ->
match argtype with
|Some(argtype) -> (type_of_name argtype)
|None -> raise (SilkError "Program Error")) args
in
let funt = make_funt argtypes rett in
Hashtbl.add scopeenv name funt
end
else ();
let typenv = scopeenv::typenv in
(* evaluate *)
let bodyt, typenv = typify_expr body typenv in
(* get evaluated types *)
let argtypes = List.map (fun argname ->
let argtype, _ = typify_expr (Var(argname)) typenv in
typeof argtype) argnames
in
(* rollback scope *)
let typenv = List.tl typenv in
(* build function type *)
let funct = make_funt argtypes (typeof bodyt) in
Hashtbl.add (List.hd typenv) name funct;
(TDefun(name, argnames, bodyt, funct), typenv)
end
let typify exprs =
let typed_expr, _ = typify_expr exprs [Hashtbl.create 10] in
typed_expr