ParserTable.java
package org.sterling.source.parser;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.sterling.SterlingException;
import org.sterling.source.syntax.NodeKind;
import org.sterling.source.syntax.SourceNode;
public class ParserTable {
private static final ParserAction ERROR = new ParserAction() {
@Override
public void invoke(TableDrivenParser parser) throws SterlingException {
parser.error();
}
};
private static Map<NodeKind, List<NodeKind>> initLookAheadMap(Collection<ParserRule> rules) {
Map<NodeKind, List<NodeKind>> lookAheadMap = new ConcurrentHashMap<>();
for (ParserRule rule : rules) {
ParserState state = rule.getState();
if (!lookAheadMap.containsKey(state.getStack())) {
lookAheadMap.put(state.getStack(), new CopyOnWriteArrayList<NodeKind>());
}
lookAheadMap.get(state.getStack()).add(state.getLookAhead());
}
return lookAheadMap;
}
private static Map<ParserState, ParserAction> initTable(Collection<ParserRule> rules) {
Map<ParserState, ParserAction> stateActionMap = new ConcurrentHashMap<>();
for (ParserRule rule : rules) {
if (stateActionMap.containsKey(rule.getState())) {
throw new IllegalArgumentException("Duplicate rule for parser state " + rule.getState());
}
stateActionMap.put(rule.getState(), rule.getAction());
}
return stateActionMap;
}
private final Map<ParserState, ParserAction> table;
private final Map<NodeKind, List<NodeKind>> lookAheadMap;
private final ParserAction errorAction;
public ParserTable(Collection<ParserRule> rules) {
this.lookAheadMap = initLookAheadMap(rules);
this.table = initTable(rules);
this.errorAction = ERROR;
}
public ParserAction getAction(ParserState state) {
if (table.containsKey(state)) {
return table.get(state);
} else {
return errorAction;
}
}
public ParserAction getErrorAction() {
return errorAction;
}
public List<NodeKind> getLookAhead(SourceNode node) {
NodeKind stack = node.getKind();
if (hasLookAhead(stack)) {
return new ArrayList<>(lookAheadMap.get(stack));
} else {
throw new IllegalStateException("No look-ahead tokens registered to " + stack);
}
}
private boolean hasLookAhead(NodeKind stack) {
return lookAheadMap.containsKey(stack);
}
}