package polyglot.frontend; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; import polyglot.types.reflect.ClassFileLoader; import polyglot.main.Report; import polyglot.util.*; /** * This is the main entry point for the compiler. It contains a work list that * contains entries for all classes that must be compiled (or otherwise worked * on). */ public class Compiler { /** The extension info */ private ExtensionInfo extensionInfo; /** A list of all extension infos active in this compiler. */ private List allExtensions; /** The error queue handles outputting error messages. */ private ErrorQueue eq; /** * Class file loader. There should be only one of these so we can cache * across type systems. */ private ClassFileLoader loader; /** * The output files generated by the compiler. This is used to to call the * post-compiler (e.g., javac). */ private Collection outputFiles = new HashSet(); /** * Initialize the compiler. * * @param extensionInfo the <code>ExtensionInfo</code> this compiler is for. */ public Compiler(ExtensionInfo extensionInfo) { this(extensionInfo, new StdErrorQueue(System.err, extensionInfo.getOptions().error_count, extensionInfo.compilerName())); } /** * Initialize the compiler. * * @param extensionInfo the <code>ExtensionInfo</code> this compiler is for. */ public Compiler(ExtensionInfo extensionInfo, ErrorQueue eq) { this.extensionInfo = extensionInfo; this.eq = eq; this.allExtensions = new ArrayList(2); loader = new ClassFileLoader(extensionInfo); // This must be done last. extensionInfo.initCompiler(this); } /** Return a set of output filenames resulting from a compilation. */ public Collection outputFiles() { return outputFiles; } /** * Compile all the files listed in the set of strings <code>source</code>. * Return true on success. The method <code>outputFiles</code> can be * used to obtain the output of the compilation. This is the main entry * point for the compiler, called from main(). */ public boolean compile(Collection sources) { boolean okay = false; try { try { SourceLoader source_loader = sourceExtension().sourceLoader(); for (Iterator i = sources.iterator(); i.hasNext(); ) { String sourceName = (String) i.next(); FileSource source = source_loader.fileSource(sourceName); // mark this source as being explicitly specified // by the user. source.setUserSpecified(true); sourceExtension().addJob(source); } okay = sourceExtension().runToCompletion(); } catch (FileNotFoundException e) { eq.enqueue(ErrorInfo.IO_ERROR, "Cannot find source file \"" + e.getMessage() + "\"."); } catch (IOException e) { eq.enqueue(ErrorInfo.IO_ERROR, e.getMessage()); } catch (InternalCompilerError e) { // Report it like other errors, but rethrow to get the stack trace. try { eq.enqueue(ErrorInfo.INTERNAL_ERROR, e.message(), e.position()); } catch (ErrorLimitError e2) { } eq.flush(); throw e; } catch (RuntimeException e) { // Flush the error queue, then rethrow to get the stack trace. eq.flush(); throw e; } } catch (ErrorLimitError e) { } eq.flush(); for (Iterator i = allExtensions.iterator(); i.hasNext(); ) { ExtensionInfo ext = (ExtensionInfo) i.next(); ext.getStats().report(); } return okay; } /** Get the compiler's class file loader. */ public ClassFileLoader loader() { return this.loader; } /** Should fully qualified class names be used in the output? */ public boolean useFullyQualifiedNames() { return extensionInfo.getOptions().fully_qualified_names; } /** Return a list of all languages extensions active in the compiler. */ public void addExtension(ExtensionInfo ext) { allExtensions.add(ext); } /** Return a list of all languages extensions active in the compiler. */ public List allExtensions() { return allExtensions; } /** Get information about the language extension being compiled. */ public ExtensionInfo sourceExtension() { return extensionInfo; } /** Maximum number of characters on each line of output */ public int outputWidth() { return extensionInfo.getOptions().output_width; } /** Should class info be serialized into the output? */ public boolean serializeClassInfo() { return extensionInfo.getOptions().serialize_type_info; } /** Get the compiler's error queue. */ public ErrorQueue errorQueue() { return eq; } static { // FIXME: if we get an io error (due to too many files open, for example) // it will throw an exception. but, we won't be able to do anything with // it since the exception handlers will want to load // polyglot.util.CodeWriter and polyglot.util.ErrorInfo to print and // enqueue the error; but the classes must be in memory since the io // can't open any files; thus, we force the classloader to load the class // file. try { ClassLoader loader = Compiler.class.getClassLoader(); // loader.loadClass("polyglot.util.CodeWriter"); // loader.loadClass("polyglot.util.ErrorInfo"); loader.loadClass("polyglot.util.StdErrorQueue"); } catch (ClassNotFoundException e) { throw new InternalCompilerError(e.getMessage()); } } }