70 lines
2.1 KiB
Java
70 lines
2.1 KiB
Java
package function.builtin.special;
|
|
|
|
import static function.builtin.EVAL.eval;
|
|
import static recursion.TailCalls.done;
|
|
import static recursion.TailCalls.tailCall;
|
|
import static sexpression.Nil.NIL;
|
|
|
|
import function.ArgumentValidator;
|
|
import function.FunctionNames;
|
|
import function.LispSpecialFunction;
|
|
import recursion.TailCall;
|
|
import sexpression.Cons;
|
|
import sexpression.Nil;
|
|
import sexpression.SExpression;
|
|
|
|
@FunctionNames({ "COND" })
|
|
public class COND extends LispSpecialFunction {
|
|
|
|
private ArgumentValidator argumentValidator;
|
|
|
|
public COND(String name) {
|
|
this.argumentValidator = new ArgumentValidator(name);
|
|
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
|
|
this.argumentValidator.setEveryArgumentExcludedType(Nil.class);
|
|
}
|
|
|
|
@Override
|
|
public SExpression call(Cons argumentList) {
|
|
argumentValidator.validate(argumentList);
|
|
|
|
return callTailRecursive(argumentList).invoke();
|
|
}
|
|
|
|
private TailCall<SExpression> callTailRecursive(Cons argumentList) {
|
|
if (argumentList.isNull())
|
|
return done(NIL);
|
|
|
|
Cons clause = (Cons) argumentList.getFirst();
|
|
Cons remainingClauses = (Cons) argumentList.getRest();
|
|
SExpression test = eval(clause.getFirst());
|
|
|
|
if (isTestSuccessful(test))
|
|
return done(evaluateConsequents(clause.getRest(), test));
|
|
|
|
return tailCall(() -> 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();
|
|
}
|
|
|
|
}
|