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