package function.builtin.special; import static function.builtin.EVAL.eval; import static sexpression.Nil.NIL; import function.*; import sexpression.*; @FunctionNames({ "COND" }) public class COND extends LispSpecialFunction { private ArgumentValidator argumentValidator; public COND() { this.argumentValidator = new ArgumentValidator("COND"); this.argumentValidator.setEveryArgumentExpectedType(Cons.class); this.argumentValidator.setEveryArgumentExcludedType(Nil.class); } public SExpression call(Cons argumentList) { argumentValidator.validate(argumentList); return callTailRecursive(argumentList); } private SExpression callTailRecursive(Cons argumentList) { if (argumentList.isNull()) return NIL; Cons clause = (Cons) argumentList.getFirst(); Cons remainingClauses = (Cons) argumentList.getRest(); SExpression test = eval(clause.getFirst()); if (isTestSuccessful(test)) return evaluateConsequents(clause.getRest(), test); return callTailRecursive(remainingClauses); } private boolean isTestSuccessful(SExpression test) { return test != NIL; } private SExpression evaluateConsequents(SExpression consequentList, SExpression test) { SExpression lastConsequentValue = test; for (; consequentList.isCons(); consequentList = advanceCons(consequentList)) lastConsequentValue = eval(getFirst(consequentList)); return lastConsequentValue; } private SExpression advanceCons(SExpression knownCons) { return ((Cons) knownCons).getRest(); } private SExpression getFirst(SExpression knownCons) { return ((Cons) knownCons).getFirst(); } }