src.org.python.antlr.PythonTree Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-standalone Show documentation
Show all versions of jython-standalone Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
package org.python.antlr;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.python.core.PyObject;
import org.python.core.PyType;
import org.python.core.Traverseproc;
import org.python.core.Visitproc;
import org.python.antlr.ast.Name;
import org.python.antlr.ast.VisitorIF;
import java.util.ArrayList;
import java.util.List;
public class PythonTree extends AST implements Traverseproc {
public boolean from_future_checked = false;
private int charStartIndex = -1;
private int charStopIndex = -1;
private CommonTree node;
/** Who is the parent node of this node; if null, implies node is root */
private PythonTree parent;
public PythonTree() {
node = new CommonTree();
}
public PythonTree(PyType subType) {
super(subType);
node = new CommonTree();
}
public PythonTree(Token t) {
node = new CommonTree(t);
}
public PythonTree(int ttype, Token t) {
CommonToken c = new CommonToken(ttype, t.getText());
c.setLine(t.getLine());
c.setTokenIndex(t.getTokenIndex());
c.setCharPositionInLine(t.getCharPositionInLine());
c.setChannel(t.getChannel());
c.setStartIndex(((CommonToken)t).getStartIndex());
c.setStopIndex(((CommonToken)t).getStopIndex());
node = new CommonTree(c);
}
public PythonTree(PythonTree tree) {
node = new CommonTree(tree.getNode());
charStartIndex = tree.getCharStartIndex();
charStopIndex = tree.getCharStopIndex();
}
public CommonTree getNode() {
return node;
}
public Token getToken() {
return node.getToken();
}
public PythonTree dupNode() {
return new PythonTree(this);
}
public boolean isNil() {
return node.isNil();
}
public int getAntlrType() {
return node.getType();
}
public String getText() {
return node.getText();
}
public int getLine() {
if (node.getToken()==null || node.getToken().getLine()==0) {
if ( getChildCount()>0 ) {
return getChild(0).getLine();
}
return 1;
}
return node.getToken().getLine();
}
public int getCharPositionInLine() {
Token token = node.getToken();
if (token==null || token.getCharPositionInLine()==-1) {
if (getChildCount()>0) {
return getChild(0).getCharPositionInLine();
}
return 0;
} else if (token != null && token.getCharPositionInLine() == -2) {
//XXX: yucky fix because CPython's ast uses -1 as a real value
// for char pos in certain circumstances (for example, the
// char pos of multi-line strings. I would just use -1,
// but ANTLR is using -1 in special ways also.
return -1;
}
return token.getCharPositionInLine();
}
public int getTokenStartIndex() {
return node.getTokenStartIndex();
}
public void setTokenStartIndex(int index) {
node.setTokenStartIndex(index);
}
public int getTokenStopIndex() {
return node.getTokenStopIndex();
}
public void setTokenStopIndex(int index) {
node.setTokenStopIndex(index);
}
public int getCharStartIndex() {
if (charStartIndex == -1 && node.getToken() != null) {
return ((CommonToken)node.getToken()).getStartIndex();
}
return charStartIndex ;
}
public void setCharStartIndex(int index) {
charStartIndex = index;
}
/*
* Adding one to stopIndex from Tokens. ANTLR defines the char position as
* being the array index of the actual characters. Most tools these days
* define document offsets as the positions between the characters. If you
* imagine drawing little boxes around each character and think of the
* numbers as pointing to either the left or right side of a character's
* box, then 0 is before the first character - and in a Document of 10
* characters, position 10 is after the last character.
*/
public int getCharStopIndex() {
if (charStopIndex == -1 && node.getToken() != null) {
return ((CommonToken)node.getToken()).getStopIndex() + 1;
}
return charStopIndex;
}
public void setCharStopIndex(int index) {
charStopIndex = index;
}
public int getChildIndex() {
return node.getChildIndex();
}
public PythonTree getParent() {
return parent;
}
public void setParent(PythonTree t) {
this.parent = t;
}
public void setChildIndex(int index) {
node.setChildIndex(index);
}
/**
* Converts a list of Name to a dotted-name string.
* Because leading dots are indexable identifiers (referring
* to parent directories in relative imports), a Name list
* may include leading dots, but not dots between names.
*/
public static String dottedNameListToString(List names) {
if (names == null) {
return "";
}
StringBuilder sb = new StringBuilder();
boolean leadingDot = true;
for (int i = 0, len = names.size(); i < len; i++) {
Name name = names.get(i);
String id = name.getInternalId();
if (id == null) {
continue;
}
if (!".".equals(id)) {
leadingDot = false;
}
sb.append(id);
if (i < len - 1 && !leadingDot) {
sb.append(".");
}
}
return sb.toString();
}
@Override
public String toString() {
if (isNil()) {
return "None";
}
if ( getAntlrType()==Token.INVALID_TOKEN_TYPE ) {
return "";
}
if ( node.getToken()==null ) {
return null;
}
return node.getToken().getText() + "(" + this.getLine() + "," + this.getCharPositionInLine() + ")";
}
public String toStringTree() {
if (children == null || children.size() == 0) {
return this.toString();// + "[" + this.info() + "]";
}
StringBuffer buf = new StringBuffer();
if (!isNil()) {
buf.append("(");
buf.append(this.toString());// + "[" + this.info() + "]");
buf.append(' ');
}
for (int i = 0; children != null && i < children.size(); i++) {
PythonTree t = children.get(i);
if (i > 0) {
buf.append(' ');
}
buf.append(t.toStringTree());
}
if (!isNil()) {
buf.append(")");
}
return buf.toString();
}
protected String dumpThis(String s) {
return s;
}
protected String dumpThis(Object o) {
if (o instanceof PythonTree) {
return ((PythonTree)o).toStringTree();
}
return String.valueOf(o);
}
protected String dumpThis(Object[] s) {
StringBuffer sb = new StringBuffer();
if (s == null) {
sb.append("null");
} else {
sb.append("(");
for (int i = 0; i < s.length; i++) {
if (i > 0)
sb.append(", ");
sb.append(dumpThis(s[i]));
}
sb.append(")");
}
return sb.toString();
}
public R accept(VisitorIF visitor) throws Exception {
throw new RuntimeException("Unexpected node: " + this);
}
public void traverse(VisitorIF> visitor) throws Exception {
throw new RuntimeException("Cannot traverse node: " + this);
}
//XXX: From here down copied from org.antlr.runtime.tree.BaseTree
protected List children;
public PythonTree getChild(int i) {
if ( children==null || i>=children.size() ) {
return null;
}
return children.get(i);
}
/** Get the children internal List; note that if you directly mess with
* the list, do so at your own risk.
*/
public List getChildren() {
return children;
}
public PythonTree getFirstChildWithType(int type) {
for (int i = 0; children!=null && i < children.size(); i++) {
PythonTree t = children.get(i);
if ( t.getAntlrType()==type ) {
return t;
}
}
return null;
}
public int getChildCount() {
if ( children==null ) {
return 0;
}
return children.size();
}
/** Add t as child of this node.
*
* Warning: if t has no children, but child does
* and child isNil then this routine moves children to t via
* t.children = child.children; i.e., without copying the array.
*/
public void addChild(PythonTree t) {
if ( t==null ) {
return; // do nothing upon addChild(null)
}
PythonTree childTree = t;
if ( childTree.isNil() ) { // t is an empty node possibly with children
if ( this.children!=null && this.children == childTree.children ) {
throw new RuntimeException("attempt to add child list to itself");
}
// just add all of childTree's children to this
if ( childTree.children!=null ) {
if ( this.children!=null ) { // must copy, this has children already
int n = childTree.children.size();
for (int i = 0; i < n; i++) {
PythonTree c = childTree.children.get(i);
this.children.add(c);
// handle double-link stuff for each child of nil root
c.setParent(this);
c.setChildIndex(children.size()-1);
}
}
else {
// no children for this but t has children; just set pointer
// call general freshener routine
this.children = childTree.children;
this.freshenParentAndChildIndexes();
}
}
}
else { // child is not nil (don't care about children)
if ( children==null ) {
children = createChildrenList(); // create children list on demand
}
children.add(t);
childTree.setParent(this);
childTree.setChildIndex(children.size()-1);
}
}
/** Add all elements of kids list as children of this node */
public void addChildren(List kids) {
for (int i = 0; i < kids.size(); i++) {
PythonTree t = kids.get(i);
addChild(t);
}
}
public void setChild(int i, PythonTree t) {
if ( t==null ) {
return;
}
if ( t.isNil() ) {
throw new IllegalArgumentException("Can't set single child to a list");
}
if ( children==null ) {
children = createChildrenList();
}
children.set(i, t);
t.setParent(this);
t.setChildIndex(i);
}
public Object deleteChild(int i) {
if ( children==null ) {
return null;
}
PythonTree killed = children.remove(i);
// walk rest and decrement their child indexes
this.freshenParentAndChildIndexes(i);
return killed;
}
/** Delete children from start to stop and replace with t even if t is
* a list (nil-root tree). num of children can increase or decrease.
* For huge child lists, inserting children can force walking rest of
* children to set their childindex; could be slow.
*/
public void replaceChildren(int startChildIndex, int stopChildIndex, Object t) {
if ( children==null ) {
throw new IllegalArgumentException("indexes invalid; no children in list");
}
int replacingHowMany = stopChildIndex - startChildIndex + 1;
int replacingWithHowMany;
PythonTree newTree = (PythonTree)t;
List newChildren = null;
// normalize to a list of children to add: newChildren
if ( newTree.isNil() ) {
newChildren = newTree.children;
}
else {
newChildren = new ArrayList(1);
newChildren.add(newTree);
}
replacingWithHowMany = newChildren.size();
int numNewChildren = newChildren.size();
int delta = replacingHowMany - replacingWithHowMany;
// if same number of nodes, do direct replace
if ( delta == 0 ) {
int j = 0; // index into new children
for (int i=startChildIndex; i<=stopChildIndex; i++) {
PythonTree child = newChildren.get(j);
children.set(i, child);
child.setParent(this);
child.setChildIndex(i);
j++;
}
}
else if ( delta > 0 ) { // fewer new nodes than there were
// set children and then delete extra
for (int j=0; j createChildrenList() {
return new ArrayList();
}
/** Set the parent and child index values for all child of t */
public void freshenParentAndChildIndexes() {
freshenParentAndChildIndexes(0);
}
public void freshenParentAndChildIndexes(int offset) {
int n = getChildCount();
for (int c = offset; c < n; c++) {
PythonTree child = getChild(c);
child.setChildIndex(c);
child.setParent(this);
}
}
/* Traverseproc implementation */
@Override
public int traverse(Visitproc visit, Object arg) {
return parent != null ? visit.visit(parent, arg) : 0;
}
@Override
public boolean refersDirectlyTo(PyObject ob) {
return ob != null && ob == parent;
}
}