ParserTableActionBuilder.java

package org.sterling.source.parser;

import static org.sterling.source.parser.ParserRule.rule;
import static org.sterling.source.parser.ParserState.state;
import static org.sterling.source.parser.TableDrivenParser.Derive;

import java.util.LinkedHashSet;
import java.util.Set;
import org.sterling.source.exception.ParserException;
import org.sterling.source.parser.TableDrivenParser.TryDerive;
import org.sterling.source.syntax.NodeKind;

public class ParserTableActionBuilder {

    private static final ParserAction OUTPUT = new ParserAction() {
        @Override
        public void invoke(TableDrivenParser parser) throws ParserException {
            parser.output();
        }
    };
    private final ParserTableBuilder builder;
    private final NodeKind stack;
    private final Set<NodeKind> lookAhead;
    private boolean seenLookAhead;

    public ParserTableActionBuilder(ParserTableBuilder builder, NodeKind stack) {
        this.builder = builder;
        this.stack = stack;
        this.lookAhead = new LinkedHashSet<>();
    }

    public ParserTableActionBuilder derive(NodeKind... stack) {
        return then(new Derive(stack));
    }

    public ParserTable getTable() {
        return builder.getTable();
    }

    public ParserTableActionBuilder or(NodeKind... lookAhead) {
        shouldHaveLookAhead();
        addLookAhead(lookAhead);
        return this;
    }

    public ParserTableActionBuilder output() {
        return then(OUTPUT);
    }

    public ParserTableActionBuilder sees(NodeKind... lookAhead) {
        if (seenLookAhead) {
            throw new IllegalStateException("Have already seen look-ahead tokens for stack " + stack);
        }
        seenLookAhead = true;
        addLookAhead(lookAhead);
        return this;
    }

    public ParserTableActionBuilder then(ParserAction action) {
        for (NodeKind lookAhead : this.lookAhead) {
            builder.addRule(rule(state(stack, lookAhead), action));
        }
        return this;
    }

    public ParserTableActionBuilder tryDerive(NodeKind... tries) {
        return then(new TryDerive(tries));
    }

    public ParserTableActionBuilder when(NodeKind stack) {
        return new ParserTableActionBuilder(builder, stack);
    }

    private void addLookAhead(NodeKind[] lookAhead) {
        for (NodeKind kind : lookAhead) {
            if (this.lookAhead.contains(kind)) {
                throw new IllegalStateException("Look-ahead " + kind + " already added for stack " + stack);
            }
            this.lookAhead.add(kind);
        }
    }

    private void shouldHaveLookAhead() {
        if (!seenLookAhead) {
            throw new IllegalStateException("Have not seen look-ahead tokens for stack " + stack);
        }
    }
}