/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.tools.main;
import java.io.*;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import org.visage.api.VisageTaskEvent;
import org.visage.api.VisageTaskListener;
import com.sun.source.util.TaskEvent;
import com.sun.tools.mjavac.util.*;
import com.sun.tools.mjavac.code.*;
import org.visage.tools.tree.*;
import com.sun.tools.mjavac.jvm.*;
import com.sun.tools.mjavac.code.Symbol.*;
import com.sun.tools.mjavac.tree.JCTree.JCCompilationUnit;
import org.visage.tools.comp.*;
import org.visage.tools.code.*;
import org.visage.tools.util.MsgSym;
import static com.sun.tools.mjavac.util.ListBuffer.lb;
import org.visage.tools.antlr.VisageSyntacticAnalysis;
import org.visage.tools.tree.xml.TreeXMLTransformer;
import org.visage.tools.util.PlatformPlugin;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/** This class could be the main entry point for GJC when GJC is used as a
* component in a larger software system. It provides operations to
* construct a new compiler, and to run a new compiler on a set of source
* files.
*
* <p><b>This is NOT part of any API supported by Sun Microsystems. If
* you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class VisageCompiler implements ClassReader.SourceCompleter {
private final static String visageErrorsKey = "org.visage.tools.resources.visagecompiler";
/** The context key for the compiler. */
protected static final Context.Key<VisageCompiler> compilerKey =
new Context.Key<VisageCompiler>();
/** Get the JavaCompiler instance for this context. */
public static VisageCompiler instance(Context context) {
VisageCompiler instance = context.get(compilerKey);
if (instance == null)
instance = new VisageCompiler(context);
return instance;
}
/** The current version number as a string.
*/
public static String version() {
return version("release");
}
/** The current full version number as a string.
*/
public static String fullVersion() {
return version("full"); // mm.mm.oo[-milestone]-build
}
private static final String versionRBName = "org.visage.tools.resources.version";
private static ResourceBundle versionRB;
private static String version(String key) {
if (versionRB == null) {
try {
versionRB = ResourceBundle.getBundle(versionRBName);
} catch (MissingResourceException e) {
// HACK: MESSAGE_VERSION_RESOURCE_MISSING is currently defined in visagecompiler.properties
return Main.getVisageLocalizedString(MsgSym.MESSAGEPREFIX_COMPILER_MISC
+ MsgSym.MESSAGE_VERSION_RESOURCE_MISSING, System.getProperty("java.version"));
// return Log.getLocalizedString(MsgSym.MESSAGE_VERSION_RESOURCE_MISSING, System.getProperty("java.version"));
}
}
try {
return versionRB.getString(key);
}catch (MissingResourceException e) {
// HACK: MESSAGE_VERSION_UNKNOWN is currently defined in visagecompiler.properties
return Main.getVisageLocalizedString(MsgSym.MESSAGEPREFIX_COMPILER_MISC
+ MsgSym.MESSAGE_VERSION_UNKNOWN, System.getProperty("java.version"));
// return Log.getLocalizedString(MsgSym.MESSAGE_VERSION_UNKNOWN, System.getProperty("java.version"));
}
}
private static enum CompilePolicy {
/*
* Just attribute the parse trees
*/
ATTR_ONLY,
/*
* Just attribute and do flow analysis on the parse trees.
* This should catch most user errors.
*/
CHECK_ONLY,
/*
* Attribute everything, then do flow analysis for everything,
* then desugar everything, and only then generate output.
* Means nothing is generated if there are any errors in any classes.
*/
SIMPLE,
/*
* After attributing everything and doing flow analysis,
* group the work by compilation unit.
* Then, process the work for each compilation unit together.
* Means nothing is generated for a compilation unit if the are any errors
* in the compilation unit (or in any preceding compilation unit.)
*/
BY_FILE,
/*
* Completely process each entry on the todo list in turn.
* -- this is the same for 1.5.
* Means output might be generated for some classes in a compilation unit
* and not others.
*/
BY_TODO;
static CompilePolicy decode(String option) {
if (option == null)
return DEFAULT_COMPILE_POLICY;
else if (option.equals("attr"))
return ATTR_ONLY;
else if (option.equals("check"))
return CHECK_ONLY;
else if (option.equals("simple"))
return SIMPLE;
else if (option.equals("byfile"))
return BY_FILE;
else if (option.equals("bytodo"))
return BY_TODO;
else
return DEFAULT_COMPILE_POLICY;
}
}
private static CompilePolicy DEFAULT_COMPILE_POLICY = CompilePolicy.BY_TODO;
private static enum ImplicitSourcePolicy {
/** Don't generate or process implicitly read source files. */
NONE,
/** Generate classes for implicitly read source files. */
CLASS,
/** Like CLASS, but generate warnings if annotation processing occurs */
UNSET;
static ImplicitSourcePolicy decode(String option) {
if (option == null)
return UNSET;
else if (option.equals("none"))
return NONE;
else if (option.equals("class"))
return CLASS;
else
return UNSET;
}
}
/** Command line options
*/
protected Options options;
/** The log to be used for error reporting.
*/
public Log log;
/** The tree factory module.
*/
protected VisageTreeMaker make;
/** The class writer.
*/
protected ClassWriter writer;
/** The module for the symbol table entry phases.
*/
protected VisageEnter enter;
/** The symbol table.
*/
protected VisageSymtab syms;
/** The language version.
*/
protected Source source;
/** The name table.
*/
protected Name.Table names;
/** The bind analyzer.
*/
protected VisageBoundContextAnalysis bindAnalyzer;
/** Fill in the synthetic definitions needed in a bound function.
*/
protected VisageBoundFiller boundFill;
/** The local var bind converter.
*/
protected VisageLocalToClass localToClass;
/** The type conversion inserter.
*/
protected VisageLower convertTypes;
/** The attributor.
*/
protected VisageAttr attr;
/** The checker.
*/
protected VisageCheck chk;
/** The annotation annotator.
*/
protected VisageAnnotate annotate;
/** The back-end preper
*/
protected VisagePrepForBackEnd prepForBackEnd;
/** Optimization statistics
*/
protected VisageOptimizationStatistics optStat;
/** The Java Compiler instance the processes the flow through gen.
*/
protected VisageJavaCompiler visageJavaCompiler;
/** Force a completion failure on this name
*/
protected final Name completionFailureName;
/** Type utilities.
*/
protected Types types;
/** Access to file objects.
*/
protected JavaFileManager fileManager;
/** Optional listener for progress events
*/
protected VisageTaskListener taskListener;
protected final VisageSyntacticAnalysis syntacticAnalysis;
protected final VisageDecompose decomposeBindExpressions;
protected final VisageVarUsageAnalysis varUsageAnalysis;
protected final VisageToJava visageToJava;
/**
* Flag set if any implicit source files read.
**/
protected boolean implicitSourceFilesRead;
protected Context context;
/** Construct a new compiler using a shared context.
*/
public VisageCompiler(final Context context) {
this.context = context;
context.put(compilerKey, this);
registerServices(context);
VisageClassReader.instance(context).sourceCompleter = this;
visageJavaCompiler = VisageJavaCompiler.instance(context);
names = Name.Table.instance(context);
options = Options.instance(context);
log = Log.instance(context);
make = (VisageTreeMaker)VisageTreeMaker.instance(context);
writer = ClassWriter.instance(context);
enter = VisageEnter.instance(context);
todo = VisageTodo.instance(context);
fileManager = context.get(JavaFileManager.class);
syntacticAnalysis = VisageSyntacticAnalysis.instance(context);
decomposeBindExpressions = VisageDecompose.instance(context);
varUsageAnalysis = VisageVarUsageAnalysis.instance(context);
visageToJava = VisageToJava.instance(context);
prepForBackEnd = VisagePrepForBackEnd.instance(context);
// Add the visage message resource bundle
Messages.instance(context).add(visageErrorsKey);
try {
// catch completion problems with predefineds
syms = (VisageSymtab)VisageSymtab.instance(context);
} catch (CompletionFailure ex) {
// inlined Check.completionError as it is not initialized yet
log.error(MsgSym.MESSAGE_CANNOT_ACCESS, ex.sym, ex.errmsg);
if (ex instanceof ClassReader.BadClassFile)
throw new Abort();
}
source = Source.instance(context);
attr = VisageAttr.instance(context);
bindAnalyzer = VisageBoundContextAnalysis.instance(context);
boundFill = VisageBoundFiller.instance(context);
localToClass = VisageLocalToClass.instance(context);
convertTypes = VisageLower.instance(context);
chk = VisageCheck.instance(context);
annotate = VisageAnnotate.instance(context);
optStat = VisageOptimizationStatistics.instance(context);
types = Types.instance(context);
taskListener = context.get(VisageTaskListener.class);
verbose = options.get("-verbose") != null;
sourceOutput = options.get("-printsource") != null; // used to be -s
stubOutput = options.get("-stubs") != null;
relax = options.get("-relax") != null;
printFlat = options.get("-printflat") != null;
attrParseOnly = options.get("-attrparseonly") != null;
encoding = options.get("-encoding");
lineDebugInfo = options.get("-g:") == null ||
options.get("-g:lines") != null;
devVerbose = options.get("dev") != null;
processPcks = options.get("process.packages") != null;
verboseCompilePolicy = options.get("verboseCompilePolicy") != null;
if (attrParseOnly)
compilePolicy = CompilePolicy.ATTR_ONLY;
else
compilePolicy = CompilePolicy.decode(options.get("compilePolicy"));
implicitSourcePolicy = ImplicitSourcePolicy.decode(options.get("-implicit"));
completionFailureName =
(options.get("failcomplete") != null)
? names.fromString(options.get("failcomplete"))
: null;
}
/* Switches:
*/
/** Verbose output.
*/
public boolean verbose;
/** Emit plain Java source files rather than class files.
*/
public boolean sourceOutput;
/** Emit stub source files rather than class files.
*/
public boolean stubOutput;
/** Generate attributed parse tree only.
*/
public boolean attrParseOnly;
/** Switch: relax some constraints for producing the jsr14 prototype.
*/
boolean relax;
/** Debug switch: Emit Java sources after inner class flattening.
*/
public boolean printFlat;
/** The encoding to be used for source input.
*/
public String encoding;
/** Generate code with the LineNumberTable attribute for debugging
*/
public boolean lineDebugInfo;
/** Switch: should we debug ignored exceptions
*/
protected boolean devVerbose;
/** Switch: should we (annotation) process packages as well
*/
protected boolean processPcks;
/** Switch: is annotation processing requested explitly via
* CompilationTask.setProcessors?
*/
protected boolean explicitAnnotationProcessingRequested = false;
/**
* The policy for the order in which to perform the compilation
*/
CompilePolicy compilePolicy;
/**
* The policy for what to do with implicitly read source files
*/
ImplicitSourcePolicy implicitSourcePolicy;
/**
* Report activity related to compilePolicy
*/
public boolean verboseCompilePolicy;
/** A queue of all as yet unattributed classes.
*/
public VisageTodo todo;
private Set<VisageEnv<VisageAttrContext>> deferredSugar = new HashSet<VisageEnv<VisageAttrContext>>();
/** The set of currently compiled inputfiles, needed to ensure
* we don't accidentally overwrite an input file when -s is set.
* initialized by `compile'.
*/
protected Set<JavaFileObject> inputFiles = new HashSet<JavaFileObject>();
/** The number of errors reported so far.
*/
public int errorCount() {
return log.nerrors;
}
protected final <T> List<T> stopIfError(ListBuffer<T> listBuffer) {
if (errorCount() == 0)
return listBuffer.toList();
else
return List.nil();
}
protected final <T> List<T> stopIfError(List<T> list) {
if (errorCount() == 0)
return list;
else
return List.nil();
}
/** The number of warnings reported so far.
*/
public int warningCount() {
return log.nwarnings;
}
/** Try to open input stream with given name.
* Report an error if this fails.
* @param filename The file name of the input stream to be opened.
*/
public CharSequence readSource(JavaFileObject filename) {
try {
inputFiles.add(filename);
return filename.getCharContent(false);
} catch (IOException e) {
log.error(MsgSym.MESSAGE_ERROR_READING_FILE, filename, e.getLocalizedMessage());
return null;
}
}
/** Parse contents of input stream.
* @param filename The name of the file from which input stream comes.
* @param input The input stream to be parsed.
*/
protected VisageScript parse(JavaFileObject filename, CharSequence content) {
long msec = now();
VisageScript tree = null;
if (content != null) {
if (verbose) {
printVerbose(MsgSym.MESSAGE_PARSING_STARTED, filename);
}
if (taskListener != null) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.PARSE, filename);
taskListener.started(e);
}
int initialErrorCount = log.nerrors;
// Parse the input, returning the AST
tree = syntacticAnalysis.parse(content, filename.getName());
parseErrors |= (log.nerrors > initialErrorCount);
if (tree != null && lineDebugInfo) {
String hunk = content.toString();
tree.lineMap = Position.makeLineMap(hunk.toCharArray(), hunk.length(), false);
}
}
if (verbose) {
printVerbose(MsgSym.MESSAGE_PARSING_DONE, Long.toString(elapsed(msec)));
}
// test shouldn't be needed when we have better error recovery
if (tree == null) {
// We have nothing, so make an empty module
tree = make.Script(null, List.<VisageTree>nil());
}
tree.sourcefile = filename;
printVisageSource("dumpvisage", tree, content);
if (content != null && taskListener != null) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.PARSE, tree);
taskListener.finished(e);
}
TreeXMLTransformer.afterParse(context, tree);
return tree;
}
// where
public boolean keepComments = false;
protected boolean keepComments() {
return keepComments || sourceOutput || stubOutput;
}
/** Parse contents of file.
* @param filename The name of the file to be parsed.
*/
public VisageScript parse(JavaFileObject filename) {
JavaFileObject prev = log.useSource(filename);
try {
VisageScript t = parse(filename, readSource(filename));
if (t.endPositions != null)
log.setEndPosTable(filename, t.endPositions);
return t;
} finally {
log.useSource(prev);
}
}
/** Emit Java-like source corresponding to translated tree.
*/
void printJavaSource(VisageEnv<VisageAttrContext> env) {
String dump = options.get("dumpjava");
if (dump != null) {
try {
String fn = env.toplevel.sourcefile.toString().replace(".visage", ".javadump");
File outFile = new File(dump, (new File(fn)).getName());
outFile.getParentFile().mkdirs();
FileWriter fw = new FileWriter(outFile);
BufferedWriter out = new BufferedWriter(fw);
try {
new JavaPretty(out, true, context).printUnit(env.translatedToplevel, null);
} finally {
out.close();
}
} catch (IOException ex) {
System.err.println("Exception thrown in Visage pretty printing: " + ex);
}
}
}
/** Emit Java-like source corresponding to translated tree.
*/
void printOptimizationStatistics() {
String which = options.get("optstats");
if (which != null) {
optStat.printData(which);
}
}
/** Emit pretty=printed visage source corresponding to an input file.
*/
void printVisageSource(String opt, VisageScript cu, CharSequence content) {
String dump = options.get(opt);
BufferedWriter out = null;
if (dump != null) {
try {
try {
String fn = cu.sourcefile.toString().replace(".visage", ".visagedump");
File outFile = new File(dump, (new File(fn)).getName());
FileWriter fw = new FileWriter(outFile);
out = new BufferedWriter(fw);
new VisagePretty(out, true, content).printUnit(cu);
} finally {
if (out != null) {
out.close();
}
}
} catch (IOException ex) {
System.err.println("Exception thrown in Visage pretty printing: " + ex);
}
}
}
/** Complete compiling a source file that has been accessed
* by the class file reader.
* @param c The class the source file of which needs to be compiled.
* @param filename The name of the source file.
* @param f An input stream that reads the source file.
*/
public void complete(ClassSymbol c) throws CompletionFailure {
// System.err.println("completing " + c);//DEBUG
if (completionFailureName == c.fullname) {
throw new CompletionFailure(c, "user-selected completion failure by class name");
}
VisageScript tree;
JavaFileObject filename = c.classfile;
JavaFileObject prev = log.useSource(filename);
try {
tree = parse(filename, filename.getCharContent(false));
} catch (IOException e) {
log.error(MsgSym.MESSAGE_ERROR_READING_FILE, filename, e);
tree = make.Script(null, List.<VisageTree>nil());
} finally {
log.useSource(prev);
}
if (taskListener != null) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.ENTER, tree);
taskListener.started(e);
}
enter.complete(List.of(tree), c);
if (taskListener != null) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.ENTER, tree);
taskListener.finished(e);
}
TreeXMLTransformer.afterEnter(context, tree, c);
if (enter.getEnv(c) == null) {
boolean isPkgInfo =
tree.sourcefile.isNameCompatible("package-info",
JavaFileObject.Kind.SOURCE);
if (isPkgInfo) {
if (enter.getEnv(tree.packge) == null) {
String msg
= Log.getLocalizedString(MsgSym.MESSAGE_FILE_DOES_NOT_CONTAIN_PACKAGE,
c.location());
throw new ClassReader.BadClassFile(c, filename, msg);
}
} else {
throw new
ClassReader.BadClassFile(c, filename, Log.
getLocalizedString(MsgSym.MESSAGE_FILE_DOES_NOT_CONTAIN_CLASS,
c.fullname));
}
}
implicitSourceFilesRead = true;
}
/** Track when the JavaCompiler has been used to compile something. */
private boolean hasBeenUsed = false;
private long start_msec = 0;
public long elapsed_msec = 0;
/** Track whether any errors occurred while parsing source text. */
private boolean parseErrors = false;
public void compile(List<JavaFileObject> sourceFileObject)
throws Throwable {
compile(sourceFileObject, List.<String>nil(), null, null, false);
}
/**
* Main method: compile a list of files, return all compiled classes
*
* @param sourceFileObjects file objects to be compiled
* @param classnames class names to process for annotations
* @param processors user provided annotation processors to bypass
* discovery, {@code null} means that no processors were provided
*/
public void compile(List<JavaFileObject> sourceFileObjects,
List<String> classnames,
Scope namedImportScope,
Scope starImportScope,
boolean preserveSymbols)
throws IOException // TODO: temp, from JavacProcessingEnvironment
{
// as a JavaCompiler can only be used once, throw an exception if
// it has been used before.
if (hasBeenUsed)
throw new AssertionError("attempt to reuse JavaCompiler");
hasBeenUsed = true;
start_msec = now();
try {
// Translate VisageTrees into Javac trees.
List<VisageScript> cus = stopIfError(parseFiles(sourceFileObjects));
// stopIfError(buildVisageModule(cus, sourceFileObjects));
if (namedImportScope != null)
cus.head.namedImportScope = namedImportScope;
if (starImportScope != null)
cus.head.starImportScope = starImportScope;
// These method calls must be chained to avoid memory leaks
enterTrees(cus);
compile2(null);
if (attr != null) {
attr.clearCaches();
}
close(! preserveSymbols);
} catch (Abort ex) {
if (devVerbose)
ex.printStackTrace();
}
}
public List<VisageEnv<VisageAttrContext>> visageToJava(List<VisageEnv<VisageAttrContext>> envs) {
ListBuffer<VisageEnv<VisageAttrContext>> results = lb();
for (List<VisageEnv<VisageAttrContext>> l = envs; l.nonEmpty(); l = l.tail) {
visageToJava(l.head, results);
}
return stopIfError(results);
}
public List<VisageEnv<VisageAttrContext>> visageToJava(VisageEnv<VisageAttrContext> env) {
ListBuffer<VisageEnv<VisageAttrContext>> results = lb();
visageToJava(env, results);
return stopIfError(results);
}
protected void visageToJava(final VisageEnv<VisageAttrContext> env, ListBuffer<VisageEnv<VisageAttrContext>> results) {
try {
if (errorCount() > 0)
return;
if (relax || deferredSugar.contains(env)) {
results.append(env);
return;
}
if (verboseCompilePolicy)
Log.printLines(log.noticeWriter, "[toJava " + env.enclClass.sym + "]");
JavaFileObject prev = log.useSource(
env.enclClass.sym.sourcefile != null ?
env.enclClass.sym.sourcefile :
env.toplevel.sourcefile);
try {
make.at(Position.FIRSTPOS);
visageToJava.toJava(env);
if (errorCount() > 0)
return;
results.append(env);
}
catch (RuntimeException ex) {
if (env.where != null)
log.note(env.where, MsgSym.MESSAGE_VISAGE_INTERNAL_ERROR,
VisageCompiler.fullVersion());
throw ex;
}
finally {
log.useSource(prev);
}
}
finally {
if (taskListener != null) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.ANALYZE, env.translatedToplevel, env.enclClass.sym);
taskListener.finished(e);
}
}
}
/**
* The phases following annotation processing: attribution,
* desugar, and finally code generation.
*/
private void compile2(ListBuffer<JavaFileObject> results) throws IOException {
try {
switch (compilePolicy) {
case ATTR_ONLY:
attribute(todo);
break;
case CHECK_ONLY:
backEnd(prepForBackEnd(visageToJava(varAnalysis(decomposeBinds(lower(attribute(todo)))))), results);
break;
case SIMPLE:
backEnd(prepForBackEnd(visageToJava(varAnalysis(decomposeBinds(lower(attribute(todo)))))), results);
break;
case BY_FILE: {
ListBuffer<VisageEnv<VisageAttrContext>> envbuff = ListBuffer.lb();
for (List<VisageEnv<VisageAttrContext>> list : groupByFile(visageToJava(varAnalysis(decomposeBinds(lower(attribute(todo)))))).values())
envbuff.appendList(prepForBackEnd(list));
backEnd(envbuff.toList(), results);
break;
}
case BY_TODO: {
ListBuffer<VisageEnv<VisageAttrContext>> envbuff = ListBuffer.lb();
while (todo.nonEmpty()) {
envbuff.append(attribute(todo.next()));
}
backEnd(prepForBackEnd(visageToJava(varAnalysis(decomposeBinds(lower(stopIfError(envbuff)))))), results);
break;
}
default:
assert false: "unknown compile policy";
}
} catch (Abort ex) {
if (devVerbose)
ex.printStackTrace();
}
if (verbose) {
elapsed_msec = elapsed(start_msec);
printVerbose(MsgSym.MESSAGE_TOTAL, Long.toString(elapsed_msec));
}
reportDeferredDiagnostics();
if (!log.hasDiagnosticListener()) {
printCount(MsgSym.MESSAGEPREFIX_ERROR, errorCount());
printCount(MsgSym.MESSAGEPREFIX_WARN, warningCount());
}
((VisageTypes) types).clearCaches();
}
/**
* Generate any files on the todo list. Called by VisagecTaskImpl.
*/
public void generate(List<VisageEnv<VisageAttrContext>> genlist, ListBuffer<JavaFileObject> results) throws IOException {
todo.appendList(genlist);
compile2(results);
}
private void backEnd(List<VisageEnv<VisageAttrContext>> envs, ListBuffer<JavaFileObject> results) throws IOException {
ListBuffer<JCCompilationUnit> javaTrees = lb();
for (VisageEnv<VisageAttrContext> env : envs) {
javaTrees.append(env.translatedToplevel);
}
PlatformPlugin plugin = PlatformPlugin.instance(context);
if (plugin != null) {
plugin.process(javaTrees);
if (Log.instance(context).nerrors > 0)
return;
}
visageJavaCompiler.backEnd(javaTrees.toList(), results);
}
/**
* Parses a list of files.
*/
public List<VisageScript> parseFiles(List<JavaFileObject> fileObjects) throws IOException {
if (errorCount() > 0)
return List.nil();
//parse all files
ListBuffer<VisageScript> trees = lb();
for (JavaFileObject fileObject : fileObjects)
trees.append(parse(fileObject));
return trees.toList();
}
/**
* Enter the symbols found in a list of parse trees.
* As a side-effect, this puts elements on the "todo" list.
* Also stores a list of all top level classes in rootClasses.
*/
public List<VisageScript> enterTrees(List<VisageScript> roots) {
//enter symbols for all files
if (taskListener != null) {
for (VisageScript unit: roots) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.ENTER, unit);
taskListener.started(e);
}
}
enter.main(roots);
if (taskListener != null) {
for (VisageScript unit: roots) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.ENTER, unit);
taskListener.finished(e);
}
}
//If generating source, remember the classes declared in
//the original compilation units listed on the command line.
if (sourceOutput || stubOutput) {
ListBuffer<VisageClassDeclaration> cdefs = lb();
for (VisageScript unit : roots) {
for (List<VisageTree> defs = unit.defs;
defs.nonEmpty();
defs = defs.tail) {
if (defs.head instanceof VisageClassDeclaration)
cdefs.append((VisageClassDeclaration)defs.head);
}
}
}
return roots;
}
/**
* Check for errors -- called by VisageTaskImpl.
*/
public void errorCheck() throws IOException {
backEnd(prepForBackEnd(visageToJava(varAnalysis(decomposeBinds(lower(attribute(todo)))))), null);
}
/**
* Attribute the existing VisageTodo list. Called by VisageTaskImpl.
*/
public List<VisageEnv<VisageAttrContext>> attribute() {
return attribute(todo);
}
/**
* Attribute a list of parse trees, such as found on the "todo" list.
* Note that attributing classes may cause additional files to be
* parsed and entered via the SourceCompleter.
* Attribution of the entries in the list does not stop if any errors occur.
* @returns a list of environments for attributd classes.
*/
public List<VisageEnv<VisageAttrContext>> attribute(ListBuffer<VisageEnv<VisageAttrContext>> envs) {
ListBuffer<VisageEnv<VisageAttrContext>> results = lb();
while (envs.nonEmpty())
results.append(attribute(envs.next()));
return results.toList();
}
/**
* Attribute a parse tree.
* @returns the attributed parse tree
*/
public VisageEnv<VisageAttrContext> attribute(VisageEnv<VisageAttrContext> env) {
if (verboseCompilePolicy)
Log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]");
if (verbose)
printVerbose(MsgSym.MESSAGE_CHECKING_ATTRIBUTION, env.enclClass.sym);
if (taskListener != null) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
taskListener.started(e);
}
JavaFileObject prev = log.useSource(
env.enclClass.sym.sourcefile != null ?
env.enclClass.sym.sourcefile :
env.toplevel.sourcefile);
try {
attr.attribClass(env.tree.pos(), env.tree instanceof VisageClassDeclaration ? (VisageClassDeclaration)env.tree : null,
env.enclClass.sym);
printVisageSource("dumpattr", env.toplevel, null);
}
finally {
log.useSource(prev);
}
if (taskListener != null) {
VisageTaskEvent e = new VisageTaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
taskListener.finished(e);
}
TreeXMLTransformer.afterAnalyze(context, env.toplevel, env.enclClass.sym);
return env;
}
public List<VisageEnv<VisageAttrContext>> decomposeBinds(List<VisageEnv<VisageAttrContext>> envs) {
for (List<VisageEnv<VisageAttrContext>> l = envs; l.nonEmpty(); l = l.tail) {
decomposeBinds(l.head);
}
return envs;
}
protected void decomposeBinds(VisageEnv<VisageAttrContext> env) {
try {
// Lower has smashed our analysis
bindAnalyzer.analyzeBindContexts(env);
if (verboseCompilePolicy)
Log.printLines(log.noticeWriter, "[decompose " + env.enclClass.sym + "]");
boundFill.fill(env);
printVisageSource("dumpfill", env.toplevel, null);
// VisageLocalToClass needs var analysis info
varUsageAnalysis.analyzeVarUse(env);
localToClass.inflateAsNeeded(env);
printVisageSource("dumpinflate", env.toplevel, null);
decomposeBindExpressions.decompose(env);
printVisageSource("dumpdecompose", env.toplevel, null);
} catch (RuntimeException ex) {
if (env.where != null) {
log.note(env.where, MsgSym.MESSAGE_VISAGE_INTERNAL_ERROR,
VisageCompiler.fullVersion());
}
throw ex;
}
}
/**
* Analyze variable usage.
* @returns the list of attributed parse trees
*/
public List<VisageEnv<VisageAttrContext>> varAnalysis(List<VisageEnv<VisageAttrContext>> envs) {
for (List<VisageEnv<VisageAttrContext>> l = envs; l.nonEmpty(); l = l.tail) {
varAnalysis(l.head);
}
return envs;
}
/**
* Morph types.
* @returns the attributed parse tree
*/
public VisageEnv<VisageAttrContext> varAnalysis(VisageEnv<VisageAttrContext> env) {
if (verboseCompilePolicy)
Log.printLines(log.noticeWriter, "[type-morph " + env.enclClass.sym + "]");
JavaFileObject prev = log.useSource(
env.enclClass.sym.sourcefile != null ?
env.enclClass.sym.sourcefile :
env.toplevel.sourcefile);
try {
varUsageAnalysis.analyzeVarUse(env);
}
finally {
log.useSource(prev);
}
return env;
}
/**
* Normalize tree before translation
* @returns the list of attributed parse trees
*/
public List<VisageEnv<VisageAttrContext>> lower(List<VisageEnv<VisageAttrContext>> envs) {
for (List<VisageEnv<VisageAttrContext>> l = envs; l.nonEmpty(); l = l.tail) {
lower(l.head);
}
return envs;
}
/**
* Normalize tree before translation
* @returns the attributed parse tree
*/
public VisageEnv<VisageAttrContext> lower(VisageEnv<VisageAttrContext> env) {
if (verboseCompilePolicy)
Log.printLines(log.noticeWriter, "[lower " + env.enclClass.sym + "]");
JavaFileObject prev = log.useSource(
env.enclClass.sym.sourcefile != null ?
env.enclClass.sym.sourcefile :
env.toplevel.sourcefile);
try {
convertTypes.lower(env);
printVisageSource("dumplower", env.toplevel, null);
}
finally {
log.useSource(prev);
}
return env;
}
public List<VisageEnv<VisageAttrContext>> prepForBackEnd(List<VisageEnv<VisageAttrContext>> envs) {
printOptimizationStatistics();
for (List<VisageEnv<VisageAttrContext>> l = envs; l.nonEmpty(); l = l.tail) {
prepForBackEnd(l.head);
}
return envs;
}
public VisageEnv<VisageAttrContext> prepForBackEnd(VisageEnv<VisageAttrContext> env) {
if (verboseCompilePolicy)
Log.printLines(log.noticeWriter, "[prep-for-back-end " + env.enclClass.sym + "]");
printJavaSource(env);
JavaFileObject prev = log.useSource(
env.enclClass.sym.sourcefile != null ?
env.enclClass.sym.sourcefile :
env.toplevel.sourcefile);
try {
prepForBackEnd.prep(env);
}
finally {
log.useSource(prev);
}
return env;
}
// where
Map<VisageScript, List<VisageEnv<VisageAttrContext>>> groupByFile(List<VisageEnv<VisageAttrContext>> list) {
// use a LinkedHashMap to preserve the order of the original list as much as possible
Map<VisageScript, List<VisageEnv<VisageAttrContext>>> map = new LinkedHashMap<VisageScript, List<VisageEnv<VisageAttrContext>>>();
Set<VisageScript> fixupSet = new HashSet<VisageScript>();
for (List<VisageEnv<VisageAttrContext>> l = list; l.nonEmpty(); l = l.tail) {
VisageEnv<VisageAttrContext> env = l.head;
List<VisageEnv<VisageAttrContext>> sublist = map.get(env.toplevel);
if (sublist == null)
sublist = List.of(env);
else {
// this builds the list for the file in reverse order, so make a note
// to reverse the list before returning.
sublist = sublist.prepend(env);
fixupSet.add(env.toplevel);
}
map.put(env.toplevel, sublist);
}
// fixup any lists that need reversing back to the correct order
for (VisageScript tree: fixupSet)
map.put(tree, map.get(tree).reverse());
return map;
}
public void reportDeferredDiagnostics() {
chk.reportDeferredDiagnostics();
}
/** Close the compiler, flushing the logs
*/
public void close() {
close(true);
}
private void close(boolean disposeNames) {
make = null;
writer = null;
enter = null;
if (todo != null)
todo.clear();
todo = null;
syms = null;
source = null;
attr = null;
chk = null;
annotate = null;
types = null;
log.flush();
try {
fileManager.flush();
} catch (IOException e) {
throw new Abort(e);
} finally {
if (names != null && disposeNames)
names.dispose();
names = null;
}
}
/** Output for "-verbose" option.
* @param key The key to look up the correct internationalized string.
* @param arg An argument for substitution into the output string.
*/
protected void printVerbose(String key, Object arg) {
Log.printLines(log.noticeWriter, Log.getLocalizedString(MsgSym.MESSAGEPREFIX_VERBOSE + key, arg));
}
/** Print numbers of errors and warnings.
*/
protected void printCount(String kind, int count) {
if (count != 0) {
String text;
if (count == 1)
text = Log.getLocalizedString(MsgSym.MESSAGEPREFIX_COUNT + kind, String.valueOf(count));
else
text = Log.getLocalizedString(MsgSym.MESSAGEPREFIX_COUNT + kind + MsgSym.MESSAGESUFFIX_PLURAL, String.valueOf(count));
Log.printLines(log.errWriter, text);
log.errWriter.flush();
}
}
private static long now() {
return System.currentTimeMillis();
}
private static long elapsed(long then) {
return now() - then;
}
public void initRound(VisageCompiler prev) {
keepComments = prev.keepComments;
start_msec = prev.start_msec;
hasBeenUsed = true;
}
public static void enableLogging() {
Logger logger = Logger.getLogger(com.sun.tools.mjavac.Main.class.getPackage().getName());
logger.setLevel(Level.ALL);
for (Handler h : logger.getParent().getHandlers()) {
h.setLevel(Level.ALL);
}
}
protected void registerServices(final Context context) {
TreeXMLTransformer.preRegister(context);
// if fileManager not already set, register the JavacFileManager to be used
if (context.get(JavaFileManager.class) == null) {
org.visage.tools.util.VisageFileManager.preRegister(context);
}
org.visage.tools.code.VisageSymtab.preRegister(context);
org.visage.tools.code.VisageTypes.preRegister(context);
}
}