signature CPSOPTINTERP = sig structure C : CORE_ML structure Cps : CPS structure Senv : SENV structure Simplify' : SIMPLIFY' sharing Cps.CoreML = C sharing Senv.Core_ML = Cps.CoreML val interpreter : unit -> unit end structure CpsOptInterp : CPSOPTINTERP = struct structure T = TypeCheck structure TC = TypeContext structure A = AbSyn structure C = Core_ML structure Cps = Cps structure S = Senv structure Simplify' = Simplify' structure PP = Cps_Opt_PP(structure Simplify' = Simplify') structure Cps_PP = Cps_PP(structure Cps = Cps) structure CoreMLPP = Core_ML_PP(structure Core_ML = C) structure SenvPP = SenvPP(structure Senv = S) structure PrettyPrinter = PrettyPrinter structure Id = Id (*-------------- Interpreter ---------------*) (* raised when an error occurs during interpretation *) exception Error val error = fn s:string => (print("RUNTIME ERROR: "^s);print "\n"; raise Error) open Simplify (* runtime env *) datatype renv = EmptyREnv | REnv of value*renv and contEnv = EmptyCEnv | CEnv of ({arg: Id.t, v:value ref} * contEnv) and value = Int_v of int (* an int or a char *) | Real_v of real (* a real *) | String_v of string (* a string *) | Char_v of char (* a char *) | Tuple_v of (value ref) list (* a tuple *) | Closure_v of opt_exp * (renv ref) (* "code"* runtime env *) | Cont_v of opt_cont | True_v | False_v | Nil_v | None_v | Some_v | Cons_v | Nop_v exception stop of value val maxSize = 10001 (* convert a machine value to a string for printing *) fun value2string(v:value):string = case v of Int_v(i) => Int.toString i | Real_v(r) => Real.toString r | String_v (s) => s | Char_v (c) => Char.toString c | Tuple_v (tl) => let fun conv(nil) = "()" (*error "empty tuple"*) | conv(v::nil) = value2string(!v) | conv(v::rest) = value2string(!v)^","^conv(rest) in "("^(conv(tl))^")" end | Closure_v(e, renv) => "Closure("^ PP.ppCpsOptExp e^"), renv(dummy) )" | Cont_v(c) => (case c of Ret_opt (l,i,e) => "Continuation:(" ^Label.stringRep(l)^ ","^ Id.stringRep(i)^ ")"^ PP.ppCpsOptExp e^ " renv(dummy))") | True_v => "true" | False_v => "false" | Nil_v => "Nil" | None_v => "NONE" | Some_v => "SOME" | Cons_v => "Cons" | Nop_v => "NOP" (* print a machine value *) fun print_value(v:value):unit = print(value2string(v)) datatype state = S of {return: value, env: renv, cEnv : contEnv, tail: state} | Empty fun push(stack,return,renv,cenv) = S {return=return,env=renv,cEnv=cenv,tail = stack} fun pop(Empty) = error("empty continuation stack:pop") | pop(S {return,env,cEnv,tail}) = tail val label_fn: Label.t -> word = HashString.hashString o Label.stringRep val initialSize = 1001 exception unknownCont val LabelRep: (Label.t, value) HashTable.hash_table = HashTable.mkTable (label_fn,Label.equals) (initialSize,unknownCont) fun lookup(renv:renv, i:int) = case renv of EmptyREnv => error("wrong renv: lookup failed on var: "^Int.toString(i)) | REnv(v,renv') => if i = 0 then v else lookup(renv',i-1) fun lookupContEnv(env,id) = (case env of EmptyCEnv => error("binding for continuation argument "^Id.stringRep(id)^" not found in lookupContEnv") | CEnv ({arg,v},tail) => if Id.equals(arg,id) then (!v) else lookupContEnv(tail,id)) fun updateContEnv(env,id,v') = (case env of EmptyCEnv => error("binding for continuation argument "^Id.stringRep(id)^" not found in updateContEnv") | CEnv ({arg,v},tail) => if Id.equals(arg,id) then v := v' else updateContEnv(tail,id,v')) fun boundContEnv(env,id) = (case env of EmptyCEnv => false | CEnv ({arg,v},tail) => if Id.equals(arg,id) then true else boundContEnv(tail,id)) fun eval_be(v1:value,bop:C.cbinop,v2:value): value = case bop of C.Plus_c => (case v1 of Int_v(i1) => (case v2 of Int_v(i2) => Int_v( i1 + i2) | _ => error("Binop Plus: expect Int (2)")) | Real_v(i1) => ( case v2 of Real_v(i2) => Real_v( i1 + i2) | _ => error("Binop Plus: expect Real (2)")) | _ => error("Binop Plus: expect Real (1)")) | C.Times_c => (case v1 of Int_v(i1) => ( case v2 of Int_v(i2) => Int_v( i1 * i2) | _ => error("Binop Times: expect Int (2)")) | Real_v(i1) => ( case v2 of Real_v(i2) => Real_v( i1 * i2) | _ => error("Binop Times: expect Real (2)")) | _ => error("Binop Times: expect Real (1)")) | C.Minus_c => (case v1 of Int_v(i1) => ( case v2 of Int_v(i2) => Int_v( i1 - i2) | _ => error("Binop Minus: expect Int (2)")) | Real_v(i1) => ( case v2 of Real_v(i2) => Real_v( i1 - i2) | _ => error("Binop Minus: expect Real (2)")) | _ => error("Binop Minus: expect Real (1)")) | C.Equal_c => (case v1 of Int_v(i1) => ( case v2 of Int_v(i2) => if i1 = i2 then Tuple_v([ref True_v]) else Tuple_v([ref False_v]) | _ => error("Binop Equal: operand types mismatch (Int)")) | String_v(i1) => ( case v2 of String_v(i2) => if i1 = i2 then Tuple_v([ref True_v]) else Tuple_v([ref False_v]) | _ => error("Binop Equal: operand types mismatch (String)")) | _ => error("Binop Equal: wrong operand types")) | C.Concat_c => (case v1 of String_v(i1) => ( case v2 of String_v(i2) => String_v( i1 ^ i2) | _ => error("Binop Concat: expect Int (2)")) | _ => error("Binop Concat: expect Int (1)")) | C.GreaterThan_c => (case v1 of Int_v(i1) => ( case v2 of Int_v(i2) => if i1 > i2 then Tuple_v([ref True_v]) else Tuple_v([ref False_v]) | _ => error("Binop GreaterThan: expect Int (2)")) | _ => error("Binop GreaterThan: expect Int (1)")) | C.LessThan_c => (case v1 of Int_v(i1) => ( case v2 of Int_v(i2) => if i1 < i2 then Tuple_v([ref True_v]) else Tuple_v([ref False_v]) | _ => error("Binop LessThan: expect Int (2)")) | _ => error("Binop LessThan: expect Int (1)")) fun eval_ue(uop:C.cunop,v:value): value = case uop of C.Not_c => (case v of Tuple_v([ref True_v]) => Tuple_v([ref False_v]) | Tuple_v([ref False_v]) => Tuple_v([ref True_v]) | _ => error("type mismatch for Bool (1)") ) | C.Neg_c => (case v of Int_v(i) => Int_v(~i) | _ => error("type mismatch for Int (1)")) | C.isNullary_c => (case v of True_v => Tuple_v([ref True_v]) |False_v => Tuple_v([ref True_v]) |Nil_v => Tuple_v([ref True_v]) |None_v => Tuple_v([ref True_v]) |Some_v => Tuple_v([ref False_v]) |Cons_v => Tuple_v([ref False_v]) |_ => error("wrong type of isNullary")) | C.isValueCarry_c => (case v of True_v => Tuple_v([ref False_v]) |False_v => Tuple_v([ref False_v]) |Nil_v => Tuple_v([ref False_v]) |None_v => Tuple_v([ref False_v]) |Some_v => Tuple_v([ref True_v]) |Cons_v => Tuple_v([ref True_v]) |_ => error("wrong type in isValueCarry")) | C.isNil_c => (case v of True_v => Tuple_v([ref False_v]) |False_v => Tuple_v([ref False_v]) |Nil_v => Tuple_v([ref True_v]) |None_v => Tuple_v([ref False_v]) |Some_v => Tuple_v([ref False_v]) |Cons_v => Tuple_v([ref False_v]) |_ => error("wrong type in isNil: ")) | C.isNone_c => (case v of True_v => Tuple_v([ref False_v]) |False_v => Tuple_v([ref False_v]) |Nil_v => Tuple_v([ref False_v]) |None_v => Tuple_v([ref True_v]) |Some_v => Tuple_v([ref False_v]) |Cons_v => Tuple_v([ref False_v]) |_ => error("wrong type in isNone")) | C.isTrue_c => (case v of True_v => Tuple_v([ref True_v]) |False_v => Tuple_v([ref False_v]) |Nil_v => Tuple_v([ref False_v]) |None_v => Tuple_v([ref False_v]) |Some_v => Tuple_v([ref False_v]) |Cons_v => Tuple_v([ref False_v]) |_ => error("wrong type in isTrue")) | C.isFalse_c => (case v of True_v => Tuple_v([ref False_v]) |False_v => Tuple_v([ref True_v]) |Nil_v => Tuple_v([ref False_v]) |None_v => Tuple_v([ref False_v]) |Some_v => Tuple_v([ref False_v]) |Cons_v => Tuple_v([ref False_v]) |_ => error("wrong type in isFalse")) | C.isSome_c => (case v of True_v => Tuple_v([ref False_v]) |False_v => Tuple_v([ref False_v]) |Nil_v => Tuple_v([ref False_v]) |None_v => Tuple_v([ref False_v]) |Some_v => Tuple_v([ref True_v]) |Cons_v => Tuple_v([ref False_v]) |_ => error("wrong type in isSome")) | C.isCons_c => (case v of True_v => Tuple_v([ref False_v]) |False_v => Tuple_v([ref False_v]) |Nil_v => Tuple_v([ref False_v]) |None_v => Tuple_v([ref False_v]) |Some_v => Tuple_v([ref False_v]) |Cons_v => Tuple_v([ref True_v]) |_ => error("wrong type in isCons")) fun eval(renv:renv, cEnv: contEnv, s:state,e:opt_exp) = (case e of Simple_opt (Int_o(i)) => Int_v(i) | Simple_opt (Real_o(r)) => Real_v(r) | Simple_opt (String_o(s)) => String_v(s) | Simple_opt (Char_o(c)) => Char_v(c) | Simple_opt (Var_o(i)) => lookup(renv,i) | Simple_opt(Unop_o(uop,cps_exp)) => let val v=eval(renv,cEnv,s,Simple_opt cps_exp) in eval_ue(uop, v) end | Simple_opt(Constructor_o(C.CTrue)) => True_v | Simple_opt(Constructor_o(C.CFalse)) => False_v | Simple_opt(Constructor_o(C.CNil)) => Nil_v | Simple_opt(Constructor_o(C.CNone)) => None_v | Simple_opt(Constructor_o(C.VSome)) => Some_v | Simple_opt(Constructor_o(C.VCons)) => Cons_v | Simple_opt(Tuple_o(cps_exps)) => Tuple_v(List.map (fn e => ref(eval(renv,cEnv,s,Simple_opt e))) cps_exps) | Simple_opt(Ith_o(ce1,ce2)) => let val iv = eval(renv,cEnv,s,Simple_opt ce1) val e = eval(renv,cEnv,s,Simple_opt ce2) in (case e of Tuple_v(lst) => (case iv of Int_v i => !(List.nth(lst,i-1)) | _ => error("non-integer index in tuple select")) | _ => error("inappropriate object in tuple select ")) end | Simple_opt(Binop_o(ce1,bop,ce2)) => eval_be(eval(renv,cEnv,s,Simple_opt ce1), bop, eval(renv,cEnv,s,Simple_opt ce2)) | Simple_opt(SetIth_o(ce1,ce2,ce3)) => let val v1 = eval(renv,cEnv,s,Simple_opt ce1) val v2 = eval(renv,cEnv,s,Simple_opt ce2) val v3 = eval(renv,cEnv,s,Simple_opt ce3) fun update(0, _ , v:value) = error("SetIth_c: index out of bound") | update(_,nil,v:value) = error("SetIth_c: list out of bound") | update(i,v1::lst,v:value) = v1 := v in case v1 of Int_v(i) => (case v2 of Tuple_v(lst) => (update(i,lst,v3);v2) | _ => error("SetIth_c: Exepct a Tuple ")) | _ => error("SetIth_c: wrong type of index of tuples") end | Simple_opt(Error_o(_)) => error("program runtime error -- check your MiniML program code") | Simple_opt(Fn_o(cexp)) => Closure_v(cexp, ref renv) | Simple_opt(RetVal_o(i)) => lookupContEnv(cEnv,i) | Simple_opt(Nop_o) => error("unspecified instruction") | Simple_opt(Store_o(cVar,e)) => let val v = eval(renv,cEnv,s,Simple_opt(e)) val _ = updateContEnv(cEnv,cVar,v) in v end | If_opt(test,trueBranch,falseBranch) => (case eval(renv,cEnv,s,Simple_opt test) of Tuple_v([ref True_v]) => eval(renv,cEnv,s,trueBranch) | Tuple_v([ref False_v]) => eval(renv,cEnv,s, falseBranch) | _ => error("type mismatch for Bool (2)")) | Letrec_opt(ce1,ce2) => let val c = Closure_v(ce1,ref EmptyREnv) val renv' = REnv(c,renv) fun set_renv(renv:renv, Closure_v(code,r_renv)) = r_renv := renv | set_renv(_) = error("Attempting to set environment of a non-letrec closure") in (set_renv(renv',c); eval(renv',cEnv,s,ce2)) end | Tail_opt(f,arg) => let val v1 = eval(renv,cEnv,s,Simple_opt f) val v2 = eval(renv,cEnv,s,Simple_opt arg) in (case v1 of Closure_v(code,r_renv) => eval(REnv(v2,!r_renv),cEnv,s,code) | _ => error ("Tail call expects a function: "^value2string(v1))) end | NonTail_opt(f,arg,l) => let val c = (HashTable.lookup LabelRep l handle unknownCont => error("Unknown continuation: " ^ Label.stringRep(l))) val v1 = eval(renv,cEnv,s,Simple_opt f) val v2 = eval(renv,cEnv,s,Simple_opt arg) in (case v1 of Closure_v(code,r_renv) => eval(REnv(v2,!r_renv),EmptyCEnv,push(s,c,renv,cEnv),code) | _ => error "Nontail call expects a function") end | Return_opt(e) => let val v = eval(renv,cEnv,s,Simple_opt e) in (case s of Empty => raise stop(v) | S { return,env,cEnv,tail} => (case return of Cont_v(c) => let val Ret_opt(l,arg,cpsExp) = c in eval(env, CEnv ({arg = arg,v = ref v}, cEnv), pop(s),cpsExp) end | _ => error("Non-continuation found on continuation stack"))) handle stop(v) => (print("Program terminated with value: "^value2string(v)^"\n"); v) end | Block_opt(es) => let val newCEnv = (List.foldl (fn (e,acc) => (case e of Simple_opt(Store_o(cVar,v)) => CEnv( { arg = cVar, v = ref(Nop_v) }, acc) | _ => acc)) cEnv es) val vs = (List.map (fn (e) => eval(renv,newCEnv,s,e)) es) in List.last(vs) end | Goto_opt(l,e) => let val v = eval(renv,cEnv,s,Simple_opt e) val c = (HashTable.lookup LabelRep l handle unknownCont => error("Unknown continuation: " ^ Label.stringRep(l))) in case c of Cont_v(c) => let val Ret_opt(l,arg,cpsExp) = c in eval(renv, CEnv({arg=arg, v = ref v}, cEnv),s, cpsExp) end | _ => error("Non continuation has a label") end) val noisy = ref false fun evaluate(e,contList,env) = (let val (e',ks) = transform(e,contList) val ks' = (List.map (fn (c as Ret_opt(l,id,e)) => Ret_opt(l,id,simplify(e,ks))) ks) val s = simplify(e',ks') val _ = (List.map(fn (c as Ret_opt(l,id,e)) => HashTable.insert LabelRep (l,Cont_v(Ret_opt(l,id,e)))) ks') val _ = (print("\n"); print("Optimized Expression: \n ----------------------- \n\n"); print(PP.ppCpsOptExp(s) ^ "\n"); print("Non-Inlined Continuations: \n ------------------------ \n"); List.map (fn (k as Ret_opt(l,id,e)) => let val Cont_v(k') = (HashTable.lookup LabelRep l) in (if not(inlinable(l,ks)) then (print(PP.ppContOptExp(k')); print("\n")) else ()) end) ks; if (!noisy) then print("Inlined Continuations: \n ----------------------- \n") else (); if (!noisy) then (List.map (fn (k as Ret_opt(l,id,e)) => let val Cont_v(k') = (HashTable.lookup LabelRep l) in (if inlinable(l,ks) then (print(PP.ppContOptExp(k')); print("\n")) else ()) end) ks; ()) else ()) in eval(env,EmptyCEnv,Empty,s) end) (*-------------- Interpreter ---------------*) (* The toplevel environment: keep a substitution for toplevel * declarations, and a type context for the type of the toplevel * identifiers *) type global_env = {type_context: TC.context, compiler_context:S.senv, top_level: renv} (* reconstruct a string from a list of tokens, inserting spaces *) fun reconstructString (sl:string list):string = ListFormat.fmt {final="",init="",fmt=fn x => x,sep=" "} sl (* the interpreter entry point *) fun interpreter ():unit = let (* execute a command *) fun interpretCommand (s:string,genv:global_env):unit = let (* load an expression from a file *) fun load (f:string,compile):unit = let val instream = TextIO.openIn (f) val parsed = Parser.parse(instream) val _ = TextIO.closeIn(instream) val newEnv = interpretParse (parsed,genv,compile) in interpreter_loop (newEnv) end (* display the parse tree of an expression *) fun show_parse (rest:string list):unit = let val s = reconstructString (rest) in (case Parser.parseString (s) of NONE => () | SOME (A.Exp_t (e)) => (print (PrettyPrinter.ppExp (e)); print "\n") | SOME(A.Decl_t (ds))=> (print (foldr (fn (d,s)=>(PrettyPrinter.ppDecl d)^s)"" ds); print "\n")); interpreter_loop(genv) end (* perform an underlying system call *) fun system (rest:string list):unit = let val s = reconstructString (rest) in OS.Process.system (s); interpreter_loop (genv) end in case Substring.getc (Substring.full (s)) of NONE => interpreter_loop (genv) | SOME (#":",ss) => let val t = String.tokens Char.isSpace (Substring.string (ss)) in case t of ("l"::f::_) => load (f,true) | ("e"::rest) => (interpretParse(Parser.parseString(reconstructString(rest)),genv:global_env,true); interpreter_loop(genv)) | ("p"::rest) => show_parse (rest) | ("t"::rest) => (interpretParse(Parser.parseString(reconstructString(rest)),genv:global_env,false); interpreter_loop(genv)) | ("tl"::f::_) => load(f,false) | ("q"::_) => print "Bye.\n" | _ => (print "Command not recognized\n"; interpreter_loop (genv)) end | _ => (print "Command not recognized\n"; interpreter_loop (genv)) end (* if input is an expression or a declaration, parse * to obtain an abstract syntax tree *) and interpretParse (p:A.top_level option,genv:global_env,compile:bool) = let val {type_context,compiler_context,top_level} = genv fun comp_exp e = let val typ = T.tcheck (type_context,e) handle Fail s => Error.static ("TypeChecker Failure: " ^ s) val _ = print "Type checking successful ...\n" val _ = print(PrettyPrinter.ppTyp(typ) ^ "\n") val cexp = if compile then C.comp_exp e else C.Nop val _ = print "Core ML compilation successful ...\n" val _ = if (!noisy) then (print(CoreMLPP.ppCexp(cexp)); print("\n\n")) else () val (c,contList) = if compile then let val (c,contList) = Cps.cps(cexp,NONE,[]) in (c,contList) end else (Cps.Simple_cps(Cps.Nop_s),[]) val _ = if (!noisy) then (print(Cps_PP.ppCpsExp(c)); print("\n: Continuations:\n"); (List.map (fn cont => (print(Cps_PP.ppContExp cont); print("\n\n"))) contList); print("\n\n")) else () val (sexp,sContList) = if compile then S.comp_senv(c,contList,compiler_context) else (S.Simple_se(S.Nop_s),[]) val _ = (print "\n\n"; print "Static Environment Compilation successful:\n"; print "--------------------\n"; if (!noisy) then (print (SenvPP.ppSenvExp sexp); print("\n\n Continuations: \n\n"); (List.map (fn cont => (print(SenvPP.ppContSenvExp cont); print("\n\n"))) sContList); print "\n\n") else ()) in (typ,sexp,sContList) end in case p of NONE => genv | SOME(A.Decl_t([])) => genv (* evaluate an expression *) | SOME (A.Exp_t (exp)) => let val (_, c,contList) = comp_exp(exp) in if compile then (evaluate(c,contList,top_level); genv) else genv end | SOME (A.Decl_t (A.Val_d(A.Id_p(x),e1)::ds)) => (* for declarations: val x = e, evaluate e and push * it into the interpreter's environment, and then * enter a binding into both the type-checker's and * compiler's context *) let val (typ,c,contList) = comp_exp(e1) in (interpretParse (SOME(A.Decl_t(ds)), {type_context = TC.add_var(type_context, x, typ), compiler_context = S.addvar compiler_context x, top_level = REnv(evaluate(c,contList,top_level),top_level)}, compile)) end | SOME(A.Decl_t((d as A.Fun_d({name,arg,arg_typ,ret_typ},body))::ds))=> let val e = A.Let_e([d],A.Id_e(name)) val (typ,c,contList) = comp_exp(e) in (interpretParse (SOME(A.Decl_t(ds)), {type_context = TC.add_var(type_context, name, typ), compiler_context = S.addvar compiler_context name, top_level = REnv(evaluate(c,contList,top_level),top_level)}, compile)) end (* we don't deal with all of the other forms of declarations at * the top-level *) | SOME (A.Decl_t(_)) => (print "Sorry, only val and fun top-level declarations "; print "are supported in this version of Mini-ML.\n"; genv) end (* the main interpreter loop. It passes the toplevel env around *) and interpreter_loop (genv:global_env):unit = let fun processLine ():unit = (case TextIO.inputLine (TextIO.stdIn) of NONE => () | SOME c => (case c of "" => () | s => if (String.isPrefix ":" s) (* if it is a command *) then interpretCommand (s,genv) else let val s = String.extract (s,0,SOME (size (s)-1)) val newEnv = interpretParse (Parser.parseString (s),genv,true) in interpreter_loop (newEnv) end)) in TextIO.output (TextIO.stdOut, "Cps> "); TextIO.flushOut (TextIO.stdOut); processLine () handle Error.Error => interpreter_loop (genv) | e => (print "EXCEPTION: "; print (exnMessage (e)); print "\n"; interpreter_loop (genv)) end val line = String.implode (List.tabulate (78,fn _ => #"-")) in print (concat [line,"\nCS502 MiniML compiler/Optimized CPS interpreter\n"]); interpreter_loop ({type_context=TC.empty_env, compiler_context=S.emptyStaticEnv, top_level=EmptyREnv}) end end