forked from jasder/antlr
fix labeling, add comments
This commit is contained in:
parent
4fdd520c2e
commit
49c4a5ec12
|
@ -3,7 +3,9 @@ package org.antlr.v4.runtime.tree.pattern;
|
|||
/** A chunk is either a token reference, a rule reference, or some plaintext
|
||||
* within a tree pattern. Function split() in the pattern matcher returns
|
||||
* a list of chunks in preparation for creating a token stream by tokenize().
|
||||
* From there, we get a parse tree from with compile().
|
||||
* From there, we get a parse tree from with compile(). These chunks are
|
||||
* converted to RuleTagToken, TokenTagToken, or the regular tokens
|
||||
* of the text surrounding the tags.
|
||||
*/
|
||||
abstract class Chunk {
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
package org.antlr.v4.runtime.tree.pattern;
|
||||
|
||||
import org.antlr.v4.runtime.misc.Pair;
|
||||
import org.antlr.v4.runtime.misc.MultiMap;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** The result of matching a tree against a tree pattern.
|
||||
* If there is no match, field mismatchedNode is set to the offending
|
||||
* treenode.
|
||||
*/
|
||||
public class ParseTreeMatch {
|
||||
/** Tree we tried to match */
|
||||
protected ParseTree tree;
|
||||
|
@ -12,13 +17,66 @@ public class ParseTreeMatch {
|
|||
/** To what pattern? */
|
||||
protected ParseTreePattern pattern;
|
||||
|
||||
protected List<Pair<String,? extends ParseTree>> labels;
|
||||
/** Map a label or token/rule name to List of nodes in tree we match */
|
||||
protected MultiMap<String, ParseTree> labels;
|
||||
|
||||
/** Where in actual parse tree we failed if we can't match pattern */
|
||||
ParseTree mismatchedNode;
|
||||
protected ParseTree mismatchedNode;
|
||||
|
||||
public ParseTreeMatch(ParseTree tree, ParseTreePattern pattern) {
|
||||
this.tree = tree;
|
||||
this.pattern = pattern;
|
||||
this.labels = new MultiMap<String, ParseTree>();
|
||||
}
|
||||
|
||||
/** Get the node associated with label. E.g., for pattern <id:ID>,
|
||||
* get("id") returns the node matched for that ID. If there are more than
|
||||
* one nodes matched with that label, this returns the first one matched.
|
||||
* If there is no node associated with the label, this returns null.
|
||||
*
|
||||
* Pattern tags like <ID> and <expr> without labels are considered to be
|
||||
* labeled with ID and expr, respectively.
|
||||
*/
|
||||
public ParseTree get(String label) {
|
||||
List<ParseTree> parseTrees = labels.get(label);
|
||||
if ( parseTrees==null ) return null;
|
||||
return parseTrees.get(0); // return first if multiple
|
||||
}
|
||||
|
||||
/** Return all nodes matched that are labeled with parameter label.
|
||||
* If there is only one such node, return a list with one element.
|
||||
* If there are no nodes matched with that label, return an empty list.
|
||||
*
|
||||
* Pattern tags like <ID> and <expr> without labels are considered to be
|
||||
* labeled with ID and expr, respectively.
|
||||
*/
|
||||
public List<ParseTree> getAll(String label) {
|
||||
List<ParseTree> nodes = labels.get(label);
|
||||
if ( nodes==null ) return Collections.emptyList();
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/** Return a mapping from label->[list of nodes]. This includes
|
||||
* token and rule references such as <ID> and <expr>
|
||||
*/
|
||||
public MultiMap<String, ParseTree> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
/** Return the node at which we first detected a mismatch. Return
|
||||
* null if we have not found an error.
|
||||
*/
|
||||
public ParseTree getMismatchedNode() {
|
||||
return mismatchedNode;
|
||||
}
|
||||
|
||||
/** Return the tree pattern we are matching against */
|
||||
public ParseTreePattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/** Return the parse tree we are trying to match to a pattern */
|
||||
public ParseTree getTree() {
|
||||
return tree;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,20 +100,20 @@ public class ParseTreePatternMatcher {
|
|||
public boolean matches(ParseTree tree, String patternRuleName, String pattern) {
|
||||
ParseTreePattern p = compile(patternRuleName, pattern);
|
||||
ParseTreeMatch match = new ParseTreeMatch(tree, p);
|
||||
matches_(tree, p.patternTree, p, match);
|
||||
matches_(tree, p.patternTree, match);
|
||||
return match.mismatchedNode==null;
|
||||
}
|
||||
|
||||
public boolean matches(ParseTree tree, ParseTreePattern pattern) {
|
||||
ParseTreeMatch match = new ParseTreeMatch(tree, pattern);
|
||||
matches_(tree, pattern.patternTree, pattern, match);
|
||||
matches_(tree, pattern.patternTree, match);
|
||||
return match.mismatchedNode==null;
|
||||
}
|
||||
|
||||
public ParseTreeMatch match(ParseTree tree, String patternRuleName, String pattern) {
|
||||
ParseTreePattern p = compile(patternRuleName, pattern);
|
||||
ParseTreeMatch match = new ParseTreeMatch(tree, p);
|
||||
if ( matches_(tree, p.patternTree, p, match) ) {
|
||||
if ( matches_(tree, p.patternTree, match) ) {
|
||||
return match;
|
||||
}
|
||||
return match;
|
||||
|
@ -121,13 +121,12 @@ public class ParseTreePatternMatcher {
|
|||
|
||||
public ParseTreeMatch match(ParseTree tree, ParseTreePattern pattern) {
|
||||
ParseTreeMatch match = new ParseTreeMatch(tree, pattern);
|
||||
matches_(tree, pattern.patternTree, pattern, match);
|
||||
matches_(tree, pattern.patternTree, match);
|
||||
return match;
|
||||
}
|
||||
|
||||
protected boolean matches_(ParseTree tree,
|
||||
ParseTree patternTree,
|
||||
ParseTreePattern pattern,
|
||||
ParseTreeMatch match)
|
||||
{
|
||||
if ( tree==null || patternTree==null ) {
|
||||
|
@ -141,6 +140,12 @@ public class ParseTreePatternMatcher {
|
|||
// 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)
|
||||
match.labels.map(tokenTagToken.tokenName, tree);
|
||||
if ( tokenTagToken.label!=null ) {
|
||||
match.labels.map(tokenTagToken.label, tree);
|
||||
}
|
||||
}
|
||||
else if ( t1.getText().equals(t2.getText()) ) { // x and x
|
||||
}
|
||||
|
@ -157,9 +162,15 @@ public class ParseTreePatternMatcher {
|
|||
ParserRuleContext r1 = (ParserRuleContext)tree;
|
||||
ParserRuleContext r2 = (ParserRuleContext)patternTree;
|
||||
// (expr ...) and <expr>
|
||||
if ( isRuleTag(r2) ) {
|
||||
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)
|
||||
match.labels.map(ruleTagToken.ruleName, tree);
|
||||
if ( ruleTagToken.label!=null ) {
|
||||
match.labels.map(ruleTagToken.label, tree);
|
||||
}
|
||||
}
|
||||
else {
|
||||
match.mismatchedNode = r1;
|
||||
|
@ -174,7 +185,7 @@ public class ParseTreePatternMatcher {
|
|||
int n = r1.getChildCount();
|
||||
for (int i = 0; i<n; i++) {
|
||||
boolean childMatch =
|
||||
matches_(r1.getChild(i), patternTree.getChild(i), pattern, match);
|
||||
matches_(r1.getChild(i), patternTree.getChild(i), match);
|
||||
if ( !childMatch ) return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -185,18 +196,18 @@ public class ParseTreePatternMatcher {
|
|||
}
|
||||
|
||||
/** Is t (expr <expr>) subtree? */
|
||||
public boolean isRuleTag(ParseTree t) {
|
||||
public RuleTagToken getRuleTagToken(ParseTree t) {
|
||||
if ( t instanceof RuleNode ) {
|
||||
RuleNode r = (RuleNode)t;
|
||||
if ( r.getChildCount()==1 && r.getChild(0) instanceof TerminalNode ) {
|
||||
TerminalNode c = (TerminalNode)r.getChild(0);
|
||||
if ( c.getSymbol() instanceof RuleTagToken ) {
|
||||
System.out.println("rule tag subtree "+t.toStringTree(parser));
|
||||
return true;
|
||||
return (RuleTagToken)c.getSymbol();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
public ParseTreePattern compile(String patternRuleName, String pattern) {
|
||||
|
|
Loading…
Reference in New Issue