Package org.rascalmpl.semantics.dynamic

Source Code of org.rascalmpl.semantics.dynamic.Import

/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:

*   * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
*   * Tijs van der Storm - Tijs.van.der.Storm@cwi.nl
*   * Mark Hills - Mark.Hills@cwi.nl (CWI)
*   * Arnold Lankamp - Arnold.Lankamp@cwi.nl
*******************************************************************************/
package org.rascalmpl.semantics.dynamic;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.IList;
import org.eclipse.imp.pdb.facts.IListWriter;
import org.eclipse.imp.pdb.facts.IMap;
import org.eclipse.imp.pdb.facts.INode;
import org.eclipse.imp.pdb.facts.ISet;
import org.eclipse.imp.pdb.facts.ISetWriter;
import org.eclipse.imp.pdb.facts.ISourceLocation;
import org.eclipse.imp.pdb.facts.IString;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.IValueFactory;
import org.eclipse.imp.pdb.facts.type.Type;
import org.rascalmpl.ast.ImportedModule;
import org.rascalmpl.ast.LocationLiteral;
import org.rascalmpl.ast.Module;
import org.rascalmpl.ast.Name;
import org.rascalmpl.ast.QualifiedName;
import org.rascalmpl.ast.SyntaxDefinition;
import org.rascalmpl.ast.Tag;
import org.rascalmpl.ast.TagString.Lexical;
import org.rascalmpl.interpreter.IEvaluator;
import org.rascalmpl.interpreter.asserts.ImplementationError;
import org.rascalmpl.interpreter.control_exceptions.Throw;
import org.rascalmpl.interpreter.debug.DebugUpdater;
import org.rascalmpl.interpreter.env.Environment;
import org.rascalmpl.interpreter.env.GlobalEnvironment;
import org.rascalmpl.interpreter.env.ModuleEnvironment;
import org.rascalmpl.interpreter.result.ICallableValue;
import org.rascalmpl.interpreter.result.Result;
import org.rascalmpl.interpreter.result.ResultFactory;
import org.rascalmpl.interpreter.result.SourceLocationResult;
import org.rascalmpl.interpreter.staticErrors.ModuleImport;
import org.rascalmpl.interpreter.staticErrors.ModuleNameMismatch;
import org.rascalmpl.interpreter.staticErrors.StaticError;
import org.rascalmpl.interpreter.staticErrors.UndeclaredModule;
import org.rascalmpl.interpreter.staticErrors.UndeclaredModuleProvider;
import org.rascalmpl.interpreter.utils.Modules;
import org.rascalmpl.interpreter.utils.Names;
import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory;
import org.rascalmpl.library.lang.rascal.syntax.RascalParser;
import org.rascalmpl.parser.ASTBuilder;
import org.rascalmpl.parser.Parser;
import org.rascalmpl.parser.ParserGenerator;
import org.rascalmpl.parser.gtd.IGTD;
import org.rascalmpl.parser.gtd.exception.ParseError;
import org.rascalmpl.parser.gtd.exception.UndeclaredNonTerminalException;
import org.rascalmpl.parser.gtd.result.action.IActionExecutor;
import org.rascalmpl.parser.gtd.result.out.DefaultNodeFlattener;
import org.rascalmpl.parser.uptr.UPTRNodeFactory;
import org.rascalmpl.parser.uptr.action.NoActionExecutor;
import org.rascalmpl.uri.URIResolverRegistry;
import org.rascalmpl.uri.URIUtil;
import org.rascalmpl.values.ValueFactoryFactory;
import org.rascalmpl.values.uptr.Factory;
import org.rascalmpl.values.uptr.ProductionAdapter;
import org.rascalmpl.values.uptr.SymbolAdapter;
import org.rascalmpl.values.uptr.TreeAdapter;
import org.rascalmpl.values.uptr.visitors.IdentityTreeVisitor;

public abstract class Import {
 
  static public class External extends org.rascalmpl.ast.Import.External {

