]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/unification/UPending.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.runtime / src / org / simantics / scl / runtime / unification / UPending.java
diff --git a/bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/unification/UPending.java b/bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/unification/UPending.java
new file mode 100644 (file)
index 0000000..86dff5e
--- /dev/null
@@ -0,0 +1,95 @@
+package org.simantics.scl.runtime.unification;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.runtime.function.Function;
+import org.simantics.scl.runtime.tuple.Tuple;
+import org.simantics.scl.runtime.tuple.Tuple0;
+
+public class UPending {
+    private static final int STATE_UNFORCED = 0;
+    private static final int STATE_CURRENTLY_FORCING = 1;
+    private static final int STATE_FORCED = 2;
+    private static final int STATE_UNFORCED_CHECK_PENDING = 3;
+    
+    @SuppressWarnings("rawtypes")
+    private final Function proc;
+    private int state = 0;
+    private Object value = null;
+
+    @SuppressWarnings("rawtypes")
+    public UPending(Function proc) {
+        this.proc = proc;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public Object force() {
+        switch(state) {
+        case STATE_UNFORCED:
+            state = STATE_CURRENTLY_FORCING;
+            value = proc.apply(Tuple0.INSTANCE);
+            state = STATE_FORCED;
+            return value;
+        case STATE_CURRENTLY_FORCING:
+            throw new RuntimeUnificationException("Pending unification node depends recursively on itself.");
+        case STATE_FORCED:
+            return value;
+        case STATE_UNFORCED_CHECK_PENDING: {
+            ArrayList<Object> checks = (ArrayList<Object>)value;
+            state = STATE_CURRENTLY_FORCING;
+            value = proc.apply(Tuple0.INSTANCE);
+            state = STATE_FORCED;
+            for(Object check : checks)
+                semiUnification(value, check);
+            return value;
+        }
+        default:
+            throw new IllegalStateException();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void checkAgains(Object check) {
+        ArrayList<Object> checks;
+        switch(state) {
+        case STATE_UNFORCED:
+            checks = new ArrayList<Object>(2);
+            checks.add(check);
+            state = STATE_UNFORCED_CHECK_PENDING;
+            value = checks;
+            return;            
+        case STATE_CURRENTLY_FORCING:
+            throw new RuntimeUnificationException("Pending unification node depends recursively on itself.");
+        case STATE_FORCED:
+            semiUnification(value, check);
+            return;
+        case STATE_UNFORCED_CHECK_PENDING:
+            checks = (ArrayList<Object>)value;
+            checks.add(check);
+            return;
+        default:
+            throw new IllegalStateException();
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    private static void semiUnification(Object constant, Object pendingOrConsOrConstant) {
+        if(pendingOrConsOrConstant instanceof UCons) {
+            UCons cons = (UCons)pendingOrConsOrConstant;
+            Tuple components = (Tuple)cons.tag.destructor.apply(constant);
+            Unification.unify(cons.components, components);
+            cons.components = components;
+        }
+        else if(pendingOrConsOrConstant instanceof UPending) {
+            UPending pending = (UPending)pendingOrConsOrConstant;
+            Object otherConstant = pending.force();
+            if(constant == null ? otherConstant != null : !constant.equals(otherConstant))
+                throw new RuntimeUnificationException("Unification failed: " + constant + " != " + otherConstant + ".");
+        }
+        else {
+            if(constant == null ? pendingOrConsOrConstant != null : !constant.equals(pendingOrConsOrConstant))
+                throw new RuntimeUnificationException();
+        }
+    }
+}
\ No newline at end of file