aontu 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +203 -0
- package/dist/cli.js.map +1 -0
- package/dist/ctx.d.ts +2 -5
- package/dist/ctx.js +1 -2
- package/dist/ctx.js.map +1 -1
- package/dist/lang.d.ts +1 -5
- package/dist/lang.js +24 -100
- package/dist/lang.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +0 -5
- package/dist/type.js.map +1 -1
- package/dist/unify.js +13 -292
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +2 -6
- package/dist/utility.js.map +1 -1
- package/dist/val/BagVal.d.ts +3 -0
- package/dist/val/BagVal.js +6 -6
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/ConjunctVal.d.ts +1 -1
- package/dist/val/ConjunctVal.js +14 -137
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/CopyFuncVal.js +2 -3
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.js +0 -4
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/ExpectVal.js +3 -16
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/JunctionVal.d.ts +0 -1
- package/dist/val/JunctionVal.js +1 -6
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.js +2 -0
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.d.ts +0 -1
- package/dist/val/ListVal.js +66 -33
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/MapVal.d.ts +2 -3
- package/dist/val/MapVal.js +95 -67
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MoveFuncVal.d.ts +1 -2
- package/dist/val/MoveFuncVal.js +13 -78
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/PathFuncVal.js +4 -25
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PlusOpVal.d.ts +1 -1
- package/dist/val/PrefVal.js +5 -18
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/{PathVal.d.ts → RefVal.d.ts} +3 -4
- package/dist/val/{PathVal.js → RefVal.js} +77 -75
- package/dist/val/RefVal.js.map +1 -0
- package/dist/val/Val.d.ts +1 -2
- package/dist/val/Val.js +8 -7
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +2 -2
- package/dist/val/VarVal.js.map +1 -1
- package/package.json +9 -4
- package/src/cli.ts +193 -0
- package/src/ctx.ts +3 -16
- package/src/lang.ts +23 -113
- package/src/type.ts +0 -5
- package/src/unify.ts +13 -310
- package/src/utility.ts +2 -5
- package/src/val/BagVal.ts +7 -6
- package/src/val/ConjunctVal.ts +13 -131
- package/src/val/CopyFuncVal.ts +2 -3
- package/src/val/DisjunctVal.ts +0 -6
- package/src/val/ExpectVal.ts +4 -18
- package/src/val/JunctionVal.ts +1 -5
- package/src/val/KeyFuncVal.ts +3 -0
- package/src/val/ListVal.ts +88 -38
- package/src/val/MapVal.ts +124 -75
- package/src/val/MoveFuncVal.ts +14 -79
- package/src/val/PathFuncVal.ts +4 -29
- package/src/val/PrefVal.ts +6 -19
- package/src/val/{RefVal.ts.old → RefVal.ts} +19 -30
- package/src/val/Val.ts +9 -9
- package/src/val/VarVal.ts +2 -2
- package/README.md +0 -18
- package/dist/val/PathVal.js.map +0 -1
- package/dist/val/SpreadVal.d.ts +0 -20
- package/dist/val/SpreadVal.js +0 -194
- package/dist/val/SpreadVal.js.map +0 -1
- package/src/val/PathVal.ts +0 -435
- package/src/val/SpreadVal.ts +0 -275
package/src/val/DisjunctVal.ts
CHANGED
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
top
|
|
31
31
|
} from './top'
|
|
32
32
|
|
|
33
|
-
|
|
34
33
|
import { NilVal, TRIAL_NIL } from '../val/NilVal'
|
|
35
34
|
import { PrefVal } from '../val/PrefVal'
|
|
36
35
|
import { JunctionVal } from '../val/JunctionVal'
|
|
@@ -68,11 +67,6 @@ class DisjunctVal extends JunctionVal {
|
|
|
68
67
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
69
68
|
peer = peer ?? top()
|
|
70
69
|
|
|
71
|
-
// Fast path: already-done disjunct unifying with TOP.
|
|
72
|
-
if (this.done && peer.isTop) {
|
|
73
|
-
return this
|
|
74
|
-
}
|
|
75
|
-
|
|
76
70
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Disjunct', this, peer)
|
|
77
71
|
|
|
78
72
|
if (!this.prefsRanked) {
|
package/src/val/ExpectVal.ts
CHANGED
|
@@ -51,25 +51,11 @@ class ExpectVal extends FeatureVal {
|
|
|
51
51
|
this.peer = undefined === this.peer ? peer :
|
|
52
52
|
unite(te ? ctx.clone({ explain: ec(te, 'PEER') }) : ctx, this.peer, peer, 'expect-peer')
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
while (peg?.isExpect) {
|
|
57
|
-
peg = peg.peg
|
|
58
|
-
}
|
|
54
|
+
const peeru =
|
|
55
|
+
unite(te ? ctx.clone({ explain: ec(te, 'EXPECT') }) : ctx, this.peer, this.peg, 'expect-self')
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
out.dc = this.dc + 1
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
(this as any)._expectDepth = ((this as any)._expectDepth || 0) + 1
|
|
66
|
-
const peeru =
|
|
67
|
-
unite(te ? ctx.clone({ explain: ec(te, 'EXPECT') }) : ctx, this.peer, peg, 'expect-self')
|
|
68
|
-
;(this as any)._expectDepth--
|
|
69
|
-
|
|
70
|
-
if (peeru.isGenable) {
|
|
71
|
-
out = peeru
|
|
72
|
-
}
|
|
57
|
+
if (peeru.isGenable) {
|
|
58
|
+
out = peeru
|
|
73
59
|
}
|
|
74
60
|
}
|
|
75
61
|
|
package/src/val/JunctionVal.ts
CHANGED
|
@@ -17,7 +17,6 @@ import { FeatureVal } from './FeatureVal'
|
|
|
17
17
|
// (ConjunctVal and DisjunctVal)
|
|
18
18
|
abstract class JunctionVal extends FeatureVal {
|
|
19
19
|
isJunction = true
|
|
20
|
-
_canonCache?: string
|
|
21
20
|
|
|
22
21
|
constructor(
|
|
23
22
|
spec: ValSpec,
|
|
@@ -39,13 +38,10 @@ abstract class JunctionVal extends FeatureVal {
|
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
get canon() {
|
|
42
|
-
|
|
43
|
-
const c = this.peg.map((v: Val) => {
|
|
41
|
+
return this.peg.map((v: Val) => {
|
|
44
42
|
return (v as any).isJunction && Array.isArray(v.peg) && 1 < v.peg.length ?
|
|
45
43
|
'(' + v.canon + ')' : v.canon // v.id + '=' + v.canon
|
|
46
44
|
}).join(this.getJunctionSymbol()) // + '<' + (this.mark.hide ? 'H' : '') + '>'
|
|
47
|
-
if (this.done) this._canonCache = c
|
|
48
|
-
return c
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
// Abstract method to be implemented by subclasses to define their junction symbol
|
package/src/val/KeyFuncVal.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { ConjunctVal } from '../val/ConjunctVal'
|
|
|
18
18
|
|
|
19
19
|
import { FuncBaseVal } from './FuncBaseVal'
|
|
20
20
|
|
|
21
|
+
|
|
21
22
|
class KeyFuncVal extends FuncBaseVal {
|
|
22
23
|
isKeyFunc = true
|
|
23
24
|
|
|
@@ -40,12 +41,14 @@ class KeyFuncVal extends FuncBaseVal {
|
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
44
|
+
// TODO: this delay makes keys in spreads and refs work, but it is a hack - find a better way.
|
|
43
45
|
let out: Val = this
|
|
44
46
|
|
|
45
47
|
if (ctx.cc < 3) {
|
|
46
48
|
this.notdone()
|
|
47
49
|
|
|
48
50
|
if (peer.isTop || (peer.id === this.id)) {
|
|
51
|
+
// TODO: clone needed to avoid triggering unify_cycle - find a better way
|
|
49
52
|
out = this.clone(ctx)
|
|
50
53
|
}
|
|
51
54
|
else if (peer.isNil) {
|
package/src/val/ListVal.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
DONE,
|
|
12
|
+
SPREAD,
|
|
12
13
|
} from '../type'
|
|
13
14
|
|
|
14
15
|
import { AontuContext } from '../ctx'
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
top
|
|
30
31
|
} from './top'
|
|
31
32
|
|
|
33
|
+
import { ConjunctVal } from './ConjunctVal'
|
|
32
34
|
import { NilVal } from './NilVal'
|
|
33
35
|
import { BagVal } from './BagVal'
|
|
34
36
|
import { empty } from './Val'
|
|
@@ -36,7 +38,6 @@ import { empty } from './Val'
|
|
|
36
38
|
|
|
37
39
|
class ListVal extends BagVal {
|
|
38
40
|
isList = true
|
|
39
|
-
_canonCache?: string
|
|
40
41
|
|
|
41
42
|
constructor(
|
|
42
43
|
spec: {
|
|
@@ -50,6 +51,24 @@ class ListVal extends BagVal {
|
|
|
50
51
|
throw new AontuError('ListVal spec.peg undefined')
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
let spread = (this.peg as any)[SPREAD]
|
|
55
|
+
delete (this.peg as any)[SPREAD]
|
|
56
|
+
|
|
57
|
+
if (spread) {
|
|
58
|
+
if ('&' === spread.o) {
|
|
59
|
+
|
|
60
|
+
// TODO: handle existing spread!
|
|
61
|
+
this.spread.cj =
|
|
62
|
+
Array.isArray(spread.v) ?
|
|
63
|
+
1 < spread.v.length ?
|
|
64
|
+
new ConjunctVal({ peg: spread.v }, ctx) :
|
|
65
|
+
spread.v[0] :
|
|
66
|
+
spread.v
|
|
67
|
+
|
|
68
|
+
// let tmv = Array.isArray(spread.v) ? spread.v : [spread.v]
|
|
69
|
+
// this.spread.cj = new ConjunctVal({ peg: tmv }, ctx)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
53
72
|
}
|
|
54
73
|
|
|
55
74
|
|
|
@@ -67,7 +86,8 @@ class ListVal extends BagVal {
|
|
|
67
86
|
let out: ListVal | NilVal = (peer.isTop ? this : new ListVal({ peg: [] }, ctx))
|
|
68
87
|
|
|
69
88
|
out.closed = this.closed
|
|
70
|
-
out.optionalKeys =
|
|
89
|
+
out.optionalKeys = [...this.optionalKeys]
|
|
90
|
+
out.spread.cj = this.spread.cj
|
|
71
91
|
out.site = this.site
|
|
72
92
|
|
|
73
93
|
if (peer instanceof ListVal) {
|
|
@@ -77,6 +97,13 @@ class ListVal extends BagVal {
|
|
|
77
97
|
}
|
|
78
98
|
else {
|
|
79
99
|
out.closed = out.closed || peer.closed
|
|
100
|
+
out.spread.cj = null == out.spread.cj ? peer.spread.cj : (
|
|
101
|
+
null == peer.spread.cj ? out.spread.cj : (
|
|
102
|
+
out.spread.cj =
|
|
103
|
+
unite(te ? ctx.clone({ explain: ec(te, 'SPR') }) : ctx,
|
|
104
|
+
out.spread.cj, peer.spread.cj, 'list-peer')
|
|
105
|
+
)
|
|
106
|
+
)
|
|
80
107
|
}
|
|
81
108
|
}
|
|
82
109
|
|
|
@@ -84,39 +111,29 @@ class ListVal extends BagVal {
|
|
|
84
111
|
if (!exit) {
|
|
85
112
|
out.dc = this.dc + 1
|
|
86
113
|
|
|
87
|
-
|
|
88
|
-
if (peer.isTop) {
|
|
89
|
-
let allChildrenDone = true
|
|
90
|
-
for (let key in this.peg) {
|
|
91
|
-
if (DONE !== this.peg[key]?.dc) {
|
|
92
|
-
allChildrenDone = false
|
|
93
|
-
break
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (allChildrenDone) {
|
|
97
|
-
out.dc = DONE
|
|
98
|
-
ctx.explain && explainClose(te, out)
|
|
99
|
-
return out
|
|
100
|
-
}
|
|
101
|
-
}
|
|
114
|
+
let spread_cj = out.spread.cj || TOP
|
|
102
115
|
|
|
103
|
-
//
|
|
116
|
+
// Always unify children first
|
|
104
117
|
for (let key in this.peg) {
|
|
105
118
|
const keyctx = ctx.descend(key)
|
|
119
|
+
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
106
120
|
const child = this.peg[key]
|
|
107
121
|
|
|
108
122
|
propagateMarks(this, child)
|
|
109
123
|
|
|
110
124
|
out.peg[key] =
|
|
111
|
-
undefined === child ?
|
|
125
|
+
undefined === child ? key_spread_cj :
|
|
112
126
|
child.isNil ? child :
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
child
|
|
127
|
+
key_spread_cj.isNil ? key_spread_cj :
|
|
128
|
+
key_spread_cj.isTop && child.done ? child :
|
|
129
|
+
child.isTop && key_spread_cj.done ? key_spread_cj :
|
|
130
|
+
unite(te ? keyctx.clone({ explain: ec(te, 'PEG:' + key) }) : keyctx,
|
|
131
|
+
child, key_spread_cj, 'list-own')
|
|
116
132
|
|
|
117
133
|
done = (done && DONE === out.peg[key].dc)
|
|
118
134
|
}
|
|
119
135
|
|
|
136
|
+
const allowedKeys: string[] = this.closed ? Object.keys(this.peg) : []
|
|
120
137
|
let bad: NilVal | undefined = undefined
|
|
121
138
|
|
|
122
139
|
if (peer instanceof ListVal) {
|
|
@@ -124,10 +141,11 @@ class ListVal extends BagVal {
|
|
|
124
141
|
te ? ctx.clone({ explain: ec(te, 'PER') }) : ctx,
|
|
125
142
|
peer, TOP, 'list-peer-list') as ListVal)
|
|
126
143
|
|
|
144
|
+
// NOTE: peerkey is the index
|
|
127
145
|
for (let peerkey in upeer.peg) {
|
|
128
146
|
let peerchild = upeer.peg[peerkey]
|
|
129
147
|
|
|
130
|
-
if (this.closed && !(peerkey
|
|
148
|
+
if (this.closed && !allowedKeys.includes(peerkey)) {
|
|
131
149
|
bad = makeNilErr(ctx, 'closed', peerchild, undefined)
|
|
132
150
|
}
|
|
133
151
|
|
|
@@ -137,11 +155,19 @@ class ListVal extends BagVal {
|
|
|
137
155
|
|
|
138
156
|
let oval = out.peg[peerkey] =
|
|
139
157
|
undefined === child ? peerchild :
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
158
|
+
child.isTop && peerchild.done ? peerchild :
|
|
159
|
+
child.isNil ? child :
|
|
160
|
+
peerchild.isNil ? peerchild :
|
|
161
|
+
unite(te ? peerctx.clone({ explain: ec(te, 'CHD') }) : peerctx,
|
|
162
|
+
child, peerchild, 'list-peer')
|
|
163
|
+
|
|
164
|
+
if (this.spread.cj) {
|
|
165
|
+
let key_spread_cj = spread_cj.spreadClone(peerctx)
|
|
166
|
+
|
|
167
|
+
oval = out.peg[peerkey] =
|
|
168
|
+
unite(te ? peerctx.clone({ explain: ec(te, 'PSP:' + peerkey) }) : peerctx,
|
|
169
|
+
out.peg[peerkey], key_spread_cj, 'list-spread')
|
|
170
|
+
}
|
|
145
171
|
|
|
146
172
|
propagateMarks(this, oval)
|
|
147
173
|
|
|
@@ -171,18 +197,39 @@ class ListVal extends BagVal {
|
|
|
171
197
|
}
|
|
172
198
|
|
|
173
199
|
|
|
174
|
-
// Spread clone:
|
|
175
|
-
//
|
|
200
|
+
// Spread clone: only deep-clone children that are path-dependent
|
|
201
|
+
// (isFunc, isRef). Share all other children directly.
|
|
202
|
+
// Spread clone: when all children are ScalarKindVal (simple type
|
|
203
|
+
// constraints like `string`, `number`), share them directly to avoid
|
|
204
|
+
// N x M allocations. ScalarKindVal is safe to share: it is immutable,
|
|
205
|
+
// always done, never path-dependent, and never has marks mutated.
|
|
206
|
+
// For anything more complex, fall back to full deep clone.
|
|
176
207
|
spreadClone(ctx: AontuContext): Val {
|
|
208
|
+
// B1: share directly when the spread tree has no path-dependent
|
|
209
|
+
// leaves. See MapVal.spreadClone for rationale.
|
|
177
210
|
if (!this.isPathDependent) return this
|
|
178
211
|
|
|
212
|
+
let allScalarKind = true
|
|
213
|
+
for (let key in this.peg) {
|
|
214
|
+
if (!(this.peg[key] as any)?.isScalarKind) {
|
|
215
|
+
allScalarKind = false
|
|
216
|
+
break
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!allScalarKind) {
|
|
221
|
+
return this.clone(ctx)
|
|
222
|
+
}
|
|
223
|
+
|
|
179
224
|
let out = (super.clone(ctx) as ListVal)
|
|
180
225
|
|
|
181
226
|
for (let entry of Object.entries(this.peg)) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
227
|
+
out.peg[entry[0]] = entry[1]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Must create a new spread object to avoid mutating the original.
|
|
231
|
+
out.spread = {
|
|
232
|
+
cj: this.spread.cj ? this.spread.cj.spreadClone(ctx) : undefined,
|
|
186
233
|
}
|
|
187
234
|
|
|
188
235
|
out.closed = this.closed
|
|
@@ -198,6 +245,10 @@ class ListVal extends BagVal {
|
|
|
198
245
|
out.peg[entry[0]] =
|
|
199
246
|
(entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx, spec?.mark ? { mark: spec.mark } : {}) : entry[1]
|
|
200
247
|
}
|
|
248
|
+
if (this.spread.cj) {
|
|
249
|
+
out.spread.cj = this.spread.cj.clone(ctx, spec?.mark ? { mark: spec.mark } : {})
|
|
250
|
+
}
|
|
251
|
+
|
|
201
252
|
out.closed = this.closed
|
|
202
253
|
out.optionalKeys = [...this.optionalKeys]
|
|
203
254
|
|
|
@@ -207,19 +258,18 @@ class ListVal extends BagVal {
|
|
|
207
258
|
|
|
208
259
|
|
|
209
260
|
get canon() {
|
|
210
|
-
if (this._canonCache !== undefined) return this._canonCache
|
|
211
261
|
// console.log('LISTVAL-CANON', this.optionalKeys)
|
|
212
262
|
let keys = Object.keys(this.peg)
|
|
213
|
-
|
|
263
|
+
return '' +
|
|
214
264
|
// this.errcanon() +
|
|
215
265
|
'[' +
|
|
266
|
+
(this.spread.cj ? '&:' + this.spread.cj.canon +
|
|
267
|
+
(0 < keys.length ? ',' : '') : '') +
|
|
216
268
|
keys
|
|
217
269
|
.map(k => this.optionalKeys.includes(k) ?
|
|
218
270
|
k + '?:' + this.peg[k].canon :
|
|
219
271
|
this.peg[k].canon).join(',') +
|
|
220
272
|
']'
|
|
221
|
-
if (this.done) this._canonCache = c
|
|
222
|
-
return c
|
|
223
273
|
}
|
|
224
274
|
}
|
|
225
275
|
|
package/src/val/MapVal.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
DONE,
|
|
11
|
+
SPREAD,
|
|
11
12
|
} from '../type'
|
|
12
13
|
|
|
13
14
|
import { AontuContext } from '../ctx'
|
|
@@ -27,13 +28,13 @@ import {
|
|
|
27
28
|
} from './top'
|
|
28
29
|
|
|
29
30
|
|
|
31
|
+
import { ConjunctVal } from './ConjunctVal'
|
|
30
32
|
import { NilVal } from './NilVal'
|
|
31
33
|
import { BagVal } from './BagVal'
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
class MapVal extends BagVal {
|
|
35
37
|
isMap = true
|
|
36
|
-
_canonCache?: string
|
|
37
38
|
|
|
38
39
|
constructor(
|
|
39
40
|
spec: ValSpec,
|
|
@@ -47,6 +48,23 @@ class MapVal extends BagVal {
|
|
|
47
48
|
|
|
48
49
|
this.mark.type = !!spec.mark?.type
|
|
49
50
|
this.mark.hide = !!spec.mark?.hide
|
|
51
|
+
|
|
52
|
+
let spread = (this.peg as any)[SPREAD]
|
|
53
|
+
delete (this.peg as any)[SPREAD]
|
|
54
|
+
|
|
55
|
+
if (spread) {
|
|
56
|
+
if ('&' === spread.o) {
|
|
57
|
+
// TODO: handle existing spread!
|
|
58
|
+
this.spread.cj =
|
|
59
|
+
Array.isArray(spread.v) ?
|
|
60
|
+
1 < spread.v.length ?
|
|
61
|
+
new ConjunctVal({ peg: spread.v }, ctx) :
|
|
62
|
+
spread.v[0] :
|
|
63
|
+
spread.v
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// console.log('MAPVAL-ctor', this.type, spec)
|
|
50
68
|
}
|
|
51
69
|
|
|
52
70
|
|
|
@@ -57,23 +75,6 @@ class MapVal extends BagVal {
|
|
|
57
75
|
|
|
58
76
|
const TOP = top()
|
|
59
77
|
peer = peer ?? TOP
|
|
60
|
-
|
|
61
|
-
// Fast path: both maps done, no spreads, peer's keys are a
|
|
62
|
-
// subset of this's keys with the same child references, and
|
|
63
|
-
// neither side has type/hide marks. No new information.
|
|
64
|
-
if (this.done && peer instanceof MapVal && peer.done
|
|
65
|
-
&& !this.mark.type && !this.mark.hide
|
|
66
|
-
&& !peer.mark.type && !peer.mark.hide) {
|
|
67
|
-
let canSkip = true
|
|
68
|
-
for (const k in peer.peg) {
|
|
69
|
-
if (this.peg[k] !== peer.peg[k]) {
|
|
70
|
-
canSkip = false
|
|
71
|
-
break
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (canSkip) return this
|
|
75
|
-
}
|
|
76
|
-
|
|
77
78
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Map', this, peer)
|
|
78
79
|
|
|
79
80
|
let done: boolean = true
|
|
@@ -83,7 +84,8 @@ class MapVal extends BagVal {
|
|
|
83
84
|
let out: MapVal | NilVal = (peer.isTop ? this : new MapVal({ peg: {} }, ctx))
|
|
84
85
|
|
|
85
86
|
out.closed = this.closed
|
|
86
|
-
out.optionalKeys =
|
|
87
|
+
out.optionalKeys = [...this.optionalKeys]
|
|
88
|
+
out.spread.cj = this.spread.cj
|
|
87
89
|
out.site = this.site
|
|
88
90
|
|
|
89
91
|
if (peer instanceof MapVal) {
|
|
@@ -106,47 +108,53 @@ class MapVal extends BagVal {
|
|
|
106
108
|
out = peer.unify(this, te ? ctx.clone({ explain: ec(te, 'SPC') }) : ctx) as MapVal
|
|
107
109
|
exit = true
|
|
108
110
|
}
|
|
111
|
+
|
|
109
112
|
}
|
|
113
|
+
|
|
114
|
+
if (!exit) {
|
|
115
|
+
out.spread.cj = null == out.spread.cj ? peer.spread.cj : (
|
|
116
|
+
null == peer.spread.cj ? out.spread.cj : (
|
|
117
|
+
out.spread.cj =
|
|
118
|
+
unite(te ? ctx.clone({ explain: ec(te, 'SPR') }) : ctx,
|
|
119
|
+
out.spread.cj, peer.spread.cj, 'map-self')
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// console.log('MAPVAL-PEER-OTHER', this.id, this.canon, this.done, peer.id, peer.canon, peer.done)
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
|
|
113
129
|
if (!exit) {
|
|
114
130
|
out.dc = this.dc + 1
|
|
115
131
|
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
let allChildrenDone = true
|
|
120
|
-
for (let key in this.peg) {
|
|
121
|
-
if (DONE !== this.peg[key]?.dc) {
|
|
122
|
-
allChildrenDone = false
|
|
123
|
-
break
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (allChildrenDone) {
|
|
127
|
-
out.dc = DONE
|
|
128
|
-
ctx.explain && explainClose(te, out)
|
|
129
|
-
return out
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
+
// let newtype = this.type || peer.type
|
|
133
|
+
|
|
134
|
+
let spread_cj = out.spread.cj ?? TOP
|
|
132
135
|
|
|
133
|
-
//
|
|
136
|
+
// Always unify own children first
|
|
134
137
|
for (let key in this.peg) {
|
|
135
|
-
const child = this.peg[key]
|
|
136
138
|
const keyctx = ctx.descend(key)
|
|
137
139
|
|
|
140
|
+
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
141
|
+
const child = this.peg[key]
|
|
142
|
+
|
|
138
143
|
propagateMarks(this, child)
|
|
139
144
|
|
|
140
145
|
out.peg[key] =
|
|
141
|
-
undefined === child ?
|
|
146
|
+
undefined === child ? key_spread_cj :
|
|
142
147
|
child.isNil ? child :
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
child
|
|
148
|
+
key_spread_cj.isNil ? key_spread_cj :
|
|
149
|
+
key_spread_cj.isTop && child.done ? child :
|
|
150
|
+
child.isTop && key_spread_cj.done ? key_spread_cj :
|
|
151
|
+
unite(te ? keyctx.clone({ explain: ec(te, 'KEY:' + key) }) : keyctx,
|
|
152
|
+
child, key_spread_cj, 'map-own')
|
|
146
153
|
|
|
147
154
|
done = (done && DONE === out.peg[key].dc)
|
|
148
155
|
}
|
|
149
156
|
|
|
157
|
+
const allowedKeys: string[] = this.closed ? Object.keys(this.peg) : []
|
|
150
158
|
let bad: NilVal | undefined = undefined
|
|
151
159
|
|
|
152
160
|
if (peer instanceof MapVal) {
|
|
@@ -157,14 +165,12 @@ class MapVal extends BagVal {
|
|
|
157
165
|
for (let peerkey in upeer.peg) {
|
|
158
166
|
let peerchild = upeer.peg[peerkey]
|
|
159
167
|
|
|
160
|
-
if (this.closed && !(peerkey
|
|
168
|
+
if (this.closed && !allowedKeys.includes(peerkey)) {
|
|
161
169
|
bad = makeNilErr(ctx, 'closed', peerchild, undefined)
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
// key optionality is additive
|
|
165
|
-
if (
|
|
166
|
-
&& upeer.optionalKeys.includes(peerkey)
|
|
167
|
-
&& !out.optionalKeys.includes(peerkey)) {
|
|
173
|
+
if (upeer.optionalKeys.includes(peerkey) && !out.optionalKeys.includes(peerkey)) {
|
|
168
174
|
out.optionalKeys.push(peerkey)
|
|
169
175
|
}
|
|
170
176
|
|
|
@@ -174,11 +180,19 @@ class MapVal extends BagVal {
|
|
|
174
180
|
|
|
175
181
|
let oval = out.peg[peerkey] =
|
|
176
182
|
undefined === child ? this.handleExpectedVal(peerkey, peerchild, this, ctx) :
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
183
|
+
child.isTop && peerchild.done ? peerchild :
|
|
184
|
+
child.isNil ? child :
|
|
185
|
+
peerchild.isNil ? peerchild :
|
|
186
|
+
unite(te ? peerctx.clone({ explain: ec(te, 'CHD') }) : peerctx,
|
|
187
|
+
child, peerchild, 'map-peer')
|
|
188
|
+
|
|
189
|
+
if (this.spread.cj) {
|
|
190
|
+
let key_spread_cj = spread_cj.spreadClone(peerctx)
|
|
191
|
+
|
|
192
|
+
oval = out.peg[peerkey] =
|
|
193
|
+
unite(te ? peerctx.clone({ explain: ec(te, 'PSP:' + peerkey) }) : peerctx,
|
|
194
|
+
oval, key_spread_cj, 'map-peer-spread')
|
|
195
|
+
}
|
|
182
196
|
|
|
183
197
|
propagateMarks(this, oval)
|
|
184
198
|
|
|
@@ -199,41 +213,66 @@ class MapVal extends BagVal {
|
|
|
199
213
|
out.dc = done ? DONE : out.dc
|
|
200
214
|
propagateMarks(peer, out)
|
|
201
215
|
propagateMarks(this, out)
|
|
202
|
-
|
|
203
216
|
}
|
|
204
217
|
}
|
|
205
218
|
|
|
219
|
+
// console.log(
|
|
220
|
+
// 'MAPVAL-OUT', out.canon,
|
|
221
|
+
// '\n SELF', this,
|
|
222
|
+
// '\n PEER', peer,
|
|
223
|
+
// '\n OUT', out,
|
|
224
|
+
// '\n FROM', (out as any).spread.cj
|
|
225
|
+
// )
|
|
226
|
+
|
|
206
227
|
ctx.explain && explainClose(te, out)
|
|
207
228
|
|
|
208
229
|
return out
|
|
209
230
|
}
|
|
210
231
|
|
|
211
232
|
|
|
212
|
-
//
|
|
213
|
-
//
|
|
233
|
+
// Spread clone: return a Val usable as the per-key spread constraint.
|
|
234
|
+
//
|
|
235
|
+
// Three tiers:
|
|
236
|
+
// 1. tree is path-independent (no RefVal/KeyFuncVal/PathFuncVal/
|
|
237
|
+
// MoveFuncVal/SuperFuncVal anywhere below): return `this` directly.
|
|
238
|
+
// Nothing in the unify path mutates the spread root, and no
|
|
239
|
+
// child depends on its own stored .path, so sharing is safe.
|
|
240
|
+
// 2. top-level children are all ScalarKindVal: shallow clone
|
|
241
|
+
// (share children, fresh MapVal wrapper).
|
|
242
|
+
// 3. otherwise: full deep clone via `this.clone(ctx)`.
|
|
243
|
+
//
|
|
244
|
+
// Tier 1 handles the foo-sdk common case of simple type-constraint
|
|
245
|
+
// spreads like `&:{active: *true | boolean, version: *'0.0.1' | string}`,
|
|
246
|
+
// which are cloned thousands of times per run.
|
|
214
247
|
spreadClone(ctx: AontuContext): Val {
|
|
215
248
|
if (!this.isPathDependent) return this
|
|
216
249
|
|
|
250
|
+
let allScalarKind = true
|
|
251
|
+
for (let key in this.peg) {
|
|
252
|
+
if (!(this.peg[key] as any)?.isScalarKind) {
|
|
253
|
+
allScalarKind = false
|
|
254
|
+
break
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!allScalarKind) {
|
|
259
|
+
return this.clone(ctx)
|
|
260
|
+
}
|
|
261
|
+
|
|
217
262
|
let out = (super.clone(ctx) as MapVal)
|
|
218
263
|
out.peg = {}
|
|
219
264
|
|
|
220
265
|
for (let entry of Object.entries(this.peg)) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
wrapper.mark = { ...child.mark }
|
|
228
|
-
out.peg[entry[0]] = wrapper
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
out.peg[entry[0]] = child
|
|
232
|
-
}
|
|
266
|
+
out.peg[entry[0]] = entry[1]
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Must create a new spread object to avoid mutating the original.
|
|
270
|
+
out.spread = {
|
|
271
|
+
cj: this.spread.cj ? this.spread.cj.spreadClone(ctx) : undefined,
|
|
233
272
|
}
|
|
234
273
|
|
|
235
274
|
out.closed = this.closed
|
|
236
|
-
out.optionalKeys =
|
|
275
|
+
out.optionalKeys = [...this.optionalKeys]
|
|
237
276
|
|
|
238
277
|
return out
|
|
239
278
|
}
|
|
@@ -246,25 +285,36 @@ class MapVal extends BagVal {
|
|
|
246
285
|
for (let entry of Object.entries(this.peg)) {
|
|
247
286
|
out.peg[entry[0]] =
|
|
248
287
|
(entry[1] as any)?.isVal ?
|
|
288
|
+
// (entry[1] as Val).clone(ctx, spec?.mark ? { mark: spec.mark } : {}) :
|
|
249
289
|
(entry[1] as Val).clone(ctx, {
|
|
250
290
|
mark: spec?.mark ?? {},
|
|
251
291
|
path: [...out.path, entry[0]]
|
|
252
292
|
}) :
|
|
253
293
|
entry[1]
|
|
254
294
|
}
|
|
295
|
+
if (this.spread.cj) {
|
|
296
|
+
out.spread.cj = this.spread.cj.clone(ctx, spec?.mark ? { mark: spec.mark } : {})
|
|
297
|
+
}
|
|
255
298
|
|
|
256
299
|
out.closed = this.closed
|
|
257
300
|
out.optionalKeys = [...this.optionalKeys]
|
|
258
301
|
|
|
302
|
+
// out.from = this.from
|
|
303
|
+
|
|
304
|
+
// console.log('MAPVAL-CLONE', this.canon, '->', out.canon)
|
|
259
305
|
return out
|
|
260
306
|
}
|
|
261
307
|
|
|
262
308
|
|
|
263
309
|
get canon() {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
310
|
+
let keys = Object.keys(this.peg)
|
|
311
|
+
return '' +
|
|
312
|
+
// this.errcanon() +
|
|
313
|
+
// (this.mark.type ? '<type>' : '') +
|
|
314
|
+
// (this.id + '=') +
|
|
267
315
|
'{' +
|
|
316
|
+
(this.spread.cj ? '&:' + this.spread.cj.canon +
|
|
317
|
+
(0 < keys.length ? ',' : '') : '') +
|
|
268
318
|
keys
|
|
269
319
|
.map(k => [
|
|
270
320
|
JSON.stringify(k) +
|
|
@@ -273,19 +323,18 @@ class MapVal extends BagVal {
|
|
|
273
323
|
(this.peg[k]?.canon ?? this.peg[k])
|
|
274
324
|
])
|
|
275
325
|
.join(',') +
|
|
276
|
-
'}'
|
|
277
|
-
|
|
278
|
-
return c
|
|
326
|
+
'}' // + '<' + (this.mark.hide ? 'H' : '') + '>'
|
|
327
|
+
|
|
279
328
|
}
|
|
280
329
|
|
|
281
330
|
|
|
282
|
-
inspection(
|
|
283
|
-
return ''
|
|
331
|
+
inspection(d?: number) {
|
|
332
|
+
return this.spread.cj ? '&:' + this.spread.cj.inspect(null == d ? 0 : d + 1) : ''
|
|
284
333
|
}
|
|
285
334
|
|
|
286
335
|
}
|
|
287
336
|
|
|
288
337
|
|
|
289
338
|
export {
|
|
290
|
-
MapVal
|
|
339
|
+
MapVal
|
|
291
340
|
}
|