001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * 2013, Jesper Öqvist <jesper.oqvist@cs.lth.se> 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions are met: 007 * 008 * 1. Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * 2. Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * 3. Neither the name of the copyright holder nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 023 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 029 * POSSIBILITY OF SUCH DAMAGE. 030 */ 031 032 import org.jastadd.util.*; 033 034 import java.util.Collections; 035 036 aspect FrontendMain { 037 public long Program.javaParseTime; 038 public long Program.bytecodeParseTime; 039 public long Program.codeGenTime; 040 public long Program.errorCheckTime; 041 public int Program.numJavaFiles; 042 public int Program.numClassFiles; 043 044 /** 045 * Reset the profile statistics. 046 */ 047 public void Program.resetStatistics() { 048 javaParseTime = 0; 049 bytecodeParseTime = 0; 050 codeGenTime = 0; 051 errorCheckTime = 0; 052 numJavaFiles = 0; 053 numClassFiles = 0; 054 } 055 056 public void Program.printStatistics(PrintStream out) { 057 out.println("javaParseTime: " + javaParseTime); 058 out.println("numJavaFiles: " + numJavaFiles); 059 out.println("bytecodeParseTime: " + javaParseTime); 060 out.println("numClassFiles: " + numClassFiles); 061 out.println("errorCheckTime: " + errorCheckTime); 062 out.println("codeGenTime: " + codeGenTime); 063 } 064 065 /** 066 * Abstract Java compiler frontend. 067 */ 068 abstract public class Frontend { 069 protected Program program; 070 071 /** 072 * Compile success 073 */ 074 public static final int EXIT_SUCCESS = 0; 075 076 /** 077 * Lexical/semantic error. 078 */ 079 public static final int EXIT_ERROR = 1; 080 081 /** 082 * Command-line configuration error. 083 */ 084 public static final int EXIT_CONFIG_ERROR = 2; 085 086 /** 087 * The compiler terminated by system error. 088 */ 089 public static final int EXIT_SYSTEM_ERROR = 3; 090 091 /** 092 * The compiler terminated abnormally. 093 */ 094 public static final int EXIT_UNHANDLED_ERROR = 4; 095 096 private final String name; 097 private final String version; 098 099 /** 100 * Initialize the program object. 101 */ 102 protected Frontend() { 103 this("Unknown", "0"); 104 } 105 106 /** 107 * Initialize the program object and set compiler name and version. 108 * @param name compiler name 109 * @param version compiler version 110 */ 111 protected Frontend(String name, String version) { 112 this.name = name; 113 this.version = version; 114 program = new Program(); 115 program.state().reset(); 116 } 117 118 /** 119 * Process all compilation units listed in the command-line arguments, and 120 * all compilation units referenced from those. 121 * 122 * @return 0 on success, 1 on error, 2 on configuration error, 3 on system 123 * error, 4 on unhandled error 124 */ 125 public int run(String[] args, BytecodeReader reader, JavaParser parser) { 126 127 program.resetStatistics(); 128 program.initBytecodeReader(reader); 129 program.initJavaParser(parser); 130 131 initOptions(); 132 int argResult = processArgs(args); 133 if (argResult != 0) { 134 return argResult; 135 } 136 137 Collection<String> files = program.options().files(); 138 139 if (program.options().hasOption("-version")) { 140 printVersion(); 141 return EXIT_SUCCESS; 142 } 143 144 if (program.options().hasOption("-help") || files.isEmpty()) { 145 printUsage(); 146 return EXIT_SUCCESS; 147 } 148 149 Collection<CompilationUnit> work = new LinkedList<CompilationUnit>(); 150 151 try { 152 for (String file: files) { 153 program.addSourceFile(file); 154 } 155 156 int compileResult = EXIT_SUCCESS; 157 158 // process source compilation units 159 Iterator<CompilationUnit> iter = program.compilationUnitIterator(); 160 while (iter.hasNext()) { 161 CompilationUnit unit = iter.next(); 162 work.add(unit); 163 int result = processCompilationUnit(unit); 164 switch (result) { 165 case EXIT_SUCCESS: 166 break; 167 case EXIT_UNHANDLED_ERROR: 168 return result; 169 default: 170 compileResult = result; 171 } 172 } 173 174 // Process library compilation units. 175 RobustMap<String, CompilationUnit> valueMap = (RobustMap<String, CompilationUnit>) 176 program.getLibCompilationUnitValueMap(); 177 if (valueMap != null) { 178 iter = valueMap.robustValueIterator(); 179 while (iter.hasNext()) { 180 CompilationUnit unit = iter.next(); 181 work.add(unit); 182 int result = processCompilationUnit(unit); 183 switch (result) { 184 case EXIT_SUCCESS: 185 break; 186 case EXIT_UNHANDLED_ERROR: 187 return result; 188 default: 189 compileResult = result; 190 } 191 } 192 } 193 194 if (compileResult != EXIT_SUCCESS) { 195 return compileResult; 196 } 197 198 for (CompilationUnit unit: work) { 199 if (unit != null && unit.fromSource()) { 200 long start = System.nanoTime(); 201 processNoErrors(unit); 202 program.codeGenTime += System.nanoTime() - start; 203 } 204 } 205 206 } catch (AbstractClassfileParser.ClassfileFormatError e) { 207 System.err.println(e.getMessage()); 208 return EXIT_UNHANDLED_ERROR; 209 } catch (Throwable t) { 210 System.err.println("Fatal exception:"); 211 t.printStackTrace(System.err); 212 return EXIT_UNHANDLED_ERROR; 213 } finally { 214 if (program.options().hasOption("-profile")) { 215 program.printStatistics(System.out); 216 } 217 } 218 return EXIT_SUCCESS; 219 } 220 221 private Collection<Problem> EMPTY_PROBLEM_LIST = Collections.emptyList(); 222 223 /** 224 * Processes from-source compilation units by error-checking them. 225 * This method only report semantic errors and warnings. 226 * 227 * @return zero on success, non-zero on error 228 */ 229 protected int processCompilationUnit(CompilationUnit unit) throws Error { 230 if (unit != null && unit.fromSource()) { 231 try { 232 Collection<Problem> errors = unit.parseErrors(); 233 Collection<Problem> warnings = EMPTY_PROBLEM_LIST; 234 // Compute static semantic errors when there are no parse errors 235 // or the recover from parse errors option is specified. 236 if (errors.isEmpty() || program.options().hasOption("-recover")) { 237 long start = System.nanoTime(); 238 unit.collectErrors(); 239 errors = unit.errors(); 240 warnings = unit.warnings(); 241 program.errorCheckTime += System.nanoTime() - start; 242 } 243 if (!errors.isEmpty()) { 244 processErrors(errors, unit); 245 return EXIT_ERROR; 246 } else { 247 if (!warnings.isEmpty() && !program.options().hasOption("-nowarn")) { 248 processWarnings(warnings, unit); 249 } 250 } 251 } catch (Error e) { 252 System.err.println("Encountered error while processing " + unit.pathName()); 253 throw e; 254 } 255 } 256 return EXIT_SUCCESS; 257 } 258 259 /** 260 * Initialize the command-line options. 261 * Override this method to add your own command-line options. 262 */ 263 protected void initOptions() { 264 Options options = program.options(); 265 options.initOptions(); 266 options.addKeyOption("-version"); 267 options.addKeyOption("-print"); 268 options.addKeyOption("-g"); 269 options.addKeyOption("-g:none"); 270 options.addKeyOption("-g:lines,vars,source"); 271 options.addKeyOption("-nowarn"); 272 options.addKeyOption("-verbose"); 273 options.addKeyOption("-deprecation"); 274 options.addKeyValueOption("-classpath"); 275 options.addKeyValueOption("-cp"); 276 options.addKeyValueOption("-sourcepath"); 277 options.addKeyValueOption("-bootclasspath"); 278 options.addKeyValueOption("-extdirs"); 279 options.addKeyValueOption("-d"); 280 options.addKeyValueOption("-encoding"); 281 options.addKeyValueOption("-source"); 282 options.addKeyValueOption("-target"); 283 options.addKeyOption("-help"); 284 options.addKeyOption("-O"); 285 options.addKeyOption("-J-Xmx128M"); 286 options.addKeyOption("-recover"); 287 options.addKeyOption("-XprettyPrint"); 288 options.addKeyOption("-XdumpTree"); 289 290 // non-javac options 291 options.addKeyOption("-profile"); // output profiling information 292 options.addKeyOption("-debug"); // extra debug checks and information 293 } 294 295 /** 296 * Configure the compiler with command-line arguments. 297 * @return 0 if there were no configuration errors 298 */ 299 protected int processArgs(String[] args) { 300 program.options().addOptions(args); 301 boolean error = false; 302 Collection<String> files = program.options().files(); 303 for (String file: files) { 304 if (!new File(file).isFile()) { 305 System.err.println("Error: neither a valid option nor a filename: " + file); 306 error = true; 307 } 308 } 309 return error ? EXIT_CONFIG_ERROR : EXIT_SUCCESS; 310 } 311 312 /** 313 * Print errors for a compilation unit. 314 * 315 * @param errors collection of compile problems 316 * @param unit affected compilation unit 317 */ 318 protected void processErrors(Collection<Problem> errors, CompilationUnit unit) { 319 System.err.println("Errors:"); 320 for (Iterator iter2 = errors.iterator(); iter2.hasNext(); ) { 321 System.err.println(iter2.next()); 322 } 323 } 324 325 /** 326 * Print the warnings for a compilation unit. 327 * 328 * @param warnings collection of warnings 329 * @param unit affected compilation unit 330 */ 331 protected void processWarnings(Collection<Problem> warnings, CompilationUnit unit) { 332 System.err.println("Warnings:"); 333 for (Problem warning : warnings) { 334 System.err.println(warning); 335 } 336 } 337 338 /** 339 * Called for each from-source compilation unit with no errors. 340 */ 341 protected void processNoErrors(CompilationUnit unit) { 342 } 343 344 /** 345 * Echo the command-line usage help to sysout. 346 */ 347 protected void printUsage() { 348 System.out.println(name() + " " + version()); 349 System.out.println("\n" 350 + "Usage: java " + name() + " <options> <source files>\n" 351 + " -verbose Output messages about what the compiler is doing\n" 352 + " -classpath <path> Specify where to find user class files\n" 353 + " -sourcepath <path> Specify where to find input source files\n" 354 + " -bootclasspath <path> Override location of bootstrap class files\n" 355 + " -extdirs <dirs> Override location of installed extensions\n" 356 + " -d <directory> Specify where to place generated class files\n" 357 + " -nowarn Disable warning messages\n" 358 + " -help Print a synopsis of standard options\n" 359 + " -version Print version information"); 360 } 361 362 /** 363 * Echo the version to sysout. 364 */ 365 protected void printVersion() { 366 System.out.println(name() + " " + version()); 367 } 368 369 /** 370 * @return the name of the compiler 371 */ 372 protected String name() { 373 return name; 374 } 375 376 /** 377 * @return the version of the compiler 378 */ 379 protected String version() { 380 return version; 381 } 382 } 383 }