+ fun dupchk mark l src =
+ 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 mark ("multiple definition of variable " ^ (Symbol.name n) ^ " in " ^ src);
+ raise ErrorMsg.Error )
+ end) l
+
+ fun check_lvalue prog vars mark (A.Marked m) = check_lvalue prog vars (Mark.ext m) (Mark.data m)
+ | check_lvalue prog vars mark (e as A.Var _) = typeof prog vars mark e
+ | check_lvalue prog vars mark (e as A.Member _) = typeof prog vars mark e
+ | check_lvalue prog vars mark (e as A.DerefMember _) = typeof prog vars mark e
+ | check_lvalue prog vars mark (e as A.Dereference _) = typeof prog vars mark e
+ | check_lvalue prog vars mark (e as A.ArrIndex _) = typeof prog vars mark e
+ | check_lvalue prog vars mark _ = ( ErrorMsg.error mark ("invalid lvalue") ; raise ErrorMsg.Error )
+ fun typecheck_stm prog vars mark stm =
+ case stm
+ of A.Assign (e1, e2) =>
+ if not (T.castable (check_lvalue prog vars mark e1, typeof prog vars mark e2))
+ then (ErrorMsg.error mark "incompatible types in assignment" ; raise ErrorMsg.Error )
+ else if not (T.issmall (check_lvalue prog vars mark e1))
+ then (ErrorMsg.error mark "lvalue is not small" ; raise ErrorMsg.Error)
+ else ()
+ | A.AsnOp (oper, e1, e2) => typecheck_stm prog vars mark (A.Assign (e1, A.OpExp (oper, [e1, e2])))
+ | A.Effect e =>
+ if not (T.issmall (typeof prog vars mark e))
+ then (ErrorMsg.error mark "simple statement's value not small" ; raise ErrorMsg.Error )
+ else ()
+ | A.Return e => (typeof prog vars mark e ; ())
+ | A.Nop => ()
+ | A.Break => ()
+ | A.Continue => ()
+ | A.If (e, s, NONE) =>
+ if T.castable (T.Int, typeof prog vars mark e)
+ then (List.app (typecheck_stm prog vars mark) s)
+ else (ErrorMsg.error mark "conditional in if statement is not of int type" ; raise ErrorMsg.Error )
+ | A.If (e, s1, SOME s2) =>
+ if T.castable (T.Int, typeof prog vars mark e)
+ then (List.app (typecheck_stm prog vars mark) s1 ; List.app (typecheck_stm prog vars mark) s2)
+ else (ErrorMsg.error mark "conditional in if statement is not of int type" ; raise ErrorMsg.Error )
+ | A.For (sbegin, e, sloop, s) =>
+ if T.castable (T.Int, typeof prog vars mark e)
+ 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))
+ else (ErrorMsg.error mark "conditional in for statement is not of int type" ; raise ErrorMsg.Error )
+ | A.While (e, s) =>
+ if T.castable (T.Int, typeof prog vars mark e)
+ then (List.app (typecheck_stm prog vars mark) s)
+ else (ErrorMsg.error mark "conditional in while statement is not of int type" ; raise ErrorMsg.Error )
+ | A.MarkedStm (m) => typecheck_stm prog vars (Mark.ext m) (Mark.data m)
+
+ (* XXX does not check big vs. small types *)
+ fun typecheck_type (tds, funcs) mark T.Int = ()
+ | typecheck_type (tds, funcs) mark T.String = ()
+ | typecheck_type (tds, funcs) mark T.TNull = ()
+ | typecheck_type (tds, funcs) mark (T.Pointer t) = typecheck_type (tds, funcs) mark t
+ | typecheck_type (tds, funcs) mark (T.Array t) = typecheck_type (tds, funcs) mark t
+ | typecheck_type (tds, funcs) mark (T.Typedef t) =
+ case (Symbol.look tds t)
+ of SOME _ => ()
+ | NONE => (ErrorMsg.error mark ("typedef `"^(Symbol.name t)^"' does not exist") ; raise ErrorMsg.Error)
+
+ fun typecheck_fn prog _ (id, A.MarkedFunction m) = typecheck_fn prog (Mark.ext m) (id, Mark.data m)
+ | typecheck_fn (prog as (tds, funcs)) mark (id, A.Extern (t, al)) =
+ (if (String.isPrefix "_l5_" (Symbol.name id))
+ then
+ let
+ val n = String.extract (Symbol.name id, 4, NONE)
+ in
+ if List.exists (fn (id, f) => case (AU.Function.data f) of A.Function _ => (Symbol.name id = n) | _ => false) (Symbol.elemsi funcs)
+ then (ErrorMsg.error mark ("you anus, extern " ^ Symbol.name id ^ " conflicts with local function"); raise ErrorMsg.Error)
+ else ()
+ end
+ else () ;
+ dupchk mark al ;
+ List.app (typecheck_type prog mark) (List.map (fn (_, t) => t) al) ;
+ A.Extern (t, al))
+ | typecheck_fn prog mark (id, A.Function (t, al, vl, sl)) =
+ let
+ val () = dupchk mark (al @ vl) ("function `"^Symbol.name id^"'") (* Before we do any bindings, check for duplicate names. *)
+ val () = List.app (typecheck_type prog mark) (List.map (fn (_, t) => t) (al @ vl))
+ val env = Symbol.empty
+ val env = bindvars env ASSIGNED al
+ val env = bindvars env UNASSIGNED vl
+ val vars = Symbol.empty
+ val vars = bindtypes vars al
+ val vars = bindtypes vars vl
+ val () = breakcheck sl mark
+ val () = if not (returncheck prog vars NONE t sl)
+ then ( ErrorMsg.error mark ("function `"^ Symbol.name id ^ "' does not return in all cases");
+ raise ErrorMsg.Error )
+ else ()
+ val () = List.app (
+ fn (n, t) =>
+ if (T.issmall t)
+ then ()
+ else ( ErrorMsg.error mark ("variable `"^(Symbol.name n)^"' in function `"^(Symbol.name id)^"' not small") ; raise ErrorMsg.Error))
+ (al @ vl)
+ val () = List.app (typecheck_stm prog vars mark) sl
+ in
+ A.Function (t, al, vl, varcheck env sl NONE)
+ end
+
+ structure SymbolSet = ListSetFn (
+ struct
+ type ord_key = Symbol.symbol
+ val compare = Symbol.compare
+ end
+ )
+
+ fun typecheck_structs (prog as (tds, funcs)) =
+ let
+ exception Yuq
+
+ val all = SymbolSet.addList (SymbolSet.empty, Symbol.keys tds)
+ fun lookup mark sym =
+ let
+ val s = case Symbol.look tds sym
+ of SOME a => a
+ | NONE => (ErrorMsg.error mark ("typedef `"^(Symbol.name sym)^"' does not exist") ; raise ErrorMsg.Error)
+ val vl = case T.defdata s
+ of T.Struct vl => vl
+ | T.MarkedTypedef v => raise ErrorMsg.InternalError "data returned marked type"
+ in
+ (vl, T.defmark s)
+ end
+ fun checksym mark sym stack k remaining =
+ if not (SymbolSet.member (remaining, sym))
+ then k remaining
+ else if (SymbolSet.member (stack, sym))
+ then ( ErrorMsg.error mark ("structure `"^ (Symbol.name sym) ^"' is involved in a recursive mess") ; raise Yuq)
+ else
+ let
+ val stack' = SymbolSet.add (stack, sym)
+ val (vl, mark') = lookup mark sym
+ val () = dupchk mark vl ("structure `"^(Symbol.name sym)^"'")
+ fun remove k remaining' = k (SymbolSet.delete (remaining', sym))
+ val newk = (* OH GOD D: *)
+ foldr
+ (fn ((_, T.Typedef s), k') => checksym mark' s stack' k'
+ | (_, k') => k')
+ (remove k)
+ vl
+ in
+ newk remaining handle Yuq => (ErrorMsg.error mark' ("from structure `"^(Symbol.name sym)^"'") ; raise Yuq)
+ end
+ fun chooseone k set =
+ case (SymbolSet.listItems set)
+ of nil => k set
+ | (h::l) => checksym NONE h SymbolSet.empty (chooseone k) set
+ in
+ chooseone (fn _ => ()) all handle Yuq => raise ErrorMsg.Error
+ end
+
+ fun typecheck (tds, funcs) =
+ let
+ val main = case (Symbol.look funcs (Symbol.symbol "main"))
+ of NONE => ( ErrorMsg.error NONE ("no function named main");
+ raise ErrorMsg.Error )
+ | SOME m => m
+ val (main, mainp) = (AU.Function.data main, AU.Function.mark main)
+ val () = case main
+ of A.Extern _ => ( ErrorMsg.error mainp ("you anus, main can't be an extern");
+ raise ErrorMsg.Error )
+ | A.Function (T.Int, nil, _, _) => ()
+ | A.Function (T.Int, _, _, _) => ( ErrorMsg.error mainp ("main should take no parameters");
+ raise ErrorMsg.Error )
+ | A.Function (_, _, _, _) => ( ErrorMsg.error mainp ("main has incorrect return type");
+ raise ErrorMsg.Error )
+ | _ => raise ErrorMsg.InternalError "marked of marked disallowed"
+ val () = typecheck_structs (tds, funcs)
+ in
+ (tds, Symbol.mapi (typecheck_fn (tds, funcs) NONE) funcs)
+ end