package edu.ucsd.arcum.builders;
import static edu.ucsd.arcum.ArcumPlugin.DEBUG;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import edu.ucsd.arcum.ArcumPlugin;
import edu.ucsd.arcum.exceptions.ArcumError;
import edu.ucsd.arcum.exceptions.FatalArcumError;
import edu.ucsd.arcum.exceptions.SourceLocation;
import edu.ucsd.arcum.exceptions.UserCompilationProblem;
import edu.ucsd.arcum.interpreter.query.ArcumDeclarationTable;
import edu.ucsd.arcum.interpreter.query.OptionMatchTable;
import edu.ucsd.arcum.ui.UIUtil;
import edu.ucsd.arcum.util.SystemUtil;
public class ArcumBuilder extends IncrementalProjectBuilder
{
public ArcumBuilder() {
if (DEBUG) {
System.out.printf("Creating a new builder! %d%n",
System.identityHashCode(this));
}
}
public static ArcumDeclarationTable reparseArcumCode(IProject project, IProgressMonitor monitor)
throws CoreException
{
if (UIUtil.getNumberOfErrors(project) > 0) {
throw new FatalArcumError("Project has errors, abort operation");
}
System.out.printf("Reparsing Arcum code in %s%n", project.getName());
ArcumDeclarationTable symbTab = ArcumDeclarationTable.newSymbolTable(project);
monitor.beginTask("Compiling Arcum Source Files", IProgressMonitor.UNKNOWN);
ArcumSourceBuilder arcumSourceBuilder = new ArcumSourceBuilder(symbTab, monitor);
project.accept(arcumSourceBuilder, 0);
if (arcumSourceBuilder.getNumberOfErrors() == 0) {
symbTab.typeCheck();
}
else {
ArcumError.stop();
}
return symbTab;
}
@Override
protected IProject[] build(final int kind, Map args, IProgressMonitor monitor)
throws CoreException
{
IWorkspaceRunnable doBuild = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
try {
if (kind == IncrementalProjectBuilder.FULL_BUILD) {
fullBuild(monitor);
}
else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor);
}
else {
incrementalBuild(delta, monitor);
}
}
}
catch (ArcumError e) {
e.printStackTrace(System.out);
e.printStackTrace(SystemUtil.getOutStream());
}
catch (CoreException e) {
e.printStackTrace(System.err);
e.printStackTrace(SystemUtil.getErrStream());
throw e;
}
catch (RuntimeException e) {
e.printStackTrace(System.err);
e.printStackTrace(SystemUtil.getErrStream());
throw e;
}
}
};
ResourcesPlugin.getWorkspace().run(doBuild, null, IWorkspace.AVOID_UPDATE, monitor);
return null;
}
// Note that this fullBuild pass already assumes that the Java builder has
// done its passes, which may have either been full or incremental.
private void fullBuild(IProgressMonitor monitor) throws CoreException {
if (DEBUG) System.out.printf("Starting fullBuild%n");
IProject project = getProject();
deleteArcumMarkers(project);
try {
ArcumDeclarationTable symbTab = reparseArcumCode(project, monitor);
List<OptionMatchTable> matchedEntities = symbTab.makeEntityTables();
// XXX (!!!): I believe this is redundant, but maybe there was a reason for it
// for (OptionMatchTable entityTable: matchedEntities) {
// entityTable.checkExtraDefinitionConditions();
// }
}
catch (UserCompilationProblem ucp) {
SourceLocation position = ucp.getPosition();
ArcumError.fatalUserError(position, "%s", ucp.getMessage());
}
finally {
monitor.done();
}
}
private static void deleteArcumMarkers(IProject project) {
try {
project.deleteMarkers(ArcumPlugin.MARKER_ID, false, IResource.DEPTH_INFINITE);
}
catch (CoreException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor)
throws CoreException
{
System.out.printf("Starting incrementalBuild%n");
// we still do a "fullBuild" of the .arcum files, but the delta visitor
// makes sure the needed Java files get new ASTs MACNEIL: in the future
// when only one AST at a time is stored in memory the two types of
// builds will be more similar
delta.accept(new ArcumBuildDeltaVisitor());
fullBuild(monitor);
}
protected void startupOnInitialize() {
// add builder init logic here
}
protected void clean(IProgressMonitor monitor) {
// add builder clean logic here
deleteArcumMarkers(getProject());
}
}