/*
* 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.api;
import org.visage.api.VisageTaskEvent;
import org.visage.api.VisageTaskListener;
import org.visage.api.VisagecTask;
import org.visage.api.tree.Tree;
import org.visage.api.tree.UnitTree;
import com.sun.tools.mjavac.model.JavacElements;
import com.sun.tools.mjavac.model.JavacTypes;
import com.sun.tools.mjavac.code.Scope;
import com.sun.tools.mjavac.util.ClientCodeException;
import com.sun.tools.mjavac.util.Context;
import com.sun.tools.mjavac.util.List;
import com.sun.tools.mjavac.util.ListBuffer;
import com.sun.tools.mjavac.util.Options;
import org.visage.tools.comp.VisageAttrContext;
import org.visage.tools.comp.VisageEnv;
import org.visage.tools.main.CommandLine;
import org.visage.tools.main.Main;
import org.visage.tools.tree.VisageScript;
import org.visage.tools.tree.VisageTree;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.lang.model.type.TypeMirror;
import javax.tools.JavaFileObject;
/**
* Visage implementation of a Visage compilation task, based on
* JavacTaskImpl. This class extends VisageTask to isolate the internal
* visage and javac compiler API from the public API.
*
* @see com.sun.tools.mjavac.api.JavacTaskImpl
* @author tball
*/
public class VisagecTaskImpl extends VisagecTask {
public Main compilerMain;
private org.visage.tools.main.VisageCompiler compiler;
private String[] args;
private Context context;
private List<JavaFileObject> fileObjects;
private Map<JavaFileObject, VisageScript> notYetEntered;
private List<VisageScript> units;
private VisageTaskListener taskListener;
private AtomicBoolean used = new AtomicBoolean();
private Integer result = null;
private List<VisageEnv<VisageAttrContext>> genList;
boolean preserveSymbols;
Scope namedImportScope;
Scope starImportScope;
VisagecTaskImpl(VisagecTool tool, Main compilerMain, String[] args, Context context, List<JavaFileObject> fileObjects) {
this.compilerMain = compilerMain;
this.args = args;
this.context = context;
this.fileObjects = fileObjects;
// null checks
compilerMain.getClass();
args.getClass();
context.getClass();
fileObjects.getClass();
Options optionTable = Options.instance(context);
optionTable.put("-Xjcov", "-Xjcov"); // generate tree end positions
}
VisagecTaskImpl(VisagecTool tool,
Main compilerMain,
Iterable<String> flags,
Context context,
Iterable<? extends JavaFileObject> fileObjects) {
this(tool, compilerMain, toArray(flags), context, toList(fileObjects));
}
static private String[] toArray(Iterable<String> flags) {
ListBuffer<String> result = new ListBuffer<String>();
if (flags != null)
for (String flag : flags)
result.append(flag);
return result.toArray(new String[result.length()]);
}
static private List<JavaFileObject> toList(Iterable<? extends JavaFileObject> fileObjects) {
if (fileObjects == null)
return List.nil();
ListBuffer<JavaFileObject> result = new ListBuffer<JavaFileObject>();
for (JavaFileObject fo : fileObjects)
result.append(fo);
return result.toList();
}
public Boolean call() {
if (!used.getAndSet(true)) {
beginContext();
try {
result = compilerMain.compile(args, context,
namedImportScope, starImportScope, preserveSymbols, fileObjects);
} finally {
endContext();
}
compilerMain = null;
args = null;
context = null;
fileObjects = null;
return result == 0;
} else {
throw new IllegalStateException("multiple calls to method 'call'");
}
}
private boolean compilationInProgress = false;
private void prepareCompiler() throws IOException {
if (!used.getAndSet(true)) {
beginContext();
compilerMain.registerServices(context, args);
compilerMain.setOptions(Options.instance(context));
compilerMain.filenames = new ListBuffer<File>();
List<File> filenames = compilerMain.processArgs(CommandLine.parse(args));
if (!filenames.isEmpty())
throw new IllegalArgumentException("Malformed arguments " + filenames.toString(" "));
compiler = org.visage.tools.main.VisageCompiler.instance(context);
compiler.keepComments = true;
notYetEntered = new HashMap<JavaFileObject, VisageScript>();
for (JavaFileObject file: fileObjects)
notYetEntered.put(file, null);
args = null;
genList = List.<VisageEnv<VisageAttrContext>>nil();
}
}
private void beginContext() {
context.put(VisagecTaskImpl.class, this);
if (context.get(VisageTaskListener.class) != null) {
context.put(VisageTaskListener.class, (VisageTaskListener) null);
}
if (taskListener != null) {
context.put(VisageTaskListener.class, wrap(taskListener));
}
if (compilationInProgress) {
throw new IllegalStateException("Compilation in progress");
}
compilationInProgress = true;
}
private VisageTaskListener wrap(final VisageTaskListener tl) {
tl.getClass(); // null check
return new VisageTaskListener() {
public void started(VisageTaskEvent e) {
try {
tl.started(e);
} catch (Throwable t) {
throw new ClientCodeException(t);
}
}
public void finished(VisageTaskEvent e) {
try {
tl.finished(e);
} catch (Throwable t) {
throw new ClientCodeException(t);
}
}
};
}
private void endContext() {
compilationInProgress = false;
}
public Iterable<? extends UnitTree> parse() throws IOException {
try {
prepareCompiler();
units = compiler.parseFiles(fileObjects);
for (VisageScript unit: units) {
JavaFileObject file = unit.getSourceFile();
if (notYetEntered.containsKey(file))
notYetEntered.put(file, unit);
}
return units;
}
finally {
parsed = true;
if (compiler != null && compiler.log != null)
compiler.log.flush();
}
}
private boolean parsed = false;
void enter() throws IOException {
prepareCompiler();
ListBuffer<VisageScript> roots = null;
if (notYetEntered.size() > 0) {
if (!parsed)
parse();
for (JavaFileObject file: fileObjects) {
VisageScript unit = notYetEntered.remove(file);
if (unit != null) {
if (roots == null)
roots = new ListBuffer<VisageScript>();
roots.append(unit);
}
}
notYetEntered.clear();
}
if (roots != null)
try {
compiler.enterTrees(roots.toList());
}
finally {
if (compiler != null && compiler.log != null)
compiler.log.flush();
}
}
public Iterable<? extends UnitTree> analyze() throws IOException {
try {
enter();
genList = genList.appendList(compiler.attribute());
return units;
} finally {
if (compiler != null && compiler.log != null)
compiler.log.flush();
}
}
public int errorCheck() throws IOException {
try {
enter();
compiler.errorCheck();
} finally {
if (compiler != null && compiler.log != null)
compiler.log.flush();
}
return compiler.errorCount();
}
public Iterable<? extends JavaFileObject> generate() throws IOException {
analyze();
final ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
compiler.generate(genList, results);
return results;
}
public void setTaskListener(VisageTaskListener taskListener) {
this.taskListener = taskListener;
}
public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
if (path == null)
return null;
Tree last = null;
for (Tree node : path) {
last = node;
}
return ((VisageTree) last).type;
}
public JavacElements getElements() {
if (context == null) {
throw new IllegalStateException();
}
return JavacElements.instance(context);
}
public JavacTypes getTypes() {
if (context == null) {
throw new IllegalStateException();
}
return JavacTypes.instance(context);
}
/**
* For internal use by Sun Microsystems only. This method will be
* removed without warning.
*/
public Context getContext() {
return context;
}
public void setPreserveSymbols(Scope namedImportScope, Scope starImportScope, boolean preserve) {
this.preserveSymbols = preserve;
this.namedImportScope = namedImportScope;
this.starImportScope = starImportScope;
}
}