+ fun bindvars sym stat l = foldr (fn ((i,t), s) => Symbol.bind s (i,(t, stat))) sym l
+ fun bindfuns sym l =
+ foldr
+ (fn (a as (A.Function (_, id, _, _, _)), s) => Symbol.bind s (id, a)
+ | (a as (A.Extern (_, id, _)), s) => Symbol.bind s (id, a))
+ sym l
+
+ fun dupchk l =
+ List.app
+ (fn (n, _) =>
+ let
+ val name = Symbol.name n
+ val all = List.filter (fn (n', _) => name = (Symbol.name n')) l
+ val count = length all
+ in
+ if count = 1
+ then ()
+ else ( ErrorMsg.error NONE ("multiple definition of variable " ^ (Symbol.name n));
+ raise ErrorMsg.Error )
+ end) l
+
+ fun typecheck_fn p (e as (A.Extern (t, id, al))) = (dupchk al; e)
+ | typecheck_fn p (A.Function (t, id, al, vl, sl)) =
+ let
+ val () = breakcheck sl NONE
+ val () = if not (returns sl)
+ then ( ErrorMsg.error NONE ("function `"^ Symbol.name id ^ "' does not return in all cases");
+ raise ErrorMsg.Error )
+ else ()
+ val env = Symbol.empty
+ val env = bindvars env ASSIGNED al
+ val env = bindvars env UNASSIGNED vl
+ val fenv = bindfuns Symbol.empty p
+ val () = dupchk (al @ vl)
+ in
+ A.Function (t, id, al, vl, varcheck env fenv sl NONE)
+ end
+
+ fun typecheck p =
+ let
+ fun getFun n =
+ List.find (fn A.Extern (_, id, _) => ((Symbol.name id) = n)
+ | A.Function (_, id, _, _, _) => ((Symbol.name id) = n))
+ p
+ val main = case (getFun "main")
+ of NONE => ( ErrorMsg.error NONE ("no function named main");
+ raise ErrorMsg.Error )
+ | SOME m => m
+ val () = case main
+ of A.Extern _ => ( ErrorMsg.error NONE ("you anus, main can't be an extern");
+ raise ErrorMsg.Error )
+ | A.Function (A.Int, _, nil, _, _) => ()
+ | A.Function (A.Int, _, _, _, _) => ( ErrorMsg.error NONE ("main should take no parameters");
+ raise ErrorMsg.Error )
+ val () = List.app
+ (fn a =>
+ let
+ val id = case a
+ of A.Extern (_, id, _) => id
+ | A.Function (_, id, _, _, _) => id
+ val name = Symbol.name id
+ val all = List.filter
+ (fn A.Extern (_, id, _) => (Symbol.name id) = name
+ | A.Function (_, id, _, _, _) => (Symbol.name id) = name)
+ p
+ val num = length all
+ in
+ if num = 1
+ then ()
+ else ( ErrorMsg.error NONE ("multiple definition of " ^ name);
+ raise ErrorMsg.Error )
+ end) p
+ in
+ List.map (typecheck_fn p) p
+ end