    public External(IConstructor node, QualifiedName name,
        LocationLiteral at) {
      super(node, name, at);
    }
   
 
    @Override
    public Result<IValue> interpret(IEvaluator<Result<IValue>> eval) {
      // Compute the URI location, which contains the scheme (and other info we need later)
      ISourceLocation sl = (ISourceLocation)getAt().interpret(eval).getValue();
     
      // If we have a resource scheme, given as resource scheme + standard scheme, we
      // extract that out, e.g., jdbctable+mysql would give a resource scheme of
      // jdbctable and a standard URI scheme of mysql. If we do not have a separate
      // resource scheme, we just use the specified scheme, e.g., sdf would give
      // a resource scheme of sdf and a URI scheme of sdf.
      URI uri = sl.getURI();
      String resourceScheme = uri.getScheme();
     
      if (resourceScheme.contains("+")) {
        String uriScheme = resourceScheme.substring(resourceScheme.indexOf("+")+1);
        resourceScheme = resourceScheme.substring(0,resourceScheme.indexOf("+"));
        try {
          uri = URIUtil.changeScheme(uri, uriScheme);
        } catch (URISyntaxException e) {
          throw RuntimeExceptionFactory.malformedURI(uri.toString().substring(uri.toString().indexOf("+")+1), null, null);
        }
        sl = ValueFactoryFactory.getValueFactory().sourceLocation(uri);
      }
     
      String moduleName = Names.fullName(this.getName());
      IString mn = this.VF.string(moduleName);
     
      // Using the scheme, get back the correct importer
      ICallableValue importer = getImporter(resourceScheme, eval.getCurrentEnvt());
     
      if (importer != null) {
        Type[] argTypes = new org.eclipse.imp.pdb.facts.type.Type[] {TF.stringType(), TF.sourceLocationType()};
        IValue[] argValues = new IValue[] { mn, sl };
       
        // Invoke the importer, which should generate the text of the module that we need
        // to actually import.
        IValue module = importer.call(argTypes, argValues, null).getValue();
        String moduleText = module.getType().isString() ? ((IString) module).getValue() : TreeAdapter.yield((IConstructor) module);
       
        moduleText = "@generated\n" + moduleText;
       
        try {
          URIResolverRegistry reg = eval.getResolverRegistry();
          String moduleEnvName = eval.getCurrentModuleEnvironment().getName();
          URI ur = null;
          if (moduleEnvName.equals(ModuleEnvironment.SHELL_MODULE)) {
            ur = URIUtil.rootScheme("rascal");
          } else {
            ur = eval.getRascalResolver().getRootForModule((URIUtil.createRascalModule(moduleEnvName)));
          }
          Result<?> loc = new SourceLocationResult(TF.sourceLocationType(), VF.sourceLocation(ur), eval);
          String modulePath = moduleName.replaceAll("::", "/");
          loc = loc.add(ResultFactory.makeResult(TF.stringType(), VF.string(modulePath), eval));
          loc = loc.fieldUpdate("extension", ResultFactory.makeResult(TF.stringType(), VF.string(".rsc"), eval), eval.getCurrentEnvt().getStore());
         
          OutputStream outputStream;
          try {
            outputStream = reg.getOutputStream(((ISourceLocation) loc.getValue()).getURI(), false);
          }
          catch (IOException e) {
            outputStream = reg.getOutputStream(URIUtil.rootScheme("cwd"), false);
          }
         
          if (outputStream == null) {
            outputStream = reg.getOutputStream(URIUtil.rootScheme("cwd"), false);
          }
         
          BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
          writer.write(moduleText);
          writer.close();
        }
        catch (IOException e) {
          throw RuntimeExceptionFactory.moduleNotFound(mn, eval.getCurrentAST(), eval.getStackTrace());
        }
       
        importModule(Names.fullName(this.getName()), getLocation(), eval);
        return ResultFactory.nothing();
      } else {
        throw new UndeclaredModuleProvider(resourceScheme, eval.getCurrentAST());
      }
    }
   
    private ICallableValue getImporter(String s, Environment currentEnvt) {
      return currentEnvt.getHeap().getResourceImporter(s);
    }
  }
 
