KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > polyglot > visit > NodeVisitor


1 package polyglot.visit;
2
3 import polyglot.ast.Node;
4 import polyglot.util.InternalCompilerError;
5
6 /**
7  * The <code>NodeVisitor</code> represents an implementation of the "Visitor"
8  * style of tree traversal. There is a convention among <b>polyglot</b> visitors
9  * which states that traversals will <i>lazily reconstruct</i> the tree. That
10  * is, the AST is functionally "modified" by creating new nodes on each
11  * traversal, but only when necessary-- only when nodes (or their children) are
12  * actually changed. Up to three seperate calls into the visitor may be invoked
13  * for each AST node. <code>override</code> allows the visitor to redefine the
14  * entire traversal for a particular subtree. <code>enter</code> notifies the
15  * visitor that traversal of a particular subtree has begun.
16  * <code>leave</code> informs the visitor that traversal is finishing a
17  * particular subtree.
18  *
19  * @see polyglot.ast.Node#visit
20  * @see polyglot.ast.Node
21  */

22 public abstract class NodeVisitor
23 {
24     /**
25      * Given a tree rooted at <code>n</code>, the visitor has the option of
26      * overriding all traversal of the children of <code>n</code>. If no
27      * changes were made to <code>n</code> and the visitor wishes to prevent
28      * further traversal of the tree, then it should return <code>n</code>. If
29      * changes were made to the subtree, then the visitor should return a
30      * <i>copy</i> of <code>n</code> with appropriate changes. Finally, if the
31      * visitor does not wish to override traversal of the subtree rooted at
32      * <code>n</code>, then it should return <code>null</code>.
33      * <p>
34      * The default implementation of this method is to call
35      * {@link #override(Node) override(n)}, as most subclasses do not need to know
36      * the parent of the node <code>n</code>.
37      *
38      * @param parent The parent of <code>n</code>,
39      * <code>null</code> if <code>n</code> has no parent.
40      * @param n The root of the subtree to be traversed.
41      * @return A node if normal traversal is to stop, <code>null</code> if it
42      * is to continue.
43      */

44     public Node override(Node parent, Node n) {
45         return override(n);
46     }
47
48     /**
49      * Given a tree rooted at <code>n</code>, the visitor has the option of
50      * overriding all traversal of the children of <code>n</code>. If no
51      * changes were made to <code>n</code> and the visitor wishes to prevent
52      * further traversal of the tree, then it should return <code>n</code>. If
53      * changes were made to the subtree, then the visitor should return a
54      * <i>copy</i> of <code>n</code> with appropriate changes. Finally, if the
55      * visitor does not wish to override traversal of the subtree rooted at
56      * <code>n</code>, then it should return <code>null</code>.
57      * <p>
58      * This method is typically called by the method
59      * {@link #override(Node, Node) override(parent, n)}. If a subclass overrides the
60      * method {@link #override(Node, Node) override(parent, n)} then this method
61      * may not be called.
62      *
63      * @param n The root of the subtree to be traversed.
64      * @return A node if normal traversal is to stop, <code>null</code> if it
65      * is to continue.
66      */

67     public Node override(Node n) {
68     return null;
69     }
70
71     /**
72      * Begin normal traversal of a subtree rooted at <code>n</code>. This gives
73      * the visitor the option of changing internal state or returning a new
74      * visitor which will be used to visit the children of <code>n</code>.
75      * <p>
76      * The default implementation of this method is to call
77      * {@link #enter(Node) enter(n)}, as most subclasses do not need to know
78      * the parent of the node <code>n</code>.
79      *
80      * @param parent The parent of <code>n</code>, <code>null</code> if <code>n</code> has no parent.
81      * @param n The root of the subtree to be traversed.
82      * @return The <code>NodeVisitor</code> which should be used to visit the
83      * children of <code>n</code>.
84      */

85     public NodeVisitor enter(Node parent, Node n) {
86         return enter(n);
87     }
88
89     /**
90      * Begin normal traversal of a subtree rooted at <code>n</code>. This gives
91      * the visitor the option of changing internal state or returning a new
92      * visitor which will be used to visit the children of <code>n</code>.
93      * <p>
94      * This method is typically called by the method
95      * {@link #enter(Node, Node) enter(parent, n)}. If a subclass overrides the
96      * method {@link #enter(Node, Node) enter(parent, n)} then this method
97      * may not be called.
98      *
99      * @param n The root of the subtree to be traversed.
100      * @return The <code>NodeVisitor</code> which should be used to visit the
101      * children of <code>n</code>.
102      */

103     public NodeVisitor enter(Node n) {
104         return this;
105     }
106
107     /**
108      * This method is called after all of the children of <code>n</code>
109      * have been visited. In this case, these children were visited by the
110      * visitor <code>v</code>. This is the last chance for the visitor to
111      * modify the tree rooted at <code>n</code>. This method will be called
112      * exactly the same number of times as <code>entry</code> is called.
113      * That is, for each node that is not overriden, <code>enter</code> and
114      * <code>leave</code> are each called exactly once.
115      * <p>
116      * Note that if <code>old == n</code> then the vistior should make a copy
117      * of <code>n</code> before modifying it. It should then return the
118      * modified copy.
119      * <p>
120      * The default implementation of this method is to call
121      * {@link #leave(Node, Node, NodeVisitor) leave(old, n, v)},
122      * as most subclasses do not need to know the parent of the
123      * node <code>n</code>.
124      *
125      * @param parent The parent of <code>old</code>,
126      * <code>null</code> if <code>old</code> has no parent.
127      * @param old The original state of root of the current subtree.
128      * @param n The current state of the root of the current subtree.
129      * @param v The <code>NodeVisitor</code> object used to visit the children.
130      * @return The final result of the traversal of the tree rooted at
131      * <code>n</code>.
132      */

133     public Node leave(Node parent, Node old, Node n, NodeVisitor v) {
134         return leave(old, n, v);
135     }
136
137     /**
138      * This method is called after all of the children of <code>n</code>
139      * have been visited. In this case, these children were visited by the
140      * visitor <code>v</code>. This is the last chance for the visitor to
141      * modify the tree rooted at <code>n</code>. This method will be called
142      * exactly the same number of times as <code>entry</code> is called.
143      * That is, for each node that is not overriden, <code>enter</code> and
144      * <code>leave</code> are each called exactly once.
145      * <p>
146      * Note that if <code>old == n</code> then the vistior should make a copy
147      * of <code>n</code> before modifying it. It should then return the
148      * modified copy.
149      * <p>
150      * This method is typically called by the method
151      * {@link #leave(Node, Node, Node, NodeVisitor) leave(parent, old, n v)}.
152      * If a subclass overrides the method
153      * {@link #leave(Node, Node, Node, NodeVisitor) leave(parent, old, n v)}
154      * then this method may not be called.
155      *
156      * @param old The original state of root of the current subtree.
157      * @param n The current state of the root of the current subtree.
158      * @param v The <code>NodeVisitor</code> object used to visit the children.
159      * @return The final result of the traversal of the tree rooted at
160      * <code>n</code>.
161      */

162     public Node leave(Node old, Node n, NodeVisitor v) {
163         return n;
164     }
165
166     /**
167      * The begin method is called before the entire tree is visited.
168      * This method allows the visitor to perform any initialization
169      * that cannot be done when the visitor is created.
170      * If <code>null</code> is returned, the ast is not traversed.
171      *
172      * @return the <code>NodeVisitor</code> to traverse the ast with. If
173      * <code>null</code> is returned, the ast is not traversed.
174      */

175     public NodeVisitor begin() {
176         return this;
177     }
178
179     /**
180      * The finish method is called after the entire tree has been visited.
181      * This method allows the visitor to perform any last minute cleanup,
182      * including flushing buffers and I/O connections.
183      */

184     public void finish() { }
185     public void finish(Node ast) { this.finish(); }
186
187     public String JavaDoc toString() {
188         return getClass().getName();
189     }
190
191     /**
192      * Visit the edge between the parent node <code>parent</code>, and child
193      * node <code>child</code>. This method recursively visits the subtree rooted
194      * at <code>child</code>.
195      *
196      * @param parent the parent node of <code>child</code>, <code>null</code> if
197      * <code>child</code> was visited by calling
198      * {@link polyglot.ast.Node#visit(NodeVisitor) polyglot.ast.Node.visit(NodeVisitor)} instead
199      * of {@link polyglot.ast.Node#visitChild(polyglot.ast.Node, NodeVisitor)
200      * Node.visitChild(Node, NodeVisitor)}.
201      * @param child the child node of <code>parent</code> to be visited.
202      * @return the (possibly new) version of <code>child</code> after the
203      * subtree rooted at <code>child</code> has been recursively visited.
204      */

205     public Node visitEdge(Node parent, Node child) {
206     Node n = override(parent, child);
207
208     if (n == null) {
209         NodeVisitor v_ = this.enter(parent, child);
210
211         if (v_ == null) {
212         throw new InternalCompilerError(
213             "NodeVisitor.enter() returned null.");
214         }
215
216         n = child.visitChildren(v_);
217
218         if (n == null) {
219         throw new InternalCompilerError(
220             "Node_c.visitChildren() returned null.");
221         }
222
223         n = this.leave(parent, child, n, v_);
224
225         if (n == null) {
226         throw new InternalCompilerError(
227             "NodeVisitor.leave() returned null.");
228         }
229     }
230
231     return n;
232     }
233 }
234
Popular Tags