Search in sources :

Example 11 with Tree

use of org.antlr.v4.runtime.tree.Tree in project antlr4 by antlr.

the class ParseTreePatternMatcher method match.

/**
	 * Compare {@code pattern} matched against {@code tree} and return a
	 * {@link ParseTreeMatch} object that contains the matched elements, or the
	 * node at which the match failed. Pass in a compiled pattern instead of a
	 * string representation of a tree pattern.
	 */
public ParseTreeMatch match(ParseTree tree, ParseTreePattern pattern) {
    MultiMap<String, ParseTree> labels = new MultiMap<String, ParseTree>();
    ParseTree mismatchedNode = matchImpl(tree, pattern.getPatternTree(), labels);
    return new ParseTreeMatch(tree, pattern, labels, mismatchedNode);
}
Also used : MultiMap(org.antlr.v4.runtime.misc.MultiMap) ParseTree(org.antlr.v4.runtime.tree.ParseTree)

Example 12 with Tree

use of org.antlr.v4.runtime.tree.Tree in project antlr4 by antlr.

the class ParseTreePatternMatcher method matchImpl.

// ---- SUPPORT CODE ----
/**
	 * Recursively walk {@code tree} against {@code patternTree}, filling
	 * {@code match.}{@link ParseTreeMatch#labels labels}.
	 *
	 * @return the first node encountered in {@code tree} which does not match
	 * a corresponding node in {@code patternTree}, or {@code null} if the match
	 * was successful. The specific node returned depends on the matching
	 * algorithm used by the implementation, and may be overridden.
	 */
protected ParseTree matchImpl(ParseTree tree, ParseTree patternTree, MultiMap<String, ParseTree> labels) {
    if (tree == null) {
        throw new IllegalArgumentException("tree cannot be null");
    }
    if (patternTree == null) {
        throw new IllegalArgumentException("patternTree cannot be null");
    }
    // x and <ID>, x and y, or x and x; or could be mismatched types
    if (tree instanceof TerminalNode && patternTree instanceof TerminalNode) {
        TerminalNode t1 = (TerminalNode) tree;
        TerminalNode t2 = (TerminalNode) patternTree;
        ParseTree mismatchedNode = null;
        // both are tokens and they have same type
        if (t1.getSymbol().getType() == t2.getSymbol().getType()) {
            if (t2.getSymbol() instanceof TokenTagToken) {
                // x and <ID>
                TokenTagToken tokenTagToken = (TokenTagToken) t2.getSymbol();
                // track label->list-of-nodes for both token name and label (if any)
                labels.map(tokenTagToken.getTokenName(), tree);
                if (tokenTagToken.getLabel() != null) {
                    labels.map(tokenTagToken.getLabel(), tree);
                }
            } else if (t1.getText().equals(t2.getText())) {
            // x and x
            } else {
                // x and y
                if (mismatchedNode == null) {
                    mismatchedNode = t1;
                }
            }
        } else {
            if (mismatchedNode == null) {
                mismatchedNode = t1;
            }
        }
        return mismatchedNode;
    }
    if (tree instanceof ParserRuleContext && patternTree instanceof ParserRuleContext) {
        ParserRuleContext r1 = (ParserRuleContext) tree;
        ParserRuleContext r2 = (ParserRuleContext) patternTree;
        ParseTree mismatchedNode = null;
        // (expr ...) and <expr>
        RuleTagToken ruleTagToken = getRuleTagToken(r2);
        if (ruleTagToken != null) {
            ParseTreeMatch m = null;
            if (r1.getRuleContext().getRuleIndex() == r2.getRuleContext().getRuleIndex()) {
                // track label->list-of-nodes for both rule name and label (if any)
                labels.map(ruleTagToken.getRuleName(), tree);
                if (ruleTagToken.getLabel() != null) {
                    labels.map(ruleTagToken.getLabel(), tree);
                }
            } else {
                if (mismatchedNode == null) {
                    mismatchedNode = r1;
                }
            }
            return mismatchedNode;
        }
        // (expr ...) and (expr ...)
        if (r1.getChildCount() != r2.getChildCount()) {
            if (mismatchedNode == null) {
                mismatchedNode = r1;
            }
            return mismatchedNode;
        }
        int n = r1.getChildCount();
        for (int i = 0; i < n; i++) {
            ParseTree childMatch = matchImpl(r1.getChild(i), patternTree.getChild(i), labels);
            if (childMatch != null) {
                return childMatch;
            }
        }
        return mismatchedNode;
    }
    // if nodes aren't both tokens or both rule nodes, can't match
    return tree;
}
Also used : ParserRuleContext(org.antlr.v4.runtime.ParserRuleContext) TerminalNode(org.antlr.v4.runtime.tree.TerminalNode) ParseTree(org.antlr.v4.runtime.tree.ParseTree)

