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;
                }
            }
        }
        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);

            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()
        {
            globalenv = new Env(null, null, null);
            reader = new Reader(this);
            symbolTable = new SymbolTable();

            Assembly[] asm = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly a in asm)
            {
                addTypesFrom(a);
            }

            internBuiltins();
            Primitives.internAll(this);
            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);
        }
 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 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;
        }
        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);
        }
 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);
 }
        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 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);
     }
 }
 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 void setval(Object val, Env env)
 {
     sym.setGlobalValue(val);
 }
 public Object eval(Env env)
 {
     return sym.getGlobalValue();
 }
 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)
 {
     DynamicEnv d = DynamicEnv.find(sym);
     if (d != null)
         return d.val;
     return sym.getGlobalValue();
 }
 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);
     }
 }
 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);
 }
 internal Env(Parameter[] vars, Object[] vals, Env parent)
 {
     this.vars = vars; this.vals = vals; this.parent = parent;
 }
 internal ArgSpecs copy(Env env)
 {
     ArgSpecs a = (ArgSpecs)MemberwiseClone();
     a.env = env;
     return a;
 }
 public Object eval(Env env)
 {
     return env.getValue(var);
 }
        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 ArgSpecs(Env env)
 {
     this.env = env;
 }
 public void setval(Object val, Env env)
 {
     env.setValue(var, val);
 }
 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 Macro(Cons args, Env env, Interpreter interpreter, Loc loc)
     : base(args, env, interpreter, loc)
 {
 }
 public Object eval(Env env)
 {
     return val;
 }