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