1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 package org.codehaus.groovy.control;
48
49 import org.codehaus.groovy.control.messages.ExceptionMessage;
50 import org.codehaus.groovy.control.messages.Message;
51 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
52 import org.codehaus.groovy.control.messages.WarningMessage;
53 import org.codehaus.groovy.syntax.SyntaxException;
54
55 import java.io.PrintWriter;
56 import java.util.Iterator;
57 import java.util.LinkedList;
58 import java.util.List;
59
60
61 /***
62 * A base class for data structures that can collect messages and errors
63 * during processing.
64 *
65 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
66 * @version $Id: ProcessingUnit.java,v 1.8 2005/02/17 10:56:46 jstrachan Exp $
67 */
68
69 public abstract class ProcessingUnit {
70
71 /***
72 * WarningMessages collected during processing
73 */
74 protected LinkedList warnings;
75 /***
76 * ErrorMessages collected during processing
77 */
78 protected LinkedList errors;
79 /***
80 * Set on the first fatal error
81 */
82 protected boolean fatal;
83
84 /***
85 * The current phase
86 */
87 protected int phase;
88 /***
89 * Set true if phase is finished
90 */
91 protected boolean phaseComplete;
92
93 /***
94 * Configuration and other settings that control processing
95 */
96 protected CompilerConfiguration configuration;
97 /***
98 * Warnings will be filtered on this level
99 */
100 protected int warningLevel;
101 /***
102 * A place to send warning output
103 */
104 protected PrintWriter output;
105 /***
106 * The number of non-fatal errors to allow before fail()
107 */
108 protected int tolerance;
109
110 /***
111 * The ClassLoader to use during processing
112 */
113 protected ClassLoader classLoader;
114
115
116 /***
117 * Initialize the ProcessingUnit to the empty state.
118 */
119
120 public ProcessingUnit(CompilerConfiguration configuration, ClassLoader classLoader) {
121 this.warnings = null;
122 this.errors = null;
123 this.fatal = false;
124
125 this.phase = Phases.INITIALIZATION;
126 this.classLoader = (classLoader == null ? new CompilerClassLoader() : classLoader);
127
128 configure((configuration == null ? new CompilerConfiguration() : configuration));
129 }
130
131
132 /***
133 * Reconfigures the ProcessingUnit.
134 */
135
136 public void configure(CompilerConfiguration configuration) {
137 this.configuration = configuration;
138 this.warningLevel = configuration.getWarningLevel();
139 this.output = configuration.getOutput();
140 this.tolerance = configuration.getTolerance();
141 }
142
143
144 public CompilerConfiguration getConfiguration() {
145 return configuration;
146 }
147
148 public void setConfiguration(CompilerConfiguration configuration) {
149 this.configuration = configuration;
150 }
151
152 /***
153 * Returns the class loader in use by this ProcessingUnit.
154 */
155
156 public ClassLoader getClassLoader() {
157 return classLoader;
158 }
159
160
161 /***
162 * Sets the class loader for use by this ProcessingUnit.
163 */
164
165 public void setClassLoader(ClassLoader loader) {
166 this.classLoader = loader;
167 }
168
169
170 /***
171 * Returns the current phase.
172 */
173
174 public int getPhase() {
175 return this.phase;
176 }
177
178
179 /***
180 * Returns the description for the current phase.
181 */
182
183 public String getPhaseDescription() {
184 return Phases.getDescription(this.phase);
185 }
186
187
188 /***
189 * Returns the list of warnings, or null if there are none.
190 */
191
192 public List getWarnings() {
193 return this.warnings;
194 }
195
196
197 /***
198 * Returns the list of errors, or null if there are none.
199 */
200
201 public List getErrors() {
202 return this.errors;
203 }
204
205
206 /***
207 * Returns the number of warnings.
208 */
209
210 public int getWarningCount() {
211 return ((this.warnings == null) ? 0 : this.warnings.size());
212 }
213
214
215 /***
216 * Returns the number of errors.
217 */
218
219 public int getErrorCount() {
220 return ((this.errors == null) ? 0 : this.errors.size());
221 }
222
223
224 /***
225 * Returns the specified warning message, or null.
226 */
227
228 public WarningMessage getWarning(int index) {
229 if (index < getWarningCount()) {
230 return (WarningMessage) this.warnings.get(index);
231 }
232
233 return null;
234 }
235
236
237 /***
238 * Returns the specified error message, or null.
239 */
240
241 public Message getError(int index) {
242 if (index < getErrorCount()) {
243 return (Message) this.errors.get(index);
244 }
245
246 return null;
247 }
248
249
250 /***
251 * Convenience routine to return the specified error's
252 * underlying SyntaxException, or null if it isn't one.
253 */
254
255 public SyntaxException getSyntaxError(int index) {
256 SyntaxException exception = null;
257
258 Message message = getError(index);
259 if (message != null && message instanceof SyntaxErrorMessage) {
260 exception = ((SyntaxErrorMessage) message).getCause();
261 }
262
263 return exception;
264 }
265
266
267 /***
268 * Convenience routine to return the specified error's
269 * underlying Exception, or null if it isn't one.
270 */
271
272 public Exception getException(int index) {
273 Exception exception = null;
274
275 Message message = getError(index);
276 if (message != null) {
277 if (message instanceof ExceptionMessage) {
278 exception = ((ExceptionMessage) message).getCause();
279 }
280 else if (message instanceof SyntaxErrorMessage) {
281 exception = ((SyntaxErrorMessage) message).getCause();
282 }
283 }
284
285 return exception;
286 }
287
288
289
290
291
292
293
294
295 /***
296 * Adds a WarningMessage to the message set.
297 */
298
299 public void addWarning(WarningMessage message) {
300 if (message.isRelevant(this.warningLevel)) {
301 if (this.warnings == null) {
302 this.warnings = new LinkedList();
303 }
304
305 this.warnings.add(message);
306 }
307 }
308
309
310 /***
311 * Adds a non-fatal error to the message set.
312 */
313
314 public void addError(Message message) throws CompilationFailedException {
315 if (this.errors == null) {
316 this.errors = new LinkedList();
317 }
318
319 this.errors.add(message);
320
321 if (this.errors.size() >= this.tolerance) {
322 fail();
323 }
324 }
325
326
327 /***
328 * Adds an optionally-fatal error to the message set. Throws
329 * the unit as a PhaseFailedException, if the error is fatal.
330 */
331
332 public void addError(Message message, boolean fatal) throws CompilationFailedException {
333 if (fatal) {
334 addFatalError(message);
335 }
336 else {
337 addError(message);
338 }
339 }
340
341
342 /***
343 * Adds a fatal exception to the message set and throws
344 * the unit as a PhaseFailedException.
345 */
346
347 public void addFatalError(Message message) throws CompilationFailedException {
348 addError(message);
349 fail();
350 }
351
352
353 public void addException(Exception cause) throws CompilationFailedException {
354 addError(new ExceptionMessage(cause));
355 fail();
356 }
357
358
359
360
361
362
363 /***
364 * Returns true if there are any errors pending.
365 */
366
367 public boolean hasErrors() {
368 return this.errors != null;
369 }
370
371
372 /***
373 * Marks the current phase complete and processes any
374 * errors.
375 */
376
377 public void completePhase() throws CompilationFailedException {
378
379
380
381 if (this.warnings != null) {
382 Janitor janitor = new Janitor();
383
384 try {
385 Iterator iterator = this.warnings.iterator();
386 while (iterator.hasNext()) {
387 WarningMessage warning = (WarningMessage) iterator.next();
388 warning.write(output, this, janitor);
389 }
390
391 this.warnings = null;
392 }
393 finally {
394 janitor.cleanup();
395 }
396 }
397
398
399
400
401 if (this.hasErrors()) {
402 fail();
403 }
404 else {
405 phaseComplete = true;
406 }
407 }
408
409
410 /***
411 * A synonym for <code>gotoPhase( phase + 1 )</code>.
412 */
413
414 public void nextPhase() throws CompilationFailedException {
415 gotoPhase(this.phase + 1);
416 }
417
418
419 /***
420 * Wraps up any pending operations for the current phase
421 * and switches to the next phase.
422 */
423
424 public void gotoPhase(int phase) throws CompilationFailedException {
425 if (!this.phaseComplete) {
426 completePhase();
427 }
428
429 this.phase = phase;
430 this.phaseComplete = false;
431 }
432
433
434 /***
435 * Causes the current phase to fail by throwing a
436 * CompilationFailedException.
437 */
438
439 protected void fail() throws CompilationFailedException {
440
441 Throwable firstException = null;
442 for (Iterator iter = errors.iterator(); iter.hasNext();) {
443 Message message = (Message) iter.next();
444 if (message instanceof ExceptionMessage) {
445 ExceptionMessage exceptionMessage = (ExceptionMessage) message;
446 firstException = exceptionMessage.getCause();
447 if (firstException != null) {
448 break;
449 }
450 }
451 if (message instanceof SyntaxErrorMessage) {
452 SyntaxErrorMessage exceptionMessage = (SyntaxErrorMessage) message;
453 firstException = exceptionMessage.getCause();
454 if (firstException != null) {
455 break;
456 }
457 }
458 }
459
460 if (firstException != null) {
461 throw new CompilationFailedException(phase, this, firstException);
462 }
463 else {
464 throw new CompilationFailedException(phase, this);
465 }
466 }
467
468
469
470
471
472
473
474
475 /***
476 * Writes error messages to the specified PrintWriter.
477 */
478
479 public void write(PrintWriter writer, Janitor janitor) {
480 if (this.warnings != null) {
481 Iterator iterator = this.warnings.iterator();
482 while (iterator.hasNext()) {
483 WarningMessage warning = (WarningMessage) iterator.next();
484 warning.write(writer, this, janitor);
485 }
486
487 this.warnings = null;
488 }
489
490 if (this.errors != null) {
491 Iterator iterator = this.errors.iterator();
492 while (iterator.hasNext()) {
493 Message message = (Message) iterator.next();
494 message.write(writer, this, janitor);
495 }
496
497
498
499 }
500 }
501
502
503 }
504
505
506
507