View Javadoc

    1   /*
    2    $Id: CompilationUnit.java,v 1.10 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 org.codehaus.groovy.GroovyBugError;
    50  import org.codehaus.groovy.ast.ClassNode;
    51  import org.codehaus.groovy.ast.CompileUnit;
    52  import org.codehaus.groovy.ast.ModuleNode;
    53  import org.codehaus.groovy.classgen.*;
    54  import org.codehaus.groovy.control.io.InputStreamReaderSource;
    55  import org.codehaus.groovy.control.io.ReaderSource;
    56  import org.codehaus.groovy.control.messages.ExceptionMessage;
    57  import org.codehaus.groovy.control.messages.Message;
    58  import org.codehaus.groovy.tools.GroovyClass;
    59  import org.objectweb.asm.ClassVisitor;
    60  import org.objectweb.asm.ClassWriter;
    61
    62  import java.io.*;
    63  import java.net.MalformedURLException;
    64  import java.net.URL;
    65  import java.security.CodeSource;
    66  import java.util.*;
    67
    68
    69  /***
    70   * Collects all compilation data as it is generated by the compiler system.
    71   * Allows additional source units to be added and compilation run again (to
    72   * affect only the deltas).
    73   *
    74   * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
    75   * @version $Id: CompilationUnit.java,v 1.10 2004/12/15 00:19:52 zohar Exp $
    76   */
    77
    78  public class CompilationUnit extends ProcessingUnit {
    79
    80      //---------------------------------------------------------------------------
    81      // CONSTRUCTION AND SUCH
    82
    83      protected HashMap sources;    // The SourceUnits from which this unit is built
    84      protected ArrayList names;      // Names for each SourceUnit in sources.
    85
    86      protected CompileUnit ast;        // The overall AST for this CompilationUnit.
    87      protected ArrayList classes;    // The classes generated during classgen.
    88
    89      protected Verifier verifier;   // For use by verify().
    90
    91      protected ClassCompletionVerifier completionVerifier; // for use by checkClassCompletion
    92
    93      protected boolean debug;      // Controls behaviour of classgen() and other routines.
    94      protected boolean configured; // Set true after the first configure() operation
    95
    96      protected ClassgenCallback classgenCallback;  // A callback for use during classgen()
    97      protected ProgressCallback progressCallback;  // A callback for use during compile()
    98
    99
    100     /***
    101      * Initializes the CompilationUnit with defaults.
    102      */
    103     public CompilationUnit() {
    104         this(null, null, null);
    105     }
    106
    107
    108     /***
    109      * Initializes the CompilationUnit with defaults except for class loader.
    110      */
    111     public CompilationUnit(ClassLoader loader) {
    112         this(null, null, loader);
    113     }
    114
    115
    116     /***
    117      * Initializes the CompilationUnit with no security considerations.
    118      */
    119     public CompilationUnit(CompilerConfiguration configuration) {
    120         this(configuration, null, null);
    121     }
    122
    123
    124     /***
    125      * Initializes the CompilationUnit with a CodeSource for controlling
    126      * security stuff and a class loader for loading classes.
    127      */
    128
    129     public CompilationUnit(CompilerConfiguration configuration, CodeSource security, ClassLoader loader) {
    130         super(configuration, loader);
    131
    132         this.names = new ArrayList();
    133         this.sources = new HashMap();
    134
    135         this.ast = new CompileUnit(this.classLoader, security, this.configuration);
    136         this.classes = new ArrayList();
    137
    138         this.verifier = new Verifier();
    139         this.completionVerifier = new ClassCompletionVerifier();
    140
    141         this.classgenCallback = null;
    142     }
    143
    144
    145     /***
    146      * Reconfigures the CompilationUnit.
    147      */
    148
    149     public void configure(CompilerConfiguration configuration) {
    150         super.configure(configuration);
    151         this.debug = configuration.getDebug();
    152
    153
    154         //
    155         // Configure our class loader's classpath, if it is of
    156         // a configurable type.  We can't reconfigure it,
    157         // unfortunately, due to limitations in URLClassLoader.
    158
    159         if (!this.configured && this.classLoader instanceof CompilerClassLoader) {
    160             CompilerClassLoader loader = (CompilerClassLoader) this.classLoader;
    161
    162             Iterator iterator = configuration.getClasspath().iterator();
    163             while (iterator.hasNext()) {
    164                 try {
    165                     this.configured = true;
    166                     loader.addPath((String) iterator.next());
    167                 } catch (MalformedURLException e) {
    168                     throw new ConfigurationException(e);
    169                 }
    170             }
    171         }
    172     }
    173
    174
    175     /***
    176      * Returns the CompileUnit that roots our AST.
    177      */
    178
    179     public CompileUnit getAST() {
    180         return this.ast;
    181     }
    182
    183
    184     /***
    185      * Get the GroovyClasses generated by compile().
    186      */
    187
    188     public List getClasses() {
    189         return classes;
    190     }
    191
    192
    193     /***
    194      * Convenience routine to get the first ClassNode, for
    195      * when you are sure there is only one.
    196      */
    197
    198     public ClassNode getFirstClassNode() {
    199         return (ClassNode) ((ModuleNode) this.ast.getModules().get(0)).getClasses().get(0);
    200     }
    201
    202
    203     /***
    204      * Convenience routine to get the named ClassNode.
    205      */
    206
    207     public ClassNode getClassNode(final String name) {
    208         final ClassNode[] result = new ClassNode[]{null};
    209         LoopBodyForPrimaryClassNodeOperations handler = new LoopBodyForPrimaryClassNodeOperations() {
    210             public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
    211                 if (classNode.getName().equals(name)) {
    212                     result[0] = classNode;
    213                 }
    214             }
    215         };
    216
    217         try {
    218             applyToPrimaryClassNodes(handler);
    219         } catch (CompilationFailedException e) {
    220             if (debug) e.printStackTrace();
    221         }
    222         return result[0];
    223     }
    224
    225
    226
    227
    228
    229
    230     //---------------------------------------------------------------------------
    231     // SOURCE CREATION
    232
    233     /***
    234      * Adds a set of file paths to the unit.
    235      */
    236
    237     public void addSources(String[] paths) {
    238         for (int i = 0; i < paths.length; i++) {
    239             File file = new File(paths[i]);
    240             addSource(file);
    241         }
    242     }
    243
    244
    245     /***
    246      * Adds a set of source files to the unit.
    247      */
    248
    249     public void addSources(File[] files) {
    250         for (int i = 0; i < files.length; i++) {
    251             addSource(files[i]);
    252         }
    253     }
    254
    255
    256     /***
    257      * Adds a source file to the unit.
    258      */
    259
    260     public SourceUnit addSource(File file) {
    261         return addSource(new SourceUnit(file, configuration, classLoader));
    262     }
    263
    264
    265     /***
    266      * Adds a source file to the unit.
    267      */
    268
    269     public SourceUnit addSource(URL url) {
    270         return addSource(new SourceUnit(url, configuration, classLoader));
    271     }
    272
    273
    274     /***
    275      * Adds a InputStream source to the unit.
    276      */
    277
    278     public SourceUnit addSource(String name, InputStream stream) {
    279         ReaderSource source = new InputStreamReaderSource(stream, configuration);
    280         return addSource(new SourceUnit(name, source, configuration, classLoader));
    281     }
    282
    283
    284     /***
    285      * Adds a SourceUnit to the unit.
    286      */
    287
    288     public SourceUnit addSource(SourceUnit source) {
    289         String name = source.getName();
    290
    291         source.setClassLoader(this.classLoader);
    292
    293         names.add(name);
    294         sources.put(name, source);
    295
    296         return source;
    297     }
    298
    299
    300     /***
    301      * Returns an iterator on the unit's SourceUnits.
    302      */
    303
    304     public Iterator iterator() {
    305         return new Iterator() {
    306             Iterator nameIterator = names.iterator();
    307
    308             public boolean hasNext() {
    309                 return nameIterator.hasNext();
    310             }
    311
    312             public Object next() {
    313                 String name = (String) nameIterator.next();
    314                 return sources.get(name);
    315             }
    316
    317             public void remove() {
    318                 throw new UnsupportedOperationException();
    319             }
    320         };
    321     }
    322
    323
    324     /***
    325      * Adds a ClassNode directly to the unit (ie. without source).
    326      * Used primarily for testing support.
    327      */
    328
    329     public void addClassNode(ClassNode node) {
    330         ModuleNode module = new ModuleNode(this.ast);
    331         this.ast.addModule(module);
    332         module.addClass(node);
    333     }
    334
    335
    336
    337
    338     //---------------------------------------------------------------------------
    339     // EXTERNAL CALLBACKS
    340
    341     /***
    342      * A callback interface you can use to "accompany" the classgen()
    343      * code as it traverses the ClassNode tree.  You will be called-back
    344      * for each primary and inner class.  Use setClassgenCallback() before
    345      * running compile() to set your callback.
    346      */
    347
    348     public static abstract class ClassgenCallback {
    349         public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException;
    350     }
    351
    352
    353     /***
    354      * Sets a ClassgenCallback.  You can have only one, and setting
    355      * it to null removes any existing setting.
    356      */
    357
    358     public void setClassgenCallback(ClassgenCallback visitor) {
    359         this.classgenCallback = visitor;
    360     }
    361
    362
    363     /***
    364      * A callback interface you can use to get a callback after every
    365      * unit of the compile process.  You will be called-back with a
    366      * ProcessingUnit and a phase indicator.  Use setProgressCallback()
    367      * before running compile() to set your callback.
    368      */
    369
    370     public static abstract class ProgressCallback {
    371         public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException;
    372     }
    373
    374
    375     /***
    376      * Sets a ProgressCallback.  You can have only one, and setting
    377      * it to null removes any existing setting.
    378      */
    379
    380     public void setProgressCallback(ProgressCallback callback) {
    381         this.progressCallback = callback;
    382     }
    383
    384
    385
    386
    387     //---------------------------------------------------------------------------
    388     // ACTIONS
    389
    390
    391     /***
    392      * Synonym for compile(Phases.ALL).
    393      */
    394
    395     public void compile() throws CompilationFailedException {
    396         compile(Phases.ALL);
    397     }
    398
    399
    400     /***
    401      * Compiles the compilation unit from sources.
    402      */
    403
    404     public void compile(int throughPhase) throws CompilationFailedException {
    405         //
    406         // To support delta compilations, we always restart
    407         // the compiler.  The individual passes are responsible
    408         // for not reprocessing old code.
    409
    410         gotoPhase(Phases.INITIALIZATION);
    411
    412         do {
    413             if (throughPhase < Phases.PARSING) {
    414                 break;
    415             }
    416
    417             gotoPhase(Phases.PARSING);
    418             parse();
    419
    420             if (throughPhase < Phases.CONVERSION) {
    421                 break;
    422             }
    423
    424             gotoPhase(Phases.CONVERSION);
    425             convert();
    426
    427             if (throughPhase < Phases.CLASS_GENERATION) {
    428                 break;
    429             }
    430
    431             gotoPhase(Phases.CLASS_GENERATION);
    432             classgen();
    433
    434             if (throughPhase < Phases.OUTPUT) {
    435                 break;
    436             }
    437
    438             gotoPhase(Phases.OUTPUT);
    439             output();
    440
    441             if (throughPhase < Phases.FINALIZATION) {
    442                 break;
    443             }
    444
    445             gotoPhase(Phases.FINALIZATION);
    446
    447         } while (false);
    448
    449     }
    450
    451
    452     /***
    453      * Parses all sources.
    454      */
    455
    456     public void parse() throws CompilationFailedException {
    457         if (this.phase != Phases.PARSING) {
    458             throw new GroovyBugError("CompilationUnit not read for parse()");
    459         }
    460
    461         applyToSourceUnits(parse);
    462
    463         completePhase();
    464         applyToSourceUnits(mark);
    465     }
    466
    467
    468     /***
    469      * Runs parse() on a single SourceUnit.
    470      */
    471
    472     private LoopBodyForSourceUnitOperations parse = new LoopBodyForSourceUnitOperations() {
    473         public void call(SourceUnit source) throws CompilationFailedException {
    474             source.parse();
    475
    476             if (CompilationUnit.this.progressCallback != null) {
    477                 CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
    478             }
    479         }
    480     };
    481
    482
    483     /***
    484      * Builds ASTs for all parsed sources.
    485      */
    486
    487     public void convert() throws CompilationFailedException {
    488         if (this.phase != Phases.CONVERSION) {
    489             throw new GroovyBugError("CompilationUnit not ready for convert()");
    490         }
    491
    492         applyToSourceUnits(convert);
    493
    494         completePhase();
    495         applyToSourceUnits(mark);
    496     }
    497
    498
    499     /***
    500      * Runs convert() on a single SourceUnit.
    501      */
    502
    503     private LoopBodyForSourceUnitOperations convert = new LoopBodyForSourceUnitOperations() {
    504         public void call(SourceUnit source) throws CompilationFailedException {
    505             source.convert();
    506             CompilationUnit.this.ast.addModule(source.getAST());
    507
    508             if (CompilationUnit.this.progressCallback != null) {
    509                 CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
    510             }
    511         }
    512     };
    513
    514
    515     /***
    516      * Expands and canonicalizes the ASTs generated during
    517      * parsing and conversion, then generates classes.
    518      */
    519
    520     public void classgen() throws CompilationFailedException {
    521         if (this.phase != Phases.CLASS_GENERATION) {
    522             throw new GroovyBugError("CompilationUnit not ready for classgen()");
    523         }
    524
    525         applyToPrimaryClassNodes(classgen);
    526
    527         completePhase();
    528         applyToSourceUnits(mark);
    529
    530
    531         //
    532         // Callback progress, if necessary
    533
    534         if (this.progressCallback != null) {
    535             this.progressCallback.call(this, CompilationUnit.this.phase);
    536         }
    537
    538     }
    539
    540
    541     /***
    542      * Runs classgen() on a single ClassNode.
    543      */
    544
    545     private LoopBodyForPrimaryClassNodeOperations classgen = new LoopBodyForPrimaryClassNodeOperations() {
    546         public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
    547             //
    548             // Run the Verifier on the outer class
    549
    550             verifier.visitClass(classNode);
    551
    552
    553             //
    554             // Prep the generator machinery
    555
    556             ClassVisitor visitor = createClassVisitor();
    557
    558             String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
    559             ClassGenerator generator = new AsmClassGenerator2(context, visitor, classLoader, sourceName);
    560
    561             //
    562             // Run the generation and create the class (if required)
    563
    564             generator.visitClass(classNode);
    565             completionVerifier.visitClass(classNode);
    566
    567             if (!debug) {
    568                 byte[] bytes = ((ClassWriter) visitor).toByteArray();
    569                 /* this. */classes.add(new GroovyClass(classNode.getName(), bytes));
    570             }
    571
    572
    573
    574
    575             //
    576             // Handle any callback that's been set
    577
    578             if (CompilationUnit.this.classgenCallback != null) {
    579                 if (debug) {
    580                     try {
    581                         classgenCallback.call(visitor, classNode);
    582                     } catch (Throwable t) {
    583                         output.println("Classgen callback threw: " + t);
    584                         t.printStackTrace(output);
    585                     }
    586                 } else {
    587                     classgenCallback.call(visitor, classNode);
    588                 }
    589             }
    590
    591
    592             //
    593             // Recurse for inner classes
    594
    595             LinkedList innerClasses = generator.getInnerClasses();
    596             while (!innerClasses.isEmpty()) {
    597                 classgen.call(source, context, (ClassNode) innerClasses.removeFirst());
    598             }
    599
    600         }
    601
    602     };
    603
    604     protected ClassVisitor createClassVisitor() {
    605         /*** avoid runtime dependency on asm util
    606          ClassVisitor visitor;
    607          if( debug )
    608          {
    609          visitor = new DumpClassVisitor(output);
    610          }
    611          else
    612
    613          {
    614          visitor = new ClassWriter(true);
    615          }
    616          return visitor;
    617          */
    618         return new ClassWriter(true);
    619     }
    620
    621
    622     /***
    623      * Outputs the generated class files to permanent storage.
    624      */
    625
    626     public void output() throws CompilationFailedException {
    627         if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
    628             throw new GroovyBugError("CompilationUnit not ready for output()");
    629         }
    630
    631         boolean failures = false;
    632
    633         Iterator iterator = this.classes.iterator();
    634         while (iterator.hasNext()) {
    635             //
    636             // Get the class and calculate its filesystem name
    637
    638             GroovyClass gclass = (GroovyClass) iterator.next();
    639             String name = gclass.getName().replace('.', File.separatorChar) + ".class";
    640             File path = new File(configuration.getTargetDirectory(), name);
    641
    642             //
    643             // Ensure the path is ready for the file
    644
    645             File directory = path.getParentFile();
    646             if (directory != null && !directory.exists()) {
    647                 directory.mkdirs();
    648             }
    649
    650             //
    651             // Create the file and write out the data
    652
    653             byte[] bytes = gclass.getBytes();
    654
    655             FileOutputStream stream = null;
    656             try {
    657                 stream = new FileOutputStream(path);
    658                 stream.write(bytes, 0, bytes.length);
    659             } catch (IOException e) {
    660                 addError(Message.create(e.getMessage()));
    661                 failures = true;
    662             } finally {
    663                 if (stream != null) {
    664                     try {
    665                         stream.close();
    666                     } catch (Exception e) {
    667                     }
    668                 }
    669             }
    670         }
    671
    672         if (failures) {
    673             fail();
    674         }
    675
    676         completePhase();
    677         applyToSourceUnits(mark);
    678
    679
    680         //
    681         // Callback progress, if necessary
    682
    683         if (CompilationUnit.this.progressCallback != null) {
    684             CompilationUnit.this.progressCallback.call(this, this.phase);
    685         }
    686     }
    687
    688
    689     /***
    690      * Returns true if there are any errors pending.
    691      */
    692
    693     public boolean hasErrors() {
    694         boolean hasErrors = false;
    695
    696         Iterator keys = names.iterator();
    697         while (keys.hasNext()) {
    698             String name = (String) keys.next();
    699             SourceUnit source = (SourceUnit) sources.get(name);
    700
    701             if (source.hasErrors()) {
    702                 hasErrors = true;
    703                 break;
    704             }
    705         }
    706
    707         return hasErrors || super.hasErrors();
    708     }
    709
    710
    711
    712
    713     //---------------------------------------------------------------------------
    714     // PHASE HANDLING
    715
    716
    717     /***
    718      * Updates the phase marker on all sources.
    719      */
    720
    721     protected void mark() throws CompilationFailedException {
    722         applyToSourceUnits(mark);
    723     }
    724
    725
    726     /***
    727      * Marks a single SourceUnit with the current phase,
    728      * if it isn't already there yet.
    729      */
    730
    731     private LoopBodyForSourceUnitOperations mark = new LoopBodyForSourceUnitOperations() {
    732         public void call(SourceUnit source) throws CompilationFailedException {
    733             if (source.phase < phase) {
    734                 source.gotoPhase(phase);
    735             }
    736
    737             if (source.phase == phase && phaseComplete && !source.phaseComplete) {
    738                 source.completePhase();
    739             }
    740         }
    741     };
    742
    743
    744
    745
    746     //---------------------------------------------------------------------------
    747     // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
    748
    749     /***
    750      * An callback interface for use in the applyToSourceUnits loop driver.
    751      */
    752
    753     public abstract class LoopBodyForSourceUnitOperations {
    754         public abstract void call(SourceUnit source) throws CompilationFailedException;
    755     }
    756
    757
    758     /***
    759      * A loop driver for applying operations to all SourceUnits.
    760      * Automatically skips units that have already been processed
    761      * through the current phase.
    762      */
    763
    764     public void applyToSourceUnits(LoopBodyForSourceUnitOperations body) throws CompilationFailedException {
    765         boolean failures = false;
    766
    767         Iterator keys = names.iterator();
    768         while (keys.hasNext()) {
    769             String name = (String) keys.next();
    770             SourceUnit source = (SourceUnit) sources.get(name);
    771             if (source.phase <= phase) {
    772                 try {
    773                     body.call(source);
    774                 } catch (CompilationFailedException e) {
    775                     throw e;
    776                 } catch (Exception e) {
    777                     throw new GroovyBugError(e);
    778                 }
    779             }
    780         }
    781
    782         if (failures) {
    783             fail();
    784         }
    785     }
    786
    787
    788
    789
    790     //---------------------------------------------------------------------------
    791     // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS
    792
    793
    794     /***
    795      * An callback interface for use in the applyToSourceUnits loop driver.
    796      */
    797
    798     public abstract class LoopBodyForPrimaryClassNodeOperations {
    799         public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
    800     }
    801
    802
    803     /***
    804      * A loop driver for applying operations to all primary ClassNodes in
    805      * our AST.  Automatically skips units that have already been processed
    806      * through the current phase.
    807      */
    808
    809     public void applyToPrimaryClassNodes(LoopBodyForPrimaryClassNodeOperations body) throws CompilationFailedException {
    810         boolean failures = false;
    811
    812         Iterator modules = this.ast.getModules().iterator();
    813         while (modules.hasNext()) {
    814             ModuleNode module = (ModuleNode) modules.next();
    815
    816             try {
    817                 Iterator classNodes = module.getClasses().iterator();
    818                 while (classNodes.hasNext()) {
    819                     ClassNode classNode = (ClassNode) classNodes.next();
    820                     SourceUnit context = module.getContext();
    821                     if (context == null || context.phase <= phase) {
    822                         body.call(module.getContext(), new GeneratorContext(this.ast), classNode);
    823                     }
    824                 }
    825             } catch (CompilationFailedException e) {
    826                 failures = true;
    827                 addError(new ExceptionMessage(e));
    828             } catch (Exception e) {
    829                 failures = true;
    830 //                String msg = e.getMessage();
    831 //                if (e instanceof RuntimeParserException) {
    832 //                    RuntimeParserException rpe = (RuntimeParserException) e;
    833 //                    ASTNode node = rpe.getNode();
    834 //                    msg += ". The probable error location: [" + node.getLineNumber() + ":" + node.getColumnNumber() + "]";
    835 //                }
    836                 addError(new ExceptionMessage(e));
    837             }
    838         }
    839
    840         if (failures) {
    841             fail();
    842         }
    843     }
    844
    845
    846
    847
    848     //---------------------------------------------------------------------------
    849     // OUTPUT
    850
    851
    852     /***
    853      * Writes error messages to the specified PrintWriter.
    854      */
    855
    856     public void write(PrintWriter writer, Janitor janitor) {
    857         super.write(writer, janitor);
    858
    859         Iterator keys = names.iterator();
    860         while (keys.hasNext()) {
    861             String name = (String) keys.next();
    862             SourceUnit source = (SourceUnit) sources.get(name);
    863
    864             if (source.hasErrors()) {
    865                 source.write(writer, janitor);
    866             }
    867         }
    868
    869     }
    870
    871
    872 }
    873
    874
    875
    876