]> Joshua Wise's Git repositories - snipe.git/blame - type/typechecker.sml
Initial import of l5c
[snipe.git] / type / typechecker.sml
CommitLineData
6ade8b0a 1(* L3 Compiler
12aa4087
JW
2 * TypeChecker
3 * Author: Alex Vaynberg <alv@andrew.cmu.edu>
4 * Modified: Frank Pfenning <fp@cs.cmu.edu>
6ade8b0a
JW
5 * Modified: Joshua Wise <jwise>
6 * Modified: Chris Lu <czl>
12aa4087
JW
7 *)
8
9signature TYPE_CHECK =
10sig
11 (* prints error message and raises ErrorMsg.error if error found *)
0a24e44d 12 val typecheck : Ast.program -> Ast.program
5c79bb68 13 val typeof : Ast.program -> Type.vtype Symbol.table -> Mark.ext option -> Ast.exp -> Type.vtype
12aa4087
JW
14end;
15
16structure TypeChecker :> TYPE_CHECK =
17struct
18 structure A = Ast
1144856b 19 structure AU = AstUtils
5c79bb68 20 structure T = Type
1144856b
JW
21
22 fun typeof (tds, funcs) vars mark e =
23 ( case e
24 of A.Var a => (case Symbol.look vars a
25 of NONE => (ErrorMsg.error mark ("variable `"^(Symbol.name a)^"' not declared here") ; raise ErrorMsg.Error)
26 | SOME t => t)
5c79bb68 27 | A.ConstExp _ => T.Int
1144856b
JW
28 | A.OpExp (A.EQ, [a, b]) =>
29 (case (typeof (tds, funcs) vars mark a, typeof (tds, funcs) vars mark b)
5c79bb68 30 of (T.Int, T.Int) => T.Int (* You shall pass! *)
1144856b 31 | (a', b') =>
5c79bb68
JW
32 if (T.typeeq (a', T.TNull) andalso T.castable (b', T.TNull)) orelse
33 (T.typeeq (b', T.TNull) andalso T.castable (a', T.TNull)) orelse
34 (T.typeeq (a', b'))
35 then T.Int
36 else (ErrorMsg.error mark ("incorrect types for equality opexp:" ^ T.Print.pp_type a' ^ ", " ^ T.Print.pp_type b') ; raise ErrorMsg.Error ))
1144856b
JW
37 | A.OpExp (A.NEQ, el) => typeof (tds, funcs) vars mark (A.OpExp (A.EQ, el))
38 | A.OpExp (_, el) => (List.app
39 (fn e =>
40 (case (typeof (tds, funcs) vars mark e)
5c79bb68 41 of T.Int => ()
1144856b 42 | _ => (ErrorMsg.error mark ("incorrect type for opexp; needed int") ; raise ErrorMsg.Error)))
5c79bb68 43 el ; T.Int)
1144856b
JW
44 | A.Marked e => typeof (tds, funcs) vars (Mark.ext e) (Mark.data e)
45 | A.FuncCall (i, exps) =>
46 let
47 val func = (case Symbol.look funcs i
48 of NONE => (ErrorMsg.error mark ("function `"^(Symbol.name i)^"' not declared") ; raise ErrorMsg.Error)
49 | SOME f => f)
50 val funcmark = AU.Function.mark func
51 val (ftype, fparams) = (AU.Function.returntype func, AU.Function.params func)
52 val exptypes = List.map (fn znt => typeof (tds, funcs) vars mark znt) exps
53 val () = if (length exptypes = length fparams) then ()
54 else (ErrorMsg.error mark ("call to function `"^(Symbol.name i)^"' has incorrect parameter count [you must construct additional tycons]") ; raise ErrorMsg.Error)
55 val () = List.app
56 (fn (t, (i, t')) =>
5c79bb68 57 if not (T.castable (t', t))
1144856b
JW
58 then (ErrorMsg.error mark ("parameter `"^(Symbol.name i)^"' in function call has wrong type [you must construct additional tycons]") ; raise ErrorMsg.Error)
59 else ())
60 (ListPair.zip (exptypes, fparams))
61 in
62 ftype
63 end
64 | A.Member (e, i) =>
65 let
66 val t = typeof (tds, funcs) vars mark e
67 val name = case t
5c79bb68 68 of (T.Typedef i) => i
1144856b
JW
69 | _ => (ErrorMsg.error mark ("member operation only exists for struct types") ; raise ErrorMsg.Error)
70 val s = case Symbol.look tds name
71 of SOME s => s
72 | NONE => (ErrorMsg.error mark ("undefined structure `"^(Symbol.name name)^"' in type") ; raise ErrorMsg.Error)
5c79bb68 73 val (s, smark) = (T.defdata s, T.defmark s)
1144856b 74 val vl = case s
5c79bb68 75 of T.Struct vl => vl
1144856b
JW
76 | _ => raise ErrorMsg.InternalError "mark of marked typedef?"
77 val t = case (List.find (fn (i', t) => (Symbol.name i = Symbol.name i')) vl)
78 of SOME (_, t) => t
79 | NONE => (ErrorMsg.error mark ("undefined member `"^(Symbol.name i)^"' in struct") ; ErrorMsg.error smark ("struct `"^(Symbol.name name)^"' defined here") ; raise ErrorMsg.Error)
80 in
81 t
82 end
83 | A.DerefMember (e, i) =>
84 let
85 val t = typeof (tds, funcs) vars mark e
86 val name = case t
5c79bb68 87 of (T.Pointer (T.Typedef i)) => i
1144856b
JW
88 | _ => (ErrorMsg.error mark ("dereference and member operation only exists for struct pointer types") ; raise ErrorMsg.Error)
89 val s = case Symbol.look tds name
90 of SOME s => s
91 | NONE => (ErrorMsg.error mark ("undefined structure `"^(Symbol.name name)^"' in type") ; raise ErrorMsg.Error)
92 val (s, smark) = case s
5c79bb68
JW
93 of T.Struct vl => (s, NONE)
94 | T.MarkedTypedef m => (Mark.data m, Mark.ext m)
1144856b 95 val vl = case s
5c79bb68 96 of T.Struct vl => vl
1144856b
JW
97 | _ => raise ErrorMsg.InternalError "mark of marked typedef?"
98 val t = case (List.find (fn (i', t) => (Symbol.name i = Symbol.name i')) vl)
99 of SOME (_, t) => t
100 | NONE => (ErrorMsg.error mark ("undefined member `"^(Symbol.name i)^"' in struct") ; ErrorMsg.error smark ("struct `"^(Symbol.name name)^"' defined here") ; raise ErrorMsg.Error)
101 in
102 t
103 end
104 | A.Dereference e =>
105 (case typeof (tds, funcs) vars mark e
5c79bb68 106 of (T.Pointer e') => e'
1144856b
JW
107 | _ => (ErrorMsg.error mark ("cannot deference non-pointer type") ; raise ErrorMsg.Error))
108 | A.ArrIndex (e, i) =>
109 (case (typeof (tds, funcs) vars mark e, typeof (tds, funcs) vars mark i)
5c79bb68
JW
110 of (T.Array e', T.Int) => e'
111 | (_, T.Int) => (ErrorMsg.error mark ("cannot index non-array type") ; raise ErrorMsg.Error)
1144856b 112 | _ => (ErrorMsg.error mark ("cannot index using non-int type") ; raise ErrorMsg.Error))
5c79bb68 113 | A.New (t) => T.Pointer t
1144856b
JW
114 | A.NewArr (t, s) =>
115 (case typeof (tds, funcs) vars mark s
5c79bb68 116 of T.Int => (T.Array t)
1144856b 117 | _ => (ErrorMsg.error mark ("cannot specify non-int array dimension") ; raise ErrorMsg.Error))
5c79bb68
JW
118 | A.Null => T.TNull
119 | A.Conditional (q, e1, e2) =>
120 let
121 val _ = case typeof (tds, funcs) vars mark q
122 of T.Int => ()
123 | _ => (ErrorMsg.error mark ("ternary condition not of Int type") ; raise ErrorMsg.Error)
124 val t1 = typeof (tds, funcs) vars mark e1
125 val t2 = typeof (tds, funcs) vars mark e2
126 in
127 if (T.typeeq (t1, t2) orelse T.castable (t1, t2))
128 then t1
129 else if (T.castable (t2, t1))
130 then t2
131 else (ErrorMsg.error mark ("ternary types do not agree [you must construct additional tycons]") ; raise ErrorMsg.Error)
132 end
1144856b 133 )
6ade8b0a
JW
134
135 datatype asn = ASSIGNED | UNASSIGNED
12aa4087 136
1144856b
JW
137 (* returncheck prog vars mark t l
138 * Determines if the statement list 'l' is guaranteed to return vtype 't'.
139 * If it ever does not return vtype 't', then raises an error.
140 * true if vtype 't' is always returned, or false if there is a possibility that vtype 't' will not be returned.
141 *)
142 fun returncheck prog vars mark t l =
143 let
144 fun returns' nil = false
145 | returns' (A.Assign _ :: stms) = returns' stms
146 | returns' (A.AsnOp _ :: stms) = returns' stms
147 | returns' (A.Effect _ :: stms) = returns' stms
148 | returns' (A.Return e :: stms) =
5c79bb68 149 if (T.castable (t, typeof prog vars mark e))
1144856b
JW
150 then true
151 else (ErrorMsg.error mark ("return value of incorrect type for function") ; raise ErrorMsg.Error)
152 | returns' (A.Nop :: stms) = returns' stms
153 | returns' (A.Break :: stms) = true (* blah *)
154 | returns' (A.Continue :: stms) = true (* blah *)
155 | returns' (A.If (_, s1, NONE) :: stms) = returns' stms
156 | returns' (A.If (_, s1, SOME s2) :: stms) = (returns' s1 andalso returns' s2) orelse returns' stms
157 | returns' (A.For _ :: stms) = returns' stms
158 | returns' (A.While _ :: stms) = returns' stms
159 | returns' (A.MarkedStm m :: stms) = returncheck prog vars (Mark.ext m) t (Mark.kane m :: stms)
160 in
161 returns' l
162 end
163
164 (* returns l
165 * true iff the statement list 'l' always returns.
166 *)
0a24e44d
JW
167 fun returns nil = false
168 | returns (A.Assign _ :: stms) = returns stms
1144856b
JW
169 | returns (A.AsnOp _ :: stms) = returns stms
170 | returns (A.Effect _ :: stms) = returns stms
171 | returns (A.Return e :: stms) = true
0a24e44d
JW
172 | returns (A.Nop :: stms) = returns stms
173 | returns (A.Break :: stms) = true (* blah *)
174 | returns (A.Continue :: stms) = true (* blah *)
175 | returns (A.If (_, s1, NONE) :: stms) = returns stms
176 | returns (A.If (_, s1, SOME s2) :: stms) = (returns s1 andalso returns s2) orelse returns stms
177 | returns (A.For _ :: stms) = returns stms
178 | returns (A.While _ :: stms) = returns stms
6ade8b0a 179 | returns (A.MarkedStm m :: stms) = returns (Mark.kane m :: stms)
0a24e44d 180
1144856b
JW
181 (* breakcheck l mark
182 * Throws an error exception if a break or continue ever occurs in an illegal context.
183 *)
0a24e44d
JW
184 fun breakcheck nil mark = ()
185 | breakcheck (A.Break :: stms) mark = ( ErrorMsg.error mark ("Illegal break outside loop") ;
186 raise ErrorMsg.Error )
187 | breakcheck (A.Continue :: stms) mark = ( ErrorMsg.error mark ("Illegal continue outside loop") ;
188 raise ErrorMsg.Error )
189 | breakcheck (A.If (_, s1, NONE) :: stms) mark =
190 ( breakcheck s1 mark;
191 breakcheck stms mark)
192 | breakcheck (A.If (_, s1, SOME s2) :: stms) mark =
193 ( breakcheck s1 mark;
194 breakcheck s2 mark;
195 breakcheck stms mark)
6ade8b0a 196 | breakcheck (A.MarkedStm m :: stms) mark = (breakcheck [(Mark.kane m)] (Mark.ext m); breakcheck stms mark)
0a24e44d
JW
197 | breakcheck (_ :: stms) mark = breakcheck stms mark
198
1144856b
JW
199 (* varcheck_exp env exp mark
200 * Throws an error exception if a variable used in this excpression was unassigned or undefined in this context.
201 *)
202 fun varcheck_exp env (A.Var v) mark =
0a24e44d
JW
203 ( case Symbol.look env v
204 of NONE => ( ErrorMsg.error mark ("undefined variable `" ^ Symbol.name v ^ "'") ;
205 raise ErrorMsg.Error )
1144856b 206 | SOME UNASSIGNED => ( ErrorMsg.error mark ("usage of unassigned variable `" ^ Symbol.name v ^ "'") ;
6ade8b0a 207 raise ErrorMsg.Error )
1144856b
JW
208 | SOME ASSIGNED => ())
209 | varcheck_exp env (A.ConstExp _) mark = ()
210 | varcheck_exp env (A.OpExp (_, l)) mark = List.app (fn znt => varcheck_exp env znt mark) l
211 | varcheck_exp env (A.FuncCall (f, l)) mark = List.app (fn znt => varcheck_exp env znt mark) l
212 | varcheck_exp env (A.Marked m) mark = varcheck_exp env (Mark.kane m) (Mark.ext m)
213 | varcheck_exp env (A.Member (e, i)) mark = varcheck_exp env e mark
214 | varcheck_exp env (A.DerefMember (e, i)) mark = varcheck_exp env e mark
215 | varcheck_exp env (A.Dereference e) mark = varcheck_exp env e mark
216 | varcheck_exp env (A.ArrIndex (e1, e2)) mark = (varcheck_exp env e1 mark ; varcheck_exp env e2 mark)
217 | varcheck_exp env (A.New _) mark = ()
218 | varcheck_exp env (A.NewArr (_, e)) mark = varcheck_exp env e mark
219 | varcheck_exp env (A.Null) mark = ()
5c79bb68 220 | varcheck_exp env (A.Conditional (q, e1, e2)) mark = (varcheck_exp env q mark ; varcheck_exp env e1 mark ; varcheck_exp env e2 mark)
0a24e44d 221
1144856b
JW
222 (* computeassigns env exp
223 * Computes the assigned variables after expression exp has been executed with a starting context of env.
224 *)
0a24e44d 225 fun computeassigns env nil = env
1144856b
JW
226 | computeassigns env (A.Assign (A.Var id,e) :: stms) =
227 computeassigns (Symbol.bind env (id, ASSIGNED)) stms
228 | computeassigns env (A.Assign (A.Marked a, e) :: stms) =
229 computeassigns env (A.Assign (Mark.data a, e) :: stms)
230 | computeassigns env (A.AsnOp (oper, a, e) :: stms) =
231 computeassigns env (A.Assign (a, a) :: stms)
232 | computeassigns env (A.Assign (_) :: stms) = computeassigns env stms
233 | computeassigns env (A.Effect _ :: stms) = computeassigns env stms
0a24e44d
JW
234 | computeassigns env (A.Return _ :: stms) = env
235 | computeassigns env (A.Nop :: stms) = computeassigns env stms
236 | computeassigns env (A.Break :: stms) = env
237 | computeassigns env (A.Continue :: stms) = env
238 | computeassigns env (A.If (e, s1, NONE) :: stms) = computeassigns env stms
239 | computeassigns env (A.If (e, s1, SOME s2) :: stms) =
240 let
241 val env1 = computeassigns env s1
242 val env2 = computeassigns env s2
6ade8b0a
JW
243 val env' =
244 Symbol.intersect
1144856b
JW
245 (fn (ASSIGNED, ASSIGNED) => ASSIGNED
246 | _ => UNASSIGNED)
6ade8b0a 247 (env1, env2)
0a24e44d
JW
248 val env' =
249 if (returns s1) then env2
250 else if (returns s2) then env1
251 else env'
252 in
253 computeassigns env' stms
254 end
255 | computeassigns env (A.While (e, s1) :: stms) = computeassigns env stms
256 | computeassigns env (A.For (sbegin, e, sloop, inner) :: stms) =
257 let
258 val env' = case sbegin
259 of SOME(s) => computeassigns env [s]
260 | NONE => env
261 in
262 computeassigns env' stms
263 end
6ade8b0a 264 | computeassigns env (A.MarkedStm m :: stms) = computeassigns env ((Mark.kane m) :: stms)
0a24e44d 265
1144856b
JW
266 (* varcheck env l mark
267 * Checks that all variables used in the statement list l have been defined before being used, and removes code that is unreachable according to simple return analysis.
268 *)
269 fun varcheck env nil mark = nil
270 | varcheck env (A.Assign (A.Var id, e) :: stms) mark =
6ade8b0a
JW
271 let
272 val sym = Symbol.look env id
273 val _ = if not (isSome sym)
274 then (ErrorMsg.error mark ("assignment to undeclared variable " ^ (Symbol.name id)); raise ErrorMsg.Error)
275 else ()
1144856b
JW
276 val t = valOf sym
277 val _ = varcheck_exp env e mark
6ade8b0a 278 in
1144856b 279 A.Assign (A.Var id, e) :: (varcheck (Symbol.bind env (id, ASSIGNED)) stms mark)
6ade8b0a 280 end
1144856b
JW
281 | varcheck env (A.Assign (A.Marked a, e) :: stms) mark = varcheck env (A.Assign (Mark.data a, e) :: stms) mark
282 | varcheck env ((a as A.Assign (A.Member (e', i), e)) :: stms) mark =
283 (varcheck_exp env e' mark ;
284 varcheck_exp env e mark ;
285 a :: varcheck env stms mark)
286 | varcheck env ((a as A.Assign (A.DerefMember (e', i), e)) :: stms) mark =
287 (varcheck_exp env e' mark ;
288 varcheck_exp env e mark ;
289 a :: varcheck env stms mark)
290 | varcheck env ((a as A.Assign (A.Dereference e', e)) :: stms) mark =
291 (varcheck_exp env e' mark ;
292 varcheck_exp env e mark ;
293 a :: varcheck env stms mark)
294 | varcheck env ((a as A.Assign (A.ArrIndex (e', e''), e)) :: stms) mark =
295 (varcheck_exp env e' mark ;
296 varcheck_exp env e'' mark ;
297 varcheck_exp env e mark ;
298 a :: varcheck env stms mark)
299 | varcheck env ((a as A.Assign (A.NewArr (_, e'), e)) :: stms) mark =
300 (varcheck_exp env e' mark ;
301 varcheck_exp env e mark ;
302 a :: varcheck env stms mark)
303 | varcheck env ((A.Assign _) :: stms) mark = raise ErrorMsg.InternalError "assign to non lvalue"
5c79bb68 304 | varcheck env ((a as A.AsnOp (oper, e1, e2)) :: stms) mark = ( varcheck_exp env e1 mark ; varcheck_exp env e2 mark ; a :: varcheck env stms mark )
1144856b
JW
305 | varcheck env ((a as A.Effect e) :: stms) mark = (varcheck_exp env e mark ; a :: varcheck env stms mark)
306 | varcheck env (A.Return (e) :: stms) mark =
307 ( varcheck_exp env e mark;
0a24e44d 308 A.Return (e) :: nil )
1144856b
JW
309 | varcheck env (A.Nop :: stms) mark =
310 ( A.Nop :: (varcheck env stms mark))
311 | varcheck env (A.Break :: stms) mark =
0a24e44d 312 ( A.Break :: nil )
1144856b 313 | varcheck env (A.Continue :: stms) mark =
0a24e44d 314 ( A.Continue :: nil )
1144856b
JW
315 | varcheck env (A.If (e, s1, NONE) :: stms) mark =
316 ( varcheck_exp env e mark ;
317 varcheck env s1 mark ;
318 A.If (e, s1, NONE) :: (varcheck env stms mark) )
319 | varcheck env ((i as A.If (e, s1, SOME s2)) :: stms) mark =
320 ( varcheck_exp env e mark ;
321 varcheck env s1 mark ;
322 varcheck env s2 mark ;
0a24e44d
JW
323 A.If (e, s1, SOME s2) ::
324 (if (returns [i])
325 then nil
1144856b
JW
326 else varcheck (computeassigns env [i]) stms mark) )
327 | varcheck env (A.While (e, s1) :: stms) mark =
328 ( varcheck_exp env e mark ;
329 varcheck env s1 mark ;
330 A.While (e, s1) :: (varcheck env stms mark) )
331 | varcheck env (A.For (sbegin, e, sloop, inner) :: stms) mark =
0a24e44d
JW
332 let
333 val sbegin = case sbegin
1144856b 334 of SOME(s) => SOME (hd (varcheck env [s] mark))
0a24e44d
JW
335 | NONE => NONE
336 val env' = case sbegin
337 of SOME(s) => computeassigns env [s]
338 | NONE => env
5c79bb68 339 val _ = varcheck_exp env' e mark
1144856b 340 val inner = varcheck env' inner mark
0a24e44d
JW
341 val env'' = computeassigns env' inner
342 val sloop = case sloop
1144856b 343 of SOME(s) => SOME (hd (varcheck env'' [s] mark))
0a24e44d
JW
344 | NONE => NONE
345 in
1144856b 346 A.For (sbegin, e, sloop, inner) :: (varcheck env' stms mark)
0a24e44d 347 end
1144856b 348 | varcheck env (A.MarkedStm m :: stms) mark = varcheck env ((Mark.kane m) :: stms) (Mark.ext m)
12aa4087 349
1144856b
JW
350 fun bindvars sym stat l = foldr (fn ((i,t), s) => Symbol.bind s (i,stat)) sym l
351 fun bindtypes sym l = foldr (fn ((i,t), s) => Symbol.bind s (i,t)) sym l
6ade8b0a 352
1144856b 353 fun dupchk mark l src =
6ade8b0a
JW
354 List.app
355 (fn (n, _) =>
356 let
357 val name = Symbol.name n
358 val all = List.filter (fn (n', _) => name = (Symbol.name n')) l
359 val count = length all
360 in
361 if count = 1
362 then ()
1144856b 363 else ( ErrorMsg.error mark ("multiple definition of variable " ^ (Symbol.name n) ^ " in " ^ src);
6ade8b0a
JW
364 raise ErrorMsg.Error )
365 end) l
1144856b
JW
366
367 fun check_lvalue prog vars mark (A.Marked m) = check_lvalue prog vars (Mark.ext m) (Mark.data m)
368 | check_lvalue prog vars mark (e as A.Var _) = typeof prog vars mark e
369 | check_lvalue prog vars mark (e as A.Member _) = typeof prog vars mark e
370 | check_lvalue prog vars mark (e as A.DerefMember _) = typeof prog vars mark e
371 | check_lvalue prog vars mark (e as A.Dereference _) = typeof prog vars mark e
372 | check_lvalue prog vars mark (e as A.ArrIndex _) = typeof prog vars mark e
373 | check_lvalue prog vars mark _ = ( ErrorMsg.error mark ("invalid lvalue") ; raise ErrorMsg.Error )
374 fun typecheck_stm prog vars mark stm =
375 case stm
376 of A.Assign (e1, e2) =>
5c79bb68 377 if not (T.castable (check_lvalue prog vars mark e1, typeof prog vars mark e2))
1144856b 378 then (ErrorMsg.error mark "incompatible types in assignment" ; raise ErrorMsg.Error )
5c79bb68 379 else if not (T.issmall (check_lvalue prog vars mark e1))
1144856b
JW
380 then (ErrorMsg.error mark "lvalue is not small" ; raise ErrorMsg.Error)
381 else ()
382 | A.AsnOp (oper, e1, e2) => typecheck_stm prog vars mark (A.Assign (e1, A.OpExp (oper, [e1, e2])))
383 | A.Effect e =>
5c79bb68 384 if not (T.issmall (typeof prog vars mark e))
1144856b
JW
385 then (ErrorMsg.error mark "simple statement's value not small" ; raise ErrorMsg.Error )
386 else ()
387 | A.Return e => (typeof prog vars mark e ; ())
388 | A.Nop => ()
389 | A.Break => ()
390 | A.Continue => ()
391 | A.If (e, s, NONE) =>
5c79bb68 392 if T.castable (T.Int, typeof prog vars mark e)
1144856b
JW
393 then (List.app (typecheck_stm prog vars mark) s)
394 else (ErrorMsg.error mark "conditional in if statement is not of int type" ; raise ErrorMsg.Error )
395 | A.If (e, s1, SOME s2) =>
5c79bb68 396 if T.castable (T.Int, typeof prog vars mark e)
1144856b
JW
397 then (List.app (typecheck_stm prog vars mark) s1 ; List.app (typecheck_stm prog vars mark) s2)
398 else (ErrorMsg.error mark "conditional in if statement is not of int type" ; raise ErrorMsg.Error )
399 | A.For (sbegin, e, sloop, s) =>
5c79bb68 400 if T.castable (T.Int, typeof prog vars mark e)
1144856b
JW
401 then (List.app (typecheck_stm prog vars mark) ((case sbegin of SOME l => [l] | NONE => nil) @ (case sloop of SOME l => [l] | NONE => nil) @ s))
402 else (ErrorMsg.error mark "conditional in for statement is not of int type" ; raise ErrorMsg.Error )
403 | A.While (e, s) =>
5c79bb68 404 if T.castable (T.Int, typeof prog vars mark e)
1144856b
JW
405 then (List.app (typecheck_stm prog vars mark) s)
406 else (ErrorMsg.error mark "conditional in while statement is not of int type" ; raise ErrorMsg.Error )
407 | A.MarkedStm (m) => typecheck_stm prog vars (Mark.ext m) (Mark.data m)
408
409 (* XXX does not check big vs. small types *)
5c79bb68
JW
410 fun typecheck_type (tds, funcs) mark T.Int = ()
411 | typecheck_type (tds, funcs) mark T.TNull = ()
412 | typecheck_type (tds, funcs) mark (T.Pointer t) = typecheck_type (tds, funcs) mark t
413 | typecheck_type (tds, funcs) mark (T.Array t) = typecheck_type (tds, funcs) mark t
414 | typecheck_type (tds, funcs) mark (T.Typedef t) =
1144856b
JW
415 case (Symbol.look tds t)
416 of SOME _ => ()
417 | NONE => (ErrorMsg.error mark ("typedef `"^(Symbol.name t)^"' does not exist") ; raise ErrorMsg.Error)
6ade8b0a 418
1144856b
JW
419 fun typecheck_fn prog _ (id, A.MarkedFunction m) = typecheck_fn prog (Mark.ext m) (id, Mark.data m)
420 | typecheck_fn (prog as (tds, funcs)) mark (id, A.Extern (t, al)) =
5c79bb68 421 (if (String.isPrefix "_l5_" (Symbol.name id))
1144856b
JW
422 then
423 let
424 val n = String.extract (Symbol.name id, 4, NONE)
425 in
426 if List.exists (fn (id, f) => case (AU.Function.data f) of A.Function _ => (Symbol.name id = n) | _ => false) (Symbol.elemsi funcs)
427 then (ErrorMsg.error mark ("you anus, extern " ^ Symbol.name id ^ " conflicts with local function"); raise ErrorMsg.Error)
428 else ()
429 end
430 else () ;
431 dupchk mark al ;
432 List.app (typecheck_type prog mark) (List.map (fn (_, t) => t) al) ;
433 A.Extern (t, al))
434 | typecheck_fn prog mark (id, A.Function (t, al, vl, sl)) =
6ade8b0a 435 let
1144856b
JW
436 val () = dupchk mark (al @ vl) ("function `"^Symbol.name id^"'") (* Before we do any bindings, check for duplicate names. *)
437 val () = List.app (typecheck_type prog mark) (List.map (fn (_, t) => t) (al @ vl))
6ade8b0a
JW
438 val env = Symbol.empty
439 val env = bindvars env ASSIGNED al
440 val env = bindvars env UNASSIGNED vl
1144856b
JW
441 val vars = Symbol.empty
442 val vars = bindtypes vars al
443 val vars = bindtypes vars vl
444 val () = breakcheck sl mark
445 val () = if not (returncheck prog vars NONE t sl)
446 then ( ErrorMsg.error mark ("function `"^ Symbol.name id ^ "' does not return in all cases");
447 raise ErrorMsg.Error )
448 else ()
449 val () = List.app (
450 fn (n, t) =>
5c79bb68 451 if (T.issmall t)
1144856b
JW
452 then ()
453 else ( ErrorMsg.error mark ("variable `"^(Symbol.name n)^"' in function `"^(Symbol.name id)^"' not small") ; raise ErrorMsg.Error))
454 (al @ vl)
455 val () = List.app (typecheck_stm prog vars mark) sl
6ade8b0a 456 in
1144856b 457 A.Function (t, al, vl, varcheck env sl NONE)
6ade8b0a 458 end
1144856b
JW
459
460 structure SymbolSet = ListSetFn (
461 struct
462 type ord_key = Symbol.symbol
463 val compare = Symbol.compare
464 end
465 )
466
467 fun typecheck_structs (prog as (tds, funcs)) =
468 let
469 exception Yuq
470
471 val all = SymbolSet.addList (SymbolSet.empty, Symbol.keys tds)
472 fun lookup mark sym =
473 let
474 val s = case Symbol.look tds sym
475 of SOME a => a
476 | NONE => (ErrorMsg.error mark ("typedef `"^(Symbol.name sym)^"' does not exist") ; raise ErrorMsg.Error)
5c79bb68
JW
477 val vl = case T.defdata s
478 of T.Struct vl => vl
479 | T.MarkedTypedef v => raise ErrorMsg.InternalError "data returned marked type"
1144856b 480 in
5c79bb68 481 (vl, T.defmark s)
1144856b
JW
482 end
483 fun checksym mark sym stack k remaining =
484 if not (SymbolSet.member (remaining, sym))
485 then k remaining
486 else if (SymbolSet.member (stack, sym))
487 then ( ErrorMsg.error mark ("structure `"^ (Symbol.name sym) ^"' is involved in a recursive mess") ; raise Yuq)
488 else
489 let
490 val stack' = SymbolSet.add (stack, sym)
491 val (vl, mark') = lookup mark sym
492 val () = dupchk mark vl ("structure `"^(Symbol.name sym)^"'")
493 fun remove k remaining' = k (SymbolSet.delete (remaining', sym))
494 val newk = (* OH GOD D: *)
495 foldr
5c79bb68 496 (fn ((_, T.Typedef s), k') => checksym mark' s stack' k'
1144856b
JW
497 | (_, k') => k')
498 (remove k)
499 vl
500 in
501 newk remaining handle Yuq => (ErrorMsg.error mark' ("from structure `"^(Symbol.name sym)^"'") ; raise Yuq)
502 end
503 fun chooseone k set =
504 case (SymbolSet.listItems set)
505 of nil => k set
506 | (h::l) => checksym NONE h SymbolSet.empty (chooseone k) set
507 in
508 chooseone (fn _ => ()) all handle Yuq => raise ErrorMsg.Error
509 end
6ade8b0a 510
1144856b 511 fun typecheck (tds, funcs) =
6ade8b0a 512 let
1144856b 513 val main = case (Symbol.look funcs (Symbol.symbol "main"))
6ade8b0a
JW
514 of NONE => ( ErrorMsg.error NONE ("no function named main");
515 raise ErrorMsg.Error )
516 | SOME m => m
1144856b 517 val (main, mainp) = (AU.Function.data main, AU.Function.mark main)
6ade8b0a 518 val () = case main
1144856b 519 of A.Extern _ => ( ErrorMsg.error mainp ("you anus, main can't be an extern");
6ade8b0a 520 raise ErrorMsg.Error )
5c79bb68
JW
521 | A.Function (T.Int, nil, _, _) => ()
522 | A.Function (T.Int, _, _, _) => ( ErrorMsg.error mainp ("main should take no parameters");
6ade8b0a 523 raise ErrorMsg.Error )
1144856b
JW
524 | A.Function (_, _, _, _) => ( ErrorMsg.error mainp ("main has incorrect return type");
525 raise ErrorMsg.Error )
526 | _ => raise ErrorMsg.InternalError "marked of marked disallowed"
527 val () = typecheck_structs (tds, funcs)
6ade8b0a 528 in
1144856b 529 (tds, Symbol.mapi (typecheck_fn (tds, funcs) NONE) funcs)
6ade8b0a 530 end
12aa4087 531end
This page took 0.072432 seconds and 4 git commands to generate.