KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > polyglot > visit > ErrorHandlingVisitor


1 package polyglot.visit;
2
3 import polyglot.ast.*;
4 import polyglot.types.*;
5 import polyglot.util.*;
6 import polyglot.frontend.Job;
7 import polyglot.main.Report;
8 import java.util.*;
9
10 /**
11  */

12 public class ErrorHandlingVisitor extends HaltingVisitor
13 {
14     protected boolean error;
15     protected Job job;
16     protected TypeSystem ts;
17     protected NodeFactory nf;
18
19     public ErrorHandlingVisitor(Job job, TypeSystem ts, NodeFactory nf) {
20         this.job = job;
21         this.ts = ts;
22         this.nf = nf;
23     }
24
25     /** Returns the <code>Job</code> that this Visitor is part of.
26      *
27      * @see polyglot.frontend.Job
28      */

29     public Job job() {
30         return job;
31     }
32
33     /**
34      * Part of the initialization done by begin() in an ErrorHandlingVisitor
35      * method is initializing the error-handling state.
36      */

37     public NodeVisitor begin() {
38         this.error = false;
39         return super.begin();
40     }
41
42     /** Returns the <code>ErrorQueue</code> for the current Job.
43      *
44      * @see polyglot.util.ErrorQueue
45      */

46     public ErrorQueue errorQueue() {
47         return job.compiler().errorQueue();
48     }
49
50     /** Returns the <code>NodeFactory</code> that this Visitor is using.
51      *
52      * @see polyglot.ast.NodeFactory
53      */

54     public NodeFactory nodeFactory() {
55         return nf;
56     }
57
58     /** Returns the <code>TypeSystem</code> that this Visitor is using.
59      *
60      * @see polyglot.types.TypeSystem
61      */

62     public TypeSystem typeSystem() {
63         return ts;
64     }
65
66     /** Replaces the functionality of the <code>enter()</code> method; all
67       * sub-classes should over-ride this method instead of
68       * <code>enter()</code> if there is any chance of exceptions being
69       * generated.
70       *
71       * This method is the replacement for the <code>enter()</code> method,
72       * so that all of its subclasses gain the error handling capabilities
73       * of this visitor without having to rewrite it for the
74       * <code>enter()</code> for each sub-class.
75       *
76       * This method allows for a <code>SemanticException</code> to be
77       * thrown in the body, while <code>enter()</code> does not.
78       *
79       * @see polyglot.visit.NodeVisitor#enter(Node, Node)
80       * @throws SemanticException
81       * @param n The root of the subtree to be traversed.
82       * @return The <code>ErrorHandlingVisitor</code> which should be
83       * used to visit the children of <code>n</code>.
84      */

85     protected NodeVisitor enterCall(Node parent, Node n)
86                 throws SemanticException {
87         if (Report.should_report(Report.visit, 3))
88         Report.report(3, "enter: " + parent + " -> " + n);
89         return enterCall(n);
90     }
91
92     protected NodeVisitor enterCall(Node n) throws SemanticException {
93         return this;
94     }
95
96     /** This method determines what should be returned by <code>enter()</code>
97       * should its call to <code>enterCall()</code> throw a
98       * <code>SemanticException</code>.
99       *
100       * @param n The root of the subtree that was traversed.
101       * @return The <code>ErrorHandlingVisitor</code> which should be
102       * used to visit the childre of <code>n</code>.
103       */

104     protected NodeVisitor enterError(Node n) {
105     return this;
106     }
107
108     /** Contains all of the functionality that can be done in the <code> leave
109       * </code> method, but allows <code>SemanticExceptions</code> to be
110       * thrown.
111       *
112       * This method is in addition to the <code>leave</code> method,
113       * and allows the compiler writer to write code that can throw errors
114       * and let the polyglot infrastructure handle the exceptions.
115       *
116       * @see polyglot.visit.NodeVisitor#leave(Node, Node, NodeVisitor)
117       * @throws SemanticException
118       * @param old The original state of root of the current subtree.
119       * @param n The current state of the root of the current subtree.
120       * @param v The <code>NodeVisitor</code> object used to visit the children.
121       * @return The final result of the traversal of the tree rooted at
122       * <code>n</code>.
123       */

124     protected Node leaveCall(Node old, Node n, NodeVisitor v)
125         throws SemanticException {
126
127     return leaveCall(n);
128     }
129
130     protected Node leaveCall(Node n) throws SemanticException {
131     return n;
132     }
133
134     /** Return true if we should catch errors thrown when visiting the node. */
135     protected boolean catchErrors(Node n) {
136     return n instanceof Stmt
137         || n instanceof ClassMember
138         || n instanceof ClassDecl
139         || n instanceof Import
140         || n instanceof SourceFile;
141     }
142
143     /**
144      * Begin normal traversal of a subtree rooted at <code>n</code>. This gives
145      * the visitor the option of changing internal state or returning a new
146      * visitor which will be used to visit the children of <code>n</code>.
147      *
148      * This method delegates all responsibility of functionality to the
149      * <code>enterCall</code> method, and handles and reports any exceptions
150      * generated by <code>enterCall</code>.
151      *
152      * In overriding this method, unless the class explicitly does not
153      * want to maintain any of the error handling aspects of this class, a call
154      * <code>super.enter</code> should be embedded within the method at the
155      * end.
156      *
157      * @param n The root of the subtree to be traversed.
158      * @return The <code>NodeVisitor</code> which should be used to visit the
159      * children of <code>n</code>.
160      */

161     public NodeVisitor enter(Node parent, Node n) {
162         if (Report.should_report(Report.visit, 5))
163         Report.report(5, "enter(" + n + ")");
164
165         if (catchErrors(n)) {
166             this.error = false;
167         }
168
169         try {
170             // should copy the visitor
171
return (ErrorHandlingVisitor) enterCall(parent, n);
172         }
173     catch (SemanticException e) {
174             if (e.getMessage() != null) {
175                 Position position = e.position();
176
177                 if (position == null) {
178                     position = n.position();
179                 }
180
181                 errorQueue().enqueue(ErrorInfo.SEMANTIC_ERROR,
182                                     e.getMessage(), position);
183             }
184             else {
185                 // silent error; these should be thrown only
186
// when the error has already been reported
187
}
188
189             if (! catchErrors(n)) {
190                 this.error = true;
191             }
192
193         return enterError(n);
194         }
195     }
196
197
198     /**
199      * This method is called after all of the children of <code>n</code>
200      * have been visited. In this case, these children were visited by the
201      * visitor <code>v</code>. This is the last chance for the visitor to
202      * modify the tree rooted at <code>n</code>. This method will be called
203      * exactly the same number of times as <code>entry</code> is called.
204      * That is, for each node that is not overriden, <code>enter</code> and
205      * <code>leave</code> are each called exactly once.
206      * <p>
207      * Note that if <code>old == n</code> then the vistior should make a copy
208      * of <code>n</code> before modifying it. It should then return the
209      * modified copy.
210      *
211      * This method delegates all responsibility of functionality to the
212      * <code>leaveCall</code> method, and handles and reports any exceptions
213      * generated by <code> leaveCall</code>.
214      *
215      * In overriding this method, unless the class explicitly does not
216      * want to maintain any of the error handling aspects of this class, a call
217      * <code>super.leave</code> should be embedded within the method at the
218      * end.
219      *
220      * @param old The original state of root of the current subtree.
221      * @param n The current state of the root of the current subtree.
222      * @param v The <code>NodeVisitor</code> object used to visit the children.
223      * @return The final result of the traversal of the tree rooted at
224      * <code>n</code>.
225      */

226  
227     public Node leave(Node parent, Node old, Node n, NodeVisitor v) {
228         try {
229             if (v instanceof ErrorHandlingVisitor &&
230                 ((ErrorHandlingVisitor) v).error) {
231
232                 if (Report.should_report(Report.visit, 5))
233             Report.report(5, "leave(" + n + "): error below");
234
235                 if (catchErrors(n)) {
236                     this.error = false;
237                     ((ErrorHandlingVisitor) v).error = false;
238                 }
239                 else {
240                     // propagate the error outward
241
this.error = true;
242                 }
243
244                 // don't visit the node
245
return n;
246             }
247
248             if (Report.should_report(Report.visit, 5))
249         Report.report(5, "leave(" + n + "): calling leaveCall");
250
251             return leaveCall(old, n, v);
252     }
253     catch (SemanticException e) {
254             if (e.getMessage() != null) {
255                 Position position = e.position();
256
257                 if (position == null) {
258                     position = n.position();
259                 }
260
261                 errorQueue().enqueue(ErrorInfo.SEMANTIC_ERROR,
262                                     e.getMessage(), position);
263             }
264             else {
265                 // silent error; these should be thrown only
266
// when the error has already been reported
267
}
268
269             if (catchErrors(n)) {
270                 this.error = false;
271                 ((ErrorHandlingVisitor) v).error = false;
272             }
273             else {
274                 this.error = true;
275                 ((ErrorHandlingVisitor) v).error = true;
276             }
277
278             return n;
279         }
280     }
281 }
282
283
Popular Tags