]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/subsumption/Var.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / elaboration / subsumption / Var.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/subsumption/Var.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/elaboration/subsumption/Var.java
new file mode 100644 (file)
index 0000000..00783d8
--- /dev/null
@@ -0,0 +1,290 @@
+package org.simantics.scl.compiler.internal.elaboration.subsumption;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
+import org.simantics.scl.compiler.internal.types.effects.EffectIdMap;\r
+import org.simantics.scl.compiler.top.SCLCompilerConfiguration;\r
+import org.simantics.scl.compiler.types.TMetaVar;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.exceptions.UnificationException;\r
+\r
+public class Var {\r
+    String name;\r
+    \r
+    int constLowerBound = EffectIdMap.MIN;\r
+    int constUpperBound = EffectIdMap.MAX;\r
+    int upperApprox = EffectIdMap.MAX;\r
+    TMetaVar original;\r
+    \r
+    ArrayList<Var> simpleLowerBounds = new ArrayList<Var>();\r
+    ArrayList<Var> simpleUpperBounds = new ArrayList<Var>();\r
+    ArrayList<VUnion> complexLowerBounds = new ArrayList<VUnion>();\r
+    ArrayList<VUnion> complexUpperBounds = new ArrayList<VUnion>();\r
+    \r
+    SubSolver solver;\r
+    boolean dirty;\r
+    \r
+    public Var(TMetaVar original, String name, SubSolver solver) {\r
+        this.original = original;\r
+        this.name = name;\r
+        this.solver = solver;        \r
+        markDirty();\r
+    }\r
+\r
+    void markDirty() {\r
+        if(!dirty) {\r
+            dirty = true;\r
+            solver.dirtyQueue.add(this);\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Adds a constant constraint\r
+     */\r
+    public void addUpperBound(int c) {\r
+        c &= constUpperBound;\r
+        if(c != constUpperBound) {\r
+            if((c & constLowerBound) != constLowerBound) {\r
+                solver.errorLog.log(solver.globalLoc, "Subsumption failed: " + \r
+                        solver.effectIds.toType(constLowerBound) + " is not a subtype of " +\r
+                        solver.effectIds.toType(c)\r
+                        );\r
+                return;\r
+            }\r
+            constUpperBound = c;\r
+            for(int i=0;i<complexUpperBounds.size();++i) {\r
+                VUnion u = complexUpperBounds.get(i); \r
+                u.con &= c;\r
+                if(u.con == 0 && u.vars.size() == 1) {\r
+                    removeComplexUpperBound(i);               \r
+                    --i;\r
+                    addUpperBound(u.vars.get(0));\r
+                }\r
+            }\r
+            markDirty();\r
+        }\r
+    }\r
+    \r
+    public void addLowerBound(int c) {\r
+        if((c | constUpperBound) != constUpperBound) {\r
+            solver.errorLog.log(solver.globalLoc, "Subsumption failed: " + \r
+                    solver.effectIds.toType(c) + " is not a subtype of " +\r
+                    solver.effectIds.toType(constUpperBound)\r
+                    );\r
+            return;\r
+        }\r
+        constLowerBound |= c;\r
+        markDirty();\r
+    }\r
+    \r
+    private void removeComplexUpperBound(int i) {\r
+        VUnion u = complexUpperBounds.get(i);\r
+        int lastId = complexUpperBounds.size()-1;        \r
+        VUnion last = complexUpperBounds.remove(lastId);\r
+        if(i < lastId)\r
+            complexUpperBounds.set(i, last);\r
+        for(Var v : u.vars) {\r
+            v.complexLowerBounds.remove(u);\r
+            v.markDirty();\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Adds a simple variable constraint\r
+     */\r
+    public void addUpperBound(Var var) {\r
+        if(var == this)\r
+            return;\r
+        if(simpleUpperBounds.size() < var.simpleLowerBounds.size()) {\r
+            if(simpleUpperBounds.contains(var))\r
+                return;\r
+        }\r
+        else {\r
+            if(var.simpleLowerBounds.contains(this))\r
+                return;\r
+        }\r
+        \r
+        for(int i=0;i<complexUpperBounds.size();++i)\r
+            if(complexUpperBounds.get(i).vars.contains(var)) {\r
+                removeComplexUpperBound(i);               \r
+                --i;\r
+            }\r
+        \r
+        simpleUpperBounds.add(var);\r
+        var.simpleLowerBounds.add(this);\r
+        \r
+        markDirty();\r
+        var.markDirty();\r
+    }\r
+    \r
+    /**\r
+     * Adds a complex constraint\r
+     */\r
+    public void addUpperBound(VUnion u) {\r
+        if(u.vars.isEmpty()) {\r
+            addUpperBound(u.con);\r
+            return;\r
+        }        \r
+        if(u.vars.contains(this))\r
+            return;        \r
+        for(Var v : u.vars)\r
+            if(simpleUpperBounds.contains(v))\r
+                return;\r
+        u.con &= constUpperBound;\r
+        if(u.con == constUpperBound)\r
+            return;\r
+        if(u.con == 0 && u.vars.size() == 1)\r
+            addUpperBound(u.vars.get(0));\r
+        else {\r
+            u.low = this;\r
+            complexUpperBounds.add(u);\r
+            markDirty();\r
+            for(Var v : u.vars)\r
+                v.complexLowerBounds.add(u);\r
+        }\r
+        // TODO compare complex upper bounds together\r
+    }\r
+    \r
+    public void replaceWith(int con) {\r
+        // Check that replacement is sound\r
+        if(SCLCompilerConfiguration.DEBUG) {\r
+            if((con&constLowerBound) != constLowerBound)\r
+                throw new InternalCompilerError();\r
+            if((con|constUpperBound) != constUpperBound)\r
+                throw new InternalCompilerError();\r
+        }\r
+        \r
+        // Remove the variable and unify original TMetaVar\r
+        solver.vars.remove(original);\r
+        try {\r
+            Type type = solver.effectIds.toType(con);\r
+            if(SubSolver.DEBUG)\r
+                System.out.println(original.toString(solver.tuc) + " := " + type.toString(solver.tuc));\r
+            original.setRef(type);\r
+        } catch (UnificationException e) {\r
+            throw new InternalCompilerError();\r
+        }\r
+        \r
+        // Propagate change to lower and upper bounds\r
+        for(Var v : simpleUpperBounds) {\r
+            v.simpleLowerBounds.remove(this);\r
+            v.addLowerBound(con);\r
+            v.markDirty();\r
+        }\r
+        for(Var v : simpleLowerBounds) {\r
+            v.simpleUpperBounds.remove(this);\r
+            v.addUpperBound(con);\r
+            v.markDirty();\r
+        }\r
+        for(VUnion u : complexUpperBounds) {\r
+            u.low = null;\r
+            u.con |= ~con;\r
+            if(u.vars.size() == 1) {\r
+                Var uv = u.vars.get(0);\r
+                uv.constLowerBound |= ~u.con;\r
+                uv.complexLowerBounds.remove(u);\r
+                uv.markDirty();\r
+            }\r
+            else {\r
+                for(Var uv : u.vars)\r
+                    uv.markDirty();\r
+            }\r
+        }\r
+        for(VUnion u : complexLowerBounds) {\r
+            u.low.markDirty();\r
+            u.vars.remove(this);\r
+            u.con |= con;\r
+            u.con &= u.low.constUpperBound;\r
+            if(u.vars.isEmpty()) {\r
+                u.low.complexUpperBounds.remove(u);\r
+                u.low.addUpperBound(u.con);\r
+            }\r
+            else if(u.vars.size() == 1 && u.con == 0) {\r
+                u.low.complexUpperBounds.remove(u);\r
+                u.low.addUpperBound(u.vars.get(0));\r
+            }\r
+        }\r
+    }\r
+    \r
+    public void replaceDownwards(Var var) {\r
+        // Remove the variable and unify original TMetaVar\r
+        solver.vars.remove(original);\r
+        try {\r
+            if(SubSolver.DEBUG)\r
+                System.out.println(original.toString(solver.tuc) + " := " + var.original.toString(solver.tuc));\r
+            original.setRef(var.original);\r
+        } catch (UnificationException e) {\r
+            throw new InternalCompilerError();\r
+        }\r
+        \r
+        // Remove downwards dependencies\r
+        if(constLowerBound != 0)\r
+            throw new InternalCompilerError();\r
+        for(Var v : simpleLowerBounds)\r
+            v.simpleUpperBounds.remove(this);\r
+        if(!complexLowerBounds.isEmpty())\r
+            throw new InternalCompilerError();\r
+        var.markDirty();\r
+        \r
+        // Propagate change to upper bounds\r
+        var.addUpperBound(constUpperBound);\r
+        for(Var v : simpleUpperBounds) {\r
+            v.simpleLowerBounds.remove(this);\r
+            var.addUpperBound(v);\r
+        }\r
+        for(VUnion u : complexUpperBounds) {\r
+            var.addUpperBound(u);\r
+        }\r
+    }\r
+    \r
+    public void replaceUpwards(Var var) {\r
+        // Remove the variable and unify original TMetaVar\r
+        solver.vars.remove(original);\r
+        try {\r
+            if(SubSolver.DEBUG)\r
+                System.out.println(original.toString(solver.tuc) + " := " + var.original.toString(solver.tuc));\r
+            original.setRef(var.original);\r
+        } catch (UnificationException e) {\r
+            throw new InternalCompilerError();\r
+        }\r
+        \r
+        // Remove upwards dependencies\r
+        if(constUpperBound != EffectIdMap.MAX)\r
+            throw new InternalCompilerError();\r
+        for(Var v : simpleUpperBounds)\r
+            v.simpleLowerBounds.remove(this);\r
+        if(!complexUpperBounds.isEmpty())\r
+            throw new InternalCompilerError();\r
+        var.markDirty();\r
+        \r
+        // Propagate change to lower bounds\r
+        var.addLowerBound(constLowerBound);\r
+        for(Var v : simpleLowerBounds) {\r
+            v.simpleUpperBounds.remove(this);\r
+            v.markDirty();\r
+            v.addUpperBound(var);\r
+        }\r
+        for(VUnion u : complexLowerBounds) {\r
+            u.vars.remove(this);\r
+            if(u.low != null) {\r
+                u.low.markDirty();            \r
+                if(u.vars.isEmpty() && u.con == 0) {\r
+                    u.low.complexUpperBounds.remove(u);\r
+                    u.low.addUpperBound(var);\r
+                    continue;\r
+                }\r
+            }\r
+            u.addVar(var);\r
+        }\r
+    }\r
+\r
+    public boolean isFree() {\r
+        return constLowerBound == EffectIdMap.MIN && \r
+                constUpperBound == EffectIdMap.MAX &&\r
+                simpleLowerBounds.isEmpty() &&\r
+                simpleUpperBounds.isEmpty() &&\r
+                complexLowerBounds.isEmpty() &&\r
+                complexUpperBounds.isEmpty();\r
+    }\r
+}\r