/// <summary> /// Evaluates an expression in a given lexical environment /// </summary> /// <param name="form"></param> /// <param name="environment"></param> /// <returns></returns> public static Object Eval(Object expression, Environment environment) { profiler.TraceCall(expression); if (expression == Reader.EOFVALUE) { return(profiler.TraceReturn(expression)); } if (expression == null) { return(profiler.TraceReturn(null)); } // The expression is either an atom or a list if (Primitives.IsAtom(expression)) { // Number if (expression is double) { return(profiler.TraceReturn(expression)); } if (expression is int) { return(profiler.TraceReturn(expression)); } // Character if (expression is char) { return(profiler.TraceReturn(expression)); } // String if (expression is string) { return(profiler.TraceReturn(expression)); } Symbol sym = expression as Symbol; if (sym == Symbol.TRUE) { return(profiler.TraceReturn(true)); } if (sym == Symbol.FALSE) { return(profiler.TraceReturn(false)); } if (sym == Symbol.NULL) { return(profiler.TraceReturn(null)); } // If the symbol is bound to a value in this lexical environment if (environment.Contains(sym)) { // Then it's a variable so return it's value return(profiler.TraceReturn(environment.GetValue(sym))); } else { // Otherwise symbols evaluate to themselves return(profiler.TraceReturn(expression)); } } else { // The expression must be a list Cons cons = (Cons)expression; // Lists are assumed to be of the form (function arguments) // See if there is a binding to a function, clsoure, macro or special form // in this lexical environment object function = environment.GetValue((Symbol)cons.First()); // If there is no binding, then use the function name directly - it's probably // the name of a .NET method if (function == null) { function = cons.First(); } // If it's a special form if (function is SpecialForm) { return(profiler.TraceReturn(((SpecialForm)function)((Cons)cons.Cdr(), environment))); } // If its a macro application if (function is Macro) { object expansion = ((Macro)function).Expand((Cons)cons.Cdr()); return(profiler.TraceReturn(Runtime.Eval(expansion, environment))); } // It must be a function, closure or method invocation, // so call apply Object arguments = EvalList((Cons)cons.Cdr(), environment); return(profiler.TraceReturn(Runtime.Apply(function, arguments, environment))); } }