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