View Javadoc

    1   /*
    2    $Id: ProcessingUnit.java,v 1.3 2004/12/15 00:19:52 zohar 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.3 2004/12/15 00:19:52 zohar 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             //why? this nukes the errors once a getString call is made
    503             //this.errors = null;
    504         }
    505     }
    506
    507
    508 }
    509
    510
    511
    512