1 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 77 78 public class CompilationUnit extends ProcessingUnit { 79 80 83 protected HashMap sources; protected ArrayList names; 86 protected CompileUnit ast; protected ArrayList classes; 89 protected Verifier verifier; 91 protected ClassCompletionVerifier completionVerifier; 93 protected boolean debug; protected boolean configured; 96 protected ClassgenCallback classgenCallback; protected ProgressCallback progressCallback; 99 100 103 public CompilationUnit() { 104 this(null, null, null); 105 } 106 107 108 111 public CompilationUnit(ClassLoader loader) { 112 this(null, null, loader); 113 } 114 115 116 119 public CompilationUnit(CompilerConfiguration configuration) { 120 this(configuration, null, null); 121 } 122 123 124 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 148 149 public void configure(CompilerConfiguration configuration) { 150 super.configure(configuration); 151 this.debug = configuration.getDebug(); 152 153 154 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 178 179 public CompileUnit getAST() { 180 return this.ast; 181 } 182 183 184 187 188 public List getClasses() { 189 return classes; 190 } 191 192 193 197 198 public ClassNode getFirstClassNode() { 199 return (ClassNode) ((ModuleNode) this.ast.getModules().get(0)).getClasses().get(0); 200 } 201 202 203 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 233 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 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 259 260 public SourceUnit addSource(File file) { 261 return addSource(new SourceUnit(file, configuration, classLoader)); 262 } 263 264 265 268 269 public SourceUnit addSource(URL url) { 270 return addSource(new SourceUnit(url, configuration, classLoader)); 271 } 272 273 274 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 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 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 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 341 347 348 public static abstract class ClassgenCallback { 349 public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException; 350 } 351 352 353 357 358 public void setClassgenCallback(ClassgenCallback visitor) { 359 this.classgenCallback = visitor; 360 } 361 362 363 369 370 public static abstract class ProgressCallback { 371 public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException; 372 } 373 374 375 379 380 public void setProgressCallback(ProgressCallback callback) { 381 this.progressCallback = callback; 382 } 383 384 385 386 387 390 391 394 395 public void compile() throws CompilationFailedException { 396 compile(Phases.ALL); 397 } 398 399 400 403 404 public void compile(int throughPhase) throws CompilationFailedException { 405 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 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 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 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 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 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 534 if (this.progressCallback != null) { 535 this.progressCallback.call(this, CompilationUnit.this.phase); 536 } 537 538 } 539 540 541 544 545 private LoopBodyForPrimaryClassNodeOperations classgen = new LoopBodyForPrimaryClassNodeOperations() { 546 public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { 547 550 verifier.visitClass(classNode); 551 552 553 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 564 generator.visitClass(classNode); 565 completionVerifier.visitClass(classNode); 566 567 if (!debug) { 568 byte[] bytes = ((ClassWriter) visitor).toByteArray(); 569 classes.add(new GroovyClass(classNode.getName(), bytes)); 570 } 571 572 573 574 575 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 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 618 return new ClassWriter(true); 619 } 620 621 622 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 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 645 File directory = path.getParentFile(); 646 if (directory != null && !directory.exists()) { 647 directory.mkdirs(); 648 } 649 650 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 683 if (CompilationUnit.this.progressCallback != null) { 684 CompilationUnit.this.progressCallback.call(this, this.phase); 685 } 686 } 687 688 689 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 716 717 720 721 protected void mark() throws CompilationFailedException { 722 applyToSourceUnits(mark); 723 } 724 725 726 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 749 752 753 public abstract class LoopBodyForSourceUnitOperations { 754 public abstract void call(SourceUnit source) throws CompilationFailedException; 755 } 756 757 758 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 793 794 797 798 public abstract class LoopBodyForPrimaryClassNodeOperations { 799 public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException; 800 } 801 802 803 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 addError(new ExceptionMessage(e)); 837 } 838 } 839 840 if (failures) { 841 fail(); 842 } 843 } 844 845 846 847 848 851 852 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 877 | Popular Tags |