got a draft implementation

This commit is contained in:
Terence Parr 2013-09-11 11:25:07 -07:00
parent 8237952cbb
commit 3fda64f85b
14 changed files with 158 additions and 120 deletions

View File

@ -1,5 +1,14 @@
ANTLR v4 Honey Badger
September 11, 2013
* Copy lots of find node stuff from v3 GrammarAST to Trees class in runtime.
September 10, 2013
* Add getChildren to ParseTree [BREAKING CHANGE]
* Adding in XPath stuff.
August 31, 2013
* Lots of little fixes thanks to Coverity Scan

View File

@ -31,6 +31,8 @@
package org.antlr.v4.runtime.tree;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.Nullable;
@ -42,6 +44,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -167,6 +170,49 @@ public class Trees {
return ancestors;
}
public static Collection<ParseTree> findAllTokenNodes(ParseTree t, int ttype) {
return findAllNodes(t, ttype, true);
}
public static Collection<ParseTree> findAllRuleNodes(ParseTree t, int ruleIndex) {
return findAllNodes(t, ruleIndex, false);
}
public static List<ParseTree> findAllNodes(ParseTree t, int index, boolean findTokens) {
List<? super ParseTree> nodes = new ArrayList<ParseTree>();
_findAllNodes(t, index, findTokens, nodes);
return (List<ParseTree>)nodes;
}
public static void _findAllNodes(ParseTree t, int index, boolean findTokens,
List<? super ParseTree> nodes)
{
// check this node (the root) first
if ( t instanceof TerminalNode ) {
TerminalNode tnode = (TerminalNode)t;
if ( tnode.getSymbol().getType()==index ) nodes.add(t);
}
else {
ParserRuleContext ctx = (ParserRuleContext)t;
if ( ctx.getRuleIndex() == index ) nodes.add(t);
}
// check children
for (int i = 0; i < t.getChildCount(); i++){
_findAllNodes(t.getChild(i), index, findTokens, nodes);
}
}
public static List<Tree> descendants(ParseTree t){
List<Tree> nodes = new ArrayList<Tree>();
nodes.add(t);
int n = t.getChildCount();
for (int i = 0 ; i < n ; i++){
nodes.addAll(descendants(t.getChild(i)));
}
return nodes;
}
private Trees() {
}
}

View File

