]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/types/TMetaVar.java
migrated to svn revision 33108
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / types / TMetaVar.java
index 8d2307b232423d33182cfb8a130bc912af52012a..0d3114fc5765b0bad9a3ad11df5aaef8dc803bf1 100644 (file)
@@ -1,11 +1,10 @@
 package org.simantics.scl.compiler.types;
 
-import gnu.trove.map.hash.THashMap;
-import gnu.trove.set.hash.THashSet;
-
 import java.util.ArrayList;
 
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
 import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.internal.types.HashCodeUtils;
 import org.simantics.scl.compiler.internal.types.TypeHashCodeContext;
 import org.simantics.scl.compiler.internal.types.ast.TVarAst;
 import org.simantics.scl.compiler.internal.types.ast.TypeAst;
@@ -17,6 +16,9 @@ import org.simantics.scl.compiler.types.kinds.Kinds;
 import org.simantics.scl.compiler.types.util.Polarity;
 import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
 
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.set.hash.THashSet;
+
 
 
 /**
@@ -28,10 +30,34 @@ import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
  */
 public class TMetaVar extends Type {
     public static final TMetaVar[] EMPTY_ARRAY = new TMetaVar[0];
+    public static final boolean DEBUG = false;
     
     Type ref = null;
+    Type skeletonRef = null;
     Polarity polarity = Polarity.NO_POLARITY;
     private Kind kind;
+    private TMetaVarListener listener;
+    
+    public static abstract class TMetaVarListener {
+        private Object prev; // TMetaVarListener or TMetaVar
+        private TMetaVarListener next;
+        
+        public abstract void notifyAboutChange();
+        
+        public void remove() {
+            if(prev == null)
+                return; // Not added or not anymore listening TMetaVar
+            if(prev instanceof TMetaVar)
+                ((TMetaVar)prev).listener = next;
+            else
+                ((TMetaVarListener)prev).next = next;
+            if(next != null) {
+                next.prev = prev;
+                next = null;
+            }
+            prev = null;
+        }
+    }
     
     TMetaVar(Kind kind) {
         this.kind = kind;
@@ -115,13 +141,22 @@ public class TMetaVar extends Type {
             ref.collectEffectMetaVars(vars);
     }
 
-    public void setRef(Type a) throws UnificationException {
-        a = Types.weakCanonical(a);
-        if(a.contains(this))
-            throw new UnificationException(this, a);
-        ref = a;
+    public void setRef(Type type) throws UnificationException {
+        if(DEBUG)
+            System.out.println("setRef " + System.identityHashCode(this) + " -> " + type);
+        if(ref != null)
+            throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
+        if(type.contains(this))
+            throw new UnificationException(this, type);
+        ref = type;
         if(polarity != Polarity.NO_POLARITY)
-            a.addPolarity(polarity);
+            type.addPolarity(polarity);
+        if(skeletonRef != null) {
+            Type skeleton = skeletonRef;
+            skeletonRef = null;
+            Skeletons.unifySkeletons(skeleton, type);
+        }
+        fireNotifyAboutChange();
     }
     
     public Type getRef() {
@@ -130,10 +165,12 @@ public class TMetaVar extends Type {
     
     @Override
     public boolean contains(TMetaVar other) {
-        if(ref == null)
-            return this == other;
-        else
+        if(ref != null)
             return ref.contains(other);
+        else if(skeletonRef != null)
+            return skeletonRef.contains(other);
+        else
+            return this == other;
     }
     
     @Override
@@ -231,4 +268,79 @@ public class TMetaVar extends Type {
             return result;
         }
     }
+
+    public void setSkeletonRef(Type type) throws UnificationException {
+        if(DEBUG)
+            System.out.println("setSkeletonRef " +  System.identityHashCode(this) + " -> " + type);
+        if(ref != null || skeletonRef != null)
+            throw new InternalCompilerError("Method setRef should be called only for unbound meta variables.");
+        if(type.contains(this))
+            throw new UnificationException(this, type);
+        this.skeletonRef = type;
+        fireNotifyAboutChange();
+    }
+    
+    @Override
+    public int hashCode(int hash) {
+        if(ref == null)
+            return HashCodeUtils.update(hash, System.identityHashCode(this));
+        else
+            return ref.hashCode(hash);
+    }
+    
+    @Override
+    public int hashCode(int hash, TVar[] boundVars) {
+        if(ref == null)
+            return HashCodeUtils.update(hash, System.identityHashCode(this));
+        else
+            return ref.hashCode(hash, boundVars);
+    }
+    
+    @Override
+    public boolean equalsCanonical(Type other) {
+        return this == other;
+    }
+    
+    @Override
+    public Type canonical() {
+        if(ref == null)
+            return this;
+        else
+            return ref = ref.canonical();
+    }
+    
+    public void addListener(TMetaVarListener newListener) {
+        if(DEBUG)
+            System.out.println("addListener " + System.identityHashCode(this));
+        newListener.next = listener;
+        newListener.prev = this;
+        if(listener != null)
+            listener.prev = newListener;
+        listener = newListener;
+    }
+    
+    private void fireNotifyAboutChange() {
+        if(DEBUG)
+            System.out.println("fireNotifyAboutChange " + System.identityHashCode(this) + " " + ref);
+        TMetaVarListener cur = listener;
+        listener = null;
+        while(cur != null) {
+            if(DEBUG)
+                System.out.println("    call listener");
+            cur.prev = null; // This prevents TMetaVarListener.remove from doing anything
+            cur.notifyAboutChange();
+            TMetaVarListener next = cur.next;
+            cur.next = null;
+            cur = next;
+        }
+    }
+    
+    public TMetaVarListener getLatestListener() {
+        return listener;
+    }
+
+    @Override
+    public Kind getKind(Environment context) {
+        return kind;
+    }
 }