[Pydev-cvs] org.python.pydev/src/org/python/pydev/editor/model AbstractNode.java,NONE,1.1 NameEquals
Brought to you by:
fabioz
Update of /cvsroot/pydev/org.python.pydev/src/org/python/pydev/editor/model In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv649/src/org/python/pydev/editor/model Added Files: AbstractNode.java NameEqualsMainNode.java ModelUtils.java LocalNode.java Location.java ModuleNode.java ImportNode.java FunctionCallNode.java IModelListener.java ClassNode.java FunctionNode.java package.html Scope.java ModelMaker.java LengthEstimator.java ImportFromNode.java ImportAlias.java Log Message: Huge code rewrite. I've implemented a Python model. Model is based in AST tree, but should be simpler to use. No more visitor pattern. OutlineView and Navigation actions have been reworked to use new model, instead of traversing AST. Added Hyperlinking capability, but goto is not implemetned yet. --- NEW FILE: ModelMaker.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.eclipse.core.runtime.IStatus; import org.python.parser.SimpleNode; import org.python.parser.ast.*; import org.python.pydev.plugin.PydevPlugin; /** * Creates the model from the AST tree. */ public class ModelMaker { /* algorithm: * Traverse the top node. * For each Item found, call foundItem. * */ public static ModuleNode createModel(SimpleNode root, int lines, int cols) { ModuleNode n = new ModuleNode(null, lines, cols); PopulateModel populator = new PopulateModel(root, n); try { root.accept(populator); } catch (Exception e) { PydevPlugin.log(IStatus.ERROR, "Unexpected error populating model", e); } n.getScope().setEnd(n); return n; } /** * Problems this class is trying to solve: * * - figuring out the end position of the node. AST only has starting position, * so we need to heuristically find the end of it * * */ static class PopulateModel extends VisitorBase { SimpleNode root; AbstractNode parent; public PopulateModel(SimpleNode root, AbstractNode parent) { this.root = root; this.parent = parent; } void processAliases(AbstractNode parent, aliasType[] nodes) { for (int i=0; i<nodes.length; i++) new ImportAlias(parent, nodes[i]); } void processImport(Import node) { ImportNode newNode = new ImportNode(parent, node); // have to traverse children manually to find all imports processAliases(newNode, node.names); } void processImportFrom(ImportFrom node) { ImportFromNode newNode = new ImportFromNode(parent, node); // have to traverse children manually to find all imports processAliases(newNode, node.names); } void processClassDef(ClassDef node) { ClassNode newNode = new ClassNode(parent, node); // traverse inside the class definition PopulateModel populator = new PopulateModel(node, newNode); try { node.traverse(populator); } catch (Exception e) { PydevPlugin.log(IStatus.ERROR, "Unexpected error populating model", e); } newNode.getScope().setEnd(newNode); } void processFunctionDef(FunctionDef node) { FunctionNode newNode = new FunctionNode(parent, node); // traverse inside the function definition PopulateModel populator = new PopulateModel(node, newNode); try { node.traverse(populator); } catch (Exception e) { PydevPlugin.log(IStatus.ERROR, "Unexpected error populating model", e); } newNode.getScope().setEnd(newNode); } void processLocal(Name node) { if (!LocalNode.isBuiltin(node.id)) new LocalNode(parent, node); } void processFunctionCall(Call node) { FunctionCallNode newNode = new FunctionCallNode(parent, node); PopulateModel populator = new PopulateModel(node, newNode); try { node.traverse(populator); } catch (Exception e) { PydevPlugin.log(IStatus.ERROR, "Unexpected error populating model", e); } } void processMain(If node) { NameEqualsMainNode newNode = new NameEqualsMainNode(parent, node); } protected Object unhandled_node(SimpleNode node) throws Exception { return null; } public void traverse(SimpleNode node) throws Exception { node.traverse(this); } public Object visitClassDef(ClassDef node) throws Exception { processClassDef(node); return null; } public Object visitFunctionDef(FunctionDef node) throws Exception { processFunctionDef(node); return null; } public Object visitImport(Import node) throws Exception { processImport(node); return null; } public Object visitImportFrom(ImportFrom node) throws Exception { processImportFrom(node); return null; } /* Is every name a local? */ public Object visitName(Name node) throws Exception { processLocal(node); return null; } public Object visitCall(Call node) throws Exception { processFunctionCall(node); return null; } public Object visitIf(If node) throws Exception { if (node.test instanceof Compare) { Compare compareNode = (Compare)node.test; // handcrafted structure walking if (compareNode.left instanceof Name && ((Name)compareNode.left).id.equals("__name__") && compareNode.ops != null && compareNode.ops.length == 1 && compareNode.ops[0] == Compare.Eq) if ( true && compareNode.comparators != null && compareNode.comparators.length == 1 && compareNode.comparators[0] instanceof Str && ((Str)compareNode.comparators[0]).s.equals("__main__")) processMain(node); return null; } return super.visitIf(node); } } } --- NEW FILE: ModelUtils.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import java.util.ArrayList; import java.util.Iterator; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.python.pydev.plugin.PydevPlugin; /** * Utility functions: querying/conversion */ public class ModelUtils { public static AbstractNode getElement(AbstractNode root, int offset, IDocument doc, int properties) { try { int line = doc.getLineOfOffset(offset); IRegion r = doc.getLineInformation(line); return getElement(root, new Location(line, offset - r.getOffset()), properties); } catch (BadLocationException e) { PydevPlugin.log(IStatus.WARNING, "getElementByOffset failed", e); } return null; } /** * Depth-first search for a node that spans given location * @param root: node to start the search with * @param loc: location we are looking for * @param properties: properties node must match. Pass in PROP_ANY for all nodes * @return */ public static AbstractNode getElement(AbstractNode root, Location loc, int properties) { if (root == null) return null; Iterator i = root.getChildren().iterator(); while (i.hasNext()) { AbstractNode next = (AbstractNode)i.next(); AbstractNode retVal = getElement(next, loc, properties); if (retVal != null) return retVal; } if (loc.contained(root.getStart(), root.getEnd()) && ((root.getProperties() & properties) == properties)) { System.out.println(root.toString()); return root; } return null; } /** * @return the closest node whose node.start() <= offset */ public static AbstractNode getLessOrEqualNode(AbstractNode root, int offset, IDocument doc) { try { int line = doc.getLineOfOffset(offset); IRegion r = doc.getLineInformation(line); return getLessOrEqualNode(root, new Location(line, offset - r.getOffset())); } catch (BadLocationException e) { PydevPlugin.log(IStatus.WARNING, "getScopeByOffset failed", e); } return null; } /** * @return the closest node whose node.start() <= location */ public static AbstractNode getLessOrEqualNode(AbstractNode root, Location loc) { AbstractNode smallestSoFar = null; AbstractNode current = root; boolean greater = false; while (current != null && !greater) { if (current.getStart().compareTo(loc) <= 0) smallestSoFar = current; else greater = true; current = getNextNode(current); } return smallestSoFar; } /** * Gets the largest child of my ancestor that is smaller than me. */ private static AbstractNode getPreviousNodeHelper(AbstractNode node) { if (node == null) return null; ArrayList children = node.getChildren(); if (children.size() == 0) return node; else return getPreviousNodeHelper((AbstractNode)children.get(children.size() -1)); } /** * This gets the previous node by position. The nodes are ordered, * and each parent is smaller than its children. * The siblings after me are greater, the ones before are smaller * @return */ public static AbstractNode getPreviousNode(AbstractNode node) { if (node == null) return null; AbstractNode parent = node.getParent(); if (parent == null) return null; ArrayList children = parent.getChildren(); int pos = children.indexOf(node); if (pos == -1) { PydevPlugin.log(IStatus.ERROR, "Error traversing model tree", null); return null; } else if (pos > 0) return getPreviousNodeHelper((AbstractNode)children.get(pos-1)); else return parent; } /** * gets the smallest child of my ancestor that larger than me */ private static AbstractNode getNextNodeHelper(AbstractNode parent, AbstractNode child) { if (parent == null) return null; ArrayList children = parent.getChildren(); int pos = children.indexOf(child); if (pos == -1) { PydevPlugin.log(IStatus.ERROR, "Error traversing model tree", null); return null; } else if (pos == children.size() - 1) // last element, must traverse my parents // /\ return getNextNodeHelper(parent.getParent(), parent); else { return (AbstractNode)children.get(pos + 1); } } public static AbstractNode getNextNode(AbstractNode node) { if (node == null) return null; ArrayList children = node.getChildren(); if (children.size() > 0) return (AbstractNode)children.get(0); else return getNextNodeHelper(node.getParent(), node); } } --- NEW FILE: LengthEstimator.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.SimpleNode; import org.python.parser.ast.*; /** * LengthEstimator estimates a lenght of a node in characters. * * We need this to properly determine length of Nodes in the model. * Jython's parser only gives us the start of the node. * The estimates in this file are heuristic. */ public class LengthEstimator extends VisitorBase { int length = 0; int getLength() { return length; } protected Object unhandled_node(SimpleNode node) throws Exception { return null; } public void traverse(SimpleNode node) throws Exception { node.traverse(this); } public Object visitName(Name node) throws Exception { length += node.id.length(); return null; } public Object visitAttribute(Attribute node) throws Exception { length += node.attr.length() + 1; // +1 for '.' node.traverse(this); return null; } public Object visitCall(Call node) throws Exception { LengthEstimator e2 = new LengthEstimator(); node.traverse(e2); length += e2.getLength(); return null; } public Object visitAssert(Assert node) throws Exception { System.out.println("lenVisitAssert:" + node.toString("")); return null; } public Object visitAssign(Assign node) throws Exception { System.out.println("lenVisitAssign:" + node.toString("")); return null; } public Object visitAugAssign(AugAssign node) throws Exception { System.out.println("lenVisitAugAssign:" + node.toString("")); return null; } public Object visitBinOp(BinOp node) throws Exception { System.out.println("lenVisitBinOp:" + node.toString("")); return null; } public Object visitBoolOp(BoolOp node) throws Exception { System.out.println("lenVisitBoolOp:" + node.toString("")); return null; } public Object visitBreak(Break node) throws Exception { System.out.println("lenVisitBreak:" + node.toString("")); return null; } public Object visitClassDef(ClassDef node) throws Exception { System.out.println("lenVisitClassDef:" + node.name); return null; } public Object visitCompare(Compare node) throws Exception { System.out.println("lenVisitCompare:" + node.toString("")); return null; } public Object visitContinue(Continue node) throws Exception { System.out.println("lenVisitContinue:" + node.toString("")); return null; } public Object visitDelete(Delete node) throws Exception { System.out.println("lenVisitDelete:" + node.toString("")); return null; } public Object visitDict(Dict node) throws Exception { System.out.println("lenVisitDict:" + node.toString("")); return null; } public Object visitEllipsis(Ellipsis node) throws Exception { System.out.println("lenVisitEllipsis:" + node.toString("")); return null; } public Object visitExec(Exec node) throws Exception { System.out.println("lenVisitExec:" + node.toString("")); return null; } public Object visitExpr(Expr node) throws Exception { System.out.println("lenVisitExpr:" + node.toString("")); return null; } public Object visitExpression(Expression node) throws Exception { System.out.println("lenVisitExpression:" + node.toString("")); return null; } public Object visitExtSlice(ExtSlice node) throws Exception { System.out.println("lenVisitExtSlice:" + node.toString("")); return null; } public Object visitFor(For node) throws Exception { System.out.println("lenVisitFor:" + node.toString("")); return null; } public Object visitFunctionDef(FunctionDef node) throws Exception { System.out.println("lenVisitFunctionDef:" + node.toString("")); return null; } public Object visitGlobal(Global node) throws Exception { System.out.println("lenVisitGlobal:" + node.toString("")); return null; } public Object visitIf(If node) throws Exception { System.out.println("lenVisitIf:" + node.toString("")); return null; } public Object visitImport(Import node) throws Exception { System.out.println("lenVisitImport:" + node.toString("")); return null; } public Object visitImportFrom(ImportFrom node) throws Exception { System.out.println("lenVisitImportFrom:" + node.toString("")); return null; } public Object visitIndex(Index node) throws Exception { System.out.println("lenVisitIndex:" + node.toString("")); return null; } public Object visitInteractive(Interactive node) throws Exception { System.out.println("lenVisitInteractive:" + node.toString("")); return null; } public Object visitLambda(Lambda node) throws Exception { System.out.println("lenVisitLambda:" + node.toString("")); return null; } public Object visitList(List node) throws Exception { System.out.println("lenVisitList:" + node.toString("")); return null; } public Object visitListComp(ListComp node) throws Exception { System.out.println("lenVisitListComp:" + node.toString("")); return null; } public Object visitModule(Module node) throws Exception { System.out.println("lenVisitModule:" + node.toString("")); return null; } public Object visitNum(Num node) throws Exception { System.out.println("lenVisitNum:" + node.toString("")); return null; } public Object visitPass(Pass node) throws Exception { System.out.println("lenVisitPass:" + node.toString("")); return null; } public Object visitPrint(Print node) throws Exception { System.out.println("lenVisitPrint:" + node.toString("")); return null; } public Object visitRaise(Raise node) throws Exception { System.out.println("lenVisitRaise:" + node.toString("")); return null; } public Object visitRepr(Repr node) throws Exception { System.out.println("lenVisitRepr:" + node.toString("")); return null; } public Object visitReturn(Return node) throws Exception { System.out.println("lenVisitReturn:" + node.toString("")); return null; } public Object visitSlice(Slice node) throws Exception { System.out.println("lenVisitSlice:" + node.toString("")); return null; } public Object visitStr(Str node) throws Exception { System.out.println("lenVisitStr:" + node.toString("")); return null; } public Object visitSubscript(Subscript node) throws Exception { System.out.println("lenVisitSubscript:" + node.toString("")); return null; } public Object visitSuite(Suite node) throws Exception { System.out.println("lenVisitSuite:" + node.toString("")); return null; } public Object visitTryExcept(TryExcept node) throws Exception { System.out.println("lenVisitTryExcept:" + node.toString("")); return null; } public Object visitTryFinally(TryFinally node) throws Exception { System.out.println("lenVisitTryFinally:" + node.toString("")); return null; } public Object visitTuple(Tuple node) throws Exception { System.out.println("lenVisitTuple:" + node.toString("")); return null; } public Object visitUnaryOp(UnaryOp node) throws Exception { System.out.println("lenVisitUnaryOp:" + node.toString("")); return null; } public Object visitWhile(While node) throws Exception { System.out.println("lenVisitWhile:" + node.toString("")); return null; } public Object visitYield(Yield node) throws Exception { System.out.println("lenVisitYield:" + node.toString("")); return null; } } --- NEW FILE: ImportAlias.java --- /* * Author: atotic * Created on Apr 9, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.ast.aliasType; /** * ImportAlias represents individual imports. * * For example "import os,sys,network" generates 3 alias nodes. */ public class ImportAlias extends AbstractNode { aliasType astNode; public ImportAlias(AbstractNode parent, aliasType astNode) { super(parent); this.astNode = astNode; setStart(new Location(astNode.beginLine - 1, astNode.beginColumn - 1)); setEnd(new Location(astNode.beginLine - 1, astNode.beginColumn - 1 + astNode.name.length())); properties = PROP_CLICKABLE; } } --- NEW FILE: FunctionCallNode.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.eclipse.core.runtime.IStatus; import org.python.parser.ast.Call; import org.python.pydev.plugin.PydevPlugin; /** * Represents a function call. */ public class FunctionCallNode extends AbstractNode { Call astNode; /** * @param parent */ public FunctionCallNode(AbstractNode parent, Call astNode) { super(parent); this.astNode = astNode; this.setStart(new Location(astNode.beginLine - 1, astNode.beginColumn)); LengthEstimator estimate = new LengthEstimator(); try { astNode.traverse(estimate); } catch (Exception e) { PydevPlugin.log(IStatus.ERROR, "Unexpected error estimating length of function call", e); } this.setEnd(new Location(astNode.beginLine - 1, astNode.beginColumn + estimate.getLength())); properties = PROP_CLICKABLE; } } --- NEW FILE: LocalNode.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.ast.Name; /** * Local nodes represent locals variables. * A LocalNode is generated for every mention of the variable. * First mention is considered a declaration, and is stored inside Scope. */ public class LocalNode extends AbstractNode { // True if local is a builtin public static boolean isBuiltin(String name) { return (name.equals("None")); } Name astNode; /** * @param parent */ public LocalNode(AbstractNode parent, Name astNode) { super(parent); this.astNode = astNode; this.setStart(new Location(astNode.beginLine - 1, astNode.beginColumn)); this.setEnd(new Location(astNode.beginLine - 1, astNode.beginColumn + astNode.id.length())); parent.getScope().addLocalDefinition(this); properties = PROP_CLICKABLE; } public String toString() { return super.toString() + astNode.id; } public class PredefinedNameException extends Exception { } } --- NEW FILE: ImportNode.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.ast.Import; /** * Represents import & import as statements */ public class ImportNode extends AbstractNode { public Import astNode; public ImportNode(AbstractNode parent, Import astNode) { super(parent); this.astNode = astNode; // instead of trying to calculate its arguments, just span the "import" keyword setStart(new Location(astNode.beginLine - 1, astNode.beginColumn - 8)); setEnd(new Location(astNode.beginLine - 1, astNode.beginColumn - 2)); } } --- NEW FILE: ModuleNode.java --- /* * Author: atotic * Created on Apr 7, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; /** * Top-level node representing a python module. * * I also think of it as a file. */ public class ModuleNode extends AbstractNode { Scope scope; public ModuleNode(AbstractNode parent, int lines, int cols) { super(parent); scope = new Scope(this); // FileNode always spans the entire file this.start = Location.MIN_LOCATION; this.end = new Location(lines, cols); } public Scope getScope() { return scope; } } --- NEW FILE: ImportFromNode.java --- /* * Author: atotic * Created on Apr 9, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.ast.ImportFrom; /** * ImportFrom node spans first argument of "from import" statement. * * from repr import Repr, this node would span "repr". */ public class ImportFromNode extends AbstractNode { public ImportFrom astNode; public ImportFromNode(AbstractNode parent, ImportFrom astNode) { super(parent); this.astNode = astNode; setStart(new Location(astNode.beginLine - 1, astNode.beginColumn - 1)); setEnd(new Location(astNode.beginLine - 1, astNode.beginColumn -1 + astNode.module.length())); properties = PROP_CLICKABLE; } } --- NEW FILE: package.html --- <body> The model represents the structure of the python file. <p>{@link org.python.pydev.model.ModelMaker ModelMaker} creates the model from AST by traversing the tree. <p>{@link org.python.pydev.model.ModelUtils ModelUtils} have various utility functions for model traversal, etc. <p>{@link org.python.pydev.model.AbstractNode AbstractNode} is the main node API. Subclasses modify it as needed. See ClassNode, FunctionCallNode, etc... <p>The definitions of local variables are inferred. The first mention of every local variable (implicit definition) is stored inside Scope. Scope is intended for repository of inferred data. <p>We still need to work on processing of the include modules. </body> --- NEW FILE: FunctionNode.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.ast.FunctionDef; /** * Represents a function definition. */ public class FunctionNode extends AbstractNode { public FunctionDef astNode; Scope scope; public FunctionNode(AbstractNode parent, FunctionDef node) { super(parent); this.astNode = node; scope = new Scope(this); setStart(new Location(astNode.beginLine - 1, astNode.beginColumn + 3)); setEnd(new Location(astNode.beginLine - 1, astNode.beginColumn + 3 + astNode.name.length())); properties = PROP_CLICKABLE; } public Scope getScope() { return scope; } } --- NEW FILE: NameEqualsMainNode.java --- /* * Author: atotic * Created on Apr 9, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.ast.If; /** * if __name__ == 'main' Node. */ public class NameEqualsMainNode extends AbstractNode { If astNode; public NameEqualsMainNode(AbstractNode parent, If astNode) { super(parent); this.astNode = astNode; this.setStart(new Location(astNode.beginLine, astNode.beginColumn-1)); this.setEnd(new Location(astNode.beginLine, astNode.beginColumn + 22)); } } --- NEW FILE: Scope.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import java.util.ArrayList; import java.util.Iterator; /** * Scope represents scope where local variables belong to. * * There is a scope hierarchy: * ModuleNode scope * Function scope * Class scope * Function scope */ public class Scope { private ArrayList locals; private AbstractNode start; private AbstractNode end; private Scope parent; private ArrayList children; public Scope(AbstractNode start) { this.start = start; AbstractNode startParent = start.getParent(); if (startParent != null) { parent = startParent.getScope(); parent.addChild(this); } children = new ArrayList(); } private void addChild(Scope scope) { children.add(scope); } public ArrayList getChildren() { return children; } public LocalNode getLocalByName(String name) { if (locals == null) return null; Iterator i = locals.iterator(); while (i.hasNext()) { LocalNode l = (LocalNode)i.next(); if (l.toString().equals(name)) return l; } return null; } void addLocalDefinition(LocalNode newLocal) { if (locals == null) locals = new ArrayList(); if (getLocalByName(newLocal.toString()) == null) locals.add(newLocal); } public Location getStart() { return start.getStart(); } public AbstractNode getStartNode() { return start; } public Scope getParent() { return parent; } public Location getEnd() { return end.getEnd(); } /** * Computes where the last child of the node ends */ public void setEnd(AbstractNode end) { ArrayList children = end.getChildren(); int size = children.size(); AbstractNode trueEndNode = size > 0 ? (AbstractNode)children.get(size-1) : end; this.end = trueEndNode; } } --- NEW FILE: ClassNode.java --- /* * Author: atotic * Created on Apr 8, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.python.parser.ast.ClassDef; /** * Represents a class definition. */ public class ClassNode extends AbstractNode { public ClassDef astNode; Scope scope; public ClassNode(AbstractNode parent, ClassDef astNode) { super(parent); this.astNode = astNode; scope = new Scope(this); setStart(new Location(astNode.beginLine - 1, astNode.beginColumn + 5)); setEnd(new Location(astNode.beginLine - 1, astNode.beginColumn + 5 + astNode.name.length())); properties = PROP_CLICKABLE; } public Scope getScope() { return scope; } } --- NEW FILE: Location.java --- /* * Author: atotic * Created on Apr 7, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; /** * Struct class, holds line/column information. * * Has static utility functions for Location->offset/line conversions */ public class Location { public int line; public int column; static Location MIN_LOCATION = new Location(0,0); static Location MAX_LOCATION = new Location(Integer.MAX_VALUE, Integer.MAX_VALUE); public Location() { line = column = 0; } public Location(int line, int column) { this.line = line; this.column = column; } /** * Conversion to document coordinates. */ public int toOffset(IDocument document) throws BadLocationException { return document.getLineOffset(line) + column; } /** * @param location * @param location2 * @return */ public boolean contained(Location start, Location end) { boolean startOk = (line > start.line || line == start.line && column >= start.column); boolean endOk = startOk ? (line < end.line || line == end.line && column <= end.column): false; return startOk && endOk; } public String toString() { return "L:" + Integer.toString(line) + " C:" + Integer.toString(column); } /** * standard compare * @return 1 means I win, -1 means argument wins, 0 means equal */ public int compareTo(Location l) { if (line > l.line) return 1; if (line < l.line) return -1; if (column > l.column) return 1; if (column < l.column) return -1; return 0; } /** * Utility: Converts document's offset to Location * @return Location */ static public Location offsetToLocation(IDocument document, int offset) { try { int line = document.getLineOfOffset(offset); int line_start = document.getLineOffset(line); return new Location(line, offset - line_start); } catch (BadLocationException e) { return new Location(); } } } --- NEW FILE: IModelListener.java --- /* * Author: atotic * Created on Apr 9, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; /** * PyEdit will broadcast model changes to IModelListeners. * * modelChanged is generated every time document is parsed successfully */ public interface IModelListener { /** * every time document gets parsed, it generates a new parse tree * @param root - the root of the new model */ void modelChanged(AbstractNode root); } --- NEW FILE: AbstractNode.java --- /* * Author: atotic * Created on Apr 7, 2004 * License: Common Public License v1.0 */ package org.python.pydev.editor.model; import java.util.ArrayList; /** * ModelNode is a superclass of all nodes. * It knows its location, parent & children. * * Nodes can have properties that are useful when querying * For example, clickable nodes have PROP_CLICKABLE set. */ public class AbstractNode { static ArrayList emptyChildList = new ArrayList(); // we keep an empty list around for efficiency public static int PROP_CLICKABLE = 1; // if the node can be hyperlinked public static int PROP_ANY = 0; // all properties protected Location start; // line/offset start of the text that defines this node protected Location end; // end of node text protected AbstractNode parent; protected ArrayList children; int properties = 0; // a multi-valued integer, can be PROP_CLICKABLE, or others later // properties should be set in the initializer /** * @param parent can be null */ public AbstractNode(AbstractNode parent) { this.parent = parent; if (parent != null) parent.addChild(this); } public Location getStart() { return start; } public void setStart(Location start) { this.start = start; } public Location getEnd() { return end; } public void setEnd(Location end) { this.end = end; } /** * @return an unmodifiable list of children. * It is UNMODIFIABLE because if list is empty, we return a static empty list * to save memory/speed. */ public ArrayList getChildren() { if (children == null) return emptyChildList; return children; } public void addChild(AbstractNode child) { if (children == null) children = new ArrayList(); children.add(child); } public AbstractNode getParent() { return parent; } /** * Scope is where the local variables are. Module/Class/Functions have scope, * all others inherit from the parent. */ public Scope getScope() { if (parent != null) return parent.getScope(); return null; } public int getProperties() { return properties; } public String toString() { return getClass().toString() + " " + start.toString() + end.toString(); } } |