All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snapscript.core.link.ImportTaskBuilder Maven / Gradle / Ivy

package org.snapscript.core.link;

import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Executor;

import org.snapscript.core.Context;
import org.snapscript.core.Entity;
import org.snapscript.core.Execution;
import org.snapscript.core.NameFormatter;
import org.snapscript.core.Statement;
import org.snapscript.core.error.InternalStateException;
import org.snapscript.core.module.Module;
import org.snapscript.core.module.Path;
import org.snapscript.core.scope.Scope;
import org.snapscript.core.type.TypeLoader;

public class ImportTaskBuilder {

   private final ImportEntityResolver resolver;
   private final NameFormatter formatter;
   private final Executor executor;
   private final Module parent;
   private final Set failures;
   private final Set imports;
   private final Path from;
   
   public ImportTaskBuilder(Module parent, Executor executor, Path from) {
      this.resolver = new ImportEntityResolver(parent);
      this.failures = new CopyOnWriteArraySet();
      this.imports = new CopyOnWriteArraySet();
      this.formatter = new NameFormatter();
      this.executor = executor;
      this.parent = parent;
      this.from = from;
   }
   
   public Callable createTask(String module, String name, Path path) throws Exception{
      if(!failures.contains(path)) {
         try {
            String qualifier = formatter.formatFullName(module, name);
            Context context = parent.getContext();
            TypeLoader loader = context.getLoader();
            Package entity = loader.importType(qualifier); // only explicit imports can be dynamic
            Package bundle = loader.importType(module, name); // load implicit and explicit
            
            return new DefineImport(bundle, entity, path, qualifier); // import exceptions will propagate
         } catch(Exception e) {
            failures.add(path);
         }
      }
      return null;
   }
   
   private class DefineImport implements Callable {
      
      private final Package bundle;
      private final String name;
      private final Path path;
      
      public DefineImport(Package bundle, Package entity, Path path, String name){
         this.bundle = bundle;
         this.name = name;
         this.path = path;
      }

      @Override
      public Entity call() {
         try {
            if(!imports.contains(path)) {
               Scope scope = parent.getScope();
               PackageDefinition definition = bundle.create(scope); 
               Statement statement = definition.define(scope, from);
               
               if(imports.add(path)) {
                  Runnable task = new CompileImport(statement, path);
                  
                  if(executor != null) {
                     executor.execute(task); // compile must be asynchronous to avoid deadlock
                  } else {
                     task.run();
                  }
               }
            }
         } catch(Exception e) {
            throw new InternalStateException("Could not import '" + path+"'", e);
         }
         return resolver.resolveEntity(name);
      }
   }

   private class CompileImport implements Runnable {

      private final Statement statement;
      private final Path path;
      
      public CompileImport(Statement statement, Path path) {
         this.statement = statement;
         this.path = path;
      }
      
      @Override
      public void run() {
         try {
            Scope scope = parent.getScope();
            Execution execution = statement.compile(scope, null);
            
            execution.execute(scope);
         }catch(Exception e){
            throw new InternalStateException("Could not compile import '" + path +"'", e); // hidden exception
         }
      }
      
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy