]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/repository/ModuleRepository.java
Compilation of SCL expressions from SCL
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / module / repository / ModuleRepository.java
index 5078d00802ba7fb257c37daa13cf49c43eb51e37..0f0b8542049a53c7f8eea2667ba15c40789f0f7b 100644 (file)
@@ -4,12 +4,13 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
+import org.simantics.scl.compiler.compilation.CompilationContext;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.environment.ConcreteEnvironment;
+import org.simantics.scl.compiler.environment.EmptyEnvironment;
 import org.simantics.scl.compiler.environment.Environment;
 import org.simantics.scl.compiler.environment.NamespaceImpl.ModuleImport;
 import org.simantics.scl.compiler.environment.NamespaceSpec;
@@ -20,10 +21,12 @@ import org.simantics.scl.compiler.errors.CompilationError;
 import org.simantics.scl.compiler.errors.DoesNotExist;
 import org.simantics.scl.compiler.errors.Failable;
 import org.simantics.scl.compiler.errors.Failure;
+import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.errors.Success;
 import org.simantics.scl.compiler.module.ImportDeclaration;
 import org.simantics.scl.compiler.module.Module;
 import org.simantics.scl.compiler.module.options.ModuleCompilationOptionsAdvisor;
+import org.simantics.scl.compiler.module.repository.UpdateListener.Observable;
 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
 import org.simantics.scl.compiler.runtime.RuntimeEnvironmentImpl;
 import org.simantics.scl.compiler.runtime.RuntimeModule;
@@ -36,6 +39,7 @@ import org.simantics.scl.compiler.top.ValueNotFound;
 import org.simantics.scl.compiler.types.Types;
 
 import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TObjectLongHashMap;
 import gnu.trove.procedure.TObjectObjectProcedure;
 import gnu.trove.set.hash.THashSet;
 
@@ -67,9 +71,9 @@ public class ModuleRepository {
         PENDING_MODULES.get().remove(moduleName);
     }
     
