//////////////// Evaluation /** Evaluate an object, x, in an environment. **/ public Object eval(Object x, Environment env) { // The purpose of the while loop is to allow tail recursion. // The idea is that in a tail recursive position, we do "x = ..." // and loop, rather than doing "return eval(...)". while (true) { if (x is String) { // VARIABLE return env.lookup((String)x); } else if (!(x is Pair)) { // CONSTANT return x; } else { Object fn = first(x); Object args = rest(x); if(fn is String) { String sfn = (String) fn; if (sfn == "quote") { // QUOTE return first(args); } else if (sfn == "begin") { // BEGIN for (; rest(args) != null; args = rest(args)) { eval(first(args), env); } x = first(args); } else if (sfn == "define") { // DEFINE if (first(args) is Pair) return env.define(first(first(args)), eval(cons("lambda", cons(rest(first(args)), rest(args))), env)); else return env.define(first(args), eval(second(args), env)); } else if (sfn == "set!") { // SET! return env.set(first(args), eval(second(args), env)); } else if (sfn == "if") { // IF x = (truth(eval(first(args), env))) ? second(args) : third(args); } else if (sfn == "cond") { // COND x = reduceCond(args, env); } else if (sfn == "lambda") { // LAMBDA return new Closure(first(args), rest(args), env); } else if (sfn == "macro") { // MACRO return new Macro(first(args), rest(args), env); } else { error("Unknown primitive fn" + fn); } } else { // PROCEDURE CALL: fn = eval(fn, env); if (fn is Macro) { // (MACRO CALL) x = ((Macro)fn).expand(this, (Pair)x, args); } else if (fn is Closure) { // (CLOSURE CALL) Closure f = (Closure)fn; x = f.body; env = new Environment(f.parms, evalList(args, env), f.env); } else { // (OTHER PROCEDURE CALL) return Procedure.proc(fn).apply(this, evalList(args, env)); } } } } }