package function.builtin.special; import function.ArgumentValidator; import function.FunctionNames; import function.LispSpecialFunction; import recursion.TailCall; import sexpression.Cons; import sexpression.SExpression; import static function.builtin.EVAL.eval; import static recursion.TailCalls.done; import static recursion.TailCalls.tailCall; import static sexpression.Nil.NIL; @FunctionNames({ "PROGN", "BEGIN" }) public class PROGN extends LispSpecialFunction { private ArgumentValidator argumentValidator; public PROGN(String name) { this.argumentValidator = new ArgumentValidator(name); } @Override public SExpression call(Cons argumentList) { argumentValidator.validate(argumentList); return callTailRecursive(argumentList, NIL).invoke(); } private TailCall callTailRecursive(Cons argumentList, SExpression lastValue) { if (argumentList.isNull()) return done(lastValue); SExpression currentValue = eval(argumentList.getFirst()); Cons remainingValues = (Cons) argumentList.getRest(); return tailCall(() -> callTailRecursive(remainingValues, currentValue)); } }