]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/unification/UPending.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.scl.runtime / src / org / simantics / scl / runtime / unification / UPending.java
1 package org.simantics.scl.runtime.unification;
2
3 import java.util.ArrayList;
4
5 import org.simantics.scl.runtime.function.Function;
6 import org.simantics.scl.runtime.tuple.Tuple;
7 import org.simantics.scl.runtime.tuple.Tuple0;
8
9 public class UPending {
10     private static final int STATE_UNFORCED = 0;
11     private static final int STATE_CURRENTLY_FORCING = 1;
12     private static final int STATE_FORCED = 2;
13     private static final int STATE_UNFORCED_CHECK_PENDING = 3;
14     
15     @SuppressWarnings("rawtypes")
16     private final Function proc;
17     private int state = 0;
18     private Object value = null;
19
20     @SuppressWarnings("rawtypes")
21     public UPending(Function proc) {
22         this.proc = proc;
23     }
24     
25     @SuppressWarnings("unchecked")
26     public Object force() {
27         switch(state) {
28         case STATE_UNFORCED:
29             state = STATE_CURRENTLY_FORCING;
30             value = proc.apply(Tuple0.INSTANCE);
31             state = STATE_FORCED;
32             return value;
33         case STATE_CURRENTLY_FORCING:
34             throw new RuntimeUnificationException("Pending unification node depends recursively on itself.");
35         case STATE_FORCED:
36             return value;
37         case STATE_UNFORCED_CHECK_PENDING: {
38             ArrayList<Object> checks = (ArrayList<Object>)value;
39             state = STATE_CURRENTLY_FORCING;
40             value = proc.apply(Tuple0.INSTANCE);
41             state = STATE_FORCED;
42             for(Object check : checks)
43                 semiUnification(value, check);
44             return value;
45         }
46         default:
47             throw new IllegalStateException();
48         }
49     }
50
51     @SuppressWarnings("unchecked")
52     public void checkAgains(Object check) {
53         ArrayList<Object> checks;
54         switch(state) {
55         case STATE_UNFORCED:
56             checks = new ArrayList<Object>(2);
57             checks.add(check);
58             state = STATE_UNFORCED_CHECK_PENDING;
59             value = checks;
60             return;            
61         case STATE_CURRENTLY_FORCING:
62             throw new RuntimeUnificationException("Pending unification node depends recursively on itself.");
63         case STATE_FORCED:
64             semiUnification(value, check);
65             return;
66         case STATE_UNFORCED_CHECK_PENDING:
67             checks = (ArrayList<Object>)value;
68             checks.add(check);
69             return;
70         default:
71             throw new IllegalStateException();
72         }
73     }
74     
75     @SuppressWarnings("unchecked")
76     private static void semiUnification(Object constant, Object pendingOrConsOrConstant) {
77         if(pendingOrConsOrConstant instanceof UCons) {
78             UCons cons = (UCons)pendingOrConsOrConstant;
79             Tuple components = (Tuple)cons.tag.destructor.apply(constant);
80             Unification.unify(cons.components, components);
81             cons.components = components;
82         }
83         else if(pendingOrConsOrConstant instanceof UPending) {
84             UPending pending = (UPending)pendingOrConsOrConstant;
85             Object otherConstant = pending.force();
86             if(constant == null ? otherConstant != null : !constant.equals(otherConstant))
87                 throw new RuntimeUnificationException("Unification failed: " + constant + " != " + otherConstant + ".");
88         }
89         else {
90             if(constant == null ? pendingOrConsOrConstant != null : !constant.equals(pendingOrConsOrConstant))
91                 throw new RuntimeUnificationException();
92         }
93     }
94 }
95