forked from jasder/antlr
got a draft implementation
This commit is contained in:
parent
8237952cbb
commit
3fda64f85b
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
public abstract Collection<? extends ParseTree> evaluate(ParseTree t);
|
||||
public abstract Collection<ParseTree> evaluate(ParseTree t);
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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());}};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue