3 * Author: Alex Vaynberg <alv@andrew.cmu.edu>
4 * Modified: Frank Pfenning <fp@cs.cmu.edu>
6 * Simple typechecker that is based on a unit Symbol.table
7 * This is all that is needed since there is only an integer type present
10 signature TYPE_CHECK =
12 (* prints error message and raises ErrorMsg.error if error found *)
13 val typecheck : Ast.program -> Ast.program
16 structure TypeChecker :> TYPE_CHECK =
20 fun returns nil = false
21 | returns (A.Assign _ :: stms) = returns stms
22 | returns (A.Return _ :: stms) = true
23 | returns (A.Nop :: stms) = returns stms
24 | returns (A.Break :: stms) = true (* blah *)
25 | returns (A.Continue :: stms) = true (* blah *)
26 | returns (A.If (_, s1, NONE) :: stms) = returns stms
27 | returns (A.If (_, s1, SOME s2) :: stms) = (returns s1 andalso returns s2) orelse returns stms
28 | returns (A.For _ :: stms) = returns stms
29 | returns (A.While _ :: stms) = returns stms
30 | returns (A.MarkedStm m :: stms) = returns (Mark.data m :: stms)
32 fun breakcheck nil mark = ()
33 | breakcheck (A.Break :: stms) mark = ( ErrorMsg.error mark ("Illegal break outside loop") ;
34 raise ErrorMsg.Error )
35 | breakcheck (A.Continue :: stms) mark = ( ErrorMsg.error mark ("Illegal continue outside loop") ;
36 raise ErrorMsg.Error )
37 | breakcheck (A.If (_, s1, NONE) :: stms) mark =
40 | breakcheck (A.If (_, s1, SOME s2) :: stms) mark =
44 | breakcheck (A.MarkedStm m :: stms) mark = (breakcheck [(Mark.data m)] (Mark.ext m); breakcheck stms mark)
45 | breakcheck (_ :: stms) mark = breakcheck stms mark
47 fun varcheck_exp env (A.Var v) mark =
48 ( case Symbol.look env v
49 of NONE => ( ErrorMsg.error mark ("undefined variable `" ^ Symbol.name v ^ "'") ;
50 raise ErrorMsg.Error )
52 | varcheck_exp env (A.ConstExp _) mark = ()
53 | varcheck_exp env (A.OpExp (_, l)) mark = List.app (fn znt => varcheck_exp env znt mark) l
54 | varcheck_exp env (A.Marked m) mark = varcheck_exp env (Mark.data m) (Mark.ext m)
56 fun computeassigns env nil = env
57 | computeassigns env (A.Assign (id,e) :: stms) =
58 computeassigns (Symbol.bind env (id, ())) stms
59 | computeassigns env (A.Return _ :: stms) = env
60 | computeassigns env (A.Nop :: stms) = computeassigns env stms
61 | computeassigns env (A.Break :: stms) = env
62 | computeassigns env (A.Continue :: stms) = env
63 | computeassigns env (A.If (e, s1, NONE) :: stms) = computeassigns env stms
64 | computeassigns env (A.If (e, s1, SOME s2) :: stms) =
66 val env1 = computeassigns env s1
67 val env2 = computeassigns env s2
68 val env' = Symbol.intersect (env1, env2)
70 if (returns s1) then env2
71 else if (returns s2) then env1
74 computeassigns env' stms
76 | computeassigns env (A.While (e, s1) :: stms) = computeassigns env stms
77 | computeassigns env (A.For (sbegin, e, sloop, inner) :: stms) =
79 val env' = case sbegin
80 of SOME(s) => computeassigns env [s]
83 computeassigns env' stms
85 | computeassigns env (A.MarkedStm m :: stms) = computeassigns env ((Mark.data m) :: stms)
87 fun varcheck env nil mark = nil
88 | varcheck env (A.Assign (id, e) :: stms) mark =
89 ( varcheck_exp env e mark ;
90 A.Assign (id, e) :: (varcheck (Symbol.bind env (id, ())) stms mark) )
91 | varcheck env (A.Return (e) :: stms) mark =
92 ( varcheck_exp env e mark;
94 | varcheck env (A.Nop :: stms) mark =
95 ( A.Nop :: (varcheck env stms mark))
96 | varcheck env (A.Break :: stms) mark =
98 | varcheck env (A.Continue :: stms) mark =
100 | varcheck env (A.If (e, s1, NONE) :: stms) mark =
101 ( varcheck_exp env e mark ;
102 varcheck env s1 mark ;
103 A.If (e, s1, NONE) :: (varcheck env stms mark) )
104 | varcheck env ((i as A.If (e, s1, SOME s2)) :: stms) mark =
105 ( varcheck_exp env e mark ;
106 varcheck env s1 mark ;
107 varcheck env s2 mark ;
108 A.If (e, s1, SOME s2) ::
111 else varcheck (computeassigns env [i]) stms mark) )
112 | varcheck env (A.While (e, s1) :: stms) mark =
113 ( varcheck_exp env e mark ;
114 varcheck env s1 mark ;
115 A.While (e, s1) :: (varcheck env stms mark) )
116 | varcheck env (A.For (sbegin, e, sloop, inner) :: stms) mark =
118 val sbegin = case sbegin
119 of SOME(s) => SOME (hd (varcheck env [s] mark))
121 val env' = case sbegin
122 of SOME(s) => computeassigns env [s]
124 val _ = varcheck_exp env' e
125 val inner = varcheck env' inner mark
126 val env'' = computeassigns env' inner
127 val sloop = case sloop
128 of SOME(s) => SOME (hd (varcheck env'' [s] mark))
131 A.For (sbegin, e, sloop, inner) :: (varcheck env' stms mark)
133 | varcheck env (A.MarkedStm m :: stms) mark = varcheck env ((Mark.data m) :: stms) (Mark.ext m)
136 ( breakcheck prog NONE ;
137 if not (returns prog)
138 then (ErrorMsg.error NONE ("program does not return in all cases"); raise ErrorMsg.Error)
139 else varcheck Symbol.empty prog NONE)