Package org.sugarj

Source Code of org.sugarj.HaskellProcessor

package org.sugarj;

import static org.sugarj.common.ATermCommands.getApplicationSubterm;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.spoofax.interpreter.terms.IStrategoTerm;
import org.sugarj.common.ATermCommands;
import org.sugarj.common.CommandExecution;
import org.sugarj.common.CommandExecution.ExecutionError;
import org.sugarj.common.Environment;
import org.sugarj.common.FileCommands;
import org.sugarj.common.Log;
import org.sugarj.common.StringCommands;
import org.sugarj.common.path.AbsolutePath;
import org.sugarj.common.path.Path;
import org.sugarj.common.path.RelativePath;

/**
* @author Sebastian Erdweg <seba at informatik uni-marburg de>
*/
public class HaskellProcessor extends AbstractBaseProcessor {

  private static final long serialVersionUID = -8916207157344649789L;
 
  private final String GHC_COMMAND = "ghc";

  private String moduleHeader;
  private List<String> imports = new LinkedList<String>();
  private List<String> body = new LinkedList<String>();
  private boolean hasExtension = false;

  private Environment environment;
  private RelativePath sourceFile;
  private Path outFile;
  private Set<RelativePath> generatedModules = new HashSet<RelativePath>();
 
  private String relNamespaceName;
  private String moduleName;

  private IStrategoTerm ppTable;

  @Override
  public String getGeneratedSource() {
    if (moduleHeader == null)
      return "";
   
    if (hasExtension && body.isEmpty())
      return "";
   
    return moduleHeader + "\n"
         + StringCommands.printListSeparated(imports, "\n") + "\n"
         + StringCommands.printListSeparated(body, "\n");
  }

  @Override
  public Path getGeneratedSourceFile() {
    return outFile;
  }

  @Override
  public String getNamespace() {
    return relNamespaceName;
  }

  @Override
  public HaskellLanguage getLanguage() {
    return HaskellLanguage.getInstance();
  }


 
  /*
   * processing stuff follows here
   */
  @Override
  public void init(RelativePath sourceFile, Environment environment) {
    this.environment = environment;
    this.sourceFile = sourceFile;
    outFile = environment.createOutPath(FileCommands.dropExtension(sourceFile.getRelativePath()) + "." + HaskellLanguage.getInstance().getBaseFileExtension());
  }

  private void processNamespaceDecl(IStrategoTerm toplevelDecl) throws IOException {
    String qualifiedModuleName = prettyPrint(getApplicationSubterm(toplevelDecl, "ModuleDec", 0));
    String qualifiedModulePath = qualifiedModuleName.replace('.', '/');
    String declaredModuleName = FileCommands.fileName(qualifiedModulePath);
    moduleName = FileCommands.dropExtension(FileCommands.fileName(sourceFile.getRelativePath()));
    String declaredRelNamespaceName = FileCommands.dropFilename(qualifiedModulePath);
    relNamespaceName = FileCommands.dropFilename(sourceFile.getRelativePath());
   
    RelativePath objectFile = environment.createOutPath(getRelativeNamespaceSep() + moduleName + "." + HaskellLanguage.getInstance().getBinaryFileExtension());
    generatedModules.add(objectFile);
   
    moduleHeader = prettyPrint(toplevelDecl);
   
    if (!declaredRelNamespaceName.equals(relNamespaceName))
      throw new RuntimeException(
                      "The declared namespace '" + declaredRelNamespaceName + "'" +
                      " does not match the expected namespace '" + relNamespaceName + "'.");
   
    if (!declaredModuleName.equals(moduleName))
      throw new RuntimeException(
                      "The declared module name '" + declaredModuleName + "'" +
                      " does not match the expected module name '" + moduleName + "'.");
  }

