public Object eval(Env env) { Object f = fexpr.eval(env); Object[] args = new Object[argexprs.Length]; for(Int32 i=0;i<args.Length;i++) args[i] = argexprs[i].eval(env); Boolean doTrace = fsym != null && interpreter.traceList.Contains(fsym); try { if(doTrace) { interpreter.trace(fsym.name,args); Trace.Indent(); Object ret = Util.InvokeObject(f,args); Trace.Unindent(); return ret; } else return Util.InvokeObject(f,args); } catch(Exception ex) { if(fsym != null && !fsym.name.Equals("throw")) { throw BacktraceException.push(ex,new BacktraceFrame(loc,fsym,args) ,interpreter); } else { throw ex; } } }
public Object eval(Env env) { DynamicEnv d = DynamicEnv.find(sym); if(d != null) return d.val; return sym.getGlobalValue(); }
internal Closure(Cons args,Env env,Interpreter interpreter,Loc loc) { this.interpreter = interpreter; this.loc = loc; ArgSpecs specs = analyzeArgSpec((Cons)args.first,env,loc); //create an env expanded by params in which to analyze body Env env2 = new Env(specs.parameters, null, env, interpreter); this.argSpecs = specs; this.body = interpreter.analyze(new Cons(interpreter.BLOCK,args.rest), env2,loc); this.env = env; }
internal ApplyExpression(Cons args,Env env,Interpreter interpreter,Loc loc) { this.loc = loc; this.interpreter = interpreter; fexpr = interpreter.analyze(args.first,env,loc); if(fexpr is IVar) { fsym = ((IVar)fexpr).getSymbol(); } Int32 len = Cons.Length(args.rest); argexprs = new IExpression[len]; args = args.rest; for(Int32 i=0;i<argexprs.Length;i++,args = args.rest) { argexprs[i] = interpreter.analyze(args.first,env,loc); } }
public Interpreter(Interpreter parent) { this.Parent = parent; globalenv = new Env(null,null,null,this); reader = new Reader(this); symbolTable = new SymbolTable(this); Assembly[] asm = AppDomain.CurrentDomain.GetAssemblies(); foreach(Assembly a in asm) { addTypesFrom(a); } addTypesFrom(Assembly.LoadWithPartialName("System.Web")); internBuiltins(); Primitives.internAll(this); // MEH: EX was not set to null EX.setGlobalValue(null); LASTVAL.setGlobalValue(null); NEXTLASTVAL.setGlobalValue(null); THIRDLASTVAL.setGlobalValue(null); //these primitives are here, rather than in Primitives, because their implementation //requires calls to gfs bound to symbols Intern("intern",new Function(internf)); Intern("eval",new Function(evalf)); Intern("load",new Function(loadf)); Intern("map->list",new Function(map_to_list)); Intern("apply",new Function(apply)); Intern("<",new Function(lt)); Intern("<=",new Function(lteq)); Intern(">",new Function(gt)); Intern(">=",new Function(gteq)); Intern("==",new Function(eqeq)); Intern("!=",new Function(noteq)); strgf = (GenericFunction)intern("str").getGlobalValue(); get_enum_gf = (GenericFunction)intern("get-enum").getGlobalValue(); compare_gf = (BinOp)intern("compare").getGlobalValue(); Intern("interpreter",this); }
internal Env(Parameter[] vars, Object[] vals, Env parent) { this.vars = vars; this.vals = vals; this.parent = parent; }
internal IExpression analyze(Object expr, Env env, Loc enclosingLoc) { Symbol symbol = expr as Symbol; if(symbol != null) { if(symbol.isDynamic) return new DynamicVar(symbol); Object var = env.lookup(symbol); if(var is LocalVariable) return new LocalVar((LocalVariable)var); else return new GlobalVar((Symbol)var); } if(!(expr is Cons)) //must be literal return new QuoteExpr(expr); Cons exprs = (Cons)expr; Loc loc = (Loc)reader.locTable[expr]; if(loc != null) reader.locTable.Remove(expr); else loc = enclosingLoc; Object f = exprs.first; Cons args = exprs.rest; //see if it's a macro Symbol s = f as Symbol; if(s != null && s.isDefined() && s.getGlobalValue() is Macro) { Macro m = (Macro)s.getGlobalValue(); Object[] argarray = Cons.ToVector(args); Object mexprs = null; try { mexprs = m.Invoke(argarray); } catch(Exception ex) { BacktraceFrame frame = new BacktraceFrame(loc,s,args); throw BacktraceException.push(ex,frame,this); } try { return analyze(mexprs,env,loc); } catch(Exception ex) { BacktraceFrame frame = new BacktraceFrame(loc,"when expanding ",exprs); throw BacktraceException.push(ex,frame,this); } } Int32 numargs = Cons.Length(args); if(f == DLET) return new DynamicLet(args,env,this,loc); else if(f == FN) return new Closure(args,env,this,loc); else if(f == MACRO) return new Macro(args,env,this,loc); else if(f == WHILE) return new WhileExpression(args,env,this,loc); else if(f == BLOCK) { if(numargs == 0) return new QuoteExpr(null); //remove block from block of one else if(numargs == 1) return analyze(args.first,env,loc); else return new BlockExpression(args,env,this,loc); } else if(f == OR) { if(numargs == 0) return new QuoteExpr(null); else return new OrExpression(args,env,this,loc); } else if(f == IF) return new IfExpression(args,env,this,loc); else if(f == QUOTE) return new QuoteExpr(args.first); else if(f == SET) return new SetExpression(args,env,this,loc); else //presume funcall return new ApplyExpression(exprs,env,this,loc); }
public Object eval(Env env) { return env.getValue(var); }
public Object eval(Env env) { return sym.getGlobalValue(); }
public Object eval(Env env) { return(sym.getGlobalValue()); }
internal DynamicLet(Cons args,Env env,Interpreter interpreter,Loc loc) { this.loc = loc; this.interpreter = interpreter; Cons bindlist = (Cons)args.first; Int32 blen = Cons.Length(bindlist); if((blen%2) != 0) //odd { throw new Exception("Odd number of args in dynamic-let binding list"); } binds = new BindPair[blen/2]; for(int i = 0;i<binds.Length;i++) { binds[i].dvar = (DynamicVar)interpreter.analyze(bindlist.first, env,loc); bindlist = bindlist.rest; binds[i].expr = interpreter.analyze(bindlist.first, env,loc); bindlist = bindlist.rest; } this.body = interpreter.analyze(new Cons(interpreter.BLOCK,args.rest), env,loc); }
internal Macro(Cons args, Env env, Interpreter interpreter, Loc loc) : base(args, env, interpreter, loc) { }
public void setval(Object val, Env env) { env.setValue(var, val); }
public Object eval(Env env) { return(env.getValue(var)); }
public void setval(Object val, Env env) { sym.setGlobalValue(val); }
internal Closure copy(Env env) { Closure c = null; try { c = (Closure)this.MemberwiseClone(); } catch(Exception e) { throw new Exception("internal error: no clone " + e.Message); } c.env = env; c.argSpecs = argSpecs.copy(env); return c; }
public Object eval(Env env) { return copy(env); }
public Object eval(Env env) { DynamicEnv olddenv = DynamicEnv.current(); try { for(int i = 0;i<binds.Length;i++) { DynamicEnv.extend(binds[i].dvar.sym, binds[i].expr.eval(env)); } return body.eval(env); } catch(BacktraceException bex) { throw bex; } catch(Exception ex) { throw BacktraceException.push(ex,new BacktraceFrame(loc,"set",null),interpreter); } finally { DynamicEnv.restore(olddenv); } }
public Object eval(Env env) { try { Object retval = val.eval(env); var.setval(retval,env); return retval; } catch(BacktraceException bex) { throw bex; } catch(Exception ex) { throw BacktraceException.push(ex,new BacktraceFrame(loc,"set",null),interpreter); } }
internal WhileExpression(Cons args,Env env,Interpreter interpreter,Loc loc) { this.loc = loc; this.interpreter = interpreter; this.test = interpreter.analyze(args.first,env,loc); this.body = interpreter.analyze(new Cons(interpreter.BLOCK,args.rest),env,loc); }
public void setval(Object val,Env env) { sym.setGlobalValue(val); }
public Object eval(Env env) { try { while(Util.isTrue(test.eval(env))) { body.eval(env); } return null; } catch(BacktraceException bex) { throw bex; } catch(Exception ex) { throw BacktraceException.push(ex,new BacktraceFrame(loc,"set",null),interpreter); } }
public void setval(Object val,Env env) { env.setValue(var,val); }
public Object eval(Env env) { return val; }
public void setval(Object val,Env env) { DynamicEnv d = DynamicEnv.find(sym); if(d != null) d.val = val; sym.setGlobalValue(val); }
public Object eval(Env env) { try { for(Int32 i=0;i<exprs.Length-1;i++) exprs[i].eval(env); return exprs[exprs.Length-1].eval(env); } catch(BacktraceException bex) { throw bex; } catch(Exception ex) { throw BacktraceException.push(ex,new BacktraceFrame(loc,"set",null),interpreter); } }
internal IExpression analyze(Object expr,Env env) { return analyze(expr,env,null); }
internal OrExpression(Cons args,Env env,Interpreter interpreter,Loc loc) { this.loc = loc; this.interpreter = interpreter; exprs = new IExpression[Cons.Length(args)]; for(Int32 i=0;i<exprs.Length;i++,args = args.rest) { exprs[i] = interpreter.analyze(args.first,env,loc); } }
internal Object eval(Object x, Env env) { IExpression analyzedCode = analyze(x,env); return analyzedCode.eval(env); //Object analyzedCode = analyze(x,env); //return execute(analyzedCode, env); }
public Object eval(Env env) { try { for(Int32 i = 0; i < exprs.Length-1; i++) { Object result = exprs[i].eval(env); if(Util.isTrue(result)) return result; } return exprs[exprs.Length-1].eval(env); } catch(BacktraceException bex) { throw bex; } catch(Exception ex) { throw BacktraceException.push(ex,new BacktraceFrame(loc,"set",null),interpreter); } }
internal IfExpression(Cons args,Env env,Interpreter interpreter,Loc loc) { this.loc = loc; this.interpreter = interpreter; Int32 len = Cons.Length(args); if(len < 2 || len > 3) throw new Exception("Wrong number of args for if"); test = interpreter.analyze(args.first,env,loc); brtrue = interpreter.analyze(Cons.Second(args),env,loc); if(len == 3) brfalse = interpreter.analyze(Cons.Third(args),env,loc); else brfalse = new QuoteExpr(null); }
public Object eval(Env env) { try { if(Util.isTrue(test.eval(env))) return brtrue.eval(env); return brfalse.eval(env); } catch(BacktraceException bex) { throw bex; } catch(Exception ex) { throw BacktraceException.push(ex,new BacktraceFrame(loc,"if",null),interpreter); } }
//returns an array of evaluated args corresponding to params of argspec, //including substitution of default values where none provided, construction of //rest list etc //suitable for extending the environment prior to evaluating body of closure internal Object[] buildParamArray(Object[] code, Int32 offset, Env env//, Boolean evalArgs ) { //do nothing if fixed params and matching number if(argSpecs.nParams() == argSpecs.numReq && argSpecs.numReq == code.Length) return code; Object[] argArray = new Object[nParms()]; int nargs = code.Length-offset; if(nargs < argSpecs.numReq) throw new Exception("Too few arguments to procedure, expected at least " + argSpecs.numReq +", but found "+ nargs +" arguments"); int i; // Fill in the required parameters for(i = 0; i < argSpecs.numReq; i++) { argArray[i] = //evalArgs?Interpreter.execute(code[i+offset], env): code[i+offset]; } //now grab args to satisfy optionals if(argSpecs.numOpt > 0) { for(i = argSpecs.numReq; i < argSpecs.numReq + argSpecs.numOpt; i++) { if(i<nargs) { argArray[i] = //evalArgs?Interpreter.execute(code[i+offset], env): code[i+offset]; //if missing passed to optional, get default if(argArray[i] == Missing.Value) { argArray[i] = getDefaultParamValue(argSpecs.parameters[i]); } } else //ran out of args, default the rest { argArray[i] = getDefaultParamValue(argSpecs.parameters[i]); } } } //build a rest list Cons rest = null; for(int x = code.Length-1;x-offset >= i; --x) { Object val = //evalArgs?Interpreter.execute(code[x], env): code[x]; rest = new Cons(val, rest); } //search for key args in rest if(argSpecs.numKey > 0) { for(i = argSpecs.numReq + argSpecs.numOpt; i < argSpecs.numReq + argSpecs.numOpt + argSpecs.numKey; i++) { argArray[i] = findKeyParamValue(argSpecs.parameters[i],rest); } } // Add the rest parameter (if there is one) if(argSpecs.numRest == 1) { argArray[i] = rest; } return argArray; }
internal SetExpression(Cons args,Env env,Interpreter interpreter,Loc loc) { this.loc = loc; this.interpreter = interpreter; Int32 len = Cons.Length(args); if(len != 2) throw new Exception("Wrong number of args for set"); var = (IVar)interpreter.analyze(args.first,env,loc); val = interpreter.analyze(Cons.Second(args),env,loc); }
//parse out params from spec (which may contain &optional, &key, &rest, initforms etc internal ArgSpecs analyzeArgSpec(Cons arglist, Env env,Loc loc) { //count the params int nParams = 0; Cons a = arglist; while(a!=null) { Object p = a.first; if(p!=interpreter.AMPOPT && p!=interpreter.AMPKEY && p!=interpreter.AMPREST) ++nParams; a = a.rest; } ArgSpecs ret = new ArgSpecs(env); ret.parameters = new Parameter[nParams]; Parameter.Spec state = Parameter.Spec.REQ; int param = 0; a = arglist; while(a!=null) { Object p = a.first; switch(state) { case Parameter.Spec.REQ: if(p==interpreter.AMPOPT) state = Parameter.Spec.OPT; else if(p==interpreter.AMPKEY) state = Parameter.Spec.KEY; else if(p==interpreter.AMPREST) state = Parameter.Spec.REST; else { if(p is Symbol) { ret.parameters[param++] = new Parameter((Symbol)p,Parameter.Spec.REQ,null); ++ret.numReq; } else if(p is Cons) { ret.parameters[param] = new Parameter((Symbol)((Cons)p).first,Parameter.Spec.REQ,null); ret.parameters[param].typeSpec = interpreter.eval(Cons.Second((Cons)p),env); ++param; ++ret.numReq; } } break; case Parameter.Spec.OPT: if(p==interpreter.AMPOPT) throw new Exception("&optional can appear only once in arg list"); else if(p==interpreter.AMPKEY) state = Parameter.Spec.KEY; else if(p==interpreter.AMPREST) state = Parameter.Spec.REST; else { if(p is Symbol) { ret.parameters[param++] = new Parameter((Symbol)p,Parameter.Spec.OPT,null); ++ret.numOpt; } else if(p is Cons) { ret.parameters[param++] = new Parameter((Symbol)((Cons)p).first,Parameter.Spec.OPT, interpreter.analyze(Cons.Second((Cons)p),env,loc)); ++ret.numOpt; } else throw new Exception("&optional parameters must be symbols or (symbol init-form)"); } break; case Parameter.Spec.KEY: if(p==interpreter.AMPOPT) throw new Exception("&optional must appear before &key in arg list"); else if(p==interpreter.AMPKEY) throw new Exception("&key can appear only once in arg list"); else if(p==interpreter.AMPREST) state = Parameter.Spec.REST; else { if(p is Symbol) { ret.parameters[param] = new Parameter((Symbol)p,Parameter.Spec.KEY,null); ret.parameters[param].key = interpreter.intern(":" + ((Symbol)p).name); ++param; ++ret.numKey; } else if(p is Cons) { ret.parameters[param] = new Parameter((Symbol)((Cons)p).first,Parameter.Spec.KEY, interpreter.analyze(Cons.Second((Cons)p),env,loc)); ret.parameters[param].key = interpreter.intern(":" + ((Symbol)((Cons)p).first).name); ++param; ++ret.numKey; } else throw new Exception("&key parameters must be symbols or (symbol init-form)"); } break; case Parameter.Spec.REST: if(p==interpreter.AMPOPT) throw new Exception("&optional must appear before &rest in arg list"); else if(p==interpreter.AMPKEY) throw new Exception("&key must appear before &rest in arg list"); else if(p==interpreter.AMPREST) throw new Exception("&rest can appear only once in arg list"); else { if(!(p is Symbol)) throw new Exception("&rest parameter must be a symbol"); else { if(ret.numRest > 0) //already got a rest param throw new Exception("Only one &rest arg can be specified"); ret.parameters[param++] = new Parameter((Symbol)p,Parameter.Spec.REST,null); ++ret.numRest; } } break; } a = a.rest; } return ret; }
public Object eval(Env env) { return(val); }