  static public class Extend extends org.rascalmpl.ast.Import.Extend {
    public Extend(IConstructor node, ImportedModule module) {
      super(node, module);
    }
   
    @Override
    public Result<IValue> interpret(IEvaluator<Result<IValue>> eval) {
      String name = Names.fullName(this.getModule().getName());
      extendCurrentModule(this.getLocation(), name, eval);
      return org.rascalmpl.interpreter.result.ResultFactory.nothing();
    }
  }

  static public class Default extends org.rascalmpl.ast.Import.Default {
    public Default(IConstructor __param1, ImportedModule __param2) {
      super(__param1, __param2);
    }

    @Override
    public Result<IValue> interpret(IEvaluator<Result<IValue>> eval) {
      try {
        importModule(Names.fullName(getModule().getName()), getLocation(), eval);
      }
      finally {
        eval.setCurrentAST(this);
      }
     
      return ResultFactory.nothing();
    }
  }

  static public class Syntax extends org.rascalmpl.ast.Import.Syntax {
    public Syntax(IConstructor __param1, SyntaxDefinition __param2) {
      super(__param1, __param2);
    }

    @Override
    public Result<IValue> interpret(IEvaluator<Result<IValue>> eval) {
      String parseTreeModName = "ParseTree";
      if (!eval.__getHeap().existsModule(parseTreeModName)) {
        loadModule(getLocation(), parseTreeModName, eval);
      }
      addImportToCurrentModule(getLocation(), parseTreeModName, eval);

      getSyntax().interpret(eval);
      return nothing();
    }
  }

  public static void importModule(String name, ISourceLocation src, IEvaluator<Result<IValue>> eval) {
    GlobalEnvironment heap = eval.__getHeap();
   
    if (!heap.existsModule(name)) {
      //System.err.println("importModule: " + name);
      // deal with a fresh module that needs initialization
      heap.addModule(new ModuleEnvironment(name, heap));
      loadModule(src, name, eval);
    }
    else if (eval.getCurrentEnvt() == eval.__getRootScope()) {
      // in the root scope we treat an import as a "reload"
      heap.resetModule(name);
      loadModule(src, name, eval);
    }
   
    addImportToCurrentModule(src, name, eval);
   
    if (heap.getModule(name).isDeprecated()) {
      eval.getStdErr().println(src + ":" + name + " is deprecated, " + heap.getModule(name).getDeprecatedMessage());
    }
   
    return;
  }
 
  public static void extendCurrentModule(ISourceLocation x, String name, IEvaluator<Result<IValue>> eval) {
    GlobalEnvironment heap = eval.__getHeap();
    ModuleEnvironment other = heap.getModule(name);;
   
    if (other == null) {
      // deal with a fresh module that needs initialization
      heap.addModule(new ModuleEnvironment(name, heap));
      other = loadModule(x, name, eval);
    }
    else if (eval.getCurrentEnvt() == eval.__getRootScope()) {
      // in the root scope we treat an extend as a "reload"
      heap.resetModule(name);
      other = loadModule(x, name, eval);
    }
   
    // now simply extend the current module
    eval.getCurrentModuleEnvironment().extend(other); //heap.getModule(name));
  }
 
  public static ModuleEnvironment loadModule(ISourceLocation x, String name, IEvaluator<Result<IValue>> eval) {
    GlobalEnvironment heap = eval.getHeap();
   
    ModuleEnvironment env = heap.getModule(name);
    if (env == null) {
      env = new ModuleEnvironment(name, heap);
      heap.addModule(env);
    }
   
    try {
      Module module = buildModule(name, env, eval);

      if (isDeprecated(module)) {
        eval.getStdErr().println("WARNING: deprecated module " + name + ":" + getDeprecatedMessage(module));
      }
     
      if (module != null) {
        String internalName = org.rascalmpl.semantics.dynamic.Module.getModuleName(module);
        if (!internalName.equals(name)) {
          throw new ModuleNameMismatch(internalName, name, x);
        }
        heap.setModuleURI(name, module.getLocation().getURI());
       
        module.interpret(eval);
       
        return env;
      }
    } catch (StaticError e) {
      heap.removeModule(env);
      throw e;
    } catch (Throw e) {
      heap.removeModule(env);
      throw e;
    } catch (IOException e) {
      heap.removeModule(env);
      throw new ModuleImport(name, e.getMessage(), x);
    }

    heap.removeModule(env);
    throw new ImplementationError("Unexpected error while parsing module " + name + " and building an AST for it ", x);
  }
 
