/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * This file was originally derived from the Polyglot extensible compiler framework. * * (C) Copyright 2000-2007 Polyglot project group, Cornell University * (C) Copyright IBM Corporation 2007-2012. */ package polyglot.visit; import polyglot.ast.Node; import polyglot.util.*; /** * The <code>NodeVisitor</code> represents an implementation of the "Visitor" * style of tree traversal. There is a convention among <b>polyglot</b> visitors * which states that traversals will <i>lazily reconstruct</i> the tree. That * is, the AST is functionally "modified" by creating new nodes on each * traversal, but only when necessary-- only when nodes (or their children) are * actually changed. Up to three separate calls into the visitor may be invoked * for each AST node. <code>override</code> allows the visitor to redefine the * entire traversal for a particular subtree. <code>enter</code> notifies the * visitor that traversal of a particular subtree has begun. * <code>leave</code> informs the visitor that traversal is finishing a * particular subtree. * * @see polyglot.ast.Node#visit * @see polyglot.ast.Node */ public abstract class NodeVisitor implements Cloneable { /** * Given a tree rooted at <code>n</code>, the visitor has the option of * overriding all traversal of the children of <code>n</code>. If no * changes were made to <code>n</code> and the visitor wishes to prevent * further traversal of the tree, then it should return <code>n</code>. If * changes were made to the subtree, then the visitor should return a * <i>copy</i> of <code>n</code> with appropriate changes. Finally, if the * visitor does not wish to override traversal of the subtree rooted at * <code>n</code>, then it should return <code>null</code>. * <p> * The default implementation of this method is to call * {@link #override(Node) override(n)}, as most subclasses do not need to know * the parent of the node <code>n</code>. * * @param parent The parent of <code>n</code>, * <code>null</code> if <code>n</code> has no parent. * @param n The root of the subtree to be traversed. * @return A node if normal traversal is to stop, <code>null</code> if it * is to continue. */ public Node override(Node parent, Node n) { return override(n); } /** * Given a tree rooted at <code>n</code>, the visitor has the option of * overriding all traversal of the children of <code>n</code>. If no * changes were made to <code>n</code> and the visitor wishes to prevent * further traversal of the tree, then it should return <code>n</code>. If * changes were made to the subtree, then the visitor should return a * <i>copy</i> of <code>n</code> with appropriate changes. Finally, if the * visitor does not wish to override traversal of the subtree rooted at * <code>n</code>, then it should return <code>null</code>. * <p> * This method is typically called by the method * {@link #override(Node, Node) override(parent, n)}. If a subclass overrides the * method {@link #override(Node, Node) override(parent, n)} then this method * may not be called. * * @param n The root of the subtree to be traversed. * @return A node if normal traversal is to stop, <code>null</code> if it * is to continue. */ public Node override(Node n) { return null; } /** * Begin normal traversal of a subtree rooted at <code>n</code>. This gives * the visitor the option of changing internal state or returning a new * visitor which will be used to visit the children of <code>n</code>. * <p> * The default implementation of this method is to call * {@link #enter(Node) enter(n)}, as most subclasses do not need to know * the parent of the node <code>n</code>. * * @param parent The parent of <code>n</code>, <code>null</code> if <code>n</code> has no parent. * @param n The root of the subtree to be traversed. * @return The <code>NodeVisitor</code> which should be used to visit the * children of <code>n</code>. */ public NodeVisitor enter(Node parent, Node n) { return enter(n); } /** * Begin normal traversal of a subtree rooted at <code>n</code>. This gives * the visitor the option of changing internal state or returning a new * visitor which will be used to visit the children of <code>n</code>. * <p> * This method is typically called by the method * {@link #enter(Node, Node) enter(parent, n)}. If a subclass overrides the * method {@link #enter(Node, Node) enter(parent, n)} then this method * may not be called. * * @param n The root of the subtree to be traversed. * @return The <code>NodeVisitor</code> which should be used to visit the * children of <code>n</code>. */ public NodeVisitor enter(Node n) { return this; } /** * This method is called after all of the children of <code>n</code> * have been visited. In this case, these children were visited by the * visitor <code>v</code>. This is the last chance for the visitor to * modify the tree rooted at <code>n</code>. This method will be called * exactly the same number of times as <code>entry</code> is called. * That is, for each node that is not overriden, <code>enter</code> and * <code>leave</code> are each called exactly once. * <p> * Note that if <code>old == n</code> then the vistior should make a copy * of <code>n</code> before modifying it. It should then return the * modified copy. * <p> * The default implementation of this method is to call * {@link #leave(Node, Node, NodeVisitor) leave(old, n, v)}, * as most subclasses do not need to know the parent of the * node <code>n</code>. * * @param parent The parent of <code>old</code>, * <code>null</code> if <code>old</code> has no parent. * @param old The original state of root of the current subtree. * @param n The current state of the root of the current subtree. * @param v The <code>NodeVisitor</code> object used to visit the children. * @return The final result of the traversal of the tree rooted at * <code>n</code>. */ public Node leave(Node parent, Node old, Node n, NodeVisitor v) { return leave(old, n, v); } /** * This method is called after all of the children of <code>n</code> * have been visited. In this case, these children were visited by the * visitor <code>v</code>. This is the last chance for the visitor to * modify the tree rooted at <code>n</code>. This method will be called * exactly the same number of times as <code>entry</code> is called. * That is, for each node that is not overriden, <code>enter</code> and * <code>leave</code> are each called exactly once. * <p> * Note that if <code>old == n</code> then the vistior should make a copy * of <code>n</code> before modifying it. It should then return the * modified copy. * <p> * This method is typically called by the method * {@link #leave(Node, Node, Node, NodeVisitor) leave(parent, old, n v)}. * If a subclass overrides the method * {@link #leave(Node, Node, Node, NodeVisitor) leave(parent, old, n v)} * then this method may not be called. * * @param old The original state of root of the current subtree. * @param n The current state of the root of the current subtree. * @param v The <code>NodeVisitor</code> object used to visit the children. * @return The final result of the traversal of the tree rooted at * <code>n</code>. */ public Node leave(Node old, Node n, NodeVisitor v) { return n; } /** * The begin method is called before the entire tree is visited. * This method allows the visitor to perform any initialization * that cannot be done when the visitor is created. * If <code>null</code> is returned, the ast is not traversed. * * @return the <code>NodeVisitor</code> to traverse the ast with. If * <code>null</code> is returned, the ast is not traversed. */ public NodeVisitor begin() { return this; } /** * The finish method is called after the entire tree has been visited. * This method allows the visitor to perform any last minute cleanup, * including flushing buffers and I/O connections. */ public void finish() { } public void finish(Node ast) { this.finish(); } public String toString() { return StringUtil.getShortNameComponent(getClass().getName()); } /** * Visit the edge between the parent node <code>parent</code>, and child * node <code>child</code>. This method recursively visits the subtree rooted * at <code>child</code>. * * @param parent the parent node of <code>child</code>, <code>null</code> if * <code>child</code> was visited by calling * {@link polyglot.ast.Node#visit(NodeVisitor) Node.visit(NodeVisitor)} instead * of {@link polyglot.ast.Node#visitChild(Node, NodeVisitor) * polyglot.ast.Node.visitChild(Node, NodeVisitor)}. * @param child the child node of <code>parent</code> to be visited. * @return the (possibly new) version of <code>child</code> after the * subtree rooted at <code>child</code> has been recursively visited. */ public Node visitEdge(Node parent, Node child) { try { Node n = override(parent, child); if (n == null) { return visitEdgeNoOverride(parent, child); } return n; } catch (InternalCompilerError e) { if (e.position() == null && child != null) e.setPosition(child.position()); throw e; } } /** * Visit the edge between the parent node <code>parent</code>, and child * node <code>child</code>, without invoking <code>override</code> for * the child. This method recursively visits the subtree rooted at * <code>child</code>. * * @param parent * @param child * @return the (possibly new) version of <code>child</code> after the * subtree rooted at <code>child</code> has been recursively visited. */ public Node visitEdgeNoOverride(Node parent, Node child) { if (child == null) { return null; } NodeVisitor v_ = enter(parent, child); if (v_ == null) { throw new InternalCompilerError("NodeVisitor.enter() returned null."); } Node n = child.del().visitChildren(v_); if (n == null) { throw new InternalCompilerError("Node.visitChildren() returned null."); } try { n = this.leave(parent, child, n, v_); } catch (InternalCompilerError e) { if (e.position() == null && n != null) e.setPosition(n.position()); throw e; } return n; } // none of the subclasses override the copy, so it doesn't do a deep copy but a shallow copy. public Object shallowCopy() { try { return (NodeVisitor) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalCompilerError("Java clone() weirdness."); } } }