Search in sources :

Example 1 with DoubleKeyMap

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());
}
Also used : GrammarAST(org.antlr.v4.tool.ast.GrammarAST) ArrayList(java.util.ArrayList) GrammarASTAdaptor(org.antlr.v4.parse.GrammarASTAdaptor) DoubleKeyMap(org.antlr.v4.runtime.misc.DoubleKeyMap) Map(java.util.Map) DoubleKeyMap(org.antlr.v4.runtime.misc.DoubleKeyMap) HashSet(java.util.HashSet)

Aggregations

ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 GrammarASTAdaptor (org.antlr.v4.parse.GrammarASTAdaptor)1 DoubleKeyMap (org.antlr.v4.runtime.misc.DoubleKeyMap)1 GrammarAST (org.antlr.v4.tool.ast.GrammarAST)1