View Javadoc

1   /*
2    $Id: ProcessingUnit.java,v 1.2 2004/07/10 03:31:41 bran Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
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.2 2004/07/10 03:31:41 bran Exp $
68   */
69  
70  public abstract class ProcessingUnit
71  {
72      
73    //---------------------------------------------------------------------------
74    // CONSTRUCTION AND SUCH
75      
76      protected LinkedList    warnings;       // WarningMessages collected during processing
77      protected LinkedList    errors;         // ErrorMessages collected during processing
78      protected boolean       fatal;          // Set on the first fatal error
79      
80      protected int           phase;          // The current phase
81      protected boolean       phaseComplete;  // Set true if phase is finished
82      
83      protected CompilerConfiguration configuration;  // Configuration and other settings that control processing
84      protected int           warningLevel;   // Warnings will be filtered on this level
85      protected PrintWriter   output;         // A place to send warning output
86      protected int           tolerance;      // The number of non-fatal errors to allow before fail()
87      
88      protected ClassLoader   classLoader;    // The ClassLoader to use during processing
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   // MESSAGES
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   // PROCESSING
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         // First up, display and clear any pending warnings.
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         // Then either fail() or update the phase and return
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   // OUTPUT
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             this.errors = null;
503         }
504     }
505     
506     
507 }
508 
509 
510 
511