got a draft implementation
This commit is contained in:
parent
8237952cbb
commit
3fda64f85b
|
@ -1,5 +1,14 @@
|
||||||
ANTLR v4 Honey Badger
|
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
|
August 31, 2013
|
||||||
|
|
||||||
* Lots of little fixes thanks to Coverity Scan
|
* Lots of little fixes thanks to Coverity Scan
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
package org.antlr.v4.runtime.tree;
|
package org.antlr.v4.runtime.tree;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.Parser;
|
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.Token;
|
||||||
import org.antlr.v4.runtime.misc.NotNull;
|
import org.antlr.v4.runtime.misc.NotNull;
|
||||||
import org.antlr.v4.runtime.misc.Nullable;
|
import org.antlr.v4.runtime.misc.Nullable;
|
||||||
|
@ -42,6 +44,7 @@ import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -167,6 +170,49 @@ public class Trees {
|
||||||
return ancestors;
|
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() {
|
private Trees() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.antlr.v4.runtime.tree.xpath;
|
package org.antlr.v4.runtime.tree.xpath;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.Parser;
|
import org.antlr.v4.runtime.Parser;
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -52,6 +53,8 @@ public class XPath {
|
||||||
System.out.println(Arrays.toString(elements));
|
System.out.println(Arrays.toString(elements));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check for invalid token/rule names, bad syntax
|
||||||
|
|
||||||
public XPathElement[] split(String path) {
|
public XPathElement[] split(String path) {
|
||||||
Map<String, Integer> ruleIndexes = toMap(parser.getRuleNames());
|
Map<String, Integer> ruleIndexes = toMap(parser.getRuleNames());
|
||||||
Map<String, Integer> tokenTypes = toMap(parser.getTokenNames());
|
Map<String, Integer> tokenTypes = toMap(parser.getTokenNames());
|
||||||
|
@ -73,27 +76,14 @@ public class XPath {
|
||||||
System.out.println("missing element name after operator");
|
System.out.println("missing element name after operator");
|
||||||
}
|
}
|
||||||
String next = pathStrings.get(i);
|
String next = pathStrings.get(i);
|
||||||
if ( i==1 ) { // "/ID" is rooted element if '/' is first el
|
if ( next.equals(WILDCARD) ) {
|
||||||
if ( next.equals(WILDCARD) ) {
|
elements.add(new XPathWildcardElement());
|
||||||
elements.add(new XPathRootWildcardElement());
|
}
|
||||||
}
|
else if ( Character.isUpperCase(next.charAt(0)) ) {
|
||||||
else if ( Character.isUpperCase(next.charAt(0)) ) {
|
elements.add(new XPathTokenElement(next, tokenTypes.get(next)));
|
||||||
elements.add(new XPathRootTokenElement(next, tokenTypes.get(next)));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
elements.add(new XPathRootRuleElement(next, ruleIndexes.get(next)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( next.equals(WILDCARD) ) {
|
elements.add(new XPathRuleElement(next, ruleIndexes.get(next)));
|
||||||
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)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +93,12 @@ public class XPath {
|
||||||
System.out.println("missing element name after operator");
|
System.out.println("missing element name after operator");
|
||||||
}
|
}
|
||||||
String next = pathStrings.get(i);
|
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++;
|
i++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -122,13 +117,25 @@ public class XPath {
|
||||||
// following java xpath like methods; not sure it's best way
|
// 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.
|
/** Return a list of all nodes starting at t as root that satisfy the path.
|
||||||
*/
|
*/
|
||||||
public Collection<? extends ParseTree> evaluate(ParseTree t) {
|
public Collection<ParseTree> evaluate(final ParseTree t) {
|
||||||
// do just first for now
|
ParserRuleContext dummyRoot = new ParserRuleContext();
|
||||||
Collection<? extends ParseTree> work = elements[0].evaluate(t);
|
dummyRoot.children = new ArrayList<ParseTree>() {{add(t);}}; // don't set t's parent.
|
||||||
int i = 1;
|
|
||||||
for (ParseTree node : work) {
|
Collection<ParseTree> work = new ArrayList<ParseTree>();
|
||||||
Collection<? extends ParseTree> work2 = elements[i].evaluate(node);
|
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) {
|
public static Map<String, Integer> toMap(String[] keys) {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ public abstract class XPathElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Given tree rooted at t return all nodes matched by this path element */
|
/** 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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -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>();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);}};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
package org.antlr.v4.runtime.tree.xpath;
|
package org.antlr.v4.runtime.tree.xpath;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class XPathRuleElement extends XPathElement {
|
public class XPathRuleElement extends XPathElement {
|
||||||
protected int ruleIndex;
|
protected int ruleIndex;
|
||||||
|
@ -12,7 +15,17 @@ public class XPathRuleElement extends XPathElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends ParseTree> evaluate(ParseTree t) {
|
public Collection<ParseTree> evaluate(ParseTree t) {
|
||||||
return null;
|
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package org.antlr.v4.runtime.tree.xpath;
|
package org.antlr.v4.runtime.tree.xpath;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -14,12 +15,15 @@ public class XPathTokenElement extends XPathElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends ParseTree> evaluate(ParseTree t) {
|
public Collection<ParseTree> evaluate(ParseTree t) {
|
||||||
// return all children of t that match nodeName
|
// return all children of t that match nodeName
|
||||||
List<ParseTree> nodes = new ArrayList<ParseTree>();
|
List<ParseTree> nodes = new ArrayList<ParseTree>();
|
||||||
for (ParseTree c : t.getChildren()) {
|
for (ParseTree c : t.getChildren()) {
|
||||||
if ( c.getText().equals(nodeName) ) {
|
if ( c instanceof TerminalNode ) {
|
||||||
nodes.add(c);
|
TerminalNode tnode = (TerminalNode)c;
|
||||||
|
if ( tnode.getSymbol().getType() == tokenType ) {
|
||||||
|
nodes.add(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodes;
|
return nodes;
|
||||||
|
|
|
@ -11,7 +11,7 @@ public class XPathWildcardElement extends XPathElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends ParseTree> evaluate(final ParseTree t) {
|
public Collection<ParseTree> evaluate(final ParseTree t) {
|
||||||
return new ArrayList<ParseTree>() {{add(t);}};
|
return new ArrayList<ParseTree>() {{addAll(t.getChildren());}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,15 @@ public class TestXPath {
|
||||||
ParserRuleContext tree = parser.compilationUnit();
|
ParserRuleContext tree = parser.compilationUnit();
|
||||||
System.out.println(tree.toStringTree(parser));
|
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) ) {
|
for (ParseTree t : p.evaluate(tree) ) {
|
||||||
if ( t instanceof RuleContext ) {
|
if ( t instanceof RuleContext ) {
|
||||||
RuleContext r = (RuleContext)t;
|
RuleContext r = (RuleContext)t;
|
||||||
System.out.println(parser.ruleNames[r.getRuleIndex()]);
|
System.out.println(" "+parser.ruleNames[r.getRuleIndex()]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TerminalNode token = (TerminalNode)t;
|
TerminalNode token = (TerminalNode)t;
|
||||||
|
|
Loading…
Reference in New Issue