KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > base > JavaCompiler


1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This file is part of the compiler and core tools for the AspectJ(tm)
4  * programming language; see http://aspectj.org
5  *
6  * The contents of this file are subject to the Mozilla Public License
7  * Version 1.1 (the "License"); you may not use this file except in
8  * compliance with the License. You may obtain a copy of the License at
9  * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is AspectJ.
17  *
18  * The Initial Developer of the Original Code is Xerox Corporation. Portions
19  * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
20  * All Rights Reserved.
21  *
22  * Contributor(s):
23  */

24
25 package org.aspectj.compiler.base;
26
27 import org.aspectj.compiler.base.ast.World;
28 import org.aspectj.compiler.base.ast.AST;
29 import org.aspectj.compiler.base.ast.CompilationUnit;
30 import org.aspectj.compiler.base.ast.ASTObject;
31 import org.aspectj.compiler.base.ast.TypeDec;
32 import org.aspectj.compiler.base.parser.JavaParser;
33
34
35 import java.util.*;
36 import java.util.Stack JavaDoc;
37 import java.io.*;
38 import java.text.NumberFormat JavaDoc;
39 import java.lang.reflect.Constructor JavaDoc;
40
41 public class JavaCompiler {
42     // Compiler Options
43
private Options options = new Options();
44     // The TypeManager linked to this compiler
45
private TypeManager typeManager;
46     // The World linked to this compiler
47
protected World world;
48     // error handler
49
protected ErrorHandler errorHandler;
50     // interface scanning class
51
protected Class JavaDoc scanner;
52     // world-wide passes
53
protected List/*WorldPass*/ passes;
54     // List of idle parsers
55
private Stack JavaDoc parsers = new Stack JavaDoc();
56     // files to be compiled by javac
57
protected List/*File*/ filesToCompile;
58
59
60     /** Method to support CompilerObject delegation for Options */
61     public final Options getOptions() { return options; }
62     /** Method to support CompilerObject delegation for World */
63     public final World getWorld() { return world; }
64     /** Method to support CompilerObject delegation for TypeManager */
65     public final TypeManager getTypeManager() { return typeManager; }
66
67
68     public boolean willGenerateSourceCode() {
69         return options.usejavac || options.preprocess;
70     }
71
72     public String JavaDoc getVersion() {
73         return Options.version;
74     }
75
76     public long getBuildTime() {
77         return Options.build;
78     }
79
80     public List getFilesToCompile() {
81         if (filesToCompile == null) return new LinkedList();
82         return filesToCompile;
83     }
84
85     public void addFileToCompile(File f) {
86         if (filesToCompile == null) filesToCompile = new LinkedList();
87         filesToCompile.add(f);
88     }
89
90     public CompilationUnit newCompilationUnit(File _file) {
91         return new CompilationUnit(this,_file);
92     }
93
94     public JavaCompiler(ErrorHandler errHandler) {
95         // if err_handler isn't null use it, otherwise construct a default one
96
this.errorHandler = (errHandler != null) ? errHandler : makeErrorHandler();
97         this.errorHandler.setCompiler(this);
98     }
99
100     /**
101      * Returns a default <code>ErrorHandler</code> writing to <code>System.err</code>.
102      * @return A default <code>ErrorHandler</code> writing to <code>System.err</code>.
103      */

104     protected ErrorHandler makeErrorHandler() {
105             return new ErrorHandler(new OutputStreamWriter(System.err));
106     }
107
108
109     public JavaParser makeJavaParser() {
110         return new JavaParser(this);
111     }
112
113     public boolean isIncremental() {
114         return options.incremental;
115     }
116
117     public boolean getOptionDumpStack() {
118         return options.dumpstack;
119     }
120
121     public boolean getOptionIgnoreErrors() {
122         return options.ignoreErrors;
123     }
124
125     public boolean getOptionVerbose() {
126         return options.verbose;
127     }
128
129     public void clearState() {
130         world.cleanup();
131         filesToCompile = null;
132         errorHandler.cleanupErrorWarningCounters();
133     }
134
135     public void compile(List filenames) {
136         addPasses();
137
138        if (getOptions().threads != 0) {
139             System.out.println("warning: multi-threaded compilation not supported in this release");
140             getOptions().threads = 0;
141         }
142
143         try {
144             internalCompile(filenames);
145         } catch (CompilerErrors compilerErrors) {
146             throw compilerErrors;
147         } catch (ExitRequestException exitRequest) {
148             throw exitRequest;
149         } catch (InternalCompilerError internalError) {
150             // only throw an internal error if there's aren't any regular errors
151
if (!getOptions().torture) errorHandler.exitOnErrors();
152             throw internalError;
153         } catch (Throwable JavaDoc throwable) {
154             // only throw an internal error if there's aren't any regular errors
155
//!!! think about how this might hide errors...
156
if (!getOptions().torture) errorHandler.exitOnErrors();
157             throw new InternalCompilerError(this, throwable, getCurrentNode());
158         } finally {
159             //XXXclearState();
160
}
161     }
162
163     /* This section containce compilation pases implementations */
164     protected void createWorld(List filenames) {
165         typeManager = new TypeManager(this);
166         world = new World(this);
167         if (!typeManager.checkLoadable("java.lang", "Object")) {
168             warnNoObject();
169         }
170         if (!typeManager.checkLoadable("org.aspectj.lang", "JoinPoint")) {
171             warnNoRuntime(false);
172         }
173         if (!typeManager.checkLoadable("org.aspectj.runtime.internal", "AroundClosure")) {
174             warnNoRuntime(true);
175         }
176         // add filenames to compile, the World will check for duplications
177
for(Iterator i=filenames.iterator(); i.hasNext();) {
178             Object JavaDoc o = i.next();
179             String JavaDoc filename;
180             File file;
181             if (o instanceof String JavaDoc) {
182                 filename = (String JavaDoc)o;
183                 file = new File(filename);
184             } else {
185                 file = (File)o;
186                 filename = file.getPath();
187             }
188             world.addFile(filename);
189         }
190     }
191
192     private static final String JavaDoc noRuntimeWarning =
193       "Can't find org.aspectj.lang.JoinPoint on your classpath anywhere.\n" +
194       "You need to include aspectjrt.jar on your classpath when compiling or\n" +
195       "running applications with ajc. See README-TOOLS.html in the top directory of\n" +
196       "the distribution for more details on how to configure this correctly.";
197
198     private static final String JavaDoc oldRuntimeWarning =
199       "You appear to have an out-of-date version of aspectjrt.jar on your classpath.\n" +
200       "You need to include the latest verion of aspectjrt.jar on your classpath when\n" +
201       "compiling or running applications with ajc. See README-TOOLS.html in the top\n" +
202       "directory of the distribution for more details on how to configure this\n" +
203       "correctly.";
204
205     /**
206      * To be overridden by compilers that don't use console output.
207      */

208     protected void warnNoRuntime(boolean foundOld) {
209         System.err.println(foundOld ? oldRuntimeWarning : noRuntimeWarning);
210         System.err.println();
211         System.err.println("I looked in: ");
212         for (Iterator i = getTypeManager().getClassPathStrings().iterator(); i.hasNext(); ) {
213             System.err.print(" ");
214             System.err.println(i.next());
215         }
216         
217         //System.err.println("sun.boot.class.path: " + System.getProperty("sun.boot.class.path"));
218

219         throw new ExitRequestException(-1);
220     }
221
222
223     private static final String JavaDoc noObjectWarning =
224         "Serious configuration problem: can't find java.lang.Object";
225     private static final String JavaDoc modifiedBootpathWarning =
226         "Check your custom bootclasspath for validity: ";
227     private static final String JavaDoc jviewWarning =
228         "You must run 'claspack -auto' to use ajc with MS's jview VM";
229
230
231     private void warnNoObject() {
232         System.err.println(noObjectWarning);
233         if (options.bootclasspath != null) {
234             System.err.println(modifiedBootpathWarning+options.bootclasspath);
235         } else {
236             String JavaDoc vendor = System.getProperty("java.vm.vendor");
237             if (vendor != null && vendor.startsWith("Microsoft")) {
238                 System.err.println(jviewWarning);
239             }
240         }
241
242         throw new ExitRequestException(-1);
243     }
244
245     protected void addPasses() {}
246
247
248     public synchronized JavaParser allocateParser() {
249         JavaParser parser;
250         if (parsers.empty()) {
251             parser = makeJavaParser();
252         } else {
253             parser = (JavaParser)parsers.pop();
254         }
255         return parser;
256     }
257
258     public synchronized void freeParser(JavaParser parser) {
259         parser.cleanup(false);
260         parsers.push(parser);
261     }
262
263
264
265
266     /* This section of code handles compiler state */
267     private Hashtable timingInformation = new Hashtable();
268     private ThreadLocal JavaDoc sectionLabel = new ThreadLocal JavaDoc();
269     private ThreadLocal JavaDoc localNodes = new ThreadLocal JavaDoc();
270     private long startTime;
271
272     private Stack JavaDoc getNodes() {
273         Object JavaDoc nodes = localNodes.get();
274         if (nodes == null) {
275             nodes = new Stack JavaDoc();
276             localNodes.set(nodes);
277         }
278         return (Stack JavaDoc)nodes;
279     }
280
281     public String JavaDoc getCurrentSection() {
282         return (String JavaDoc)sectionLabel.get();
283     }
284
285     public void setCurrentSection(String JavaDoc label) {
286         sectionLabel.set(label);
287     }
288
289     private String JavaDoc formatTime(long time) {
290         NumberFormat JavaDoc format = NumberFormat.getNumberInstance();
291         format.setMinimumFractionDigits(2);
292         format.setMaximumFractionDigits(2);
293         String JavaDoc value = format.format(time/1000.0);
294         while (value.length() < 3+2) value = " "+value;
295         return value;
296     }
297
298     protected double totalWorkEstimate = 0.0;
299     protected double percentComplete = 0.0;
300     public double getPercentComplete() {
301         return percentComplete;
302     }
303
304     protected void updateCompileState(String JavaDoc section, String JavaDoc subSection, double pct) {
305         //System.out.println((int)(pct*100.0)+"% " + section+":"+subSection);
306
}
307
308
309     public void completedFile(CompilerPass pass, CompilationUnit cu) {
310         exitIfRequested();
311
312         double pct = (pass.getWorkEstimate()/totalWorkEstimate)*
313                         (1.0/getWorld().getCompilationUnits().size());
314         percentComplete += pct;
315         updateCompileState(pass.getDisplayName(), cu.getSourceCanonicalPath(),
316                                 percentComplete);
317     }
318
319     protected void initializeWorld(List filenames) {
320         // create/initialize the world
321
createWorld(filenames);
322         errorHandler.exitOnErrors();
323
324         Set doneFiles = new HashSet();
325         for(Iterator i = world.getFiles().iterator(); i.hasNext(); ) {
326             File file = new File((String JavaDoc)i.next());
327             try {
328                 if (doneFiles.contains(file.getCanonicalPath())) {
329                     showMessage(this, "ignoring duplicate file: "+file.getPath());
330                     continue;
331                 } else {
332                     doneFiles.add(file.getCanonicalPath());
333                 }
334             } catch (IOException e) {
335                 this.showError(null,e.toString());
336                 continue;
337             }
338             world.addCompilationUnit(newCompilationUnit(file));
339         }
340     }
341
342
343     private volatile boolean exitRequested = false;
344     private void exitIfRequested() {
345         if (exitRequested) {
346             //!!! this value is depended on by ajde to know that this is user
347
//!!! requested. this should be done in a more principled way.
348
throw new ExitRequestException(0);
349         }
350     }
351
352     /**
353      * This method can be called from a thread other than the thread the
354      * compiler is running in to request that the compiler exit ASAP.
355      * The compiler will then terminate when it can.
356      */

357     public void requestCompileExit() {
358         exitRequested = true;
359     }
360
361
362     protected void internalCompile(List filenames) {
363         exitRequested = false;
364         initializeWorld(filenames);
365
366         for (Iterator i = passes.iterator(); i.hasNext(); ) {
367             CompilerPass pass = (CompilerPass)i.next();
368             pass.transformWorld();
369             exitIfRequested();
370         }
371         errorHandler.exitOnErrors();
372         finish();
373     }
374
375
376     public void beginSection(String JavaDoc label) {
377         beginSection(label, true);
378     }
379
380     public void beginSection(String JavaDoc label, boolean show) {
381         if (!getNodes().empty()) {
382             // internal error, non-empty stack after section
383
}
384
385         if (show) showMessage(label);
386         if (options.timings && options.threads == 0) {
387             long thisTime = System.currentTimeMillis();
388             if (sectionLabel.get() != null) {
389                 Long JavaDoc t = (Long JavaDoc)timingInformation.get(sectionLabel.get());
390                 if (t == null) {
391                     t = new Long JavaDoc(thisTime-startTime);
392                 } else {
393                     t = new Long JavaDoc(t.longValue()+(thisTime-startTime));
394                 }
395                 timingInformation.put(sectionLabel.get(),t);
396             }
397             startTime = thisTime;
398         }
399         setCurrentSection(label);
400     }
401
402     public void finish() {
403         beginSection("compilation complete");
404         if (options.timings && options.threads == 0) {
405             errorHandler.showMessage("Timing information:");
406             Map.Entry[] a = (Map.Entry[])
407                 timingInformation.entrySet().toArray(new Map.Entry[0]);
408             Arrays.sort(a, new Comparator() {
409                     public int compare(Object JavaDoc x, Object JavaDoc y) {
410                         return
411                             ((Long JavaDoc) ((Map.Entry) x).getValue())
412                             .compareTo(((Map.Entry) y).getValue());
413                     }
414                 });
415             long totalTime = 0;
416             for (int i = 0, len = a.length; i < len; i++) {
417                 Map.Entry n = a[i];
418                 String JavaDoc sectionLabel = (String JavaDoc)n.getKey();
419                 Long JavaDoc tm = (Long JavaDoc)n.getValue();
420                 long thisTime = tm.longValue();
421                 String JavaDoc msg = " "+formatTime(thisTime)+" seconds in "+sectionLabel;
422                 totalTime += thisTime;
423                 errorHandler.showMessage(msg);
424             }
425             errorHandler.showMessage("---------------------------------------------");
426             String JavaDoc msg = " "+formatTime(totalTime)+" total seconds";
427             errorHandler.showMessage(msg);
428         }
429     }
430
431     public void enterNode(ASTObject where) {
432         getNodes().push(where);
433     }
434
435     public void exitNode(ASTObject where) {
436         if (getNodes().pop() != where) {
437             // internal error, mismatched push/pop;
438
}
439     }
440
441     public ASTObject getCurrentNode() {
442         return getNodes().empty() ? null : (ASTObject)getNodes().peek();
443     }
444
445
446     /* This code delegates error handling to ErrorHandler */
447     public void internalError(Throwable JavaDoc uncaughtException, ASTObject where) {
448         if (!errorHandler.willExitWithErrors()) {
449             errorHandler.internalError(uncaughtException, where);
450         }
451     }
452
453     public void internalError(String JavaDoc message) {
454         internalError(null, message);
455     }
456
457     public void internalError(ASTObject where, String JavaDoc message) {
458         if (!errorHandler.willExitWithErrors()) {
459             errorHandler.showError(where, "INTERNAL: " + message);
460         }
461     }
462
463     public void showError(String JavaDoc message) {
464         this.showError(null, message);
465     }
466
467     public void showError(ASTObject where, String JavaDoc message) {
468         errorHandler.showError(where, message);
469     }
470
471     public void showError(File source, int line, int column, String JavaDoc message) {
472         errorHandler.showError(source, line, column, message);
473     }
474
475     public void showWarning(ASTObject where, String JavaDoc message) {
476         errorHandler.showWarning(where, message);
477     }
478     
479     public void showWarning(ASTObject where, ErrorHandler.Message message) {
480         errorHandler.showWarning(where, message);
481     }
482
483     public void showMessage(Object JavaDoc where, String JavaDoc message) {
484         if (where != null && where instanceof ASTObject) {
485             errorHandler.showMessage((ASTObject)where, message);
486             return;
487         }
488
489         if (options.verbose) {
490             errorHandler.showMessage(" "+message);
491         }
492     }
493
494     public void showMessage(String JavaDoc message) {
495         if (options.verbose) {
496             errorHandler.showMessage(message);
497         }
498     }
499
500     public void warnVersion(String JavaDoc oldVersion, ASTObject object, String JavaDoc message) {
501         if (options.porting) {
502             showWarning(object, "Deprecated since "+oldVersion+": "+message);
503         } else {
504             errorVersion(oldVersion, object, message);
505         }
506     }
507
508     public void errorVersion(String JavaDoc oldVersion, ASTObject object, String JavaDoc message) {
509         showError(object, "Removed in "+oldVersion+": "+message);
510     }
511 }
512
Popular Tags