create match object for matching

This commit is contained in:
Terence Parr 2013-09-05 16:58:37 -07:00
parent 35e279cef1
commit 754348605d
8 changed files with 151 additions and 56 deletions

View File

@ -1,11 +0,0 @@
package org.antlr.v4.runtime.tree.pattern;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.List;
public class Match {
protected ParseTree subtree;
protected List<Pair<String,? extends ParseTree>> labels;
}

View File

@ -2,14 +2,14 @@ package org.antlr.v4.runtime.tree.pattern;
import java.util.Iterator;
public class MatchIterator implements Iterator<Match> {
public class MatchIterator implements Iterator<ParseTreeMatch> {
@Override
public boolean hasNext() {
return false;
}
@Override
public Match next() {
public ParseTreeMatch next() {
return null;
}

View File

@ -0,0 +1,21 @@
package org.antlr.v4.runtime.tree.pattern;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.List;
public class ParseTreeMatch {
/** Tree we tried to match */
protected ParseTree tree;
/** To what pattern? */
protected ParseTreePattern pattern;
protected List<Pair<String,? extends ParseTree>> labels;
public ParseTreeMatch(ParseTree tree, ParseTreePattern pattern) {
this.tree = tree;
this.pattern = pattern;
}
}

View File

@ -0,0 +1,46 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Terence Parr
* Copyright (c) 2012 Sam Harwell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.runtime.tree.pattern;
import org.antlr.v4.runtime.tree.ParseTree;
/** Record where we failed in tree. */
public class ParseTreeMatchFailed extends ParseTreeMatch {
/** Where in actual parse tree we failed to match pattern */
ParseTree offendingNode;
public ParseTreeMatchFailed(ParseTree tree, ParseTree offendingNode,
ParseTreePattern pattern)
{
super(tree, pattern);
this.offendingNode = offendingNode;
}
}

View File

@ -0,0 +1,28 @@
package org.antlr.v4.runtime.tree.pattern;
import org.antlr.v4.runtime.tree.ParseTree;
/** A pattern like "<ID> = <expr>;" converted to a ParseTree */
public class ParseTreePattern {
/** Matches a single node or subtree */
public static final ParseTreePattern WildcardPattern =
new ParseTreePattern(null, ".", null) {
public boolean matches(ParseTree t) {
return true;
}
};
public String patternRuleName;
public String pattern;
public ParseTree patternTree;
public ParseTreePattern(String patternRuleName, String pattern, ParseTree patternTree) {
this.patternRuleName = patternRuleName;
this.pattern = pattern;
this.patternTree = patternTree;
}
public boolean matches(ParseTree t) {
return false;
}
}

View File

@ -114,45 +114,77 @@ public class ParseTreePatternMatcher {
}
public boolean matches(ParseTree tree, String patternRuleName, String pattern) {
ParseTree patternTree = compilePattern(patternRuleName, pattern);
return matches_(tree, patternTree);
ParseTreePattern p = compile(patternRuleName, pattern);
ParseTreeMatch m = matches_(tree, p.patternTree, p);
return !(m instanceof ParseTreeMatchFailed);
}
protected boolean matches_(ParseTree tree, ParseTree patternTree) {
if ( tree==null || patternTree==null ) return false;
public boolean matches(ParseTree tree, ParseTreePattern pattern) {
ParseTreeMatch m = matches_(tree, pattern.patternTree, pattern);
return !(m instanceof ParseTreeMatchFailed);
}
public ParseTreeMatch match(ParseTree tree, String patternRuleName, String pattern) {
ParseTreePattern p = compile(patternRuleName, pattern);
return matches_(tree, p.patternTree, p);
}
protected ParseTreeMatch matches_(ParseTree tree, ParseTree patternTree, ParseTreePattern pattern) {
if ( tree==null || patternTree==null ) {
return new ParseTreeMatchFailed(tree, null, pattern);
}
// x and <ID>
if ( tree instanceof TerminalNode && patternTree instanceof TerminalNode ) {
TerminalNode t1 = (TerminalNode)tree;
TerminalNode t2 = (TerminalNode)patternTree;
return t1.getSymbol().getType() == t2.getSymbol().getType();
ParseTreeMatch m = null;
if ( t1.getSymbol().getType() == t2.getSymbol().getType() ) {
m = new ParseTreeMatch(tree, pattern);
}
else {
m = new ParseTreeMatchFailed(tree, t1, pattern);
}
return m;
}
if ( tree instanceof RuleNode && patternTree instanceof RuleNode ) {
RuleNode r1 = (RuleNode)tree;
RuleNode r2 = (RuleNode)patternTree;
// (expr ...) and <expr>
if ( r2 instanceof RuleSubtreeNode ) {
return r1.getRuleContext().getRuleIndex() == r2.getRuleContext().getRuleIndex();
ParseTreeMatch m = null;
if ( r1.getRuleContext().getRuleIndex() == r2.getRuleContext().getRuleIndex() ) {
m = new ParseTreeMatch(tree, pattern);
}
else {
m = new ParseTreeMatchFailed(tree, r1, pattern);
}
return m;
}
// (expr ...) and (expr ...)
if ( r1.getChildCount()!=r2.getChildCount() ) return false;
if ( r1.getChildCount()!=r2.getChildCount() ) {
return new ParseTreeMatchFailed(tree, r1, pattern);
}
int n = r1.getChildCount();
for (int i = 0; i<n; i++) {
boolean childrenMatch = matches_(r1.getChild(i), patternTree.getChild(i));
if ( !childrenMatch ) return false;
ParseTreeMatch childMatch =
matches_(r1.getChild(i), patternTree.getChild(i), pattern);
if ( childMatch instanceof ParseTreeMatchFailed ) {
return childMatch;
}
}
return true;
return new ParseTreeMatch(tree, pattern);
}
// if nodes aren't both tokens or both rule nodes, can't match
return false;
return new ParseTreeMatchFailed(tree, tree, pattern);
}
public ParseTree compilePattern(String patternRuleName, String pattern) {
List<? extends Token> tokenList = tokenizePattern(pattern);
public ParseTreePattern compile(String patternRuleName, String pattern) {
List<? extends Token> tokenList = tokenize(pattern);
ListTokenSource tokenSrc = new ListTokenSource(tokenList);
CommonTokenStream tokens = new CommonTokenStream(tokenSrc);
parser.setTokenStream(tokens);
parser.setErrorHandler(new ParseTreePatternErrorStrategy());
ParserRuleContext tree = null;
ParseTree tree = null;
try {
Method startRule = parserClass.getMethod(patternRuleName);
tree = (ParserRuleContext)startRule.invoke(parser, (Object[])null);
@ -161,10 +193,10 @@ public class ParseTreePatternMatcher {
catch (Exception e) {
throw new CannotInvokeStartRule(e);
}
return tree;
return new ParseTreePattern(patternRuleName, pattern, tree);
}
public List<? extends Token> tokenizePattern(String pattern) {
public List<? extends Token> tokenize(String pattern) {
lazyInit();
// make maps for quick look up
Map<String, Integer> tokenNameToType = toMap(parser.getTokenNames(), 0);
@ -308,13 +340,13 @@ public class ParseTreePatternMatcher {
}
// preorder
protected List<ParseTree> findAll(ParseTree t, Pattern pattern) {
protected List<ParseTree> findAll(ParseTree t, ParseTreePattern pattern) {
List<ParseTree> subtrees = new ArrayList<ParseTree>();
findAll_(t, pattern, subtrees);
return subtrees;
}
protected void findAll_(ParseTree t, Pattern pattern, List<ParseTree> subtrees) {
protected void findAll_(ParseTree t, ParseTreePattern pattern, List<ParseTree> subtrees) {
if ( pattern.matches(t) ) {
subtrees.add(t);
}

View File

@ -1,22 +0,0 @@
package org.antlr.v4.runtime.tree.pattern;
import org.antlr.v4.runtime.tree.ParseTree;
public class Pattern {
public static final Pattern WildcardPattern =
new Pattern("...") {
public boolean matches(ParseTree t) {
return true;
}
};
protected String pattern;
public Pattern(String pattern) {
this.pattern = pattern;
}
public boolean matches(ParseTree t) {
return false;
}
}

View File

@ -2,6 +2,7 @@ package org.antlr.v4.test;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.pattern.ParseTreePattern;
import org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher;
import org.junit.Test;
@ -83,7 +84,7 @@ public class TestParseTreeMatcher extends BaseTest {
new ParseTreePatternMatcher(loadLexerClassFromTempDir("XLexer"),
loadParserClassFromTempDir("XParser"));
List<? extends Token> tokens = p.tokenizePattern("<ID> = <expr> ;");
List<? extends Token> tokens = p.tokenize("<ID> = <expr> ;");
String results = tokens.toString();
String expected = "[ID:3, [@-1,1:1='=',<1>,1:1], expr:1, [@-1,1:1=';',<2>,1:1]]";
assertEquals(expected, results);
@ -106,8 +107,8 @@ public class TestParseTreeMatcher extends BaseTest {
new ParseTreePatternMatcher(loadLexerClassFromTempDir("XLexer"),
loadParserClassFromTempDir("XParser"));
ParseTree t = p.compilePattern("s", "<ID> = <expr> ;");
String results = t.toStringTree(p.getParser());
ParseTreePattern t = p.compile("s", "<ID> = <expr> ;");
String results = t.patternTree.toStringTree(p.getParser());
String expected = "(s <ID> = expr ;)";
assertEquals(expected, results);
}