  private static boolean isDeprecated(Module preModule){
    for (Tag tag : preModule.getHeader().getTags().getTags()) {
      if (((Name.Lexical) tag.getName()).getString().equals("deprecated")) {
        return true;
      }
    }
    return false;
  }
 
  private static String getDeprecatedMessage(Module preModule){
    for (Tag tag : preModule.getHeader().getTags().getTags()) {
      if (((Name.Lexical) tag.getName()).getString().equals("deprecated")) {
        String contents = ((Lexical) tag.getContents()).getString();
        return contents.substring(1, contents.length() -1);
      }
    }
    return "";
  }
 
  private static Module buildModule(String name, ModuleEnvironment env,  IEvaluator<Result<IValue>> eval) throws IOException {
    IConstructor tree = eval.parseModule(eval, URIUtil.createRascalModule(name));
    return getBuilder().buildModule(tree);
  }
 
  private static ASTBuilder getBuilder() {
    return new ASTBuilder();
  }

  private static void addImportToCurrentModule(ISourceLocation src, String name, IEvaluator<Result<IValue>> eval) {
    ModuleEnvironment module = eval.getHeap().getModule(name);
    if (module == null) {
      throw new UndeclaredModule(name, src);
    }
    ModuleEnvironment current = eval.getCurrentModuleEnvironment();
    current.addImport(name, module);
    current.setSyntaxDefined(current.definesSyntax() || module.definesSyntax());
  }
 
  public static IConstructor parseModule(char[] data, URI location, IEvaluator<Result<IValue>> eval){
    eval.__setInterrupt(false);
    IActionExecutor<IConstructor> actions = new NoActionExecutor();

    try {
      eval.startJob("Parsing " + location, 10);
      eval.event("initial parse");

      IConstructor tree = new RascalParser().parse(Parser.START_MODULE, location, data, actions, new DefaultNodeFlattener<IConstructor, IConstructor, ISourceLocation>(), new UPTRNodeFactory());

      if (TreeAdapter.isAmb(tree)) {
        // Ambiguity is dealt with elsewhere
        return tree;
      }

      IConstructor top = TreeAdapter.getStartTop(tree);

      String name = Modules.getName(top);

      // create the current module if it does not exist yet
      GlobalEnvironment heap = eval.getHeap();
      ModuleEnvironment env = heap.getModule(name);
      if(env == null){
        env = new ModuleEnvironment(name, heap);
        // do not add the module to the heap here.
      }
      env.setBootstrap(needBootstrapParser(data));

      // make sure all the imported and extended modules are loaded
      // since they may provide additional syntax definitions\
      Environment old = eval.getCurrentEnvt();
      try {
        eval.setCurrentEnvt(env);
        env.setInitialized(true);

        eval.event("defining syntax");
        ISet rules = Modules.getSyntax(top);
        for (IValue rule : rules) {
          evalImport(eval, (IConstructor) rule);
        }

        eval.event("importing modules");
        ISet imports = Modules.getImports(top);
        for (IValue mod : imports) {
          evalImport(eval, (IConstructor) mod);
        }

        eval.event("extending modules");
        ISet extend = Modules.getExtends(top);
        for (IValue mod : extend) {
          evalImport(eval, (IConstructor) mod);
        }

        eval.event("generating modules");
        ISet externals = Modules.getExternals(top);
        for (IValue mod : externals) {
          evalImport(eval, (IConstructor) mod);
        }
      }
      finally {
        eval.setCurrentEnvt(old);
      }

      // parse the embedded concrete syntax fragments of the current module
      IConstructor result = tree;
      if (!eval.getHeap().isBootstrapper() && (needBootstrapParser(data) || (env.definesSyntax() && containsBackTick(data, 0)))) {
        eval.event("parsing concrete syntax");
        result = parseFragments(eval, tree, location, env);
      }

      if (!eval.getSuspendTriggerListeners().isEmpty()) {
        result = DebugUpdater.pushDownAttributes(result);
      }

      return result;
    }
    finally {
      eval.endJob(true);
    }
  }
 
