001 /*
002 $Id: CompilationUnit.java,v 1.24 2005/06/27 17:34:03 fraz Exp $
003
004
005 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
006
007
008 Redistribution and use of this software and associated documentation
009 ("Software"), with or without modification, are permitted provided
010 that the following conditions are met:
011
012 1. Redistributions of source code must retain copyright
013 statements and notices. Redistributions must also contain a
014 copy of this document.
015
016
017 2. Redistributions in binary form must reproduce the
018 above copyright notice, this list of conditions and the
019 following disclaimer in the documentation and/or other
020 materials provided with the distribution.
021
022
023 3. The name "groovy" must not be used to endorse or promote
024 products derived from this Software without prior written
025 permission of The Codehaus. For written permission,
026 please contact info@codehaus.org.
027
028
029 4. Products derived from this Software may not be called "groovy"
030 nor may "groovy" appear in their names without prior written
031 permission of The Codehaus. "groovy" is a registered
032 trademark of The Codehaus.
033
034
035 5. Due credit should be given to The Codehaus -
036 http://groovy.codehaus.org/
037
038
039 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
040 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
041 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
042 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
043 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
044 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
045 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
046 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
047 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
048 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
049 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
050 OF THE POSSIBILITY OF SUCH DAMAGE.
051 */
052
053
054 package org.codehaus.groovy.control;
055
056 import java.io.File;
057 import java.io.FileOutputStream;
058 import java.io.IOException;
059 import java.io.InputStream;
060 import java.net.URL;
061 import java.security.CodeSource;
062 import java.util.ArrayList;
063 import java.util.HashMap;
064 import java.util.Iterator;
065 import java.util.LinkedList;
066 import java.util.List;
067
068 import org.codehaus.groovy.GroovyBugError;
069 import org.codehaus.groovy.ast.ASTNode;
070 import org.codehaus.groovy.ast.ClassNode;
071 import org.codehaus.groovy.ast.CompileUnit;
072 import org.codehaus.groovy.ast.ModuleNode;
073 import org.codehaus.groovy.classgen.AsmClassGenerator;
074 import org.codehaus.groovy.classgen.ClassCompletionVerifier;
075 import org.codehaus.groovy.classgen.ClassGenerator;
076 import org.codehaus.groovy.classgen.GeneratorContext;
077 import org.codehaus.groovy.classgen.JSRVariableScopeCodeVisitor;
078 import org.codehaus.groovy.classgen.Verifier;
079 import org.codehaus.groovy.control.io.InputStreamReaderSource;
080 import org.codehaus.groovy.control.io.ReaderSource;
081 import org.codehaus.groovy.control.messages.ExceptionMessage;
082 import org.codehaus.groovy.control.messages.Message;
083 import org.codehaus.groovy.syntax.SyntaxException;
084 import org.codehaus.groovy.tools.GroovyClass;
085 import org.objectweb.asm.ClassVisitor;
086 import org.objectweb.asm.ClassWriter;
087
088 import groovy.lang.GroovyClassLoader;
089 import groovy.lang.GroovyRuntimeException;
090
091 /**
092 * Collects all compilation data as it is generated by the compiler system.
093 * Allows additional source units to be added and compilation run again (to
094 * affect only the deltas).
095 *
096 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
097 * @version $Id: CompilationUnit.java,v 1.24 2005/06/27 17:34:03 fraz Exp $
098 */
099
100 public class CompilationUnit extends ProcessingUnit {
101
102
103 //---------------------------------------------------------------------------
104 // CONSTRUCTION AND SUCH
105
106
107 protected HashMap sources; // The SourceUnits from which this unit is built
108 protected ArrayList names; // Names for each SourceUnit in sources.
109
110
111 protected CompileUnit ast; // The overall AST for this CompilationUnit.
112 protected ArrayList classes; // The classes generated during classgen.
113
114
115 protected Verifier verifier; // For use by verify().
116
117
118 protected ClassCompletionVerifier completionVerifier; // for use by checkClassCompletion
119
120
121 protected boolean debug; // Controls behaviour of classgen() and other routines.
122 protected boolean configured; // Set true after the first configure() operation
123
124
125 protected ClassgenCallback classgenCallback; // A callback for use during classgen()
126 protected ProgressCallback progressCallback; // A callback for use during compile()
127
128
129
130 /**
131 * Initializes the CompilationUnit with defaults.
132 */
133 public CompilationUnit() {
134 this(null, null, null);
135 }
136
137
138
139 /**
140 * Initializes the CompilationUnit with defaults except for class loader.
141 */
142 public CompilationUnit(ClassLoader loader) {
143 this(null, null, loader);
144 }
145
146
147
148 /**
149 * Initializes the CompilationUnit with no security considerations.
150 */
151 public CompilationUnit(CompilerConfiguration configuration) {
152 this(configuration, null, null);
153 }
154
155 /**
156 * Initializes the CompilationUnit with a CodeSource for controlling
157 * security stuff and a class loader for loading classes.
158 */
159 public CompilationUnit(CompilerConfiguration configuration, CodeSource security, ClassLoader loader) {
160 super(configuration, loader, null);
161
162 this.names = new ArrayList();
163 this.sources = new HashMap();
164
165
166 this.ast = new CompileUnit(this.classLoader, security, this.configuration);
167 this.classes = new ArrayList();
168
169
170 this.verifier = new Verifier();
171 this.completionVerifier = new ClassCompletionVerifier();
172
173
174 this.classgenCallback = null;
175 }
176
177 /**
178 * Configures its debugging mode and classloader classpath from a given compiler configuration.
179 * This cannot be done more than once due to limitations in {@link java.net.URLClassLoader URLClassLoader}.
180 */
181 public void configure(CompilerConfiguration configuration) {
182 super.configure(configuration);
183 this.debug = configuration.getDebug();
184
185 if (!this.configured && this.classLoader instanceof GroovyClassLoader) {
186 appendCompilerConfigurationClasspathToClassLoader(configuration, (GroovyClassLoader) this.classLoader);
187 }
188
189 this.configured = true;
190 }
191
192 private void appendCompilerConfigurationClasspathToClassLoader(CompilerConfiguration configuration, GroovyClassLoader classLoader) {
193 for (Iterator iterator = configuration.getClasspath().iterator(); iterator.hasNext(); ) {
194 classLoader.addClasspath((String) iterator.next());
195 }
196 }
197
198 /**
199 * Returns the CompileUnit that roots our AST.
200 */
201 public CompileUnit getAST() {
202 return this.ast;
203 }
204
205
206 /**
207 * Get the GroovyClasses generated by compile().
208 */
209
210
211 public List getClasses() {
212 return classes;
213 }
214
215
216 /**
217 * Convenience routine to get the first ClassNode, for
218 * when you are sure there is only one.
219 */
220 public ClassNode getFirstClassNode() {
221 return (ClassNode) ((ModuleNode) this.ast.getModules().get(0)).getClasses().get(0);
222 }
223
224
225 /**
226 * Convenience routine to get the named ClassNode.
227 */
228 public ClassNode getClassNode(final String name) {
229 final ClassNode[] result = new ClassNode[]{null};
230 LoopBodyForPrimaryClassNodeOperations handler = new LoopBodyForPrimaryClassNodeOperations() {
231
232
233 public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
234
235
236 if (classNode.getName().equals(name)) {
237
238
239 result[0] = classNode;
240
241
242 }
243
244
245 }
246
247
248 };
249
250
251 try {
252 applyToPrimaryClassNodes(handler);
253 } catch (CompilationFailedException e) {
254 if (debug) e.printStackTrace();
255 }
256 return result[0];
257 }
258
259
260
261
262
263 //---------------------------------------------------------------------------
264 // SOURCE CREATION
265
266
267 /**
268 * Adds a set of file paths to the unit.
269 */
270 public void addSources(String[] paths) {
271 for (int i = 0; i < paths.length; i++) {
272 File file = new File(paths[i]);
273 addSource(file);
274 }
275 }
276
277
278 /**
279 * Adds a set of source files to the unit.
280 */
281 public void addSources(File[] files) {
282 for (int i = 0; i < files.length; i++) {
283 addSource(files[i]);
284 }
285 }
286
287
288 /**
289 * Adds a source file to the unit.
290 */
291 public SourceUnit addSource(File file) {
292 return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector()));
293 }
294
295
296 /**
297 * Adds a source file to the unit.
298 */
299 public SourceUnit addSource(URL url) {
300 return addSource(new SourceUnit(url, configuration, classLoader,getErrorCollector()));
301 }
302
303
304 /**
305 * Adds a InputStream source to the unit.
306 */
307 public SourceUnit addSource(String name, InputStream stream) {
308 ReaderSource source = new InputStreamReaderSource(stream, configuration);
309 return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector()));
310 }
311
312
313 /**
314 * Adds a SourceUnit to the unit.
315 */
316 public SourceUnit addSource(SourceUnit source) {
317 String name = source.getName();
318
319
320 source.setClassLoader(this.classLoader);
321
322
323 names.add(name);
324 sources.put(name, source);
325
326
327 return source;
328 }
329
330
331 /**
332 * Returns an iterator on the unit's SourceUnits.
333 */
334 public Iterator iterator() {
335 return new Iterator() {
336 Iterator nameIterator = names.iterator();
337
338
339 public boolean hasNext() {
340 return nameIterator.hasNext();
341 }
342
343
344 public Object next() {
345 String name = (String) nameIterator.next();
346 return sources.get(name);
347 }
348
349
350 public void remove() {
351 throw new UnsupportedOperationException();
352 }
353 };
354 }
355
356
357 /**
358 * Adds a ClassNode directly to the unit (ie. without source).
359 * Used primarily for testing support.
360 */
361 public void addClassNode(ClassNode node) {
362 ModuleNode module = new ModuleNode(this.ast);
363 this.ast.addModule(module);
364 module.addClass(node);
365 }
366
367
368
369
370
371 //---------------------------------------------------------------------------
372 // EXTERNAL CALLBACKS
373
374
375 /**
376 * A callback interface you can use to "accompany" the classgen()
377 * code as it traverses the ClassNode tree. You will be called-back
378 * for each primary and inner class. Use setClassgenCallback() before
379 * running compile() to set your callback.
380 */
381 public static abstract class ClassgenCallback {
382 public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException;
383 }
384
385
386 /**
387 * Sets a ClassgenCallback. You can have only one, and setting
388 * it to null removes any existing setting.
389 */
390 public void setClassgenCallback(ClassgenCallback visitor) {
391 this.classgenCallback = visitor;
392 }
393
394
395 /**
396 * A callback interface you can use to get a callback after every
397 * unit of the compile process. You will be called-back with a
398 * ProcessingUnit and a phase indicator. Use setProgressCallback()
399 * before running compile() to set your callback.
400 */
401 public static abstract class ProgressCallback {
402
403 public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException;
404 }
405
406 /**
407 * Sets a ProgressCallback. You can have only one, and setting
408 * it to null removes any existing setting.
409 */
410 public void setProgressCallback(ProgressCallback callback) {
411 this.progressCallback = callback;
412 }
413
414
415 //---------------------------------------------------------------------------
416 // ACTIONS
417
418
419 /**
420 * Synonym for compile(Phases.ALL).
421 */
422 public void compile() throws CompilationFailedException {
423 compile(Phases.ALL);
424 }
425
426
427 /**
428 * Compiles the compilation unit from sources.
429 */
430 public void compile(int throughPhase) throws CompilationFailedException {
431 //
432 // To support delta compilations, we always restart
433 // the compiler. The individual passes are responsible
434 // for not reprocessing old code.
435 gotoPhase(Phases.INITIALIZATION);
436
437
438 do {
439 if (throughPhase < Phases.PARSING) {
440 break;
441 }
442 gotoPhase(Phases.PARSING);
443 parse();
444
445
446 if (throughPhase < Phases.CONVERSION) {
447 break;
448 }
449
450
451 gotoPhase(Phases.CONVERSION);
452 convert();
453
454
455 if (throughPhase < Phases.CLASS_GENERATION) {
456 break;
457 }
458
459
460 gotoPhase(Phases.CLASS_GENERATION);
461 classgen();
462
463
464 if (throughPhase < Phases.OUTPUT) {
465 break;
466 }
467
468
469 gotoPhase(Phases.OUTPUT);
470 output();
471
472
473 if (throughPhase < Phases.FINALIZATION) {
474 break;
475 }
476
477
478 gotoPhase(Phases.FINALIZATION);
479 } while (false);
480 }
481
482
483
484 /**
485 * Parses all sources.
486 */
487 public void parse() throws CompilationFailedException {
488 if (this.phase != Phases.PARSING) {
489 throw new GroovyBugError("CompilationUnit not read for parse()");
490 }
491
492
493 applyToSourceUnits(parse);
494 completePhase();
495 applyToSourceUnits(mark);
496 }
497
498
499 /**
500 * Runs parse() on a single SourceUnit.
501 */
502 private LoopBodyForSourceUnitOperations parse = new LoopBodyForSourceUnitOperations() {
503 public void call(SourceUnit source) throws CompilationFailedException {
504 source.parse();
505
506
507 if (CompilationUnit.this.progressCallback != null) {
508 CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
509 }
510 }
511 };
512
513
514 /**
515 * Builds ASTs for all parsed sources.
516 */
517 public void convert() throws CompilationFailedException {
518 if (this.phase != Phases.CONVERSION) {
519 throw new GroovyBugError("CompilationUnit not ready for convert()");
520 }
521
522
523 applyToSourceUnits(convert);
524
525
526 completePhase();
527 applyToSourceUnits(mark);
528 }
529
530
531 /**
532 * Runs convert() on a single SourceUnit.
533 */
534 private LoopBodyForSourceUnitOperations convert = new LoopBodyForSourceUnitOperations() {
535 public void call(SourceUnit source) throws CompilationFailedException {
536 source.convert();
537 CompilationUnit.this.ast.addModule(source.getAST());
538
539
540 if (CompilationUnit.this.progressCallback != null) {
541 CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
542 }
543 }
544 };
545
546
547 /**
548 * Expands and canonicalizes the ASTs generated during
549 * parsing and conversion, then generates classes.
550 */
551 public void classgen() throws CompilationFailedException {
552 if (this.phase != Phases.CLASS_GENERATION) {
553 throw new GroovyBugError("CompilationUnit not ready for classgen()");
554 }
555
556 applyToPrimaryClassNodes(classgen);
557
558 completePhase();
559 applyToSourceUnits(mark);
560
561 //
562 // Callback progress, if necessary
563
564
565 if (this.progressCallback != null) {
566 this.progressCallback.call(this, CompilationUnit.this.phase);
567 }
568 }
569
570 /**
571 * Runs classgen() on a single ClassNode.
572 */
573 private LoopBodyForPrimaryClassNodeOperations classgen = new LoopBodyForPrimaryClassNodeOperations() {
574 public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
575 //
576 // Run the Verifier on the outer class
577 //
578 try {
579 verifier.visitClass(classNode);
580 } catch (GroovyRuntimeException rpe) {
581 ASTNode node = rpe.getNode();
582 getErrorCollector().addError(
583 new SyntaxException(rpe.getMessage(),null,node.getLineNumber(),node.getColumnNumber()),
584 source
585 );
586 }
587
588 //
589 // do scoping
590 //
591 if (source!=null && (!classNode.isSynthetic()) && (!"false".equals(System.getProperty("groovy.jsr.check")))) {
592 JSRVariableScopeCodeVisitor scopeVisitor = new JSRVariableScopeCodeVisitor(null ,source);
593 scopeVisitor.visitClass(classNode);
594 source.getErrorCollector().failIfErrors();
595 }
596
597 //
598 // Prep the generator machinery
599 //
600 ClassVisitor visitor = createClassVisitor();
601
602
603 String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
604 ClassGenerator generator = new AsmClassGenerator(context, visitor, classLoader, sourceName);
605
606
607 //
608 // Run the generation and create the class (if required)
609 //
610 generator.visitClass(classNode);
611 completionVerifier.visitClass(classNode);
612
613
614 if (!debug) {
615 byte[] bytes = ((ClassWriter) visitor).toByteArray();
616 /* this. */classes.add(new GroovyClass(classNode.getName(), bytes));
617 }
618
619
620 //
621 // Handle any callback that's been set
622
623
624 if (CompilationUnit.this.classgenCallback != null) {
625 classgenCallback.call(visitor, classNode);
626 }
627
628
629 //
630 // Recurse for inner classes
631
632 LinkedList innerClasses = generator.getInnerClasses();
633 while (!innerClasses.isEmpty()) {
634 classgen.call(source, context, (ClassNode) innerClasses.removeFirst());
635 }
636 }
637 };
638
639
640 protected ClassVisitor createClassVisitor() {
641 /** avoid runtime dependency on asm util
642 ClassVisitor visitor;
643 if( debug )
644 {
645 visitor = new DumpClassVisitor(output);
646 }
647 else
648 {
649 visitor = new ClassWriter(true);
650 }
651 return visitor;
652 */
653 return new ClassWriter(true);
654 }
655
656
657 /**
658 * Outputs the generated class files to permanent storage.
659 */
660 public void output() throws CompilationFailedException {
661 if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
662 throw new GroovyBugError("CompilationUnit not ready for output()");
663 }
664
665
666 boolean failures = false;
667
668
669 Iterator iterator = this.classes.iterator();
670 while (iterator.hasNext()) {
671 //
672 // Get the class and calculate its filesystem name
673
674
675 GroovyClass gclass = (GroovyClass) iterator.next();
676 String name = gclass.getName().replace('.', File.separatorChar) + ".class";
677 File path = new File(configuration.getTargetDirectory(), name);
678
679
680 //
681 // Ensure the path is ready for the file
682
683
684 File directory = path.getParentFile();
685 if (directory != null && !directory.exists()) {
686 directory.mkdirs();
687 }
688
689
690 //
691 // Create the file and write out the data
692
693 byte[] bytes = gclass.getBytes();
694
695
696 FileOutputStream stream = null;
697 try {
698 stream = new FileOutputStream(path);
699 stream.write(bytes, 0, bytes.length);
700 } catch (IOException e) {
701 getErrorCollector().addError(Message.create(e.getMessage(),this));
702 failures = true;
703 } finally {
704 if (stream != null) {
705 try {
706 stream.close();
707 } catch (Exception e) {
708 }
709 }
710 }
711 }
712
713
714 getErrorCollector().failIfErrors();
715
716
717 completePhase();
718 applyToSourceUnits(mark);
719
720
721 //
722 // Callback progress, if necessary
723
724
725 if (CompilationUnit.this.progressCallback != null) {
726 CompilationUnit.this.progressCallback.call(this, this.phase);
727 }
728 }
729
730 //---------------------------------------------------------------------------
731 // PHASE HANDLING
732
733
734 /**
735 * Updates the phase marker on all sources.
736 */
737 protected void mark() throws CompilationFailedException {
738 applyToSourceUnits(mark);
739 }
740
741
742 /**
743 * Marks a single SourceUnit with the current phase,
744 * if it isn't already there yet.
745 */
746 private LoopBodyForSourceUnitOperations mark = new LoopBodyForSourceUnitOperations() {
747 public void call(SourceUnit source) throws CompilationFailedException {
748 if (source.phase < phase) {
749 source.gotoPhase(phase);
750 }
751
752
753 if (source.phase == phase && phaseComplete && !source.phaseComplete) {
754 source.completePhase();
755 }
756 }
757 };
758
759
760
761
762
763 //---------------------------------------------------------------------------
764 // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
765
766
767 /**
768 * An callback interface for use in the applyToSourceUnits loop driver.
769 */
770 public abstract class LoopBodyForSourceUnitOperations {
771 public abstract void call(SourceUnit source) throws CompilationFailedException;
772 }
773
774
775
776
777 /**
778 * A loop driver for applying operations to all SourceUnits.
779 * Automatically skips units that have already been processed
780 * through the current phase.
781 */
782 public void applyToSourceUnits(LoopBodyForSourceUnitOperations body) throws CompilationFailedException {
783 boolean failures = false;
784
785
786 Iterator keys = names.iterator();
787 while (keys.hasNext()) {
788 String name = (String) keys.next();
789 SourceUnit source = (SourceUnit) sources.get(name);
790 if (source.phase <= phase) {
791 try {
792 body.call(source);
793 } catch (CompilationFailedException e) {
794 throw e;
795 } catch (Exception e) {
796 throw new GroovyBugError(e);
797 }
798 }
799 }
800
801
802 getErrorCollector().failIfErrors();
803 }
804
805
806 //---------------------------------------------------------------------------
807 // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS
808
809
810
811 /**
812 * An callback interface for use in the applyToSourceUnits loop driver.
813 */
814 public abstract class LoopBodyForPrimaryClassNodeOperations {
815 public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
816 }
817
818
819
820 /**
821 * A loop driver for applying operations to all primary ClassNodes in
822 * our AST. Automatically skips units that have already been processed
823 * through the current phase.
824 */
825 public void applyToPrimaryClassNodes(LoopBodyForPrimaryClassNodeOperations body) throws CompilationFailedException {
826 boolean failures = false;
827
828
829 Iterator modules = this.ast.getModules().iterator();
830 while (modules.hasNext()) {
831 ModuleNode module = (ModuleNode) modules.next();
832
833
834 try {
835 Iterator classNodes = module.getClasses().iterator();
836 while (classNodes.hasNext()) {
837 ClassNode classNode = (ClassNode) classNodes.next();
838 SourceUnit context = module.getContext();
839 if (context == null || context.phase <= phase) {
840 body.call(module.getContext(), new GeneratorContext(this.ast), classNode);
841 }
842 }
843 } catch (CompilationFailedException e) {
844 // fall thorugh, getErrorREporter().failIfErrors() will triger
845 } catch (Exception e) {
846 failures = true;
847 // String msg = e.getMessage();
848 // if (e instanceof RuntimeParserException) {
849 // RuntimeParserException rpe = (RuntimeParserException) e;
850 // ASTNode node = rpe.getNode();
851 // msg += ". The probable error location: [" + node.getLineNumber() + ":" + node.getColumnNumber() + "]";
852 // }
853
854 // check the exception for a nested compilation exception
855 ErrorCollector nestedCollector = null;
856 for (Throwable next = e.getCause(); next!=e && next!=null; next=next.getCause()) {
857 if (!(next instanceof MultipleCompilationErrorsException)) continue;
858 MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next;
859 nestedCollector = mcee.collector;
860 break;
861 }
862
863 if (nestedCollector!=null) {
864 getErrorCollector().addCollectorContents(nestedCollector);
865 } else {
866 getErrorCollector().addError(new ExceptionMessage(e,configuration.getDebug(),this));
867 }
868 }
869 }
870
871 getErrorCollector().failIfErrors();
872 }
873
874
875 //---------------------------------------------------------------------------
876 // OUTPUT
877
878
879 /**
880 * Writes error messages to the specified PrintWriter.
881 */
882 /*public void write(PrintWriter writer, Janitor janitor) {
883 super.write(writer, janitor);
884
885 Iterator keys = names.iterator();
886 while (keys.hasNext()) {
887 String name = (String) keys.next();
888 SourceUnit source = (SourceUnit) sources.get(name);
889
890 if (source.hasErrors()) {
891 source.write(writer, janitor);
892 }
893 }
894 }*/
895
896
897 }