fix labeling, add comments

This commit is contained in:
Terence Parr 2013-11-21 16:37:57 -08:00
parent 4fdd520c2e
commit 49c4a5ec12
3 changed files with 85 additions and 14 deletions

View File

@ -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 {
}

View File

@ -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;
}
}

View File

@ -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) {