package org.sugarj.driver;
import static org.sugarj.common.ATermCommands.fixSDF;
import static org.sugarj.common.ATermCommands.getApplicationSubterm;
import static org.sugarj.common.ATermCommands.isApplication;
import static org.sugarj.common.Log.log;
import static org.sugarj.driver.SDFCommands.extractSDF;
import static org.sugarj.driver.STRCommands.extractEditor;
import static org.sugarj.driver.STRCommands.extractSTR;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.ParseException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.spoofax.interpreter.terms.IStrategoAppl;
import org.spoofax.interpreter.terms.IStrategoList;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.jsglr.client.ITreeBuilder;
import org.spoofax.jsglr.client.InvalidParseTableException;
import org.spoofax.jsglr.client.ParseTable;
import org.spoofax.jsglr.client.SGLR;
import org.spoofax.jsglr.client.imploder.ImploderAttachment;
import org.spoofax.jsglr.client.imploder.TreeBuilder;
import org.spoofax.jsglr.shared.BadTokenException;
import org.spoofax.jsglr.shared.SGLRException;
import org.spoofax.jsglr.shared.TokenExpectedException;
import org.spoofax.terms.Term;
import org.strategoxt.HybridInterpreter;
import org.strategoxt.lang.StrategoException;
import org.sugarj.AbstractBaseLanguage;
import org.sugarj.AbstractBaseProcessor;
import org.sugarj.common.ATermCommands;
import org.sugarj.common.ATermCommands.PrettyPrintError;
import org.sugarj.common.CommandExecution;
import org.sugarj.common.Environment;
import org.sugarj.common.FileCommands;
import org.sugarj.common.Log;
import org.sugarj.common.StringCommands;
import org.sugarj.common.errors.SourceCodeException;
import org.sugarj.common.errors.SourceLocation;
import org.sugarj.common.path.AbsolutePath;
import org.sugarj.common.path.Path;
import org.sugarj.common.path.RelativePath;
import org.sugarj.driver.caching.ModuleKeyCache;
import org.sugarj.driver.declprovider.SourceToplevelDeclarationProvider;
import org.sugarj.driver.declprovider.TermToplevelDeclarationProvider;
import org.sugarj.driver.declprovider.ToplevelDeclarationProvider;
import org.sugarj.driver.transformations.primitive.SugarJPrimitivesLibrary;
import org.sugarj.stdlib.StdLib;
import org.sugarj.util.Pair;
import org.sugarj.util.ProcessingListener;
import org.sugarj.util.Renaming;
/**
* @author Sebastian Erdweg <seba at informatik uni-marburg de>
*/
public class Driver{
private final static int PENDING_TIMEOUT = 30000;
private static Map<Path, Entry<ToplevelDeclarationProvider, Driver>> pendingRuns = new HashMap<Path, Map.Entry<ToplevelDeclarationProvider,Driver>>();
private static List<Path> pendingInputFiles = new ArrayList<Path>();
private static List<ProcessingListener> processingListener = new LinkedList<ProcessingListener>();
private List<Driver> currentlyProcessing;
private Set<Path> circularLinks = new HashSet<Path>();
private boolean dependsOnModel = false;
private IProgressMonitor monitor;
private Environment environment;
private Result driverResult;
private Path depOutFile;
private RelativePath sourceFile;
private ToplevelDeclarationProvider declProvider;
private Path currentGrammarSDF;
private String currentGrammarModule;
private Path currentTransSTR;
private String currentTransModule;
private List<String> availableSDFImports;
private List<String> availableSTRImports;
private List<IStrategoTerm> sugaredBodyDecls = new ArrayList<IStrategoTerm>();
private List<IStrategoTerm> desugaredBodyDecls = new ArrayList<IStrategoTerm>();
private IStrategoTerm lastSugaredToplevelDecl;
private SGLR sdfParser;
private SGLR strParser;
private SGLR editorServicesParser;
private SGLR parser;
/**
* cache location -> base language -> cache
*/
private static Map<Path, Map<String,ModuleKeyCache<Path>>> sdfCaches;
private static Map<Path, Map<String,ModuleKeyCache<Path>>> strCaches;
private ModuleKeyCache<Path> sdfCache;
private ModuleKeyCache<Path> strCache;
private Path currentGrammarTBL;
private Path currentTransProg;
private boolean interrupt = false;
private boolean inDesugaredDeclList;
private AbstractBaseLanguage baseLanguage;
private AbstractBaseProcessor baseProcessor;
private boolean definesNonBaseDec = false;
public Driver(Environment env, AbstractBaseLanguage baseLang, List<Driver> currentlyProcessing) {
this.environment = env;
this.baseLanguage = baseLang;
this.baseProcessor = baseLang.createNewProcessor();
this.currentlyProcessing = currentlyProcessing;
this.driverResult = new Result(env.doGenerateFiles() ? null : env.getParseBin());
baseProcessor.setInterpreter(new HybridInterpreter());
baseProcessor.getInterpreter().addOperatorRegistry(new SugarJPrimitivesLibrary(this, environment, driverResult, monitor));
try {
if (environment.getCacheDir() != null)
FileCommands.createDir(environment.getCacheDir());
initializeCaches(environment, false);
sdfCache = selectCache(sdfCaches, baseLang, environment);
strCache = selectCache(strCaches, baseLang, environment);
} catch (IOException e) {
throw new RuntimeException("error while initializing driver", e);
}
}
private static synchronized Entry<ToplevelDeclarationProvider, Driver> getPendingRun(Path file) {
return pendingRuns.get(file);
}
private static synchronized void putPendingRun(Path file, ToplevelDeclarationProvider declProvider, Driver driver) {
pendingRuns.put(file, new AbstractMap.SimpleImmutableEntry<ToplevelDeclarationProvider, Driver>(declProvider, driver));
}
public static synchronized void addProcessingDoneListener(ProcessingListener listener) {
processingListener.add(listener);
}
public static synchronized void removeProcessingDoneListener(ProcessingListener listener) {
processingListener.remove(listener);
}
private static void waitForPending(Path file) {
int count = 0;
Object lock = new Object();
synchronized (lock) {
while (true) {
synchronized (pendingRuns) {
if (!pendingRuns.containsKey(file))
return;
}
if (count > PENDING_TIMEOUT)
throw new IllegalStateException("pending result timed out for " + file);
count += 100;
try {
lock.wait(100);
} catch (InterruptedException e) {
}
}
}
}
public static Result run(RelativePath sourceFile, Environment env, IProgressMonitor monitor, AbstractBaseLanguage baseLang) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
return run(sourceFile, env, monitor, baseLang, new LinkedList<Driver>());
}
public static Result run(RelativePath sourceFile, Environment env, IProgressMonitor monitor, AbstractBaseLanguage baseLang, List<Driver> currentlyProcessing) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
return run(FileCommands.readFileAsString(sourceFile), sourceFile, env, monitor, baseLang, currentlyProcessing);
}
public static Result run(String source, RelativePath sourceFile, Environment env, IProgressMonitor monitor, AbstractBaseLanguage baseLang) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
return run(source, sourceFile, env, monitor, baseLang, new LinkedList<Driver>());
}
public static Result run(String source, RelativePath sourceFile, Environment env, IProgressMonitor monitor, AbstractBaseLanguage baseLang, List<Driver> currentlyProcessing) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
Driver driver = new Driver(env, baseLang, currentlyProcessing);
return run(driver, new SourceToplevelDeclarationProvider(driver, source), sourceFile, monitor);
}
public static Result run(IStrategoTerm source, RelativePath sourceFile, Environment env, IProgressMonitor monitor, AbstractBaseLanguage baseLang, List<Driver> currentlyProcessing) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
Driver driver = new Driver(env, baseLang, currentlyProcessing);
return run(driver, new TermToplevelDeclarationProvider(source), sourceFile, monitor);
}
private static Result run(Driver driver, ToplevelDeclarationProvider declProvider, RelativePath sourceFile, IProgressMonitor monitor) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
Entry<ToplevelDeclarationProvider, Driver> pending = null;
String modulePath = FileCommands.dropExtension(sourceFile.getRelativePath());
pending = getPendingRun(sourceFile);
if (pending != null && !pending.getKey().equals(declProvider) && pending.getValue().environment.doGenerateFiles() == driver.environment.doGenerateFiles()) {
log.log("interrupting " + sourceFile, Log.CORE);
pending.getValue().interrupt();
}
if (pending == null) {
Result result = ModuleSystemCommands.locateResult(modulePath, driver.environment);
boolean isUpToDate = result != null && result.isUpToDate(declProvider.getSourceHashCode(), driver.environment);
if (isUpToDate) {
if (driver.environment.doGenerateFiles() && result.isParseResult()) {
Log.log.beginTask("Moving result", Log.DETAIL);
try {
result = result.moveTo(driver.environment.getBin(), false);
} finally {
Log.log.endTask();
}
}
if (driver.environment.doGenerateFiles() || result.getSugaredSyntaxTree() != null)
return result;
}
}
if (pending == null)
putPendingRun(sourceFile, declProvider, driver);
if (pending != null) {
waitForPending(sourceFile);
return run(driver, declProvider, sourceFile, monitor);
}
try {
synchronized (processingListener) {
for (ProcessingListener listener : processingListener)
listener.processingStarts(sourceFile);
}
driver.process(declProvider, sourceFile, monitor);
Driver.storeCaches(driver.environment);
synchronized (processingListener) {
for (ProcessingListener listener : processingListener)
listener.processingDone(driver.driverResult);
}
} catch (InterruptedException e) {
// nothing
} catch (Exception e) {
org.strategoxt.imp.runtime.Environment.logException(e);
} finally {
pendingRuns.remove(sourceFile);
if (!driver.environment.doGenerateFiles()) {
Path binDep = new RelativePath(driver.environment.getCompileBin(), modulePath + ".dep");
Result.cacheInMemory(binDep, driver.driverResult);
}
}
return driver.driverResult;
}
private void init(ToplevelDeclarationProvider declProvider, RelativePath sourceFile, IProgressMonitor monitor) throws FileNotFoundException, IOException, InvalidParseTableException {
this.monitor = monitor;
environment.addToIncludePath(new AbsolutePath(baseLanguage.getPluginDirectory().getAbsolutePath()));
depOutFile = null;
this.sourceFile = sourceFile;
this.declProvider = declProvider;
currentGrammarSDF = baseLanguage.getInitGrammar();
currentGrammarModule = baseLanguage.getInitGrammarModuleName();
currentTransSTR = baseLanguage.getInitTrans();
currentTransModule = baseLanguage.getInitTransModuleName();
// list of imports that contain SDF extensions
availableSDFImports = new ArrayList<String>();
availableSDFImports.add(baseLanguage.getInitGrammarModuleName());
// list of imports that contain Stratego extensions
availableSTRImports = new ArrayList<String>();
availableSTRImports.add(baseLanguage.getInitTransModuleName());
sdfParser = new SGLR(new TreeBuilder(), ATermCommands.parseTableManager.loadFromFile(StdLib.sdfTbl.getAbsolutePath()));
strParser = new SGLR(new TreeBuilder(), ATermCommands.parseTableManager.loadFromFile(StdLib.strategoTbl.getAbsolutePath()));
editorServicesParser = new SGLR(new TreeBuilder(), ATermCommands.parseTableManager.loadFromFile(StdLib.editorServicesTbl.getAbsolutePath()));
}
/**
* Process the given Extensible Java file.
*
* @throws IOException
* @throws SGLRException
* @throws InvalidParseTableException
* @throws ParseException
* @throws TokenExpectedException
* @throws InterruptedException
*/
private void process(ToplevelDeclarationProvider declProvider, RelativePath sourceFile, IProgressMonitor monitor) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
if (sourceFile == null)
throw new IllegalArgumentException("Required source file argument was null.");
List<Renaming> originalRenamings = new LinkedList<Renaming>(environment.getRenamings());
currentlyProcessing.add(this);
log.beginTask("processing", "Process " + sourceFile.getRelativePath(), Log.CORE);
boolean success = false;
try {
init(declProvider, sourceFile, monitor);
driverResult.setSourceFile(this.sourceFile, declProvider.getSourceHashCode());
baseProcessor.init(sourceFile, environment);
depOutFile = environment.createOutPath(FileCommands.dropExtension(sourceFile.getRelativePath()) + ".dep");
Path genLog = environment.createOutPath(FileCommands.dropExtension(sourceFile.getRelativePath()) + ".gen");
driverResult.setGenerationLog(genLog);
// clearGeneratedStuff();
initEditorServices();
boolean done = false;
while (!done) {
stepped();
// PARSE the next top-level declaration
lastSugaredToplevelDecl = declProvider.getNextToplevelDecl(true, false);
stepped();
IStrategoTerm analyzed = currentAnalyze(lastSugaredToplevelDecl);
analyzed = ATermCommands.copyTokens(lastSugaredToplevelDecl, analyzed);
lastSugaredToplevelDecl = analyzed;
stepped();
// DESUGAR the parsed top-level declaration
IStrategoTerm desugared = currentDesugar(analyzed);
stepped();
// RENAME the desugared top-level declaration
IStrategoTerm renamed = currentRename(desugared);
stepped();
// PROCESS the assimilated top-level declaration
processToplevelDeclaration(renamed);
done = !declProvider.hasNextToplevelDecl();
}
stepped();
// check final grammar and transformation for errors
if (!environment.isNoChecking()) {
checkCurrentGrammar();
}
stepped();
// need to build current transformation program for editor services
checkCurrentTransformation();
stepped();
// GENERATE model
generateModel();
// COMPILE the generated java file
if (circularLinks.isEmpty())
compileGeneratedFiles();
else {
Result delegate = null;
for (Driver dr : currentlyProcessing)
if (circularLinks.contains(dr.sourceFile)) {
delegate = dr.driverResult;
break;
}
if (delegate != null)
driverResult.delegateCompilation(delegate, baseProcessor.getGeneratedSourceFile(), baseProcessor.getGeneratedSource(), definesNonBaseDec);
else if (!dependsOnModel)
throw new IllegalStateException("Could not delegate compilation of circular dependency to other compiler instance.");
}
driverResult.setSugaredSyntaxTree(makeSugaredSyntaxTree());
driverResult.setDesugaredSyntaxTree(makeDesugaredSyntaxTree());
if (currentGrammarTBL != null)
driverResult.registerParseTable(currentGrammarTBL);
if (currentTransProg != null) {
driverResult.addEditorService(
ATermCommands.atermFromString(
"Builders(\"sugarj checking\", [SemanticObserver(Strategy(\"sugarj-analyze\"))])"));
driverResult.registerEditorDesugarings(currentTransProg);
}
driverResult.writeDependencyFile(depOutFile);
success = true;
}
finally {
log.endTask(success, "done processing " + sourceFile, "failed to process " + sourceFile);
driverResult.setFailed(!success);
currentlyProcessing.remove(this);
environment.setRenamings(originalRenamings);
}
}
private void compileGeneratedFiles() throws IOException {
boolean good = false;
log.beginTask("compilation", "COMPILE generated " + baseProcessor.getLanguage().getLanguageName() + " files", Log.CORE);
try {
try {
baseProcessor.compile(
baseProcessor.getGeneratedSourceFile(),
baseProcessor.getGeneratedSource(),
environment.getBin(),
new ArrayList<Path>(environment.getIncludePath()),
driverResult.getDeferredSourceFiles(),
driverResult.getGeneratedFileHashes());
} catch (ClassNotFoundException e) {
setErrorMessage("Could not resolve imported class " + e.getMessage());
} catch (SourceCodeException e) {
for (Pair<SourceLocation, String> err : e.getErrors())
setErrorMessage(err.b + " lines " + err.a.lineStart + "-" + err.a.lineEnd
+ " columns " + err.a.columnStart + "-" + err.a.columnEnd);
}
good = true;
} finally {
log.endTask(good, "compilation succeeded", "compilation failed");
}
}
private void processToplevelDeclaration(IStrategoTerm toplevelDecl) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException {
try {
if (baseLanguage.isImportDecl(toplevelDecl) || baseLanguage.isTransformationApplication(toplevelDecl)) {
if (inDesugaredDeclList || !environment.isAtomicImportParsing())
processImportDec(toplevelDecl);
else
processImportDecs(toplevelDecl);
}
else if (baseLanguage.isBaseDecl(toplevelDecl)) {
List<String> additionalModules = processLanguageDec(toplevelDecl);
for (String module : additionalModules) {
prepareImport(toplevelDecl, module);
Path clazz = ModuleSystemCommands.importBinFile(module, environment, baseProcessor, driverResult);
if (clazz == null)
setErrorMessage(toplevelDecl, "Could not resolve required module " + module);
}
}
else if (baseLanguage.isExtensionDecl(toplevelDecl))
processExtensionDec(toplevelDecl);
else if (baseLanguage.isPlainDecl(toplevelDecl)) // XXX: Decide what to do
// with "Plain"--leave in
// the language or create
// a new "Plain" language
processPlainDec(toplevelDecl);
else if (baseLanguage.isTransformationDec(toplevelDecl))
processTransformationDec(toplevelDecl);
else if (baseLanguage.isModelDec(toplevelDecl))
processModelDec(toplevelDecl);
else if (ATermCommands.isList(toplevelDecl)) {
/*
* Desugarings may generate lists of toplevel declarations.
*/
List<IStrategoTerm> list = ATermCommands.getList(toplevelDecl);
// sortForImports(list);
boolean old = inDesugaredDeclList;
inDesugaredDeclList = true;
try {
for (IStrategoTerm term : list)
processToplevelDeclaration(term);
} finally {
inDesugaredDeclList = old;
}
}
else if (ATermCommands.isString(toplevelDecl)) {
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
if (!desugaredBodyDecls.contains(toplevelDecl))
desugaredBodyDecls.add(toplevelDecl);
}
else
throw new IllegalArgumentException("unexpected toplevel declaration, desugaring probably failed: " + toplevelDecl.toString(20));
} catch (Exception e) {
String msg = e.getClass().getName() + " " + e.getLocalizedMessage() != null ? e.getLocalizedMessage() : e.toString();
if (!(e instanceof StrategoException))
e.printStackTrace();
setErrorMessage(toplevelDecl, msg);
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
}
}
private void processEditorServices(String extName, IStrategoTerm services) throws IOException {
if (!ATermCommands.isList(services))
throw new IllegalStateException("editor services are not a list: " + services);
RelativePath editorServicesFile = environment.createOutPath(baseProcessor.getRelativeNamespaceSep() + extName + ".serv");
List<IStrategoTerm> editorServices = ATermCommands.getList(services);
log.log("writing editor services to " + editorServicesFile, Log.DETAIL);
StringBuffer buf = new StringBuffer();
for (IStrategoTerm service : driverResult.getEditorServices())
buf.append(service).append('\n');
for (IStrategoTerm service : editorServices) {
driverResult.addEditorService(service);
buf.append(service).append('\n');
}
driverResult.generateFile(editorServicesFile, buf.toString());
}
private void processPlainDec(IStrategoTerm toplevelDecl) throws IOException {
log.beginTask("processing", "PROCESS plain declaration.", Log.CORE);
try {
definesNonBaseDec = true;
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
if (!desugaredBodyDecls.contains(toplevelDecl))
desugaredBodyDecls.add(toplevelDecl);
IStrategoTerm head = getApplicationSubterm(toplevelDecl, "PlainDec", 0);
IStrategoTerm body= getApplicationSubterm(toplevelDecl, "PlainDec", 1);
String extName = ATermCommands.getString(getApplicationSubterm(head, "PlainDecHead", 1));
checkModuleName(extName, toplevelDecl);
String extension = null;
if (head.getSubtermCount() >= 3 && isApplication(getApplicationSubterm(head, "PlainDecHead", 2), "Some"))
extension = Term.asJavaString(getApplicationSubterm(getApplicationSubterm(head, "PlainDecHead", 2), "Some", 0));
String fullExtName = getFullRenamedDeclarationName(extName);
fullExtName = fullExtName + (extension == null ? "" : ("." + extension));
log.log("The name is '" + extName + "'.", Log.DETAIL);
log.log("The full name is '" + fullExtName + "'.", Log.DETAIL);
if (dependsOnModel)
return;
String plainContent = Term.asJavaString(ATermCommands.getApplicationSubterm(body, "PlainBody", 0));
String ext = extension == null ? "" : ("." + extension);
RelativePath plainFile = environment.createOutPath(baseProcessor.getRelativeNamespaceSep() + extName + ext);
FileCommands.createFile(plainFile);
log.log("writing plain content to " + plainFile, Log.DETAIL);
driverResult.generateFile(plainFile, plainContent);
} finally {
log.endTask();
}
}
public Pair<IStrategoTerm, Integer> currentParse(String remainingInput, ITreeBuilder treeBuilder, boolean recovery) throws IOException, InvalidParseTableException, TokenExpectedException, SGLRException {
currentGrammarTBL = SDFCommands.compile(currentGrammarSDF, currentGrammarModule, driverResult.getTransitiveFileDependencies(), sdfParser, sdfCache, environment, baseLanguage);
ParseTable table = ATermCommands.parseTableManager.loadFromFile(currentGrammarTBL.getAbsolutePath());
Pair<SGLR, Pair<IStrategoTerm, Integer>> parseResult = null;
// read next toplevel decl and stop if that fails
try {
parseResult = SDFCommands.parseImplode(
table,
remainingInput,
sourceFile,
"ToplevelDeclaration",
recovery,
true,
treeBuilder);
// } catch (SGLRException e) {
// this.parser = e.getParser();
// log.logErr(e.getMessage(), Log.DETAIL);
// return null;
} finally {
if (parseResult != null)
this.parser = parseResult.a;
if (recovery && parser != null) {
for (BadTokenException e : parser.getCollectedErrors())
driverResult.logParseError(e);
}
}
return parseResult.b;
}
private IStrategoTerm currentAnalyze(IStrategoTerm term) throws IOException, InvalidParseTableException, TokenExpectedException, SGLRException {
// assimilate toplevelDec using current transformation
log.beginTask("analyze", "ANALYZE toplevel declaration.", Log.CORE);
try {
currentTransProg = STRCommands.compile(currentTransSTR, "main", driverResult.getTransitiveFileDependencies(), strParser, strCache, environment, baseProcessor);
return STRCommands.assimilate("analyze-main", currentTransProg, term, baseProcessor.getInterpreter());
} catch (StrategoException e) {
String msg = e.getClass().getName() + " " + e.getLocalizedMessage() != null ? e.getLocalizedMessage() : e.toString();
log.logErr(msg, Log.DETAIL);
setErrorMessage(msg);
return term;
} finally {
log.endTask();
}
}
private IStrategoTerm currentDesugar(IStrategoTerm term) throws IOException,
InvalidParseTableException, TokenExpectedException, SGLRException {
// assimilate toplevelDec using current transformation
log.beginTask("desugaring", "DESUGAR toplevel declaration.", Log.CORE);
try {
currentTransProg = STRCommands.compile(currentTransSTR, "main", driverResult.getTransitiveFileDependencies(), strParser, strCache, environment, baseProcessor);
return STRCommands.assimilate(currentTransProg, term, baseProcessor.getInterpreter());
} catch (StrategoException e) {
String msg = e.getClass().getName() + " " + e.getLocalizedMessage() != null ? e.getLocalizedMessage() : e.toString();
log.logErr(msg, Log.DETAIL);
setErrorMessage(msg);
return term;
} finally {
log.endTask();
}
}
/**
* Apply current renamings stored in environment to the given term.
*/
public IStrategoTerm currentRename(IStrategoTerm term) throws IOException, InvalidParseTableException, TokenExpectedException, SGLRException {
try {
if (currentTransProg == null)
return term;
IStrategoTerm result = STRCommands.assimilate("apply-renamings", currentTransProg, term, baseProcessor.getInterpreter());
return result == null ? term : result;
} catch (StrategoException e) {
String msg = e.getClass().getName() + " " + e.getLocalizedMessage() != null ? e.getLocalizedMessage() : e.toString();
log.logErr(msg, Log.DETAIL);
setErrorMessage(msg);
return term;
}
}
private void processImportDecs(IStrategoTerm toplevelDecl) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException {
List<IStrategoTerm> pendingImports = new ArrayList<IStrategoTerm>();
pendingImports.add(toplevelDecl);
while (declProvider.hasNextToplevelDecl()) {
IStrategoTerm term = null;
try {
log.beginSilent();
term = declProvider.getNextToplevelDecl(false, true);
}
catch (Throwable t) {
term = null;
}
finally {
log.endSilent();
}
if (term != null && (baseLanguage.isImportDecl(term) || baseLanguage.isTransformationApplication(term)))
pendingImports.add(term);
else {
declProvider.retract(term);
break;
}
}
for (IStrategoTerm pendingImport : pendingImports) {
lastSugaredToplevelDecl = pendingImport;
processImportDec(pendingImport);
}
}
private void processImportDec(IStrategoTerm toplevelDecl) {
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
if (!desugaredBodyDecls.contains(toplevelDecl))
desugaredBodyDecls.add(toplevelDecl);
log.beginTask("processing", "PROCESS import declaration.", Log.CORE);
try {
String modulePath;
boolean isCircularImport;
if (!baseLanguage.isTransformationApplication(toplevelDecl)) {
modulePath = baseProcessor.getModulePathOfImport(toplevelDecl);
isCircularImport = prepareImport(toplevelDecl, modulePath);
String localModelName = baseProcessor.getImportLocalName(toplevelDecl);
if (localModelName != null)
environment.getRenamings().add(0, new Renaming(Collections.<String>emptyList(), localModelName, FileCommands.fileName(modulePath)));
} else {
IStrategoTerm appl = baseLanguage.getTransformationApplication(toplevelDecl);
IStrategoTerm model = getApplicationSubterm(appl, "TransApp", 1);
IStrategoTerm transformation = getApplicationSubterm(appl, "TransApp", 0);
ImportCommands imp = new ImportCommands(baseProcessor, environment, this, driverResult, new STRCommands(strParser, strCache, environment, baseProcessor));
Pair<String, Boolean> transformationResult = imp.transformModel(model, transformation, toplevelDecl);
if (transformationResult == null)
return ;
modulePath = transformationResult.a;
isCircularImport = transformationResult.b;
String localModelName = baseProcessor.getImportLocalName(toplevelDecl);
if (localModelName != null)
environment.getRenamings().add(0, new Renaming(Collections.<String>emptyList(), localModelName, FileCommands.fileName(modulePath)));
else
environment.getRenamings().add(0, new Renaming(ImportCommands.getTransformationApplicationModelPath(appl, baseProcessor), modulePath));
IStrategoTerm reconstructedImport = baseProcessor.reconstructImport(modulePath, toplevelDecl);
desugaredBodyDecls.remove(toplevelDecl);
desugaredBodyDecls.add(reconstructedImport);
toplevelDecl = reconstructedImport;
}
if (isCircularImport)
return;
boolean codeImportSuccess = processImport(modulePath, toplevelDecl);
boolean modelImportSuccess = processModelImport(modulePath);
if (modelImportSuccess && !codeImportSuccess)
dependsOnModel = true;
boolean success = codeImportSuccess || modelImportSuccess;
if (!success)
setErrorMessage("module not found: " + modulePath);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
log.endTask();
}
}
/**
* Prepare import:
* - locate pre-existing result and/or source file
* - determine whether the import is circular
* - initiate subcompilation of imported source file if necessary
* - add appropriate dependencies to driverResult
*
* @param toplevelDecl
* @param modulePath
* @return true iff the import is circular.
* @throws IOException
* @throws InterruptedException
* @throws SGLRException
* @throws InvalidParseTableException
* @throws ParseException
* @throws TokenExpectedException
*/
protected boolean prepareImport(IStrategoTerm toplevelDecl, String modulePath) throws IOException, TokenExpectedException, ParseException, InvalidParseTableException, SGLRException, InterruptedException {
boolean isCircularImport = false;
if (!modulePath.startsWith("org/sugarj")) { // module is not in sugarj standard library
Result res = ModuleSystemCommands.locateResult(modulePath, environment);
RelativePath importSourceFile;
if (res != null && res.getSourceFile() != null)
importSourceFile = res.getSourceFile();
else
importSourceFile = ModuleSystemCommands.locateSourceFileOrModel(modulePath, environment.getSourcePath(), baseProcessor, environment);
boolean sourceFileAvailable = importSourceFile != null;
boolean requiresUpdate = res == null || res.getSourceFile() == null || pendingInputFiles.contains(res.getSourceFile()) || !res.isUpToDate(res.getSourceFile(), environment) || environment.doGenerateFiles() && res.isParseResult();
if (sourceFileAvailable && requiresUpdate && getCircularImportResult(importSourceFile) != null) {
// Circular import. Assume source file does not provide syntactic sugar.
log.log("Circular import detected: " + modulePath + ".", Log.IMPORT);
baseProcessor.processModuleImport(toplevelDecl);
isCircularImport = true;
circularLinks.add(importSourceFile);
}
else if (sourceFileAvailable && requiresUpdate) {
// Required module needs recompilation.
log.log("Need to compile imported module " + modulePath + " first.", Log.IMPORT);
res = subcompile(toplevelDecl, importSourceFile);
if (res == null || res.hasFailed())
setErrorMessage("Problems while compiling " + modulePath);
log.log("CONTINUE PROCESSING'" + sourceFile + "'.", Log.CORE);
}
if (isCircularImport) {
driverResult.addCircularDependency(getCircularImportResult(importSourceFile));
}
if (!isCircularImport && res != null) {
if (res.getPersistentPath() == null || res.hasPersistentVersionChanged())
setErrorMessage("Result is inconsitent with persistent version.");
driverResult.addDependency(res);
}
if (!isCircularImport && importSourceFile != null)
// if importSourceFile is delegated to something currently being processed
for (Driver dr : currentlyProcessing)
if (dr.driverResult.isDelegateOf(importSourceFile)) {
baseProcessor.processModuleImport(toplevelDecl);
isCircularImport = true;
if (dr != this)
circularLinks.add(dr.sourceFile);
break;
}
}
return isCircularImport;
}
/**
* Checks if the given source file is a circular import.
* Checks the ongoing driver runs to determine whether the source file in turn imports the current source file.
*
* @return null if the import is not circular. The path to the imported file's driver result otherwise.
*/
private Path getCircularImportResult(RelativePath importSourceFile) {
for (Driver dr : currentlyProcessing)
if (dr.sourceFile.equals(importSourceFile))
return dr.depOutFile;
return null;
}
/**
* Subcompile source file.
* @param toplevelDecl
* @param importSourceFile
* @return
* @throws InterruptedException
*/
public Result subcompile(IStrategoTerm toplevelDecl, RelativePath importSourceFile) throws InterruptedException {
try {
Result result;
if ("model".equals(FileCommands.getExtension(importSourceFile))) {
IStrategoTerm term = ATermCommands.atermFromFile(importSourceFile.getAbsolutePath());
result = run(term, importSourceFile, environment, monitor, baseProcessor.getLanguage(), currentlyProcessing);
}
else
result = run(importSourceFile, environment, monitor, baseProcessor.getLanguage(), currentlyProcessing);
if (result.isParseResult())
environment.addToIncludePath(result.getParseResultPath());
return result;
} catch (IOException e) {
setErrorMessage("Problems while compiling " + importSourceFile);
} catch (TokenExpectedException e) {
setErrorMessage("Problems while compiling " + importSourceFile);
} catch (ParseException e) {
setErrorMessage("Problems while compiling " + importSourceFile);
} catch (InvalidParseTableException e) {
setErrorMessage("Problems while compiling " + importSourceFile);
} catch (SGLRException e) {
setErrorMessage("Problems while compiling " + importSourceFile);
}
return null;
}
private boolean processImport(String modulePath, IStrategoTerm importTerm) throws IOException {
boolean success = false;
Path clazz = ModuleSystemCommands.importBinFile(modulePath, environment, baseProcessor, driverResult);
if (clazz != null || baseProcessor.isModuleExternallyResolvable(modulePath)) {
success = true;
baseProcessor.processModuleImport(importTerm);
}
Path sdf = ModuleSystemCommands.importSdf(modulePath, environment, driverResult);
if (sdf != null) {
success = true;
availableSDFImports.add(modulePath);
buildCompoundSdfModule();
}
Path str = ModuleSystemCommands.importStratego(modulePath, environment, driverResult);
if (str != null) {
success = true;
availableSTRImports.add(modulePath);
buildCompoundStrModule();
}
success |= ModuleSystemCommands.importEditorServices(modulePath, environment, driverResult);
return success;
}
private boolean processModelImport(String modulePath) throws IOException {
RelativePath model = ModuleSystemCommands.importModel(modulePath, environment, driverResult);
if (model != null) {
// availableModels.add(model);
return true;
}
return false;
}
private List<String> processLanguageDec(IStrategoTerm toplevelDecl) throws IOException {
log.beginTask("processing", "PROCESS " + baseProcessor.getLanguage().getLanguageName() + " declaration: " + ((toplevelDecl instanceof IStrategoAppl) ? ((IStrategoAppl) toplevelDecl).getName() : toplevelDecl.toString(0)), Log.CORE);
try {
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
if (!desugaredBodyDecls.contains(toplevelDecl))
desugaredBodyDecls.add(toplevelDecl);
if (dependsOnModel)
return Collections.emptyList();
return baseProcessor.processBaseDecl(toplevelDecl);
} finally {
log.endTask();
}
}
private void processExtensionDec(IStrategoTerm toplevelDecl) throws IOException, InvalidParseTableException, TokenExpectedException, SGLRException {
log.beginTask("processing", "PROCESS sugar declaration.", Log.CORE);
try {
definesNonBaseDec = true;
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
if (!desugaredBodyDecls.contains(toplevelDecl))
desugaredBodyDecls.add(toplevelDecl);
String extName = baseProcessor.getExtensionName(toplevelDecl);
String fullExtName = getFullRenamedDeclarationName(extName);
checkModuleName(extName, toplevelDecl);
log.log("The name of the sugar is '" + extName + "'.", Log.DETAIL);
log.log("The full name of the sugar is '" + fullExtName + "'.", Log.DETAIL);
if (dependsOnModel)
return;
RelativePath sdfExtension = environment.createOutPath(baseProcessor.getRelativeNamespaceSep() + extName + ".sdf");
RelativePath strExtension = environment.createOutPath(baseProcessor.getRelativeNamespaceSep() + extName + ".str");
String sdfImports = " imports " + StringCommands.printListSeparated(availableSDFImports, " ") + "\n";
String strImports = " imports " + StringCommands.printListSeparated(availableSTRImports, " ") + "\n";
// this is a list of SDF and Stratego statements
IStrategoTerm extensionBody = baseProcessor.getExtensionBody(toplevelDecl);
IStrategoTerm sdfExtract = fixSDF(extractSDF(extensionBody), baseProcessor.getInterpreter());
IStrategoTerm strExtract = extractSTR(extensionBody);
IStrategoTerm editorExtract = extractEditor(extensionBody);
String sdfExtensionHead =
"module " + fullExtName + "\n"
+ sdfImports
+ "exports " + "\n"
+ " (/)" + "\n";
String sdfExtensionContent = SDFCommands.prettyPrintSDF(sdfExtract, baseProcessor.getInterpreter());
String sdfSource = SDFCommands.makePermissiveSdf(sdfExtensionHead + sdfExtensionContent);
driverResult.generateFile(sdfExtension, sdfSource);
availableSDFImports.add(fullExtName);
if (CommandExecution.FULL_COMMAND_LINE)
log.log("Wrote SDF file to '" + sdfExtension.getAbsolutePath() + "'.", Log.DETAIL);
String strExtensionTerm = "Module(" + "\"" + fullExtName+ "\"" + ", " + strExtract + ")" + "\n";
// try {
// strExtensionTerm = STRCommands.assimilate("strip-annos", currentTransProg, strExtensionTerm, langLib.getInterpreter());
// } catch (Exception e) {
// e.printStackTrace();
// }
// String strExtensionContent = SDFCommands.prettyPrintSTR(strExtensionTerm, langLib.getInterpreter());
String strExtensionContent = SDFCommands.prettyPrintSTR(ATermCommands.atermFromString(strExtensionTerm), baseProcessor.getInterpreter());
int index = strExtensionContent.indexOf('\n');
if (index >= 0)
strExtensionContent =
strExtensionContent.substring(0, index + 1) + "\n"
+ strImports + "\n"
+ strExtensionContent.substring(index + 1);
else
strExtensionContent += strImports;
driverResult.generateFile(strExtension, strExtensionContent);
availableSTRImports.add(fullExtName);
if (CommandExecution.FULL_COMMAND_LINE)
log.log("Wrote Stratego file to '" + strExtension.getAbsolutePath() + "'.", Log.DETAIL);
processEditorServices(extName, editorExtract);
/*
* adapt current grammar
*/
if (FileCommands.exists(sdfExtension)) {
buildCompoundSdfModule();
}
/*
* adapt current transformation
*/
if (FileCommands.exists(strExtension))
buildCompoundStrModule();
} catch (PrettyPrintError e) {
setErrorMessage(e.getMsg());
} finally {
log.endTask();
}
}
private void processTransformationDec(IStrategoTerm toplevelDecl) throws IOException {
log.beginTask("processing", "PROCESS transformation declaration.", Log.CORE);
try {
definesNonBaseDec = true;
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
if (!desugaredBodyDecls.contains(toplevelDecl))
desugaredBodyDecls.add(toplevelDecl);
String extName = baseLanguage.getTransformationName(toplevelDecl);
String fullExtName = getFullRenamedDeclarationName(extName);
checkModuleName(extName, toplevelDecl);
RelativePath strExtension = environment.createOutPath(baseProcessor.getRelativeNamespaceSep() + extName + ".str");
IStrategoTerm transBody = baseLanguage.getTransformationBody(toplevelDecl);
if (isApplication(transBody, "TransformationDef"))
transBody = ATermCommands.factory.makeListCons(ATermCommands.makeAppl("Rules", "Rules", 1, transBody.getSubterm(0)), (IStrategoList) transBody.getSubterm(1));
log.log("The name of the transformation is '" + extName + "'.", Log.DETAIL);
log.log("The full name of the transformation is '" + fullExtName + "'.", Log.DETAIL);
if (dependsOnModel)
return;
String qualifiedMain = "main-" + fullExtName.replace('/', '_');
IStrategoTerm renamedTransBody = STRCommands.renameRules(transBody, "main", qualifiedMain);
String strImports = " imports " + StringCommands.printListSeparated(availableSTRImports, " ") + "\n";
String strExtensionTerm = "Module(" + "\"" + fullExtName+ "\"" + ", " + renamedTransBody + ")" + "\n";
String strExtensionContent = SDFCommands.prettyPrintSTR(ATermCommands.atermFromString(strExtensionTerm), baseProcessor.getInterpreter());
int index = strExtensionContent.indexOf('\n');
if (index >= 0)
strExtensionContent =
strExtensionContent.substring(0, index + 1) + "\n"
+ strImports + "\n"
+ strExtensionContent.substring(index + 1);
else
strExtensionContent += strImports;
driverResult.generateFile(strExtension, strExtensionContent);
availableSTRImports.add(fullExtName);
log.log("Wrote Stratego file to '" + strExtension.getAbsolutePath() + "'.", Log.DETAIL);
/*
* adapt current transformation
*/
if (FileCommands.exists(strExtension))
buildCompoundStrModule();
} finally {
log.endTask();
}
}
private String getFullRenamedDeclarationName(String declName) {
String fullExtName = baseProcessor.getRelativeNamespaceSep() + declName;
// for (Renaming ren : environment.getRenamings())
// fullExtName = StringCommands.rename(fullExtName, ren);
// fullExtName = fullExtName.replace("$", "-");
return fullExtName;
}
private void processModelDec(IStrategoTerm toplevelDecl) throws IOException {
log.beginTask("processing", "PROCESS model declaration.", Log.CORE);
try {
definesNonBaseDec = true;
if (!sugaredBodyDecls.contains(lastSugaredToplevelDecl))
sugaredBodyDecls.add(lastSugaredToplevelDecl);
if (!desugaredBodyDecls.contains(toplevelDecl))
desugaredBodyDecls.add(toplevelDecl);
String modelName = baseLanguage.getModelName(toplevelDecl);
// String fullModelName = getFullRenamedDeclarationName(modelName);
checkModuleName(modelName, toplevelDecl);
log.log("The name of the model is '" + modelName + "'.", Log.DETAIL);
// checkToplevelDeclarationName(modelName.replace("-", "$"), "model", toplevelDecl);
} finally {
log.endTask();
}
}
private void generateModel() throws IOException {
log.beginTask("Generate model.", Log.DETAIL);
try {
String moduleName = FileCommands.dropExtension(sourceFile.getRelativePath());
RelativePath modelOutFile = environment.createOutPath(moduleName + ".model");
IStrategoTerm modelTerm = makeDesugaredSyntaxTree();
String string = ATermCommands.atermToString(modelTerm);
driverResult.generateFile(modelOutFile, string);
if (modelOutFile.equals(sourceFile))
driverResult.setSourceFile(sourceFile, string.hashCode());
} finally {
log.endTask();
}
}
private void buildCompoundSdfModule() throws IOException {
FileCommands.deleteTempFiles(currentGrammarSDF);
currentGrammarSDF = FileCommands.newTempFile("sdf");
currentGrammarModule = FileCommands.fileName(currentGrammarSDF);
StringBuilder builder = new StringBuilder();
builder.append("module ").append(currentGrammarModule).append("\n");
builder.append("imports ");
for (String m : availableSDFImports)
builder.append(m).append(" ");
FileCommands.writeToFile(currentGrammarSDF, builder.toString());
}
private void buildCompoundStrModule() throws IOException {
FileCommands.deleteTempFiles(currentTransSTR);
currentTransSTR = FileCommands.newTempFile("str");
currentTransModule = FileCommands.fileName(currentTransSTR);
StringBuilder builder = new StringBuilder();
builder.append("module ").append(currentTransModule).append("\n");
builder.append("imports ");
for (String m : availableSTRImports)
builder.append(m).append(" ");
FileCommands.writeToFile(currentTransSTR, builder.toString());
}
private void checkCurrentGrammar() throws IOException, InvalidParseTableException, TokenExpectedException, SGLRException {
log.beginTask("checking grammar", "CHECK current grammar", Log.CORE);
try {
SDFCommands.compile(currentGrammarSDF, currentGrammarModule, driverResult.getTransitiveFileDependencies(), sdfParser, sdfCache, environment, baseLanguage);
} finally {
log.endTask();
}
}
private void checkCurrentTransformation() throws TokenExpectedException, IOException, InvalidParseTableException, SGLRException {
log.beginTask("checking transformation", "CHECK current transformation", Log.CORE);
try {
currentTransProg = STRCommands.compile(currentTransSTR, "main", driverResult.getTransitiveFileDependencies(), strParser, strCache, environment, baseProcessor);
} catch (StrategoException e) {
String msg = e.getClass().getName() + " " + e.getLocalizedMessage() != null ? e.getLocalizedMessage() : e.toString();
log.logErr(msg, Log.DETAIL);
setErrorMessage(msg);
} finally {
log.endTask();
}
}
private void checkModuleName(String decName, IStrategoTerm toplevelDecl) {
String expectedDecName = FileCommands.fileName(baseProcessor.getGeneratedSourceFile());
if (expectedDecName != null && !expectedDecName.equals(decName))
setErrorMessage(lastSugaredToplevelDecl, "Declaration name " + decName + " does not match file name " + expectedDecName);
}
private void initEditorServices() throws IOException, TokenExpectedException, SGLRException, InterruptedException {
List<IStrategoTerm> stdServices = parseEditorServiceFile(StdLib.stdEditor);
for (IStrategoTerm service : stdServices)
driverResult.addEditorService(service);
List<IStrategoTerm> baseServices = parseEditorServiceFile(baseLanguage.getInitEditor());
for (IStrategoTerm service : baseServices)
driverResult.addEditorService(service);
}
private List<IStrategoTerm> parseEditorServiceFile(Path editorFile) throws TokenExpectedException, BadTokenException, org.spoofax.jsglr.client.ParseException, SGLRException, InterruptedException, IOException {
IStrategoTerm initEditor = (IStrategoTerm) editorServicesParser.parse(FileCommands.readFileAsString(editorFile), editorFile.getAbsolutePath(), "Module");
IStrategoTerm services = ATermCommands.getApplicationSubterm(initEditor, "Module", 2);
if (!ATermCommands.isList(services))
throw new IllegalStateException("initial editor ill-formed");
return ATermCommands.getList(services);
}
@SuppressWarnings("unchecked")
private static synchronized void initializeCaches(Environment environment, boolean force) throws IOException {
if (environment.getCacheDir() == null)
return;
Path stdlibVersion = environment.createCachePath("version");
if (!stdlibVersion.getFile().exists() || !FileCommands.readFileAsString(stdlibVersion).equals(StdLib.VERSION)) {
for (File f : environment.getCacheDir().getFile().listFiles())
f.delete();
FileCommands.writeToFile(stdlibVersion, StdLib.VERSION);
}
Path sdfCachePath = environment.createCachePath("sdfCaches");
Path strCachePath = environment.createCachePath("strCaches");
if (sdfCaches == null || force)
sdfCaches = new HashMap<Path, Map<String,ModuleKeyCache<Path>>>();
if (strCaches == null || force)
strCaches = new HashMap<Path, Map<String, ModuleKeyCache<Path>>>();
ObjectInputStream sdfIn = null;
ObjectInputStream strIn = null;
try{
sdfIn = new ObjectInputStream(new FileInputStream(sdfCachePath.getFile()));
if (!sdfCaches.containsKey(environment.getCacheDir())) {
Map<String, ModuleKeyCache<Path>> sdfLocalCaches = (Map<String, ModuleKeyCache<Path>>) sdfIn.readObject();
sdfCaches.put(environment.getCacheDir(), sdfLocalCaches);
}
strIn = new ObjectInputStream(new FileInputStream(strCachePath.getFile()));
if (!strCaches.containsKey(environment.getCacheDir())) {
Map<String, ModuleKeyCache<Path>> strLocalCaches = (Map<String, ModuleKeyCache<Path>>) strIn.readObject();
strCaches.put(environment.getCacheDir(), strLocalCaches);
}
} catch (Exception e) {
sdfCaches.put(environment.getCacheDir(), new HashMap<String, ModuleKeyCache<Path>>());
strCaches.put(environment.getCacheDir(), new HashMap<String, ModuleKeyCache<Path>>());
for (File f : environment.getCacheDir().getFile().listFiles())
f.delete();
} finally {
if (sdfIn != null)
sdfIn.close();
if (strIn != null)
strIn.close();
}
}
private static ModuleKeyCache<Path> selectCache(Map<Path, Map<String, ModuleKeyCache<Path>>> caches, AbstractBaseLanguage baseLang, Environment environment) throws IOException {
if (caches == null)
return null;
synchronized (caches) {
ModuleKeyCache<Path> cache = caches.get(environment.getCacheDir()).get(baseLang.getLanguageName());
Path versionPath = environment.createCachePath(baseLang.getLanguageName() + ".version");
if (cache != null &&
(!FileCommands.exists(versionPath) || !baseLang.getVersion().equals(FileCommands.readFileAsString(versionPath))))
cache = null;
if (cache == null) {
cache = new ModuleKeyCache<Path>(caches);
FileCommands.writeToFile(versionPath, baseLang.getVersion());
caches.get(environment.getCacheDir()).put(baseLang.getLanguageName(), cache);
}
return cache;
}
}
//TODO is this needed?
// private static ModuleKeyCache<Path> reallocate(ModuleKeyCache<Path> cache, Environment env) {
// ModuleKeyCache<Path> res = new ModuleKeyCache<Path>();
//
// for (Entry<ModuleKey, Path> e : cache.entrySet()) {
// Map<Path, Integer> imports = new HashMap<Path, Integer>();
// for (Entry<Path, Integer> e2 : e.getKey().imports.entrySet())
// imports.put(Path.reallocate(e2.getKey(), env), e2.getValue());
//
// res.put(new ModuleKey(imports, e.getKey().body), Path.reallocate(e.getValue(), env));
// }
//
// return res;
// }
private static synchronized void storeCaches(Environment environment) throws IOException {
if (environment.getCacheDir() == null)
return;
Path cacheVersion = environment.createCachePath("version");
FileCommands.writeToFile(cacheVersion, StdLib.VERSION);
Path sdfCachePath = environment.createCachePath("sdfCaches");
Path strCachePath = environment.createCachePath("strCaches");
if (!sdfCachePath.getFile().exists())
FileCommands.createFile(sdfCachePath);
if (!strCachePath.getFile().exists())
FileCommands.createFile(strCachePath);
if (sdfCaches != null) {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(sdfCachePath.getFile()));
try {
oos.writeObject(sdfCaches.get(environment.getCacheDir()));
} finally {
oos.close();
}
}
if (strCaches != null) {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(strCachePath.getFile()));
try {
oos.writeObject(strCaches.get(environment.getCacheDir()));
} finally {
oos.close();
}
}
}
/**
* @return the non-desugared syntax tree of the complete file.
*/
private IStrategoTerm makeSugaredSyntaxTree() {
IStrategoTerm decls = ATermCommands.makeList("Decl*", declProvider.getStartToken(), sugaredBodyDecls);
IStrategoTerm term = ATermCommands.makeAppl("CompilationUnit", "CompilationUnit", 1, decls);
if (ImploderAttachment.getTokenizer(term) != null) {
ImploderAttachment.getTokenizer(term).setAst(term);
ImploderAttachment.getTokenizer(term).initAstNodeBinding();
}
return term;
}
/**
* @return the desugared syntax tree of the complete file.
*/
private IStrategoTerm makeDesugaredSyntaxTree() {
IStrategoTerm decls = ATermCommands.makeList("Decl*", declProvider.getStartToken(), desugaredBodyDecls);
IStrategoTerm term = ATermCommands.makeAppl("CompilationUnit", "CompilationUnit", 1, decls);
return term;
}
public synchronized void interrupt() {
this.interrupt = true;
}
private synchronized void stopIfInterrupted() throws InterruptedException {
if (interrupt || monitor.isCanceled()) {
monitor.setCanceled(true);
log.log("interrupted " + sourceFile, Log.CORE);
throw new InterruptedException("Compilation interrupted");
}
}
private void stepped() throws InterruptedException {
stopIfInterrupted();
monitor.worked(1);
}
private void clearGeneratedStuff() throws IOException {
if (driverResult.getGenerationLog() != null && FileCommands.exists(driverResult.getGenerationLog())) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(driverResult.getGenerationLog().getFile()));
while (true) {
try {
Path p = (Path) ois.readObject();
FileCommands.delete(p);
} catch (ClassNotFoundException e) {
}
}
} catch (EOFException e) {
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null)
ois.close();
FileCommands.delete(driverResult.getGenerationLog());
}
}
}
public void setErrorMessage(IStrategoTerm toplevelDecl, String msg) {
driverResult.logError(msg);
ATermCommands.setErrorMessage(toplevelDecl, msg);
}
public void setErrorMessage(String msg) {
setErrorMessage(lastSugaredToplevelDecl, msg);
}
private void sortForImports(List<IStrategoTerm> list) {
Collections.sort(list, new Comparator<IStrategoTerm>() {
@Override
public int compare(IStrategoTerm o1, IStrategoTerm o2) {
boolean imp1 = baseLanguage.isImportDecl(o1);
boolean imp2 = baseLanguage.isImportDecl(o2);
if (imp1 && imp2 || !imp1 && !imp2)
return 0;
return imp1 ? -1 : 1;
}
});
}
public AbstractBaseProcessor getBaseLanguage() {
return baseProcessor;
}
public String getModuleName() {
return FileCommands.fileName(sourceFile);
}
public SGLR getParser() {
return parser;
}
public IStrategoTerm getTreeForErrorMarking() {
return lastSugaredToplevelDecl;
}
public Result getCurrentResult() {
return driverResult;
}
}