  private static void evalImport(IEvaluator<Result<IValue>> eval, IConstructor mod) {
    org.rascalmpl.ast.Import imp = (org.rascalmpl.ast.Import) getBuilder().buildValue(mod);
    try {
      imp.interpret(eval);
    }
    catch (StaticError e) {
      // parsing the current module should be robust wrt errors in modules it depends on.
      eval.getMonitor().warning("could not load module " + TreeAdapter.yield(mod) + "[" + e.getMessage() + "]", imp != null ? imp.getLocation() : eval.getCurrentAST().getLocation());
      if(eval.isInterrupted()) {
        e.printStackTrace();
        throw e;
      }
    }
  }

  /**
   * This function will reconstruct a parse tree of a module, where all nested concrete syntax fragments
   * have been parsed and their original flat literal strings replaced by fully structured parse trees.
   *
   * @param module is a parse tree of a Rascal module containing flat concrete literals
   * @param parser is the parser to use for the concrete literals
   * @return parse tree of a module with structured concrete literals, or parse errors
   */
  public static IConstructor parseFragments(final IEvaluator<Result<IValue>> eval, IConstructor module, final URI location, final ModuleEnvironment env) {
    // TODO: update source code locations!!
   
     return (IConstructor) module.accept(new IdentityTreeVisitor<ImplementationError>() {
       final IValueFactory vf = eval.getValueFactory();
      
       @Override
       public IConstructor visitTreeAppl(IConstructor tree)  {
         IConstructor pattern = getConcretePattern(tree);
        
         if (pattern != null) {
           IConstructor parsedFragment = parseFragment(eval, env, (IConstructor) TreeAdapter.getArgs(tree).get(0), location);
           return TreeAdapter.setArgs(tree, vf.list(parsedFragment));
         }
         else {
           IListWriter w = vf.listWriter();
           IList args = TreeAdapter.getArgs(tree);
           for (IValue arg : args) {
             w.append(arg.accept(this));
           }
           args = w.done();
          
           return TreeAdapter.setArgs(tree, args);
         }
       }

       private IConstructor getConcretePattern(IConstructor tree) {
         String sort = TreeAdapter.getSortName(tree);
         if (sort.equals("Expression") || sort.equals("Pattern")) {
           String cons = TreeAdapter.getConstructorName(tree);
           if (cons.equals("concrete")) {
             return (IConstructor) TreeAdapter.getArgs(tree).get(0);
           }
         }
         return null;
      }

      @Override
       public IConstructor visitTreeAmb(IConstructor arg) {
         throw new ImplementationError("unexpected ambiguity: " + arg);
       }
     });
  }
 
