Clover coverage report - groovy - 1.0-beta-8
Coverage timestamp: Fri Dec 17 2004 14:55:55 GMT
file stats: LOC: 877   Methods: 39
NCLOC: 388   Classes: 5
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
CompilationUnit.java 0% 0% 0% 0%
coverage
 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  0
     public CompilationUnit() {
 104  0
         this(null, null, null);
 105   
     }
 106   
 
 107   
 
 108   
     /**
 109   
      * Initializes the CompilationUnit with defaults except for class loader.
 110   
      */
 111  0
     public CompilationUnit(ClassLoader loader) {
 112  0
         this(null, null, loader);
 113   
     }
 114   
 
 115   
 
 116   
     /**
 117   
      * Initializes the CompilationUnit with no security considerations.
 118   
      */
 119  0
     public CompilationUnit(CompilerConfiguration configuration) {
 120  0
         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  0
     public CompilationUnit(CompilerConfiguration configuration, CodeSource security, ClassLoader loader) {
 130  0
         super(configuration, loader);
 131   
 
 132  0
         this.names = new ArrayList();
 133  0
         this.sources = new HashMap();
 134   
 
 135  0
         this.ast = new CompileUnit(this.classLoader, security, this.configuration);
 136  0
         this.classes = new ArrayList();
 137   
 
 138  0
         this.verifier = new Verifier();
 139  0
         this.completionVerifier = new ClassCompletionVerifier();
 140   
 
 141  0
         this.classgenCallback = null;
 142   
     }
 143   
 
 144   
 
 145   
     /**
 146   
      * Reconfigures the CompilationUnit.
 147   
      */
 148   
 
 149  0
     public void configure(CompilerConfiguration configuration) {
 150  0
         super.configure(configuration);
 151  0
         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  0
         if (!this.configured && this.classLoader instanceof CompilerClassLoader) {
 160  0
             CompilerClassLoader loader = (CompilerClassLoader) this.classLoader;
 161   
 
 162  0
             Iterator iterator = configuration.getClasspath().iterator();
 163  0
             while (iterator.hasNext()) {
 164  0
                 try {
 165  0
                     this.configured = true;
 166  0
                     loader.addPath((String) iterator.next());
 167   
                 } catch (MalformedURLException e) {
 168  0
                     throw new ConfigurationException(e);
 169   
                 }
 170   
             }
 171   
         }
 172   
     }
 173   
 
 174   
 
 175   
     /**
 176   
      * Returns the CompileUnit that roots our AST.
 177   
      */
 178   
 
 179  0
     public CompileUnit getAST() {
 180  0
         return this.ast;
 181   
     }
 182   
 
 183   
 
 184   
     /**
 185   
      * Get the GroovyClasses generated by compile().
 186   
      */
 187   
 
 188  0
     public List getClasses() {
 189  0
         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  0
     public ClassNode getFirstClassNode() {
 199  0
         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  0
     public ClassNode getClassNode(final String name) {
 208  0
         final ClassNode[] result = new ClassNode[]{null};
 209  0
         LoopBodyForPrimaryClassNodeOperations handler = new LoopBodyForPrimaryClassNodeOperations() {
 210  0
             public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
 211  0
                 if (classNode.getName().equals(name)) {
 212  0
                     result[0] = classNode;
 213   
                 }
 214   
             }
 215   
         };
 216   
 
 217  0
         try {
 218  0
             applyToPrimaryClassNodes(handler);
 219   
         } catch (CompilationFailedException e) {
 220  0
             if (debug) e.printStackTrace();
 221   
         }
 222  0
         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  0
     public void addSources(String[] paths) {
 238  0
         for (int i = 0; i < paths.length; i++) {
 239  0
             File file = new File(paths[i]);
 240  0
             addSource(file);
 241   
         }
 242   
     }
 243   
 
 244   
 
 245   
     /**
 246   
      * Adds a set of source files to the unit.
 247   
      */
 248   
 
 249  0
     public void addSources(File[] files) {
 250  0
         for (int i = 0; i < files.length; i++) {
 251  0
             addSource(files[i]);
 252   
         }
 253   
     }
 254   
 
 255   
 
 256   
     /**
 257   
      * Adds a source file to the unit.
 258   
      */
 259   
 
 260  0
     public SourceUnit addSource(File file) {
 261  0
         return addSource(new SourceUnit(file, configuration, classLoader));
 262   
     }
 263   
 
 264   
 
 265   
     /**
 266   
      * Adds a source file to the unit.
 267   
      */
 268   
 
 269  0
     public SourceUnit addSource(URL url) {
 270  0
         return addSource(new SourceUnit(url, configuration, classLoader));
 271   
     }
 272   
 
 273   
 
 274   
     /**
 275   
      * Adds a InputStream source to the unit.
 276   
      */
 277   
 
 278  0
     public SourceUnit addSource(String name, InputStream stream) {
 279  0
         ReaderSource source = new InputStreamReaderSource(stream, configuration);
 280  0
         return addSource(new SourceUnit(name, source, configuration, classLoader));
 281   
     }
 282   
 
 283   
 
 284   
     /**
 285   
      * Adds a SourceUnit to the unit.
 286   
      */
 287   
 
 288  0
     public SourceUnit addSource(SourceUnit source) {
 289  0
         String name = source.getName();
 290   
 
 291  0
         source.setClassLoader(this.classLoader);
 292   
 
 293  0
         names.add(name);
 294  0
         sources.put(name, source);
 295   
 
 296  0
         return source;
 297   
     }
 298   
 
 299   
 
 300   
     /**
 301   
      * Returns an iterator on the unit's SourceUnits.
 302   
      */
 303   
 
 304  0
     public Iterator iterator() {
 305  0
         return new Iterator() {
 306   
             Iterator nameIterator = names.iterator();
 307   
 
 308  0
             public boolean hasNext() {
 309  0
                 return nameIterator.hasNext();
 310   
             }
 311   
 
 312  0
             public Object next() {
 313  0
                 String name = (String) nameIterator.next();
 314  0
                 return sources.get(name);
 315   
             }
 316   
 
 317  0
             public void remove() {
 318  0
                 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  0
     public void addClassNode(ClassNode node) {
 330  0
         ModuleNode module = new ModuleNode(this.ast);
 331  0
         this.ast.addModule(module);
 332  0
         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  0
     public void setClassgenCallback(ClassgenCallback visitor) {
 359  0
         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  0
     public void setProgressCallback(ProgressCallback callback) {
 381  0
         this.progressCallback = callback;
 382   
     }
 383   
 
 384   
 
 385   
 
 386   
 
 387   
     //---------------------------------------------------------------------------
 388   
     // ACTIONS
 389   
 
 390   
 
 391   
     /**
 392   
      * Synonym for compile(Phases.ALL).
 393   
      */
 394   
 
 395  0
     public void compile() throws CompilationFailedException {
 396  0
         compile(Phases.ALL);
 397   
     }
 398   
 
 399   
 
 400   
     /**
 401   
      * Compiles the compilation unit from sources.
 402   
      */
 403   
 
 404  0
     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  0
         gotoPhase(Phases.INITIALIZATION);
 411   
 
 412  0
         do {
 413  0
             if (throughPhase < Phases.PARSING) {
 414  0
                 break;
 415   
             }
 416   
 
 417  0
             gotoPhase(Phases.PARSING);
 418  0
             parse();
 419   
 
 420  0
             if (throughPhase < Phases.CONVERSION) {
 421  0
                 break;
 422   
             }
 423   
 
 424  0
             gotoPhase(Phases.CONVERSION);
 425  0
             convert();
 426   
 
 427  0
             if (throughPhase < Phases.CLASS_GENERATION) {
 428  0
                 break;
 429   
             }
 430   
 
 431  0
             gotoPhase(Phases.CLASS_GENERATION);
 432  0
             classgen();
 433   
 
 434  0
             if (throughPhase < Phases.OUTPUT) {
 435  0
                 break;
 436   
             }
 437   
 
 438  0
             gotoPhase(Phases.OUTPUT);
 439  0
             output();
 440   
 
 441  0
             if (throughPhase < Phases.FINALIZATION) {
 442  0
                 break;
 443   
             }
 444   
 
 445  0
             gotoPhase(Phases.FINALIZATION);
 446   
 
 447   
         } while (false);
 448   
 
 449   
     }
 450   
 
 451   
 
 452   
     /**
 453   
      * Parses all sources.
 454   
      */
 455   
 
 456  0
     public void parse() throws CompilationFailedException {
 457  0
         if (this.phase != Phases.PARSING) {
 458  0
             throw new GroovyBugError("CompilationUnit not read for parse()");
 459   
         }
 460   
 
 461  0
         applyToSourceUnits(parse);
 462   
 
 463  0
         completePhase();
 464  0
         applyToSourceUnits(mark);
 465   
     }
 466   
 
 467   
 
 468   
     /**
 469   
      * Runs parse() on a single SourceUnit.
 470   
      */
 471   
 
 472   
     private LoopBodyForSourceUnitOperations parse = new LoopBodyForSourceUnitOperations() {
 473  0
         public void call(SourceUnit source) throws CompilationFailedException {
 474  0
             source.parse();
 475   
 
 476  0
             if (CompilationUnit.this.progressCallback != null) {
 477  0
                 CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
 478   
             }
 479   
         }
 480   
     };
 481   
 
 482   
 
 483   
     /**
 484   
      * Builds ASTs for all parsed sources.
 485   
      */
 486   
 
 487  0
     public void convert() throws CompilationFailedException {
 488  0
         if (this.phase != Phases.CONVERSION) {
 489  0
             throw new GroovyBugError("CompilationUnit not ready for convert()");
 490   
         }
 491   
 
 492  0
         applyToSourceUnits(convert);
 493   
 
 494  0
         completePhase();
 495  0
         applyToSourceUnits(mark);
 496   
     }
 497   
 
 498   
 
 499   
     /**
 500   
      * Runs convert() on a single SourceUnit.
 501   
      */
 502   
 
 503   
     private LoopBodyForSourceUnitOperations convert = new LoopBodyForSourceUnitOperations() {
 504  0
         public void call(SourceUnit source) throws CompilationFailedException {
 505  0
             source.convert();
 506  0
             CompilationUnit.this.ast.addModule(source.getAST());
 507   
 
 508  0
             if (CompilationUnit.this.progressCallback != null) {
 509  0
                 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  0
     public void classgen() throws CompilationFailedException {
 521  0
         if (this.phase != Phases.CLASS_GENERATION) {
 522  0
             throw new GroovyBugError("CompilationUnit not ready for classgen()");
 523   
         }
 524   
 
 525  0
         applyToPrimaryClassNodes(classgen);
 526   
 
 527  0
         completePhase();
 528  0
         applyToSourceUnits(mark);
 529   
 
 530   
 
 531   
         //
 532   
         // Callback progress, if necessary
 533   
 
 534  0
         if (this.progressCallback != null) {
 535  0
             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  0
         public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
 547   
             //
 548   
             // Run the Verifier on the outer class
 549   
 
 550  0
             verifier.visitClass(classNode);
 551   
 
 552   
 
 553   
             //
 554   
             // Prep the generator machinery
 555   
 
 556  0
             ClassVisitor visitor = createClassVisitor();
 557   
 
 558  0
             String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
 559  0
             ClassGenerator generator = new AsmClassGenerator2(context, visitor, classLoader, sourceName);
 560   
 
 561   
             //
 562   
             // Run the generation and create the class (if required)
 563   
 
 564  0
             generator.visitClass(classNode);
 565  0
             completionVerifier.visitClass(classNode);
 566   
 
 567  0
             if (!debug) {
 568  0
                 byte[] bytes = ((ClassWriter) visitor).toByteArray();
 569  0
                 /* this. */classes.add(new GroovyClass(classNode.getName(), bytes));
 570   
             }
 571   
 
 572   
 
 573   
 
 574   
 
 575   
             //
 576   
             // Handle any callback that's been set
 577   
 
 578  0
             if (CompilationUnit.this.classgenCallback != null) {
 579  0
                 if (debug) {
 580  0
                     try {
 581  0
                         classgenCallback.call(visitor, classNode);
 582   
                     } catch (Throwable t) {
 583  0
                         output.println("Classgen callback threw: " + t);
 584  0
                         t.printStackTrace(output);
 585   
                     }
 586   
                 } else {
 587  0
                     classgenCallback.call(visitor, classNode);
 588   
                 }
 589   
             }
 590   
 
 591   
 
 592   
             //
 593   
             // Recurse for inner classes
 594   
 
 595  0
             LinkedList innerClasses = generator.getInnerClasses();
 596  0
             while (!innerClasses.isEmpty()) {
 597  0
                 classgen.call(source, context, (ClassNode) innerClasses.removeFirst());
 598   
             }
 599   
 
 600   
         }
 601   
 
 602   
     };
 603   
 
 604  0
     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  0
         return new ClassWriter(true);
 619   
     }
 620   
 
 621   
 
 622   
     /**
 623   
      * Outputs the generated class files to permanent storage.
 624   
      */
 625   
 
 626  0
     public void output() throws CompilationFailedException {
 627  0
         if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
 628  0
             throw new GroovyBugError("CompilationUnit not ready for output()");
 629   
         }
 630   
 
 631  0
         boolean failures = false;
 632   
 
 633  0
         Iterator iterator = this.classes.iterator();
 634  0
         while (iterator.hasNext()) {
 635   
             //
 636   
             // Get the class and calculate its filesystem name
 637   
 
 638  0
             GroovyClass gclass = (GroovyClass) iterator.next();
 639  0
             String name = gclass.getName().replace('.', File.separatorChar) + ".class";
 640  0
             File path = new File(configuration.getTargetDirectory(), name);
 641   
 
 642   
             //
 643   
             // Ensure the path is ready for the file
 644   
 
 645  0
             File directory = path.getParentFile();
 646  0
             if (directory != null && !directory.exists()) {
 647  0
                 directory.mkdirs();
 648   
             }
 649   
 
 650   
             //
 651   
             // Create the file and write out the data
 652   
 
 653  0
             byte[] bytes = gclass.getBytes();
 654   
 
 655  0
             FileOutputStream stream = null;
 656  0
             try {
 657  0
                 stream = new FileOutputStream(path);
 658  0
                 stream.write(bytes, 0, bytes.length);
 659   
             } catch (IOException e) {
 660  0
                 addError(Message.create(e.getMessage()));
 661  0
                 failures = true;
 662   
             } finally {
 663  0
                 if (stream != null) {
 664  0
                     try {
 665  0
                         stream.close();
 666   
                     } catch (Exception e) {
 667   
                     }
 668   
                 }
 669   
             }
 670   
         }
 671   
 
 672  0
         if (failures) {
 673  0
             fail();
 674   
         }
 675   
 
 676  0
         completePhase();
 677  0
         applyToSourceUnits(mark);
 678   
 
 679   
 
 680   
         //
 681   
         // Callback progress, if necessary
 682   
 
 683  0
         if (CompilationUnit.this.progressCallback != null) {
 684  0
             CompilationUnit.this.progressCallback.call(this, this.phase);
 685   
         }
 686   
     }
 687   
 
 688   
 
 689   
     /**
 690   
      * Returns true if there are any errors pending.
 691   
      */
 692   
 
 693  0
     public boolean hasErrors() {
 694  0
         boolean hasErrors = false;
 695   
 
 696  0
         Iterator keys = names.iterator();
 697  0
         while (keys.hasNext()) {
 698  0
             String name = (String) keys.next();
 699  0
             SourceUnit source = (SourceUnit) sources.get(name);
 700   
 
 701  0
             if (source.hasErrors()) {
 702  0
                 hasErrors = true;
 703  0
                 break;
 704   
             }
 705   
         }
 706   
 
 707  0
         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  0
     protected void mark() throws CompilationFailedException {
 722  0
         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  0
         public void call(SourceUnit source) throws CompilationFailedException {
 733  0
             if (source.phase < phase) {
 734  0
                 source.gotoPhase(phase);
 735   
             }
 736   
 
 737  0
             if (source.phase == phase && phaseComplete && !source.phaseComplete) {
 738  0
                 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  0
     public void applyToSourceUnits(LoopBodyForSourceUnitOperations body) throws CompilationFailedException {
 765  0
         boolean failures = false;
 766   
 
 767  0
         Iterator keys = names.iterator();
 768  0
         while (keys.hasNext()) {
 769  0
             String name = (String) keys.next();
 770  0
             SourceUnit source = (SourceUnit) sources.get(name);
 771  0
             if (source.phase <= phase) {
 772  0
                 try {
 773  0
                     body.call(source);
 774   
                 } catch (CompilationFailedException e) {
 775  0
                     throw e;
 776   
                 } catch (Exception e) {
 777  0
                     throw new GroovyBugError(e);
 778   
                 }
 779   
             }
 780   
         }
 781   
 
 782  0
         if (failures) {
 783  0
             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  0
     public void applyToPrimaryClassNodes(LoopBodyForPrimaryClassNodeOperations body) throws CompilationFailedException {
 810  0
         boolean failures = false;
 811   
 
 812  0
         Iterator modules = this.ast.getModules().iterator();
 813  0
         while (modules.hasNext()) {
 814  0
             ModuleNode module = (ModuleNode) modules.next();
 815   
 
 816  0
             try {
 817  0
                 Iterator classNodes = module.getClasses().iterator();
 818  0
                 while (classNodes.hasNext()) {
 819  0
                     ClassNode classNode = (ClassNode) classNodes.next();
 820  0
                     SourceUnit context = module.getContext();
 821  0
                     if (context == null || context.phase <= phase) {
 822  0
                         body.call(module.getContext(), new GeneratorContext(this.ast), classNode);
 823   
                     }
 824   
                 }
 825   
             } catch (CompilationFailedException e) {
 826  0
                 failures = true;
 827  0
                 addError(new ExceptionMessage(e));
 828   
             } catch (Exception e) {
 829  0
                 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  0
                 addError(new ExceptionMessage(e));
 837   
             }
 838   
         }
 839   
 
 840  0
         if (failures) {
 841  0
             fail();
 842   
         }
 843   
     }
 844   
 
 845   
 
 846   
 
 847   
 
 848   
     //---------------------------------------------------------------------------
 849   
     // OUTPUT
 850   
 
 851   
 
 852   
     /**
 853   
      * Writes error messages to the specified PrintWriter.
 854   
      */
 855   
 
 856  0
     public void write(PrintWriter writer, Janitor janitor) {
 857  0
         super.write(writer, janitor);
 858   
 
 859  0
         Iterator keys = names.iterator();
 860  0
         while (keys.hasNext()) {
 861  0
             String name = (String) keys.next();
 862  0
             SourceUnit source = (SourceUnit) sources.get(name);
 863   
 
 864  0
             if (source.hasErrors()) {
 865  0
                 source.write(writer, janitor);
 866   
             }
 867   
         }
 868   
 
 869   
     }
 870   
 
 871   
 
 872   
 }
 873   
 
 874   
 
 875   
 
 876   
 
 877