1 : |
jhr |
69 |
(* typechecker.sml
|
2 : |
|
|
*
|
3 : |
|
|
* COPYRIGHT (c) 2010 The Diderot Project (http://diderot.cs.uchicago.edu)
|
4 : |
|
|
* All rights reserved.
|
5 : |
jhr |
228 |
*
|
6 : |
jhr |
69 |
*)
|
7 : |
|
|
|
8 : |
|
|
structure Typechecker : sig
|
9 : |
|
|
|
10 : |
jhr |
88 |
exception Error
|
11 : |
|
|
|
12 : |
jhr |
86 |
val check : Error.err_stream -> ParseTree.program -> AST.program
|
13 : |
jhr |
69 |
|
14 : |
|
|
end = struct
|
15 : |
|
|
|
16 : |
jhr |
70 |
structure PT = ParseTree
|
17 : |
jhr |
69 |
structure Ty = Types
|
18 : |
jhr |
96 |
structure TU = TypeUtil
|
19 : |
jhr |
81 |
structure U = Util
|
20 : |
jhr |
69 |
|
21 : |
jhr |
228 |
datatype scope = GlobalScope | ActorScope | MethodScope | InitScope
|
22 : |
jhr |
169 |
|
23 : |
jhr |
228 |
type env = {scope : scope, env : Env.env}
|
24 : |
|
|
|
25 : |
|
|
fun actorScope {scope, env} = {scope=ActorScope, env=env}
|
26 : |
|
|
fun methodScope {scope, env} = {scope=MethodScope, env=env}
|
27 : |
|
|
fun initScope {scope, env} = {scope=InitScope, env=env}
|
28 : |
|
|
|
29 : |
|
|
fun inActor {scope=ActorScope, env} = true
|
30 : |
|
|
| inActor {scope=MethodScope, ...} = true
|
31 : |
|
|
| inActor _ = false
|
32 : |
|
|
|
33 : |
|
|
fun insertLocal ({scope, env}, x, x') = {scope=scope, env=Env.insertLocal(env, x, x')}
|
34 : |
|
|
fun insertGlobal ({scope, env}, x, x') = {scope=scope, env=Env.insertGlobal(env, x, x')}
|
35 : |
|
|
|
36 : |
jhr |
88 |
exception Error
|
37 : |
|
|
|
38 : |
jhr |
86 |
type context = Error.err_stream * Error.span
|
39 : |
|
|
|
40 : |
|
|
fun withContext ((errStrm, _), {span, tree}) =
|
41 : |
|
|
((errStrm, span), tree)
|
42 : |
|
|
fun withEnvAndContext (env, (errStrm, _), {span, tree}) =
|
43 : |
|
|
(env, (errStrm, span), tree)
|
44 : |
|
|
|
45 : |
jhr |
88 |
fun error ((errStrm, span), msg) = (
|
46 : |
|
|
Error.errorAt(errStrm, span, msg);
|
47 : |
|
|
raise Error)
|
48 : |
jhr |
86 |
|
49 : |
jhr |
88 |
datatype token
|
50 : |
|
|
= S of string | A of Atom.atom
|
51 : |
|
|
| V of AST.var | TY of Types.ty | TYS of Types.ty list
|
52 : |
|
|
|
53 : |
|
|
fun err (cxt, toks) = let
|
54 : |
|
|
fun tok2str (S s) = s
|
55 : |
|
|
| tok2str (A a) = Atom.toString a
|
56 : |
|
|
| tok2str (V x) = Var.nameOf x
|
57 : |
jhr |
96 |
| tok2str (TY ty) = TU.toString ty
|
58 : |
jhr |
88 |
| tok2str (TYS []) = "()"
|
59 : |
jhr |
96 |
| tok2str (TYS[ty]) = TU.toString ty
|
60 : |
jhr |
88 |
| tok2str (TYS tys) = String.concat[
|
61 : |
jhr |
96 |
"(", String.concatWith " * " (List.map TU.toString tys), ")"
|
62 : |
jhr |
88 |
]
|
63 : |
|
|
in
|
64 : |
|
|
error(cxt, List.map tok2str toks)
|
65 : |
|
|
end
|
66 : |
|
|
|
67 : |
jhr |
83 |
val realZero = AST.E_Lit(Literal.Float(FloatLit.zero true))
|
68 : |
|
|
|
69 : |
jhr |
70 |
(* check a differentiation level, which muse be >= 0 *)
|
70 : |
|
|
fun checkDiff (cxt, k) =
|
71 : |
|
|
if (k < 0)
|
72 : |
|
|
then raise Fail "differentiation must be >= 0"
|
73 : |
jhr |
75 |
else Ty.DiffConst(IntInf.toInt k)
|
74 : |
jhr |
70 |
|
75 : |
|
|
(* check a dimension, which must be 2 or 3 *)
|
76 : |
|
|
fun checkDim (cxt, d) =
|
77 : |
jhr |
82 |
if (d <= 0)
|
78 : |
|
|
then raise Fail "invalid dimension; must be > 0"
|
79 : |
jhr |
75 |
else Ty.DimConst(IntInf.toInt d)
|
80 : |
jhr |
70 |
|
81 : |
|
|
(* check a shape *)
|
82 : |
|
|
fun checkShape (cxt, shape) = let
|
83 : |
|
|
fun chkDim d = if (d < 1)
|
84 : |
|
|
then raise Fail "invalid shape dimension; must be >= 1"
|
85 : |
jhr |
75 |
else Ty.DimConst(IntInf.toInt d)
|
86 : |
jhr |
70 |
in
|
87 : |
|
|
Ty.Shape(List.map chkDim shape)
|
88 : |
|
|
end
|
89 : |
|
|
|
90 : |
jhr |
69 |
(* check the well-formedness of a type and translate it to an AST type *)
|
91 : |
jhr |
70 |
fun checkTy (cxt, ty) = (case ty
|
92 : |
jhr |
86 |
of PT.T_Mark m => checkTy(withContext(cxt, m))
|
93 : |
jhr |
70 |
| PT.T_Bool => Ty.T_Bool
|
94 : |
|
|
| PT.T_Int => Ty.T_Int
|
95 : |
|
|
| PT.T_Real => Ty.realTy
|
96 : |
|
|
| PT.T_String => Ty.T_String
|
97 : |
|
|
| PT.T_Vec n => (* NOTE: the parser guarantees that 2 <= n <= 4 *)
|
98 : |
|
|
Ty.vecTy(IntInf.toInt n)
|
99 : |
|
|
| PT.T_Kernel k => Ty.T_Kernel(checkDiff(cxt, k))
|
100 : |
|
|
| PT.T_Field{diff, dim, shape} => Ty.T_Field{
|
101 : |
|
|
diff = checkDiff (cxt, diff),
|
102 : |
|
|
dim = checkDim (cxt, dim),
|
103 : |
|
|
shape = checkShape (cxt, shape)
|
104 : |
|
|
}
|
105 : |
|
|
| PT.T_Tensor shape => Ty.T_Tensor(checkShape(cxt, shape))
|
106 : |
|
|
| PT.T_Image{dim, shape} => Ty.T_Image{
|
107 : |
|
|
dim = checkDim (cxt, dim),
|
108 : |
|
|
shape = checkShape (cxt, shape)
|
109 : |
|
|
}
|
110 : |
jhr |
99 |
| PT.T_Array(ty, dims) => raise Fail "Array type not supported"
|
111 : |
jhr |
69 |
(* end case *))
|
112 : |
|
|
|
113 : |
jhr |
71 |
fun checkLit lit = (case lit
|
114 : |
|
|
of (Literal.Int _) => (AST.E_Lit lit, Ty.T_Int)
|
115 : |
|
|
| (Literal.Float _) => (AST.E_Lit lit, Ty.realTy)
|
116 : |
|
|
| (Literal.String s) => (AST.E_Lit lit, Ty.T_String)
|
117 : |
|
|
| (Literal.Bool _) => (AST.E_Lit lit, Ty.T_Bool)
|
118 : |
|
|
(* end case *))
|
119 : |
|
|
|
120 : |
jhr |
85 |
(* resolve overloading: we use a simple scheme that selects the first operator in the
|
121 : |
|
|
* list that matches the argument types.
|
122 : |
|
|
*)
|
123 : |
jhr |
91 |
fun resolveOverload (cxt, rator, argTys, args, candidates) = let
|
124 : |
|
|
fun tryCandidates [] = err(cxt, [
|
125 : |
|
|
S "unable to resolve overloaded operator \"", A rator, S "\"\n",
|
126 : |
|
|
S " argument type is: ", TYS argTys, S "\n"
|
127 : |
jhr |
85 |
])
|
128 : |
|
|
| tryCandidates (x::xs) = let
|
129 : |
|
|
val (tyArgs, Ty.T_Fun(domTy, rngTy)) = Util.instantiate(Var.typeOf x)
|
130 : |
|
|
in
|
131 : |
|
|
if U.tryMatchTypes(domTy, argTys)
|
132 : |
|
|
then (AST.E_Apply(x, tyArgs, args, rngTy), rngTy)
|
133 : |
|
|
else tryCandidates xs
|
134 : |
|
|
end
|
135 : |
|
|
in
|
136 : |
|
|
tryCandidates candidates
|
137 : |
|
|
end
|
138 : |
|
|
|
139 : |
jhr |
70 |
(* typecheck an expression and translate it to AST *)
|
140 : |
jhr |
169 |
fun checkExpr (env : env, cxt, e) = (case e
|
141 : |
jhr |
86 |
of PT.E_Mark m => checkExpr (withEnvAndContext (env, cxt, m))
|
142 : |
jhr |
169 |
| PT.E_Var x => (case Env.findVar (#env env, x)
|
143 : |
jhr |
171 |
of SOME x' => (AST.E_Var x', Var.monoTypeOf x')
|
144 : |
jhr |
88 |
| NONE => err(cxt, [S "undeclared variable ", A x])
|
145 : |
jhr |
71 |
(* end case *))
|
146 : |
|
|
| PT.E_Lit lit => checkLit lit
|
147 : |
jhr |
81 |
| PT.E_OrElse(e1, e2) => let
|
148 : |
|
|
val (e1', ty1) = checkExpr(env, cxt, e1)
|
149 : |
|
|
val (e2', ty2) = checkExpr(env, cxt, e2)
|
150 : |
|
|
in
|
151 : |
|
|
case (ty1, ty2)
|
152 : |
|
|
of (Ty.T_Bool, Ty.T_Bool) =>
|
153 : |
|
|
(AST.E_Cond(e1', AST.E_Lit(Literal.Bool true), e2'), Ty.T_Bool)
|
154 : |
jhr |
99 |
| _ => err (cxt, [S "arguments to \"||\" must have bool type"])
|
155 : |
jhr |
81 |
(* end case *)
|
156 : |
|
|
end
|
157 : |
|
|
| PT.E_AndAlso(e1, e2) => let
|
158 : |
|
|
val (e1', ty1) = checkExpr(env, cxt, e1)
|
159 : |
|
|
val (e2', ty2) = checkExpr(env, cxt, e2)
|
160 : |
|
|
in
|
161 : |
|
|
case (ty1, ty2)
|
162 : |
|
|
of (Ty.T_Bool, Ty.T_Bool) =>
|
163 : |
|
|
(AST.E_Cond(e1', e2', AST.E_Lit(Literal.Bool false)), Ty.T_Bool)
|
164 : |
jhr |
99 |
| _ => err (cxt, [S "arguments to \"&&\" must have bool type"])
|
165 : |
jhr |
81 |
(* end case *)
|
166 : |
|
|
end
|
167 : |
|
|
| PT.E_BinOp(e1, rator, e2) => let
|
168 : |
|
|
val (e1', ty1) = checkExpr(env, cxt, e1)
|
169 : |
|
|
val (e2', ty2) = checkExpr(env, cxt, e2)
|
170 : |
|
|
in
|
171 : |
|
|
case Basis.findOp rator
|
172 : |
|
|
of [rator] => let
|
173 : |
|
|
val (tyArgs, Ty.T_Fun(domTy, rngTy)) = Util.instantiate(Var.typeOf rator)
|
174 : |
|
|
in
|
175 : |
|
|
if U.matchTypes(domTy, [ty1, ty2])
|
176 : |
|
|
then (AST.E_Apply(rator, tyArgs, [e1', e2'], rngTy), rngTy)
|
177 : |
jhr |
89 |
else err (cxt, [
|
178 : |
|
|
S "type error for binary operator \"", V rator, S "\"\n",
|
179 : |
|
|
S " expected: ", TYS domTy, S "\n",
|
180 : |
|
|
S " but found: ", TYS[ty1, ty2], S "\n"
|
181 : |
jhr |
85 |
])
|
182 : |
jhr |
81 |
end
|
183 : |
jhr |
91 |
| ovldList => resolveOverload (cxt, rator, [ty1, ty2], [e1', e2'], ovldList)
|
184 : |
jhr |
81 |
(* end case *)
|
185 : |
|
|
end
|
186 : |
|
|
| PT.E_UnaryOp(rator, e) => let
|
187 : |
|
|
val (e', ty) = checkExpr(env, cxt, e)
|
188 : |
|
|
in
|
189 : |
|
|
case Basis.findOp rator
|
190 : |
|
|
of [rator] => let
|
191 : |
|
|
val (tyArgs, Ty.T_Fun([domTy], rngTy)) = Util.instantiate(Var.typeOf rator)
|
192 : |
|
|
in
|
193 : |
|
|
if U.matchType(domTy, ty)
|
194 : |
|
|
then (AST.E_Apply(rator, tyArgs, [e'], rngTy), rngTy)
|
195 : |
jhr |
89 |
else err (cxt, [
|
196 : |
|
|
S "type error for unary operator \"", V rator, S "\"\n",
|
197 : |
|
|
S " expected: ", TY domTy, S "\n",
|
198 : |
|
|
S " but found: ", TY ty, S "\n"
|
199 : |
jhr |
85 |
])
|
200 : |
jhr |
81 |
end
|
201 : |
jhr |
91 |
| ovldList => resolveOverload (cxt, rator, [ty], [e'], ovldList)
|
202 : |
jhr |
81 |
(* end case *)
|
203 : |
|
|
end
|
204 : |
|
|
| PT.E_Tuple args => let
|
205 : |
|
|
val (args, tys) = checkExprList (env, cxt, args)
|
206 : |
|
|
in
|
207 : |
|
|
raise Fail "E_Tuple not yet implemented"
|
208 : |
|
|
end
|
209 : |
|
|
| PT.E_Apply(f, args) => let
|
210 : |
|
|
val (args, tys) = checkExprList (env, cxt, args)
|
211 : |
|
|
in
|
212 : |
jhr |
169 |
case Env.findFunc (#env env, f)
|
213 : |
|
|
of SOME f =>
|
214 : |
jhr |
228 |
if (inActor env) andalso (Basis.isRestricted f)
|
215 : |
|
|
then err(cxt, [S "use of restricted operation ", V f, S " in actor body"])
|
216 : |
|
|
else (case Util.instantiate(Var.typeOf f)
|
217 : |
jhr |
169 |
of (tyArgs, Ty.T_Fun(domTy, rngTy)) =>
|
218 : |
|
|
if U.matchTypes(domTy, tys)
|
219 : |
|
|
then (AST.E_Apply(f, tyArgs, args, rngTy), rngTy)
|
220 : |
|
|
else err(cxt, [
|
221 : |
|
|
S "type error in application of ", V f, S "\n",
|
222 : |
|
|
S " expected: ", TYS domTy, S "\n",
|
223 : |
|
|
S " but found: ", TYS tys, S "\n"
|
224 : |
|
|
])
|
225 : |
|
|
| _ => err(cxt, [S "application of non-function ", V f])
|
226 : |
|
|
(* end case *))
|
227 : |
jhr |
99 |
| NONE => err(cxt, [S "unknown function ", A f])
|
228 : |
jhr |
81 |
(* end case *)
|
229 : |
|
|
end
|
230 : |
jhr |
86 |
| PT.E_Cons args => let
|
231 : |
|
|
val (args, ty::tys) = checkExprList (env, cxt, args)
|
232 : |
jhr |
81 |
in
|
233 : |
jhr |
96 |
case TU.pruneHead ty
|
234 : |
jhr |
86 |
of Ty.T_Tensor shape => let
|
235 : |
|
|
fun chkTy ty' = U.matchType(ty, ty')
|
236 : |
|
|
val resTy = Ty.T_Tensor(Ty.shapeExt(shape, Ty.DimConst(List.length args)))
|
237 : |
jhr |
83 |
in
|
238 : |
jhr |
86 |
if List.all chkTy tys
|
239 : |
|
|
then (AST.E_Cons args, resTy)
|
240 : |
jhr |
99 |
else err(cxt, [S "arguments of tensor construction must have same type"])
|
241 : |
jhr |
83 |
end
|
242 : |
jhr |
99 |
| _ => err(cxt, [S "Invalid argument type for tensor construction"])
|
243 : |
jhr |
83 |
(* end case *)
|
244 : |
jhr |
81 |
end
|
245 : |
jhr |
86 |
| PT.E_Real e => (case checkExpr (env, cxt, e)
|
246 : |
|
|
of (e', Ty.T_Int) =>
|
247 : |
|
|
(AST.E_Apply(BasisVars.i2r, [], [e'], Ty.realTy), Ty.realTy)
|
248 : |
jhr |
99 |
| _ => err(cxt, [S "argument of real conversion must be int"])
|
249 : |
jhr |
86 |
(* end case *))
|
250 : |
jhr |
70 |
(* end case *))
|
251 : |
|
|
|
252 : |
jhr |
81 |
(* typecheck a list of expressions returning a list of AST expressions and a list
|
253 : |
|
|
* of types of the expressions.
|
254 : |
|
|
*)
|
255 : |
|
|
and checkExprList (env, cxt, exprs) = let
|
256 : |
|
|
fun chk (e, (es, tys)) = let
|
257 : |
|
|
val (e, ty) = checkExpr (env, cxt, e)
|
258 : |
|
|
in
|
259 : |
|
|
(e::es, ty::tys)
|
260 : |
|
|
end
|
261 : |
|
|
in
|
262 : |
|
|
List.foldr chk ([], []) exprs
|
263 : |
|
|
end
|
264 : |
|
|
|
265 : |
jhr |
72 |
fun checkVarDecl (env, cxt, kind, d) = (case d
|
266 : |
jhr |
86 |
of PT.VD_Mark m => checkVarDecl (env, (#1 cxt, #span m), kind, #tree m)
|
267 : |
jhr |
72 |
| PT.VD_Decl(ty, x, e) => let
|
268 : |
jhr |
81 |
val ty = checkTy (cxt, ty)
|
269 : |
jhr |
72 |
val x' = Var.new (x, kind, ty)
|
270 : |
|
|
val (e', ty') = checkExpr (env, cxt, e)
|
271 : |
|
|
in
|
272 : |
jhr |
99 |
(* FIXME: this check is not flexible enough; should allow lhs type to support
|
273 : |
|
|
* fewer levels of differentiation than rhs provides.
|
274 : |
|
|
*)
|
275 : |
|
|
if U.matchType(ty, ty')
|
276 : |
|
|
then (x, x', e')
|
277 : |
|
|
else err(cxt, [
|
278 : |
|
|
S "type of variable ", A x,
|
279 : |
|
|
S " does not match type of initializer\n",
|
280 : |
|
|
S " expected: ", TY ty, S "\n",
|
281 : |
|
|
S " but found: ", TY ty', S "\n"
|
282 : |
|
|
])
|
283 : |
jhr |
72 |
end
|
284 : |
|
|
(* end case *))
|
285 : |
|
|
|
286 : |
jhr |
70 |
(* typecheck a statement and translate it to AST *)
|
287 : |
jhr |
71 |
fun checkStmt (env, cxt, s) = (case s
|
288 : |
jhr |
86 |
of PT.S_Mark m => checkStmt (withEnvAndContext (env, cxt, m))
|
289 : |
jhr |
72 |
| PT.S_Block stms => let
|
290 : |
|
|
fun chk (_, [], stms) = AST.S_Block(List.rev stms)
|
291 : |
|
|
| chk (env, s::ss, stms) = let
|
292 : |
|
|
val (s', env') = checkStmt (env, cxt, s)
|
293 : |
|
|
in
|
294 : |
jhr |
81 |
chk (env', ss, s'::stms)
|
295 : |
jhr |
72 |
end
|
296 : |
|
|
in
|
297 : |
|
|
(chk (env, stms, []), env)
|
298 : |
|
|
end
|
299 : |
|
|
| PT.S_Decl vd => let
|
300 : |
jhr |
228 |
val (x, x', e) = checkVarDecl (methodScope env, cxt, Var.LocalVar, vd)
|
301 : |
jhr |
72 |
in
|
302 : |
jhr |
228 |
(AST.S_Decl(AST.VD_Decl(x', e)), insertLocal(env, x, x'))
|
303 : |
jhr |
72 |
end
|
304 : |
|
|
| PT.S_IfThen(e, s) => let
|
305 : |
jhr |
228 |
val (e', ty) = checkExpr (env, cxt, e)
|
306 : |
jhr |
81 |
val (s', _) = checkStmt (env, cxt, s)
|
307 : |
jhr |
72 |
in
|
308 : |
|
|
(* check that condition has bool type *)
|
309 : |
|
|
case ty
|
310 : |
|
|
of Ty.T_Bool => ()
|
311 : |
jhr |
99 |
| _ => err(cxt, [S "condition not boolean type"])
|
312 : |
jhr |
72 |
(* end case *);
|
313 : |
|
|
(AST.S_IfThenElse(e', s', AST.S_Block[]), env)
|
314 : |
|
|
end
|
315 : |
|
|
| PT.S_IfThenElse(e, s1, s2) => let
|
316 : |
jhr |
228 |
val (e', ty) = checkExpr (env, cxt, e)
|
317 : |
jhr |
81 |
val (s1', _) = checkStmt (env, cxt, s1)
|
318 : |
|
|
val (s2', _) = checkStmt (env, cxt, s2)
|
319 : |
jhr |
72 |
in
|
320 : |
|
|
(* check that condition has bool type *)
|
321 : |
|
|
case ty
|
322 : |
|
|
of Ty.T_Bool => ()
|
323 : |
jhr |
99 |
| _ => err(cxt, [S "condition not boolean type"])
|
324 : |
jhr |
72 |
(* end case *);
|
325 : |
|
|
(AST.S_IfThenElse(e', s1', s2'), env)
|
326 : |
|
|
end
|
327 : |
jhr |
228 |
| PT.S_Assign(x, e) => (case Env.findVar (#env env, x)
|
328 : |
jhr |
99 |
of NONE => err(cxt, [
|
329 : |
|
|
S "undefined variable ", A x
|
330 : |
|
|
])
|
331 : |
jhr |
72 |
| SOME x' => let
|
332 : |
jhr |
99 |
(* FIXME: check for polymorphic variables *)
|
333 : |
|
|
val ([], ty) = Var.typeOf x'
|
334 : |
jhr |
228 |
val (e', ty') = checkExpr (env, cxt, e)
|
335 : |
jhr |
72 |
in
|
336 : |
jhr |
99 |
if U.matchType(ty, ty')
|
337 : |
|
|
then (x, x', e')
|
338 : |
|
|
else err(cxt, [
|
339 : |
|
|
S "type of assigned variable ", A x,
|
340 : |
|
|
S " does not match type of rhs\n",
|
341 : |
|
|
S " expected: ", TY ty, S "\n",
|
342 : |
|
|
S " but found: ", TY ty', S "\n"
|
343 : |
|
|
]);
|
344 : |
jhr |
72 |
(* check that x' is mutable *)
|
345 : |
|
|
case Var.kindOf x'
|
346 : |
|
|
of Var.ActorStateVar => ()
|
347 : |
jhr |
173 |
| Var.ActorOutputVar => ()
|
348 : |
jhr |
72 |
| Var.LocalVar => ()
|
349 : |
jhr |
99 |
| _ => err(cxt, [
|
350 : |
|
|
S "assignment to immutable variable ", A x
|
351 : |
|
|
])
|
352 : |
jhr |
72 |
(* end case *);
|
353 : |
|
|
(AST.S_Assign(x', e'), env)
|
354 : |
|
|
end
|
355 : |
|
|
(* end case *))
|
356 : |
|
|
| PT.S_New(actor, args) => let
|
357 : |
jhr |
228 |
val argsAndTys' = List.map (fn e => checkExpr(env, cxt, e)) args
|
358 : |
jhr |
81 |
val (args', tys') = ListPair.unzip argsAndTys'
|
359 : |
jhr |
72 |
in
|
360 : |
jhr |
228 |
case #scope env
|
361 : |
|
|
of MethodScope => ()
|
362 : |
|
|
| InitScope => ()
|
363 : |
|
|
| _ => err(cxt, [S "invalid scope for new actor"])
|
364 : |
|
|
(* end case *);
|
365 : |
jhr |
72 |
(* FIXME: check that actor is defined and has the argument types match *)
|
366 : |
jhr |
81 |
(AST.S_New(actor, args'), env)
|
367 : |
jhr |
72 |
end
|
368 : |
jhr |
228 |
| PT.S_Die => (
|
369 : |
|
|
case #scope env
|
370 : |
|
|
of ActorScope => ()
|
371 : |
|
|
| _ => err(cxt, [S "\"die\" statment outside of actor body"])
|
372 : |
|
|
(* end case *);
|
373 : |
|
|
(AST.S_Die, env))
|
374 : |
|
|
| PT.S_Stabilize => (
|
375 : |
|
|
case #scope env
|
376 : |
|
|
of ActorScope => ()
|
377 : |
|
|
| _ => err(cxt, [S "\"stabilize\" statment outside of actor body"])
|
378 : |
|
|
(* end case *);
|
379 : |
|
|
(AST.S_Stabilize, env))
|
380 : |
jhr |
70 |
(* end case *))
|
381 : |
|
|
|
382 : |
jhr |
82 |
fun checkParams (env, cxt, params) = let
|
383 : |
|
|
fun chkParam (env, cxt, param) = (case param
|
384 : |
jhr |
86 |
of PT.P_Mark m => chkParam (withEnvAndContext (env, cxt, m))
|
385 : |
jhr |
82 |
| PT.P_Param(ty, x) => let
|
386 : |
|
|
val x' = Var.new(x, AST.ActorParam, checkTy (cxt, ty))
|
387 : |
|
|
in
|
388 : |
jhr |
228 |
(x', insertLocal(env, x, x'))
|
389 : |
jhr |
82 |
end
|
390 : |
|
|
(* end case *))
|
391 : |
|
|
fun chk (param, (xs, env)) = let
|
392 : |
|
|
val (x, env) = chkParam (env, cxt, param)
|
393 : |
|
|
in
|
394 : |
|
|
(x::xs, env)
|
395 : |
|
|
end
|
396 : |
|
|
in
|
397 : |
|
|
(* FIXME: need to check for multiple occurences of the same parameter name! *)
|
398 : |
|
|
List.foldr chk ([], env) params
|
399 : |
|
|
end
|
400 : |
|
|
|
401 : |
|
|
fun checkMethod (env, cxt, meth) = (case meth
|
402 : |
jhr |
86 |
of PT.M_Mark m => checkMethod (withEnvAndContext (env, cxt, m))
|
403 : |
jhr |
82 |
| PT.M_Method(name, body) => let
|
404 : |
jhr |
228 |
val (body, _) = checkStmt(methodScope env, cxt, body)
|
405 : |
jhr |
82 |
in
|
406 : |
|
|
AST.M_Method(name, body)
|
407 : |
|
|
end
|
408 : |
|
|
(* end case *))
|
409 : |
|
|
|
410 : |
|
|
fun checkActor (env, cxt, {name, params, state, methods}) = let
|
411 : |
|
|
(* check the actor parameters *)
|
412 : |
|
|
val (params, env) = checkParams (env, cxt, params)
|
413 : |
|
|
(* check the actor state variable definitions *)
|
414 : |
|
|
val (vds, env) = let
|
415 : |
jhr |
164 |
fun checkStateVar ((isOut, vd), (vds, env)) = let
|
416 : |
jhr |
173 |
val kind = if isOut then AST.ActorOutputVar else AST.ActorStateVar
|
417 : |
jhr |
228 |
val (x, x', e') = checkVarDecl (env, cxt, kind, vd)
|
418 : |
jhr |
82 |
in
|
419 : |
jhr |
228 |
(* check that output variables have value types *)
|
420 : |
|
|
if isOut andalso not(TU.isValueType(Var.monoTypeOf x'))
|
421 : |
|
|
then err(cxt, [
|
422 : |
|
|
S "output variable ", V x', S " has non-value type ",
|
423 : |
|
|
TY(Var.monoTypeOf x')
|
424 : |
|
|
])
|
425 : |
|
|
else ();
|
426 : |
|
|
(AST.VD_Decl(x', e')::vds, insertLocal(env, x, x'))
|
427 : |
jhr |
82 |
end
|
428 : |
|
|
val (vds, env) = List.foldl checkStateVar ([], env) state
|
429 : |
|
|
in
|
430 : |
|
|
(List.rev vds, env)
|
431 : |
|
|
end
|
432 : |
|
|
(* check the actor methods *)
|
433 : |
|
|
val methods = List.map (fn m => checkMethod (env, cxt, m)) methods
|
434 : |
|
|
in
|
435 : |
|
|
AST.D_Actor{name = name, params = params, state = vds, methods = methods}
|
436 : |
|
|
end
|
437 : |
|
|
|
438 : |
jhr |
89 |
fun checkCreate (env, cxt, PT.C_Mark m) = checkCreate (withEnvAndContext (env, cxt, m))
|
439 : |
|
|
| checkCreate (env, cxt, PT.C_Create(actor, args)) = let
|
440 : |
jhr |
228 |
val (args, tys) = checkExprList (env, cxt, args)
|
441 : |
jhr |
89 |
in
|
442 : |
|
|
(* FIXME: check against actor definition *)
|
443 : |
|
|
AST.C_Create(actor, args)
|
444 : |
|
|
end
|
445 : |
|
|
|
446 : |
|
|
fun checkIter (env, cxt, PT.I_Mark m) = checkIter (withEnvAndContext (env, cxt, m))
|
447 : |
|
|
| checkIter (env, cxt, PT.I_Range(x, e1, e2)) = let
|
448 : |
jhr |
228 |
val (e1', ty1) = checkExpr (env, cxt, e1)
|
449 : |
|
|
val (e2', ty2) = checkExpr (env, cxt, e2)
|
450 : |
jhr |
89 |
val x' = Var.new(x, Var.LocalVar, Ty.T_Int)
|
451 : |
jhr |
228 |
val env' = insertLocal(env, x, x')
|
452 : |
jhr |
89 |
in
|
453 : |
|
|
case (ty1, ty2)
|
454 : |
|
|
of (Ty.T_Int, Ty.T_Int) => (AST.I_Range(x', e1', e2'), env')
|
455 : |
|
|
| _ => err(cxt, [
|
456 : |
|
|
S "range expressions must have integer type\n",
|
457 : |
|
|
S " but found: ", TY ty1, S " .. ", TY ty2, S "\n"
|
458 : |
|
|
])
|
459 : |
|
|
(* end case *)
|
460 : |
|
|
end
|
461 : |
|
|
|
462 : |
|
|
fun checkIters (env, cxt, iters) = let
|
463 : |
|
|
fun chk (env, [], iters) = (List.rev iters, env)
|
464 : |
|
|
| chk (env, iter::rest, iters) = let
|
465 : |
|
|
val (iter, env) = checkIter (env, cxt, iter)
|
466 : |
|
|
in
|
467 : |
|
|
chk (env, rest, iter::iters)
|
468 : |
|
|
end
|
469 : |
|
|
in
|
470 : |
|
|
chk (env, iters, [])
|
471 : |
|
|
end
|
472 : |
|
|
|
473 : |
jhr |
71 |
fun checkDecl (env, cxt, d) = (case d
|
474 : |
jhr |
86 |
of PT.D_Mark m => checkDecl (withEnvAndContext (env, cxt, m))
|
475 : |
jhr |
72 |
| PT.D_Input(ty, x, optExp) => let
|
476 : |
jhr |
71 |
val ty = checkTy(cxt, ty)
|
477 : |
|
|
val x' = Var.new(x, Var.InputVar, ty)
|
478 : |
|
|
val dcl = (case optExp
|
479 : |
|
|
of NONE => AST.D_Input(x', NONE)
|
480 : |
|
|
| SOME e => let
|
481 : |
jhr |
228 |
val (e', ty') = checkExpr (env, cxt, e)
|
482 : |
jhr |
71 |
in
|
483 : |
jhr |
89 |
if U.matchType (ty, ty')
|
484 : |
|
|
then AST.D_Input(x', SOME e')
|
485 : |
|
|
else err(cxt, [
|
486 : |
|
|
S "definition of ", V x', S " has wrong type\n",
|
487 : |
|
|
S " expected: ", TY ty, S "\n",
|
488 : |
|
|
S " but found: ", TY ty', S "\n"
|
489 : |
|
|
])
|
490 : |
jhr |
71 |
end
|
491 : |
|
|
(* end case *))
|
492 : |
|
|
in
|
493 : |
jhr |
228 |
(* check that input variables have value types *)
|
494 : |
|
|
if not(TU.isValueType ty)
|
495 : |
|
|
then err(cxt, [S "input variable ", V x', S " has non-value type ", TY ty])
|
496 : |
|
|
else ();
|
497 : |
|
|
(dcl, insertGlobal(env, x, x'))
|
498 : |
jhr |
71 |
end
|
499 : |
jhr |
72 |
| PT.D_Var vd => let
|
500 : |
jhr |
228 |
val (x, x', e') = checkVarDecl (env, cxt, Var.GlobalVar, vd)
|
501 : |
jhr |
72 |
in
|
502 : |
jhr |
228 |
(AST.D_Var(AST.VD_Decl(x', e')), insertGlobal(env, x, x'))
|
503 : |
jhr |
72 |
end
|
504 : |
jhr |
228 |
| PT.D_Actor arg => (checkActor(actorScope env, cxt, arg), env)
|
505 : |
jhr |
89 |
| PT.D_InitialArray(create, iterators) => let
|
506 : |
jhr |
228 |
val env = initScope env
|
507 : |
jhr |
89 |
val (iterators, env') = checkIters (env, cxt, iterators)
|
508 : |
|
|
val create = checkCreate (env', cxt, create)
|
509 : |
|
|
in
|
510 : |
|
|
(AST.D_InitialArray(create, iterators), env)
|
511 : |
|
|
end
|
512 : |
|
|
| PT.D_InitialCollection(create, iterators) => let
|
513 : |
jhr |
228 |
val env = initScope env
|
514 : |
jhr |
89 |
val (iterators, env') = checkIters (env, cxt, iterators)
|
515 : |
|
|
val create = checkCreate (env', cxt, create)
|
516 : |
|
|
in
|
517 : |
|
|
(AST.D_InitialCollection(create, iterators), env)
|
518 : |
|
|
end
|
519 : |
jhr |
70 |
(* end case *))
|
520 : |
|
|
|
521 : |
jhr |
86 |
fun check errStrm (PT.Program{span, tree}) = let
|
522 : |
|
|
val cxt = (errStrm, span)
|
523 : |
jhr |
81 |
fun chk (env, [], dcls') = AST.Program(List.rev dcls')
|
524 : |
|
|
| chk (env, dcl::dcls, dcls') = let
|
525 : |
jhr |
86 |
val (dcl', env) = checkDecl (env, cxt, dcl)
|
526 : |
jhr |
81 |
in
|
527 : |
|
|
chk (env, dcls, dcl'::dcls')
|
528 : |
|
|
end
|
529 : |
|
|
in
|
530 : |
jhr |
228 |
chk ({scope=GlobalScope, env=Basis.env}, tree, [])
|
531 : |
jhr |
81 |
end
|
532 : |
jhr |
70 |
|
533 : |
jhr |
69 |
end
|