  @Override
  public List<String> processBaseDecl(IStrategoTerm toplevelDecl) throws IOException {
    if (getLanguage().isNamespaceDec(toplevelDecl)) {
      processNamespaceDecl(toplevelDecl);
      return Collections.emptyList();
    }
   
    IStrategoTerm term = getApplicationSubterm(toplevelDecl, "HaskellBody", 0);
    String text = null;
    try {
      text = prettyPrint(term);
    } catch (NullPointerException e) {
      ATermCommands.setErrorMessage(toplevelDecl, "pretty printing Haskell failed");
    }
    if (text != null)
      body.add(text);
    return Collections.emptyList();
  }

  @Override
  public String getModulePathOfImport(IStrategoTerm toplevelDecl) {
    return prettyPrint(getApplicationSubterm(toplevelDecl, "Import", 2)).replace('.', '/');
  }
 
  @Override
  public void processModuleImport(IStrategoTerm toplevelDecl) throws IOException {
    imports.add(prettyPrint(toplevelDecl));
  }
 
  @Override
  public String getExtensionName(IStrategoTerm decl) throws IOException {
    hasExtension = true;
    return moduleName;
  }

  private String prettyPrint(IStrategoTerm term) {
    if (ppTable == null)
      ppTable = ATermCommands.readPrettyPrintTable(getLanguage().ensureFile("org/sugarj/languages/Haskell.pp").getAbsolutePath());
   
    return ATermCommands.prettyPrint(ppTable, term, interp);
  }
 
  @Override
  public List<Path> compile(List<Path> outFiles, Path bin, List<Path> includePaths) throws IOException {
    List<String> cmds = new LinkedList<String>();
    cmds.add(GHC_COMMAND);
   
    cmds.add("-outputdir");
    cmds.add(bin.getAbsolutePath());
   
    List<Path> generatedFiles = new LinkedList<Path>();
    for (Path outFile : outFiles) {
      cmds.add(outFile.getAbsolutePath());
     
      String noExtPath = FileCommands.dropExtension(outFile.getAbsolutePath());
      if (FileCommands.fileExists(new AbsolutePath(noExtPath)))
        generatedFiles.add(new AbsolutePath(noExtPath));
      if (FileCommands.fileExists(new AbsolutePath(noExtPath + ".exe")))
        generatedFiles.add(new AbsolutePath(noExtPath + ".exe"));
      if (FileCommands.fileExists(new AbsolutePath(noExtPath + ".hi")))
        generatedFiles.add(new AbsolutePath(noExtPath + ".hi"));
      if (FileCommands.fileExists(new AbsolutePath(noExtPath + ".o")))
        generatedFiles.add(new AbsolutePath(noExtPath + ".o"));
    }
   
    if (!includePaths.isEmpty()) {
      StringBuilder searchPath = new StringBuilder("-i");
      for (Path path : includePaths)
        if (new File(path.getAbsolutePath()).isDirectory())
          searchPath.append(path.getAbsolutePath()).append(":");
      searchPath.deleteCharAt(searchPath.length() - 1);
      cmds.add(searchPath.toString());
    }
   
    new CommandExecution(false).execute(cmds.toArray(new String[cmds.size()]));
   
    return generatedFiles;
  }

  @Override
  public boolean isModuleExternallyResolvable(String relModulePath) {
    boolean oldSilent = CommandExecution.SILENT_EXECUTION;
    CommandExecution.SILENT_EXECUTION = true;
    String[] cmds = new String[]{
      "ghc-pkg",
      "find-module", relModulePath.replace('/', '.'),
      "--simple-output"
    };
   
    String[][] msg;
    try {
       msg = new CommandExecution(true).execute(cmds);
    } catch (ExecutionError e) {
      Log.log.logErr("Command execution failed: " + Arrays.toString(e.getCmds()), Log.ALWAYS);
      return false;
    } finally {
      CommandExecution.SILENT_EXECUTION = oldSilent;
    }
   
    return msg.length > 0 && msg[0].length > 0;
  }

  @Override
  public IStrategoTerm getExtensionBody(IStrategoTerm decl) {
    return getApplicationSubterm(decl, "ExtensionBody", 0);
  }
}
TOP

Related Classes of org.sugarj.HaskellProcessor

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.