Example 13 with Tree

use of org.antlr.v4.runtime.tree.Tree in project antlr4 by antlr.

the class ParseTreePatternMatcher method compile.

/**
	 * For repeated use of a tree pattern, compile it to a
	 * {@link ParseTreePattern} using this method.
	 */
public ParseTreePattern compile(String pattern, int patternRuleIndex) {
    List<? extends Token> tokenList = tokenize(pattern);
    ListTokenSource tokenSrc = new ListTokenSource(tokenList);
    CommonTokenStream tokens = new CommonTokenStream(tokenSrc);
    ParserInterpreter parserInterp = new ParserInterpreter(parser.getGrammarFileName(), parser.getVocabulary(), Arrays.asList(parser.getRuleNames()), parser.getATNWithBypassAlts(), tokens);
    ParseTree tree = null;
    try {
        parserInterp.setErrorHandler(new BailErrorStrategy());
        tree = parserInterp.parse(patternRuleIndex);
    //			System.out.println("pattern tree = "+tree.toStringTree(parserInterp));
    } catch (ParseCancellationException e) {
        throw (RecognitionException) e.getCause();
    } catch (RecognitionException re) {
        throw re;
    } catch (Exception e) {
        throw new CannotInvokeStartRule(e);
    }
    // Make sure tree pattern compilation checks for a complete parse
    if (tokens.LA(1) != Token.EOF) {
        throw new StartRuleDoesNotConsumeFullPattern();
    }
    return new ParseTreePattern(this, pattern, patternRuleIndex, tree);
}
Also used : CommonTokenStream(org.antlr.v4.runtime.CommonTokenStream) ParserInterpreter(org.antlr.v4.runtime.ParserInterpreter) ParseCancellationException(org.antlr.v4.runtime.misc.ParseCancellationException) BailErrorStrategy(org.antlr.v4.runtime.BailErrorStrategy) ListTokenSource(org.antlr.v4.runtime.ListTokenSource) ParseTree(org.antlr.v4.runtime.tree.ParseTree) RecognitionException(org.antlr.v4.runtime.RecognitionException) ParseCancellationException(org.antlr.v4.runtime.misc.ParseCancellationException) RecognitionException(org.antlr.v4.runtime.RecognitionException)

Example 14 with Tree

use of org.antlr.v4.runtime.tree.Tree in project antlr4 by antlr.

the class DefaultErrorStrategy method getMissingSymbol.

/** Conjure up a missing token during error recovery.
	 *
	 *  The recognizer attempts to recover from single missing
	 *  symbols. But, actions might refer to that missing symbol.
	 *  For example, x=ID {f($x);}. The action clearly assumes
	 *  that there has been an identifier matched previously and that
	 *  $x points at that token. If that token is missing, but
	 *  the next token in the stream is what we want we assume that
	 *  this token is missing and we keep going. Because we
	 *  have to return some token to replace the missing token,
	 *  we have to conjure one up. This method gives the user control
	 *  over the tokens returned for missing tokens. Mostly,
	 *  you will want to create something special for identifier
	 *  tokens. For literals such as '{' and ',', the default
	 *  action in the parser or tree parser works. It simply creates
	 *  a CommonToken of the appropriate type. The text will be the token.
	 *  If you change what tokens must be created by the lexer,
	 *  override this method to create the appropriate tokens.
	 */