  @SuppressWarnings("unchecked")
  public static IGTD<IConstructor, IConstructor, ISourceLocation> getParser(IEvaluator<Result<IValue>> eval, ModuleEnvironment currentModule, URI loc, boolean force) {
    if (currentModule.getBootstrap()) {
      return new RascalParser();
    }
   
    if (currentModule.hasCachedParser()) {
      String className = currentModule.getCachedParser();
      Class<?> clazz;
      for (ClassLoader cl: eval.getClassLoaders()) {
        try {
          clazz = cl.loadClass(className);
          return (IGTD<IConstructor, IConstructor, ISourceLocation>) clazz.newInstance();
        } catch (ClassNotFoundException e) {
          continue;
        } catch (InstantiationException e) {
          throw new ImplementationError("could not instantiate " + className + " to valid IGTD parser", e);
        } catch (IllegalAccessException e) {
          throw new ImplementationError("not allowed to instantiate " + className + " to valid IGTD parser", e);
        }
      }
      throw new ImplementationError("class for cached parser " + className + " could not be found");
    }

    ParserGenerator pg = eval.getParserGenerator();
    IMap definitions = currentModule.getSyntaxDefinition();
   
    Class<IGTD<IConstructor, IConstructor, ISourceLocation>> parser = eval.getHeap().getObjectParser(currentModule.getName(), definitions);

    if (parser == null || force) {
      String parserName = currentModule.getName(); // .replaceAll("::", ".");

      parser = pg.getNewParser(eval, loc, parserName, definitions);
      eval.getHeap().storeObjectParser(currentModule.getName(), definitions, parser);
    }

    try {
      return parser.newInstance();
    } catch (InstantiationException e) {
      throw new ImplementationError(e.getMessage(), e);
    } catch (IllegalAccessException e) {
      throw new ImplementationError(e.getMessage(), e);
    } catch (ExceptionInInitializerError e) {
      throw new ImplementationError(e.getMessage(), e);
    }
  }
 
  private static IConstructor parseFragment(IEvaluator<Result<IValue>> eval, ModuleEnvironment env, IConstructor tree, URI uri) {
    IConstructor symTree = TreeAdapter.getArg(tree, "symbol");
    IConstructor lit = TreeAdapter.getArg(tree, "parts");
    Map<String, IConstructor> antiquotes = new HashMap<String,IConstructor>();
   
    IGTD<IConstructor, IConstructor, ISourceLocation> parser = env.getBootstrap() ? new RascalParser() : getParser(eval, env, TreeAdapter.getLocation(tree).getURI(), false);
   
    try {
      String parserMethodName = eval.getParserGenerator().getParserMethodName(symTree);
      DefaultNodeFlattener<IConstructor, IConstructor, ISourceLocation> converter = new DefaultNodeFlattener<IConstructor, IConstructor, ISourceLocation>();
      UPTRNodeFactory nodeFactory = new UPTRNodeFactory();
   
      char[] input = replaceAntiQuotesByHoles(eval, lit, antiquotes);
     
      IConstructor fragment = (IConstructor) parser.parse(parserMethodName, uri, input, converter, nodeFactory);
      fragment = replaceHolesByAntiQuotes(eval, fragment, antiquotes);

      IConstructor prod = TreeAdapter.getProduction(tree);
      IConstructor sym = ProductionAdapter.getDefined(prod);
      sym = SymbolAdapter.delabel(sym);
      IValueFactory vf = eval.getValueFactory();
      prod = ProductionAdapter.setDefined(prod, vf.constructor(Factory.Symbol_Label, vf.string("$parsed"), sym));
      return TreeAdapter.setProduction(TreeAdapter.setArg(tree, "parts", fragment), prod);
    }
    catch (ParseError e) {
      ISourceLocation loc = TreeAdapter.getLocation(tree);
      ISourceLocation src = eval.getValueFactory().sourceLocation(loc.getURI(), loc.getOffset() + e.getOffset(), loc.getLength(), loc.getBeginLine() + e.getBeginLine() - 1, loc.getEndLine() + e.getEndLine() - 1, loc.getBeginColumn() + e.getBeginColumn(), loc.getBeginColumn() + e.getEndColumn());
      eval.getMonitor().warning("parse error in concrete syntax", src);
      return tree.asAnnotatable().setAnnotation("parseError", src);
    }
    catch (StaticError e) {
      ISourceLocation loc = TreeAdapter.getLocation(tree);
      ISourceLocation src = eval.getValueFactory().sourceLocation(loc.getURI(), loc.getOffset(), loc.getLength(), loc.getBeginLine(), loc.getEndLine(), loc.getBeginColumn(), loc.getBeginColumn());
      eval.getMonitor().warning(e.getMessage(), e.getLocation());
      return tree.asAnnotatable().setAnnotation("can not parse fragment due to " + e.getMessage(), src);
    }
    catch (UndeclaredNonTerminalException e) {
      ISourceLocation loc = TreeAdapter.getLocation(tree);
      ISourceLocation src = eval.getValueFactory().sourceLocation(loc.getURI(), loc.getOffset(), loc.getLength(), loc.getBeginLine(), loc.getEndLine(), loc.getBeginColumn(), loc.getBeginColumn());
      eval.getMonitor().warning(e.getMessage(), src);
      return tree.asAnnotatable().setAnnotation("can not parse fragment due to " + e.getMessage(), src);
    }
  }
 
