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