--- /dev/null
+package org.simantics.scl.runtime.unification;
+
+import org.simantics.scl.runtime.function.Function;
+import org.simantics.scl.runtime.tuple.Tuple;
+import org.simantics.scl.runtime.tuple.Tuple0;
+
+
+public class Unification {
+ public static Object canonical(Object a) {
+ if(a instanceof UVar) {
+ UVar ua = (UVar)a;
+ if(ua.bound)
+ return ua.ref = canonical(ua.ref);
+ else
+ return a;
+ }
+ return a;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void unify(Object a, Object b) {
+ a = canonical(a);
+ b = canonical(b);
+ if(a == b)
+ return;
+ if(a instanceof UVar) {
+ ((UVar)a).setRef(b);
+ return;
+ }
+ if(b instanceof UVar) {
+ ((UVar)b).setRef(a);
+ return;
+ }
+ if(a instanceof UPending) {
+ ((UPending)a).checkAgains(b);
+ return;
+ }
+ if(b instanceof UPending) {
+ ((UPending)b).checkAgains(a);
+ return;
+ }
+ if(a instanceof UCons) {
+ UCons ua = (UCons)a;
+ if(b instanceof UCons) {
+ UCons ub = (UCons)b;
+ if(ua.tag.id != ub.tag.id)
+ throw new RuntimeUnificationException();
+ unifyTuple(ua.components, ub.components);
+ ua.components = ub.components;
+ }
+ else {
+ Object bComponents = ua.tag.destructor.apply(b);
+ unifyTuple(ua.components, bComponents);
+ ua.components = bComponents;
+ }
+ }
+ else {
+ if(b instanceof UCons) {
+ UCons ub = (UCons)b;
+ Object aComponents = ub.tag.destructor.apply(a);
+ unifyTuple(aComponents, ub.components);
+ ub.components = aComponents;
+ }
+ else {
+ if(a == null ? b != null : !a.equals(b))
+ throw new RuntimeUnificationException();
+ }
+ }
+ }
+
+ public static void unifyTuple(Object a, Object b) {
+ if(a instanceof Tuple) {
+ Tuple ta = (Tuple)a;
+ Tuple tb = (Tuple)b;
+ int length = ta.length();
+ for(int i=0;i<length;++i)
+ unify(ta.get(i), tb.get(i));
+ }
+ else {
+ unify(a, b);
+ }
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static Object extractWithDefault(Function def, Object uni) {
+ if(uni instanceof UVar) {
+ UVar var = (UVar)uni;
+ if(var.bound)
+ return var.ref = extractWithDefault(def, var.ref);
+ else {
+ var.bound = true;
+ return var.ref = def.apply(Tuple0.INSTANCE);
+ }
+ }
+ else if(uni instanceof UCons) {
+ UCons cons = (UCons)uni;
+ return cons.tag.constructor.apply(cons.components);
+ }
+ else if(uni instanceof UPending) {
+ UPending pending = (UPending)uni;
+ return pending.force();
+ }
+ else
+ return uni;
+ }
+}