  private static char[] replaceAntiQuotesByHoles(IEvaluator<Result<IValue>> eval, IConstructor lit, Map<String, IConstructor> antiquotes) {
    IList parts = TreeAdapter.getArgs(lit);
    StringBuilder b = new StringBuilder();
   
    for (IValue elem : parts) {
      IConstructor part = (IConstructor) elem;
      String cons = TreeAdapter.getConstructorName(part);
     
      if (cons.equals("text")) {
        b.append(TreeAdapter.yield(part));
      }
      else if (cons.equals("newline")) {
        b.append('\n');
      }
      else if (cons.equals("lt")) {
        b.append('<');
      }
      else if (cons.equals("gt")) {
        b.append('>');
      }
      else if (cons.equals("bq")) {
        b.append('`');
      }
      else if (cons.equals("bs")) {
        b.append('\\');
      }
      else if (cons.equals("hole")) {
        b.append(createHole(eval, part, antiquotes));
      }
    }
   
    return b.toString().toCharArray();
  }

  private static String createHole(IEvaluator<Result<IValue>> ctx, IConstructor part, Map<String, IConstructor> antiquotes) {
    String ph = ctx.getParserGenerator().createHole(part, antiquotes.size());
    antiquotes.put(ph, part);
    return ph;
  }

  private static IConstructor replaceHolesByAntiQuotes(final IEvaluator<Result<IValue>> eval, IConstructor fragment, final Map<String, IConstructor> antiquotes) {
      return (IConstructor) fragment.accept(new IdentityTreeVisitor<ImplementationError>() {
        private final IValueFactory vf = eval.getValueFactory();
       
        @Override
        public IConstructor visitTreeAppl(IConstructor tree)  {
          String cons = TreeAdapter.getConstructorName(tree);
          if (cons == null || !cons.equals("$MetaHole") ) {
            IListWriter w = eval.getValueFactory().listWriter();
            IList args = TreeAdapter.getArgs(tree);
            for (IValue elem : args) {
              w.append(elem.accept(this));
            }
            args = w.done();
           
            return TreeAdapter.setArgs(tree, args);
          }
         
          IConstructor type = retrieveHoleType(tree);
          return antiquotes.get(TreeAdapter.yield(tree)).asAnnotatable().setAnnotation("holeType", type);
        }
       
        private IConstructor retrieveHoleType(IConstructor tree) {
          IConstructor prod = TreeAdapter.getProduction(tree);
          ISet attrs = ProductionAdapter.getAttributes(prod);

          for (IValue attr : attrs) {
            if (((IConstructor) attr).getConstructorType() == Factory.Attr_Tag) {
              IValue arg = ((IConstructor) attr).get(0);
             
              if (arg.getType().isNode() && ((INode) arg).getName().equals("holeType")) {
                return (IConstructor) ((INode) arg).get(0);
              }
            }
          }
         
          throw new ImplementationError("expected to find a holeType, but did not: " + tree);
        }

        @Override
        public IConstructor visitTreeAmb(IConstructor arg)  {
          ISetWriter w = vf.setWriter();
          for (IValue elem : TreeAdapter.getAlternatives(arg)) {
            w.insert(elem.accept(this));
          }
          return arg.set("alternatives", w.done());
        }
      });
  }
  private static boolean containsBackTick(char[] data, int offset) {
    for (int i = data.length - 1; i >= offset; --i) {
      if (data[i] == '`')
        return true;
    }
    return false;
  }
 
  private static boolean needBootstrapParser(char[] input) {
    return new String(input).contains("@bootstrapParser");
  }
}
TOP

Related Classes of org.rascalmpl.semantics.dynamic.Import

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.