protected Token getMissingSymbol(Parser recognizer) {
    Token currentSymbol = recognizer.getCurrentToken();
    IntervalSet expecting = getExpectedTokens(recognizer);
    int expectedTokenType = Token.INVALID_TYPE;
    if (!expecting.isNil()) {
        // get any element
        expectedTokenType = expecting.getMinElement();
    }
    String tokenText;
    if (expectedTokenType == Token.EOF)
        tokenText = "<missing EOF>";
    else
        tokenText = "<missing " + recognizer.getVocabulary().getDisplayName(expectedTokenType) + ">";
    Token current = currentSymbol;
    Token lookback = recognizer.getInputStream().LT(-1);
    if (current.getType() == Token.EOF && lookback != null) {
        current = lookback;
    }
    return recognizer.getTokenFactory().create(new Pair<TokenSource, CharStream>(current.getTokenSource(), current.getTokenSource().getInputStream()), expectedTokenType, tokenText, Token.DEFAULT_CHANNEL, -1, -1, current.getLine(), current.getCharPositionInLine());
}
Also used : IntervalSet(org.antlr.v4.runtime.misc.IntervalSet)

Example 15 with Tree

use of org.antlr.v4.runtime.tree.Tree in project antlr4 by antlr.

the class IterativeParseTreeWalker method walk.

@Override
public void walk(ParseTreeListener listener, ParseTree t) {
    final Deque<ParseTree> nodeStack = new ArrayDeque<ParseTree>();
    final IntegerStack indexStack = new IntegerStack();
    ParseTree currentNode = t;
    int currentIndex = 0;
    while (currentNode != null) {
        // pre-order visit
        if (currentNode instanceof ErrorNode) {
            listener.visitErrorNode((ErrorNode) currentNode);
        } else if (currentNode instanceof TerminalNode) {
            listener.visitTerminal((TerminalNode) currentNode);
        } else {
            final RuleNode r = (RuleNode) currentNode;
            enterRule(listener, r);
        }
        // Move down to first child, if exists
        if (currentNode.getChildCount() > 0) {
            nodeStack.push(currentNode);
            indexStack.push(currentIndex);
            currentIndex = 0;
            currentNode = currentNode.getChild(0);
            continue;
        }
        // No child nodes, so walk tree
        do {
            // post-order visit
            if (currentNode instanceof RuleNode) {
                exitRule(listener, (RuleNode) currentNode);
            }
            // No parent, so no siblings
            if (nodeStack.isEmpty()) {
                currentNode = null;
                currentIndex = 0;
                break;
            }
            // Move to next sibling if possible
            currentNode = nodeStack.peek().getChild(++currentIndex);
            if (currentNode != null) {
                break;
            }
            // No next, sibling, so move up
            currentNode = nodeStack.pop();
            currentIndex = indexStack.pop();
        } while (currentNode != null);
    }
}
Also used : IntegerStack(org.antlr.v4.runtime.misc.IntegerStack) ArrayDeque(java.util.ArrayDeque)

Aggregations

ParseTree (org.antlr.v4.runtime.tree.ParseTree)30 CommonTokenStream (org.antlr.v4.runtime.CommonTokenStream)21 ANTLRInputStream (org.antlr.v4.runtime.ANTLRInputStream)15 GrammarAST (org.antlr.v4.tool.ast.GrammarAST)12 ParserRuleContext (org.antlr.v4.runtime.ParserRuleContext)9 ParseCancellationException (org.antlr.v4.runtime.misc.ParseCancellationException)8 ByteArrayInputStream (java.io.ByteArrayInputStream)6 InputStream (java.io.InputStream)6 ArrayList (java.util.ArrayList)6 BailErrorStrategy (org.antlr.v4.runtime.BailErrorStrategy)6 Tree (org.antlr.v4.runtime.tree.Tree)6 IOException (java.io.IOException)5 Tree (org.antlr.runtime.tree.Tree)4 ParserInterpreter (org.antlr.v4.runtime.ParserInterpreter)4 RecognitionException (org.antlr.v4.runtime.RecognitionException)4 Rectangle2D (java.awt.geom.Rectangle2D)3 FileInputStream (java.io.FileInputStream)3 Method (java.lang.reflect.Method)3 Map (java.util.Map)3 GrammarASTAdaptor (org.antlr.v4.parse.GrammarASTAdaptor)3