use of org.antlr.v4.runtime.misc.DoubleKeyMap in project antlr4 by antlr.
the class GrammarTransformPipeline method integrateImportedGrammars.
/** Merge all the rules, token definitions, and named actions from
imported grammars into the root grammar tree. Perform:
(tokens { X (= Y 'y')) + (tokens { Z ) -> (tokens { X (= Y 'y') Z)
(@ members {foo}) + (@ members {bar}) -> (@ members {foobar})
(RULES (RULE x y)) + (RULES (RULE z)) -> (RULES (RULE x y z))
Rules in root prevent same rule from being appended to RULES node.
The goal is a complete combined grammar so we can ignore subordinate
grammars.
*/
public void integrateImportedGrammars(Grammar rootGrammar) {
List<Grammar> imports = rootGrammar.getAllImportedGrammars();
if (imports == null)
return;
GrammarAST root = rootGrammar.ast;
GrammarAST id = (GrammarAST) root.getChild(0);
GrammarASTAdaptor adaptor = new GrammarASTAdaptor(id.token.getInputStream());
GrammarAST tokensRoot = (GrammarAST) root.getFirstChildWithType(ANTLRParser.TOKENS_SPEC);
List<GrammarAST> actionRoots = root.getNodesWithType(ANTLRParser.AT);
// Compute list of rules in root grammar and ensure we have a RULES node
GrammarAST RULES = (GrammarAST) root.getFirstChildWithType(ANTLRParser.RULES);
Set<String> rootRuleNames = new HashSet<String>();
// make list of rules we have in root grammar
List<GrammarAST> rootRules = RULES.getNodesWithType(ANTLRParser.RULE);
for (GrammarAST r : rootRules) rootRuleNames.add(r.getChild(0).getText());
for (Grammar imp : imports) {
// COPY TOKENS
GrammarAST imp_tokensRoot = (GrammarAST) imp.ast.getFirstChildWithType(ANTLRParser.TOKENS_SPEC);
if (imp_tokensRoot != null) {
rootGrammar.tool.log("grammar", "imported tokens: " + imp_tokensRoot.getChildren());
if (tokensRoot == null) {
tokensRoot = (GrammarAST) adaptor.create(ANTLRParser.TOKENS_SPEC, "TOKENS");
tokensRoot.g = rootGrammar;
// ^(GRAMMAR ID TOKENS...)
root.insertChild(1, tokensRoot);
}
tokensRoot.addChildren(Arrays.asList(imp_tokensRoot.getChildren().toArray(new Tree[0])));
}
List<GrammarAST> all_actionRoots = new ArrayList<GrammarAST>();
List<GrammarAST> imp_actionRoots = imp.ast.getAllChildrenWithType(ANTLRParser.AT);
if (actionRoots != null)
all_actionRoots.addAll(actionRoots);
all_actionRoots.addAll(imp_actionRoots);
// COPY ACTIONS
if (imp_actionRoots != null) {
DoubleKeyMap<String, String, GrammarAST> namedActions = new DoubleKeyMap<String, String, GrammarAST>();
rootGrammar.tool.log("grammar", "imported actions: " + imp_actionRoots);
for (GrammarAST at : all_actionRoots) {
String scopeName = rootGrammar.getDefaultActionScope();
GrammarAST scope, name, action;
if (at.getChildCount() > 2) {
// must have a scope
scope = (GrammarAST) at.getChild(0);
scopeName = scope.getText();
name = (GrammarAST) at.getChild(1);
action = (GrammarAST) at.getChild(2);
} else {
name = (GrammarAST) at.getChild(0);
action = (GrammarAST) at.getChild(1);
}
GrammarAST prevAction = namedActions.get(scopeName, name.getText());
if (prevAction == null) {
namedActions.put(scopeName, name.getText(), action);
} else {
if (prevAction.g == at.g) {
rootGrammar.tool.errMgr.grammarError(ErrorType.ACTION_REDEFINITION, at.g.fileName, name.token, name.getText());
} else {
String s1 = prevAction.getText();
s1 = s1.substring(1, s1.length() - 1);
String s2 = action.getText();
s2 = s2.substring(1, s2.length() - 1);
String combinedAction = "{" + s1 + '\n' + s2 + "}";
prevAction.token.setText(combinedAction);
}
}
}
// Merge in any actions not in root grammar into root's tree.
for (String scopeName : namedActions.keySet()) {
for (String name : namedActions.keySet(scopeName)) {
GrammarAST action = namedActions.get(scopeName, name);
rootGrammar.tool.log("grammar", action.g.name + " " + scopeName + ":" + name + "=" + action.getText());
if (action.g != rootGrammar) {
root.insertChild(1, action.getParent());
}
}
}
}
// COPY RULES
List<GrammarAST> rules = imp.ast.getNodesWithType(ANTLRParser.RULE);
if (rules != null) {
for (GrammarAST r : rules) {
rootGrammar.tool.log("grammar", "imported rule: " + r.toStringTree());
String name = r.getChild(0).getText();
boolean rootAlreadyHasRule = rootRuleNames.contains(name);
if (!rootAlreadyHasRule) {
// merge in if not overridden
RULES.addChild(r);
rootRuleNames.add(name);
}
}
}
GrammarAST optionsRoot = (GrammarAST) imp.ast.getFirstChildWithType(ANTLRParser.OPTIONS);
if (optionsRoot != null) {
// suppress the warning if the options match the options specified
// in the root grammar
// https://github.com/antlr/antlr4/issues/707
boolean hasNewOption = false;
for (Map.Entry<String, GrammarAST> option : imp.ast.getOptions().entrySet()) {
String importOption = imp.ast.getOptionString(option.getKey());
if (importOption == null) {
continue;
}
String rootOption = rootGrammar.ast.getOptionString(option.getKey());
if (!importOption.equals(rootOption)) {
hasNewOption = true;
break;
}
}
if (hasNewOption) {
rootGrammar.tool.errMgr.grammarError(ErrorType.OPTIONS_IN_DELEGATE, optionsRoot.g.fileName, optionsRoot.token, imp.name);
}
}
}
rootGrammar.tool.log("grammar", "Grammar: " + rootGrammar.ast.toStringTree());
}
Aggregations