org.python.indexer.Outliner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-slim Show documentation
Show all versions of jython-slim 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.
/**
* Copyright 2009, Google Inc. All rights reserved.
* Licensed to PSF under a Contributor Agreement.
*/
package org.python.indexer;
import org.python.indexer.NBinding;
import org.python.indexer.Util;
import org.python.indexer.types.NModuleType;
import org.python.indexer.types.NType;
import org.python.indexer.types.NUnionType;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Generates a file outline from the index: a structure representing the
* variable and attribute definitions in a file.
*/
public class Outliner {
public static abstract class Entry {
protected String qname; // entry qualified name
protected int offset; // file offset of referenced declaration
protected NBinding.Kind kind; // binding kind of outline entry
public Entry() {
}
public Entry(String qname, int offset, NBinding.Kind kind) {
this.qname = qname;
this.offset = offset;
this.kind = kind;
}
public abstract boolean isLeaf();
public Leaf asLeaf() {
return (Leaf)this;
}
public abstract boolean isBranch();
public Branch asBranch() {
return (Branch)this;
}
public abstract boolean hasChildren();
public abstract List getChildren();
public abstract void setChildren(List children);
public String getQname() {
return qname;
}
public void setQname(String qname) {
if (qname == null) {
throw new IllegalArgumentException("qname param cannot be null");
}
this.qname = qname;
}
/**
* Returns the file offset of the beginning of the identifier referenced
* by this outline entry.
*/
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public NBinding.Kind getKind() {
return kind;
}
public void setKind(NBinding.Kind kind) {
if (kind == null) {
throw new IllegalArgumentException("kind param cannot be null");
}
this.kind = kind;
}
/**
* Returns the simple (unqualified) name of the identifier.
*/
public String getName() {
String[] parts = qname.split("[.&@%]");
return parts[parts.length-1];
}
@Override public String toString() {
StringBuilder sb = new StringBuilder();
toString(sb, 0);
return sb.toString().trim();
}
public void toString(StringBuilder sb, int depth) {
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
sb.append(getKind());
sb.append(" ");
sb.append(getName());
sb.append("\n");
if (hasChildren()) {
for (Entry e : getChildren()) {
e.toString(sb, depth + 1);
}
}
}
}
/**
* An outline entry with children.
*/
public static class Branch extends Entry {
private List children = new ArrayList();
public Branch() {
}
public Branch(String qname, int start, NBinding.Kind kind) {
super(qname, start, kind);
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public boolean isBranch() {
return true;
}
@Override
public boolean hasChildren() {
return children != null && !children.isEmpty();
}
@Override
public List getChildren() {
return children;
}
@Override
public void setChildren(List children) {
this.children = children;
}
}
/**
* An entry with no children.
*/
public static class Leaf extends Entry {
@Override
public boolean isLeaf() {
return true;
}
@Override
public boolean isBranch() {
return false;
}
public Leaf() {
}
public Leaf(String qname, int start, NBinding.Kind kind) {
super(qname, start, kind);
}
@Override
public boolean hasChildren() {
return false;
}
@Override
public List getChildren() {
return new ArrayList();
}
@Override
public void setChildren(List children) {
throw new UnsupportedOperationException("Leaf nodes cannot have children.");
}
}
/**
* Create an outline for a file in the index.
* @param idx index holding the file scope
* @param abspath the file for which to build the outline
* @return a list of entries constituting the file outline.
* Returns an empty list if the indexer hasn't indexed that path.
*/
public List generate(Indexer idx, String abspath) throws Exception {
NModuleType mt = idx.getModuleForFile(abspath);
if (mt == null) {
return new ArrayList();
}
return generate(mt.getTable(), abspath);
}
/**
* Create an outline for a symbol table.
* @param scope the file scope
* @param path the file for which we're building the outline
* @return a list of entries constituting the outline
*/
public List generate(Scope scope, String path) {
List result = new ArrayList();
Set entries = new TreeSet();
for (NBinding nb : scope.values()) {
if (!nb.isSynthetic()
&& !nb.isBuiltin()
&& !nb.getDefs().isEmpty()
&& path.equals(nb.getSignatureNode().getFile())) {
entries.add(nb);
}
}
for (NBinding nb : entries) {
Def signode = nb.getSignatureNode();
List kids = null;
if (nb.getKind() == NBinding.Kind.CLASS) {
NType realType = nb.followType();
if (realType.isUnionType()) {
for (NType t : realType.asUnionType().getTypes()) {
if (t.isClassType()) {
realType = t;
break;
}
}
}
kids = generate(realType.getTable(), path);
}
Entry kid = kids != null ? new Branch() : new Leaf();
kid.setOffset(signode.start());
kid.setQname(nb.getQname());
kid.setKind(nb.getKind());
if (kids != null) {
kid.setChildren(kids);
}
result.add(kid);
}
return result;
}
}