@ -1,6 +1,7 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
@ -52,6 +53,8 @@ public class XPath {
System.out.println(Arrays.toString(elements));
}
// TODO: check for invalid token/rule names, bad syntax
public XPathElement[] split(String path) {
Map<String, Integer> ruleIndexes = toMap(parser.getRuleNames());
Map<String, Integer> tokenTypes = toMap(parser.getTokenNames());
@ -73,27 +76,14 @@ public class XPath {
System.out.println("missing element name after operator");
}
String next = pathStrings.get(i);
if ( i==1 ) { // "/ID" is rooted element if '/' is first el
if ( next.equals(WILDCARD) ) {
elements.add(new XPathRootWildcardElement());
}
else if ( Character.isUpperCase(next.charAt(0)) ) {
elements.add(new XPathRootTokenElement(next, tokenTypes.get(next)));
}
else {
elements.add(new XPathRootRuleElement(next, ruleIndexes.get(next)));
}
if ( next.equals(WILDCARD) ) {
elements.add(new XPathWildcardElement());
}
else if ( Character.isUpperCase(next.charAt(0)) ) {
elements.add(new XPathTokenElement(next, tokenTypes.get(next)));
}
else {
if ( next.equals(WILDCARD) ) {
elements.add(new XPathWildcardElement());
}
else if ( Character.isUpperCase(next.charAt(0)) ) {
elements.add(new XPathTokenElement(next, tokenTypes.get(next)));
}
else {
elements.add(new XPathRuleElement(next, ruleIndexes.get(next)));
}
elements.add(new XPathRuleElement(next, ruleIndexes.get(next)));
}
i++;
}
@ -103,7 +93,12 @@ public class XPath {
System.out.println("missing element name after operator");
}
String next = pathStrings.get(i);
elements.add(new XPathAnywhereElement(next));
if ( Character.isUpperCase(next.charAt(0)) ) {
elements.add(new XPathTokenAnywhereElement(next, tokenTypes.get(next)));
}
else {
elements.add(new XPathRuleAnywhereElement(next, ruleIndexes.get(next)));
}
i++;
}
else {
@ -122,13 +117,25 @@ public class XPath {
// following java xpath like methods; not sure it's best way
/** Return a list of all nodes starting at t as root that satisfy the path.
*/
public Collection<? extends ParseTree> evaluate(ParseTree t) {
// do just first for now
Collection<? extends ParseTree> work = elements[0].evaluate(t);
int i = 1;
for (ParseTree node : work) {
Collection<? extends ParseTree> work2 = elements[i].evaluate(node);
public Collection<ParseTree> evaluate(final ParseTree t) {
ParserRuleContext dummyRoot = new ParserRuleContext();
dummyRoot.children = new ArrayList<ParseTree>() {{add(t);}}; // don't set t's parent.
Collection<ParseTree> work = new ArrayList<ParseTree>();
work.add(dummyRoot);
int i = 0;
while ( i < elements.length ) {
Collection<ParseTree> next = new ArrayList<ParseTree>();
for (ParseTree node : work) {
Collection<? extends ParseTree> matching = elements[i].evaluate(node);
next.addAll(matching);
}
i++;
work = next;
}
return work;
}
public static Map<String, Integer> toMap(String[] keys) {

View File

@ -1,17 +0,0 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.Collection;
/** Either ID at start of path or ...//ID in middle of path */
public class XPathAnywhereElement extends XPathElement {
public XPathAnywhereElement(String nodeName) {
super(nodeName);
}
@Override
public Collection<? extends ParseTree> evaluate(ParseTree t) {
return null;
}
}

View File

@ -15,7 +15,7 @@ public abstract class XPathElement {
}
/** Given tree rooted at t return all nodes matched by this path element */
public abstract Collection<? extends ParseTree> evaluate(ParseTree t);
public abstract Collection<ParseTree> evaluate(ParseTree t);
@Override
public String toString() {

View File

@ -1,25 +0,0 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.Collection;
public class XPathRootRuleElement extends XPathElement {
protected int ruleIndex;
public XPathRootRuleElement(String nodeName, int ruleIndex) {
super(nodeName);
this.ruleIndex = ruleIndex;
}
@Override
public Collection<? extends ParseTree> evaluate(final ParseTree t) {
ParserRuleContext ctx = (ParserRuleContext)t.getPayload();
if ( ctx.getRuleIndex() == ruleIndex ) {
return new ArrayList<ParseTree>() {{add(t);}};
}
return new ArrayList<ParseTree>();
}
}

View File

@ -1,25 +0,0 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.Collection;
public class XPathRootTokenElement extends XPathElement {
protected int tokenType;
public XPathRootTokenElement(String tokenName, int tokenType) {
super(tokenName);
this.tokenType = tokenType;
}
@Override
public Collection<? extends ParseTree> evaluate(final ParseTree t) {
Token tok = (Token)t.getPayload();
if ( tok.getType() == tokenType ) {
return new ArrayList<ParseTree>() {{add(t);}};
}
return new ArrayList<ParseTree>();
}
}

View File

@ -1,17 +0,0 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.Collection;
public class XPathRootWildcardElement extends XPathElement {
public XPathRootWildcardElement() {
super(XPath.WILDCARD);
}
@Override
public Collection<? extends ParseTree> evaluate(final ParseTree t) {
return new ArrayList<ParseTree>() {{add(t);}};
}
}

View File

@ -0,0 +1,20 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.Trees;
import java.util.Collection;
/** Either ID at start of path or ...//ID in middle of path */
public class XPathRuleAnywhereElement extends XPathElement {
protected int ruleIndex;
public XPathRuleAnywhereElement(String ruleName, int ruleIndex) {
super(ruleName);
this.ruleIndex = ruleIndex;
}
@Override
public Collection<ParseTree> evaluate(ParseTree t) {
return Trees.findAllRuleNodes(t, ruleIndex);
}
}

View File

@ -1,8 +1,11 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class XPathRuleElement extends XPathElement {
protected int ruleIndex;
@ -12,7 +15,17 @@ public class XPathRuleElement extends XPathElement {
}
@Override
public Collection<? extends ParseTree> evaluate(ParseTree t) {
return null;
public Collection<ParseTree> evaluate(ParseTree t) {
// return all children of t that match nodeName
List<ParseTree> nodes = new ArrayList<ParseTree>();
for (ParseTree c : t.getChildren()) {
if ( c instanceof ParserRuleContext ) {
ParserRuleContext ctx = (ParserRuleContext)c;
if ( ctx.getRuleIndex() == ruleIndex ) {
nodes.add(c);
}
}
}
return nodes;
}
}

View File

@ -0,0 +1,19 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.Trees;
import java.util.Collection;
public class XPathTokenAnywhereElement extends XPathElement {
protected int tokenType;
public XPathTokenAnywhereElement(String tokenName, int tokenType) {
super(tokenName);
this.tokenType = tokenType;
}
@Override
public Collection<ParseTree> evaluate(ParseTree t) {
return Trees.findAllTokenNodes(t, tokenType);
}
}

View File

@ -1,6 +1,7 @@
package org.antlr.v4.runtime.tree.xpath;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.ArrayList;
import java.util.Collection;
@ -14,12 +15,15 @@ public class XPathTokenElement extends XPathElement {
}
@Override
public Collection<? extends ParseTree> evaluate(ParseTree t) {
public Collection<ParseTree> evaluate(ParseTree t) {
// return all children of t that match nodeName
List<ParseTree> nodes = new ArrayList<ParseTree>();
for (ParseTree c : t.getChildren()) {
if ( c.getText().equals(nodeName) ) {
nodes.add(c);
if ( c instanceof TerminalNode ) {
TerminalNode tnode = (TerminalNode)c;
if ( tnode.getSymbol().getType() == tokenType ) {
nodes.add(c);
}
}
}
return nodes;

View File

@ -11,7 +11,7 @@ public class XPathWildcardElement extends XPathElement {
}
@Override
public Collection<? extends ParseTree> evaluate(final ParseTree t) {
return new ArrayList<ParseTree>() {{add(t);}};
public Collection<ParseTree> evaluate(final ParseTree t) {
return new ArrayList<ParseTree>() {{addAll(t.getChildren());}};
}
}

View File

@ -20,11 +20,15 @@ public class TestXPath {
ParserRuleContext tree = parser.compilationUnit();
System.out.println(tree.toStringTree(parser));
XPath p = new XPath(parser, "/compilationUnit/*");
// XPath p = new XPath(parser, "/compilationUnit/*");
// XPath p = new XPath(parser, "//blockStatement");
// XPath p = new XPath(parser, "//StringLiteral");
// XPath p = new XPath(parser, "//Identifier");
XPath p = new XPath(parser, "//expression/primary/Identifier");
for (ParseTree t : p.evaluate(tree) ) {
if ( t instanceof RuleContext ) {
RuleContext r = (RuleContext)t;
System.out.println(parser.ruleNames[r.getRuleIndex()]);
System.out.println(" "+parser.ruleNames[r.getRuleIndex()]);
}
else {
TerminalNode token = (TerminalNode)t;