-    private class ModuleEntry implements UpdateListener {
+    private class ModuleEntry extends UpdateListener implements Observable {
         final String moduleName;
-        WeakHashMap<UpdateListener,Object> listeners = new WeakHashMap<UpdateListener,Object>();
+        THashSet<UpdateListener> listeners = new THashSet<UpdateListener>();
         
         ModuleSource source;
         Failable<Module> compilationResult;
@@ -80,14 +84,20 @@ public class ModuleRepository {
         }
         
         synchronized void addListener(UpdateListener listener) {
-            if(listener != null)
-                listeners.put(listener, null);
+            if(listener == null || listeners == null)
+                return;
+            listeners.add(listener);
+            listener.addObservable(this);
+        }
+
+        public synchronized void removeListener(UpdateListener listener) {
+            if (listeners == null)
+                return;
+            listeners.remove(listener);
         }
         
         @Override
         public void notifyAboutUpdate() {
-            if (listeners == null)
-                return;
             ArrayList<UpdateListener> externalListeners = new ArrayList<UpdateListener>();
             notifyAboutUpdate(externalListeners);
             for(UpdateListener listener : externalListeners)
@@ -95,18 +105,26 @@ public class ModuleRepository {
         }
 
         synchronized void notifyAboutUpdate(ArrayList<UpdateListener> externalListeners) {
+            stopListening();
+            if (listeners == null)
+                return;
             if(moduleCache.get(moduleName) == this) {
                 moduleCache.remove(moduleName);
                 if(SCLCompilerConfiguration.TRACE_MODULE_UPDATE) {
                     System.out.println("Invalidate " + moduleName);
-                    for(UpdateListener l : listeners.keySet())
+                    for(UpdateListener l : listeners)
                         System.out.println("    " + l);
                 }
-                for(UpdateListener l : listeners.keySet())
+                THashSet<UpdateListener> listenersCopy = listeners;
+                listeners = null;
+                for(UpdateListener l : listenersCopy)
+                    l.stopListening();
+                for(UpdateListener l : listenersCopy)
                     if(l instanceof ModuleEntry)
                         ((ModuleEntry)l).notifyAboutUpdate(externalListeners);
-                    else
+                    else {
                         externalListeners.add(l);
+                    }
             }
         }
 
@@ -145,7 +163,7 @@ public class ModuleRepository {
                         Collection<ImportDeclaration> dependencies = module.getDependencies();
                         THashMap<String, ModuleEntry> moduleEntries;
                         try {
-                            moduleEntries = getModuleEntries(dependencies.toArray(new ImportDeclaration[dependencies.size()]), null);
+                            moduleEntries = getModuleEntries(null, dependencies.toArray(new ImportDeclaration[dependencies.size()]), null, false);
                         } catch (ImportFailureException e) {
                             throw new InternalCompilerError(e);
                         }
@@ -159,7 +177,7 @@ public class ModuleRepository {
                         if(parentModule != null)
                             parentModules.add(parentModule);
                     }*/
-                    RuntimeModule rm = new RuntimeModule(module, parentModules, source.getClassLoader());
+                    RuntimeModule rm = new RuntimeModule(module, parentModules, module.getParentClassLoader());
                     ModuleInitializer initializer = module.getModuleInitializer();
                     if(initializer != null)
                         try {
@@ -176,12 +194,17 @@ public class ModuleRepository {
             return runtimeModule;
         }
 
-        public void dispose() {
-            listeners.clear();
+        public synchronized void dispose() {
+            if (listeners != null)
+                listeners.clear();
             listeners = null;
+            stopListening();
             source = null;
             compilationResult = null;
-            runtimeModule.getResult().dispose();
+            if (runtimeModule != null) {
+                if (runtimeModule.didSucceed())
+                    runtimeModule.getResult().dispose();
+            }
             runtimeModule = null;
         }
         
@@ -215,7 +238,7 @@ public class ModuleRepository {
     public Failable<RuntimeModule> getRuntimeModule(String moduleName) {
         return getRuntimeModule(moduleName, null);
     }
-    
+
     private ModuleEntry getModuleEntry(String moduleName, UpdateListener listener) {
         /* It is deliberate that the following code does not try to prevent
          * simultaneous compilation of the same module. This is because in
@@ -235,22 +258,35 @@ public class ModuleRepository {
     }
     
     private THashMap<String, ModuleEntry> getModuleEntries(
+            CompilationContext compilationContext,
             ImportDeclaration[] imports,
-            UpdateListener listener) throws ImportFailureException {
+            UpdateListener listener,
+            boolean robustly) throws ImportFailureException {
         THashMap<String, ModuleEntry> result = new THashMap<String, ModuleEntry>();
         Collection<ImportFailure> failures = null;
         
+        TObjectLongHashMap<String> originalImports = new TObjectLongHashMap<String>(); 
         ArrayList<ImportDeclaration> stack = new ArrayList<ImportDeclaration>(imports.length);
-        for(ImportDeclaration import_ : imports)
+        for(ImportDeclaration import_ : imports) {
             stack.add(import_);
+            originalImports.put(import_.moduleName, import_.location);
+        }
         while(!stack.isEmpty()) {
             ImportDeclaration import_ = stack.remove(stack.size()-1);
             if(!result.containsKey(import_.moduleName)) {
-                ModuleEntry entry = getModuleEntry(import_.moduleName, listener);
+                boolean originalImport = originalImports.contains(import_.moduleName);
+                ModuleEntry entry = getModuleEntry(import_.moduleName, originalImport ? listener : null);
                 Failable<Module> compilationResult = entry.compilationResult;
                 if(compilationResult.didSucceed()) {
                     result.put(import_.moduleName, entry);
                     stack.addAll(compilationResult.getResult().getDependencies());
+                    if(originalImport) {
+                        String deprecation = compilationResult.getResult().getDeprecation();
+                        if(deprecation != null && compilationContext != null) {
+                            long location = originalImport ? originalImports.get(import_.moduleName) : Locations.NO_LOCATION;
+                            compilationContext.errorLog.logWarning(location, "Deprecated module " + import_.moduleName   + (deprecation.isEmpty() ? "." : ": " + deprecation));
+                        }
+                    }
                 }
                 else {
                     if(failures == null)
@@ -263,7 +299,7 @@ public class ModuleRepository {
             }
         }
         
-        if(failures != null)
+        if(failures != null && !robustly)
             throw new ImportFailureException(failures);
         
         return result;
@@ -296,11 +332,32 @@ public class ModuleRepository {
     public Environment createEnvironment(
             ImportDeclaration[] imports,
             UpdateListener listener) throws ImportFailureException {
-        THashMap<String, ModuleEntry> entries = getModuleEntries(imports, listener);
+        return createEnvironment(null, imports, listener);
+    }
+    
+    public Environment createEnvironment(
+            CompilationContext compilationContext,
+            ImportDeclaration[] imports,
+            UpdateListener listener) throws ImportFailureException {
+        THashMap<String, ModuleEntry> entries = getModuleEntries(compilationContext, imports, listener, false);
         THashMap<String, Module> moduleMap = mapEntriesToModules(entries);
         return createEnvironment(moduleMap, imports);
     }
     
+    public Environment createEnvironmentRobustly(
+            CompilationContext compilationContext,
+            ImportDeclaration[] imports,
+            UpdateListener listener) {
+        try {
+            THashMap<String, ModuleEntry> entries = getModuleEntries(compilationContext, imports, listener, true);
+            THashMap<String, Module> moduleMap = mapEntriesToModules(entries);
+            return createEnvironment(moduleMap, imports);
+        } catch(ImportFailureException e) {
+            // Should not happen because of robust flag
+            return EmptyEnvironment.INSTANCE;
+        }
+    }
+    
     public Environment createEnvironment(
             EnvironmentSpecification specification,
             UpdateListener listener) throws ImportFailureException {
@@ -312,6 +369,10 @@ public class ModuleRepository {
         return createRuntimeEnvironment(environmentSpecification, parentClassLoader, null);
     }
     
+    public RuntimeEnvironment createRuntimeEnvironment(EnvironmentSpecification environmentSpecification) throws ImportFailureException {
+        return createRuntimeEnvironment(environmentSpecification, getClass().getClassLoader());
+    }
+    
     public RuntimeEnvironment createRuntimeEnvironment(
             EnvironmentSpecification environmentSpecification,
             ClassLoader parentClassLoader,
@@ -326,14 +387,15 @@ public class ModuleRepository {
             ImportDeclaration[] imports,
             ClassLoader parentClassLoader,
             UpdateListener listener) throws ImportFailureException {
-        THashMap<String, ModuleEntry> entries = getModuleEntries(imports, listener);
+        THashMap<String, ModuleEntry> entries = getModuleEntries(null, imports, listener, false);
         THashMap<String, Module> moduleMap = mapEntriesToModules(entries);
         Environment environment = createEnvironment(moduleMap, imports);
         THashMap<String, RuntimeModule> runtimeModuleMap = mapEntriesToRuntimeModules(entries);
         return new RuntimeEnvironmentImpl(environment, parentClassLoader, runtimeModuleMap);
     }
     
-    private static Environment createEnvironment(THashMap<String, Module> moduleMap, 
+    private static Environment createEnvironment(
+            THashMap<String, Module> moduleMap, 
             ImportDeclaration[] imports) {
         NamespaceSpec spec = new NamespaceSpec();
         for(ImportDeclaration import_ : imports)
@@ -458,6 +520,6 @@ public class ModuleRepository {
     public void setAdvisor(ModuleCompilationOptionsAdvisor advisor) {
         this.advisor = advisor;
     }
-\r
+
 }
  
\ No newline at end of file