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.SExpression;

@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<SExpression> 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));
    }

}
