forked from jasder/antlr
create match object for matching
This commit is contained in:
parent
35e279cef1
commit
754348605d
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue