forked from ballerina-platform/nballerina
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcell.bal
168 lines (149 loc) · 5.51 KB
/
cell.bal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Implementation specific to basic type cell.
public const CELL_MUT_NONE = 0;
public const CELL_MUT_LIMITED = 1;
public const CELL_MUT_UNLIMITED = 2;
public type CellMutability CELL_MUT_NONE|CELL_MUT_LIMITED|CELL_MUT_UNLIMITED;
public type CellAtomicType readonly & record {|
SemType ty;
CellMutability mut;
|};
public function cellContaining(Env env, SemType ty, CellMutability mut = CELL_MUT_LIMITED) returns CellSemType {
CellAtomicType atomicCell = { ty, mut };
Atom atom = env.cellAtom(atomicCell);
BddNode bdd = bddAtom(atom);
return <CellSemType>basicSubtype(BT_CELL, bdd);
}
function cellSubtypeIsEmpty(Context cx, SubtypeData t) returns boolean {
return bddEvery(cx, <Bdd>t, (), (), cellFormulaIsEmpty);
}
function cellFormulaIsEmpty(Context cx, Conjunction? posList, Conjunction? negList) returns boolean {
CellAtomicType combined;
if posList == () {
combined = { ty: VAL, mut: CELL_MUT_UNLIMITED };
}
else {
combined = cellAtomType(posList.atom);
Conjunction? p = posList.next;
while true {
if p == () {
break;
}
combined = intersectCellAtomicType(combined, cellAtomType(p.atom));
p = p.next;
}
}
return !cellInhabited(cx, combined, negList);
}
function cellInhabited(Context cx, CellAtomicType posCell, Conjunction? negList) returns boolean {
SemType pos = posCell.ty;
if isEmpty(cx, pos) {
return false;
}
match posCell.mut {
CELL_MUT_NONE => {
return cellMutNoneInhabited(cx, pos, negList);
}
CELL_MUT_LIMITED => {
return cellMutLimitedInhabited(cx, pos, negList);
}
CELL_MUT_UNLIMITED|_ => {
return cellMutUnlimitedInhabited(cx, pos, negList);
}
}
}
function cellMutNoneInhabited(Context cx, SemType pos, Conjunction? negList) returns boolean {
SemType negListUnionResult = cellNegListUnion(negList);
// We expect `isNever` condition to be `true` when there are no negative atoms.
// Otherwise, we do `isEmpty` to conclude on the inhabitance.
return negListUnionResult == NEVER || !isEmpty(cx, diff(pos, negListUnionResult));
}
function cellNegListUnion(Conjunction? negList) returns SemType {
SemType negUnion = NEVER;
Conjunction? neg = negList;
while true {
if neg == () {
break;
}
negUnion = union(negUnion, cellAtomType(neg.atom).ty);
neg = neg.next;
}
return negUnion;
}
function cellMutLimitedInhabited(Context cx, SemType pos, Conjunction? negList) returns boolean {
if negList == () {
return true;
}
CellAtomicType negAtomicCell = cellAtomType(negList.atom);
if negAtomicCell.mut >= CELL_MUT_LIMITED && isEmpty(cx, diff(pos, negAtomicCell.ty)) {
return false;
}
return cellMutLimitedInhabited(cx, pos, negList.next);
}
function cellMutUnlimitedInhabited(Context cx, SemType pos, Conjunction? negList) returns boolean {
Conjunction? neg = negList;
while true {
if neg == () {
break;
}
if cellAtomType(neg.atom).mut == CELL_MUT_LIMITED && isSameType(cx, VAL, cellAtomType(neg.atom).ty) {
return false;
}
neg = neg.next;
}
SemType negListUnionResult = cellNegListUnlimitedUnion(negList);
// We expect `isNever` condition to be `true` when there are no negative atoms with unlimited mutability.
// Otherwise, we do `isEmpty` to conclude on the inhabitance.
return negListUnionResult == NEVER || !isEmpty(cx, diff(pos, negListUnionResult));
}
function cellNegListUnlimitedUnion(Conjunction? negList) returns SemType {
SemType negUnion = NEVER;
Conjunction? neg = negList;
while true {
if neg == () {
break;
}
if cellAtomType(neg.atom).mut == CELL_MUT_UNLIMITED {
negUnion = union(negUnion, cellAtomType(neg.atom).ty);
}
neg = neg.next;
}
return negUnion;
}
function intersectCellAtomicType(CellAtomicType c1, CellAtomicType c2) returns CellAtomicType {
SemType ty = intersect(c1.ty, c2.ty);
CellMutability mut = <CellMutability>int:min(c1.mut, c2.mut);
return { ty, mut };
}
function cellSubtypeUnion(ProperSubtypeData t1, ProperSubtypeData t2) returns ProperSubtypeData {
return cellSubtypeDataEnsureProper(bddSubtypeUnion(t1, t2));
}
function cellSubtypeIntersect(ProperSubtypeData t1, ProperSubtypeData t2) returns ProperSubtypeData {
return cellSubtypeDataEnsureProper(bddSubtypeIntersect(t1, t2));
}
function cellSubtypeDiff(ProperSubtypeData t1, ProperSubtypeData t2) returns ProperSubtypeData {
return cellSubtypeDataEnsureProper(bddSubtypeDiff(t1, t2));
}
function cellSubtypeComplement(ProperSubtypeData t) returns ProperSubtypeData {
return cellSubtypeDataEnsureProper(bddSubtypeComplement(t));
}
// SubtypeData being a boolean would result in a BasicTypeBitSet which could either be 0 or 1 << BT_CELL.
// This is to avoid cell type being a BasicTypeBitSet, as we don't want to lose the cell wrapper.
function cellSubtypeDataEnsureProper(SubtypeData subtypeData) returns ProperSubtypeData {
if subtypeData !is boolean {
return subtypeData;
}
Atom atom;
if subtypeData {
atom = ATOM_CELL_VAL;
} else {
atom = ATOM_CELL_NEVER;
}
return bddAtom(atom);
}
final BasicTypeOps cellOps = {
union: cellSubtypeUnion,
intersect: cellSubtypeIntersect,
diff: cellSubtypeDiff,
complement: cellSubtypeComplement,
isEmpty: cellSubtypeIsEmpty
};