package token;

import static recursion.TailCalls.tailCall;
import static sexpression.Nil.NIL;

import java.util.function.Supplier;

import file.FilePosition;
import recursion.TailCall;
import sexpression.Cons;
import sexpression.SExpression;

public abstract class Token {

    private String text;
    private FilePosition position;

    public Token(String text, FilePosition position) {
        this.text = text;
        this.position = position;
    }

    public String getText() {
        return text;
    }

    public FilePosition getPosition() {
        return position;
    }

    // --------------------------------------------------------------------------------------------
    // s-expression
    // ::= NUMBER | IDENTIFIER | STRING | QUOTE_MARK s-expression | LEFT_PAREN list-tail
    //
    // list-tail
    // ::= RIGHT_PAREN | s-expression list-tail
    // --------------------------------------------------------------------------------------------

    public abstract SExpression parseSExpression(Supplier<Token> getNextToken);

    protected TailCall<Cons> parseListTail(Supplier<Token> getNextToken) {
        Cons firstCons = new Cons(parseSExpression(getNextToken), NIL);
        Token next = getNextToken.get();

        return tailCall(() -> next.parseListTailRecursive(firstCons, firstCons, getNextToken));
    }

    protected TailCall<Cons> parseListTailRecursive(Cons start, Cons end, Supplier<Token> getNextToken) {
        Cons newEnd = new Cons(parseSExpression(getNextToken), NIL);
        Token next = getNextToken.get();
        end.setRest(newEnd);

        return tailCall(() -> next.parseListTailRecursive(start, newEnd, getNextToken));
    }

}
