--- /dev/null
+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