X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scl.runtime%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fruntime%2Funification%2FUPending.java;fp=bundles%2Forg.simantics.scl.runtime%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fruntime%2Funification%2FUPending.java;h=86dff5e6d588fc9fcc6e0d749c4ebb994ab581cf;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git 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 index 000000000..86dff5e6d --- /dev/null +++ b/bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/unification/UPending.java @@ -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 checks = (ArrayList)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 checks; + switch(state) { + case STATE_UNFORCED: + checks = new ArrayList(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)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