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(); } } }