org.antlr.v4.runtime.tree.Trees Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of antlr4-runtime Show documentation
Show all versions of antlr4-runtime Show documentation
The ANTLR 4 Runtime (Optimized)
/*
* Copyright (c) 2012 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD-3-Clause license that
* can be found in the LICENSE.txt file in the project root.
*/
package org.antlr.v4.runtime.tree;
import org.antlr.v4.runtime.CommonToken;
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.atn.ATN;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.runtime.misc.Predicate;
import org.antlr.v4.runtime.misc.Utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** A set of utility routines useful for all kinds of ANTLR trees. */
public class Trees {
/** Print out a whole tree in LISP form. {@link #getNodeText} is used on the
* node payloads to get the text for the nodes. Detect
* parse trees and extract data appropriately.
*/
public static String toStringTree(@NotNull Tree t) {
return toStringTree(t, (List)null);
}
/** Print out a whole tree in LISP form. {@link #getNodeText} is used on the
* node payloads to get the text for the nodes. Detect
* parse trees and extract data appropriately.
*/
public static String toStringTree(@NotNull Tree t, @Nullable Parser recog) {
String[] ruleNames = recog != null ? recog.getRuleNames() : null;
List ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null;
return toStringTree(t, ruleNamesList);
}
/** Print out a whole tree in LISP form. {@link #getNodeText} is used on the
* node payloads to get the text for the nodes.
*/
public static String toStringTree(@NotNull final Tree t, @Nullable final List ruleNames) {
String s = Utils.escapeWhitespace(getNodeText(t, ruleNames), false);
if ( t.getChildCount()==0 ) return s;
StringBuilder buf = new StringBuilder();
buf.append("(");
s = Utils.escapeWhitespace(getNodeText(t, ruleNames), false);
buf.append(s);
buf.append(' ');
for (int i = 0; i0 ) buf.append(' ');
buf.append(toStringTree(t.getChild(i), ruleNames));
}
buf.append(")");
return buf.toString();
}
public static String getNodeText(@NotNull Tree t, @Nullable Parser recog) {
String[] ruleNames = recog != null ? recog.getRuleNames() : null;
List ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null;
return getNodeText(t, ruleNamesList);
}
public static String getNodeText(@NotNull Tree t, @Nullable List ruleNames) {
if ( ruleNames!=null ) {
if ( t instanceof RuleNode ) {
RuleContext ruleContext = ((RuleNode)t).getRuleContext();
int ruleIndex = ruleContext.getRuleIndex();
String ruleName = ruleNames.get(ruleIndex);
int altNumber = ruleContext.getAltNumber();
if ( altNumber!=ATN.INVALID_ALT_NUMBER ) {
return ruleName+":"+altNumber;
}
return ruleName;
}
else if ( t instanceof ErrorNode ) {
return t.toString();
}
else if ( t instanceof TerminalNode) {
Token symbol = ((TerminalNode)t).getSymbol();
if (symbol != null) {
String s = symbol.getText();
return s;
}
}
}
// no recog for rule names
Object payload = t.getPayload();
if ( payload instanceof Token ) {
return ((Token)payload).getText();
}
return t.getPayload().toString();
}
/** Return ordered list of all children of this node */
public static List getChildren(Tree t) {
List kids = new ArrayList();
for (int i=0; i getAncestors(@NotNull Tree t) {
if ( t.getParent()==null ) return Collections.emptyList();
List ancestors = new ArrayList();
t = t.getParent();
while ( t!=null ) {
ancestors.add(0, t); // insert at start
t = t.getParent();
}
return ancestors;
}
/** Return true if t is u's parent or a node on path to root from u.
* Use == not equals().
*
* @since 4.5.1
*/
public static boolean isAncestorOf(Tree t, Tree u) {
if ( t==null || u==null || t.getParent()==null ) return false;
Tree p = u.getParent();
while ( p!=null ) {
if ( t==p ) return true;
p = p.getParent();
}
return false;
}
public static Collection findAllTokenNodes(ParseTree t, int ttype) {
return findAllNodes(t, ttype, true);
}
public static Collection findAllRuleNodes(ParseTree t, int ruleIndex) {
return findAllNodes(t, ruleIndex, false);
}
public static List findAllNodes(ParseTree t, int index, boolean findTokens) {
List nodes = new ArrayList();
_findAllNodes(t, index, findTokens, nodes);
return nodes;
}
public static void _findAllNodes(ParseTree t, int index, boolean findTokens,
List super ParseTree> nodes)
{
// check this node (the root) first
if ( findTokens && t instanceof TerminalNode ) {
TerminalNode tnode = (TerminalNode)t;
if ( tnode.getSymbol().getType()==index ) nodes.add(t);
}
else if ( !findTokens && t instanceof ParserRuleContext ) {
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);
}
}
/** Get all descendents; includes t itself.
*
* @since 4.5.1
*/
public static List getDescendants(ParseTree t) {
List nodes = new ArrayList();
nodes.add(t);
int n = t.getChildCount();
for (int i = 0 ; i < n ; i++){
nodes.addAll(getDescendants(t.getChild(i)));
}
return nodes;
}
/** @deprecated */
@Deprecated
public static List descendants(ParseTree t) {
return getDescendants(t);
}
/** Find smallest subtree of t enclosing range startTokenIndex..stopTokenIndex
* inclusively using postorder traversal. Recursive depth-first-search.
*
* @since 4.5
*/
@Nullable
public static ParserRuleContext getRootOfSubtreeEnclosingRegion(@NotNull ParseTree t,
int startTokenIndex, // inclusive
int stopTokenIndex) // inclusive
{
int n = t.getChildCount();
for (int i = 0; i=r.getStart().getTokenIndex() && // is range fully contained in t?
(r.getStop()==null || stopTokenIndex<=r.getStop().getTokenIndex()) )
{
// note: r.getStop()==null likely implies that we bailed out of parser and there's nothing to the right
return r;
}
}
return null;
}
/** Replace any subtree siblings of root that are completely to left
* or right of lookahead range with a CommonToken(Token.INVALID_TYPE,"...")
* node. The source interval for t is not altered to suit smaller range!
*
* WARNING: destructive to t.
*
* @since 4.5.1
*/
public static void stripChildrenOutOfRange(ParserRuleContext t,
ParserRuleContext root,
int startIndex,
int stopIndex)
{
if ( t==null ) return;
for (int i = 0; i < t.getChildCount(); i++) {
ParseTree child = t.getChild(i);
Interval range = child.getSourceInterval();
if ( child instanceof ParserRuleContext && (range.b < startIndex || range.a > stopIndex) ) {
if ( isAncestorOf(child, root) ) { // replace only if subtree doesn't have displayed root
CommonToken abbrev = new CommonToken(Token.INVALID_TYPE, "...");
t.children.set(i, new TerminalNodeImpl(abbrev));
}
}
}
}
/** Return first node satisfying the pred
*
* @since 4.5.1
*/
public static Tree findNodeSuchThat(Tree t, Predicate pred) {
if ( pred.eval(t) ) return t;
if ( t==null ) return null;
int n = t.getChildCount();
for (int i = 0 ; i < n ; i++){
Tree u = findNodeSuchThat(t.getChild(i), pred);
if ( u!=null ) return u;
}
return null;
}
private Trees() {
}
}