Package org.sugarj.driver

Source Code of org.sugarj.driver.Driver

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;
  }
}
TOP

Related Classes of org.sugarj.driver.Driver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.