aontu 0.40.0 → 0.42.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/aontu.js +7 -0
- package/dist/aontu.js.map +1 -1
- package/dist/ctx.d.ts +14 -2
- package/dist/ctx.js +56 -9
- package/dist/ctx.js.map +1 -1
- package/dist/err.js +36 -15
- package/dist/err.js.map +1 -1
- package/dist/lang.d.ts +5 -1
- package/dist/lang.js +100 -24
- package/dist/lang.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +5 -0
- package/dist/type.js.map +1 -1
- package/dist/unify.js +372 -55
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +6 -2
- package/dist/utility.js.map +1 -1
- package/dist/val/BagVal.d.ts +0 -3
- 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 +138 -15
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/CopyFuncVal.js +3 -2
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.js +40 -10
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/ExpectVal.js +17 -4
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FuncBaseVal.js +2 -2
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/IntegerVal.js +1 -1
- package/dist/val/IntegerVal.js.map +1 -1
- package/dist/val/JunctionVal.d.ts +1 -0
- package/dist/val/JunctionVal.js +6 -1
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.js +0 -2
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.d.ts +1 -0
- package/dist/val/ListVal.js +36 -65
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/MapVal.d.ts +3 -2
- package/dist/val/MapVal.js +71 -91
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MoveFuncVal.d.ts +2 -1
- package/dist/val/MoveFuncVal.js +78 -13
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.d.ts +2 -1
- package/dist/val/NilVal.js +15 -1
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/OpBaseVal.js +1 -1
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/PathFuncVal.js +25 -4
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/{RefVal.d.ts → PathVal.d.ts} +4 -3
- package/dist/val/{RefVal.js → PathVal.js} +75 -77
- package/dist/val/PathVal.js.map +1 -0
- package/dist/val/PlusOpVal.d.ts +1 -1
- package/dist/val/PrefVal.js +20 -7
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/SpreadVal.d.ts +20 -0
- package/dist/val/SpreadVal.js +194 -0
- package/dist/val/SpreadVal.js.map +1 -0
- package/dist/val/Val.d.ts +4 -1
- package/dist/val/Val.js +88 -44
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +3 -3
- package/dist/val/VarVal.js.map +1 -1
- package/package.json +6 -7
- package/src/aontu.ts +9 -1
- package/src/ctx.ts +95 -11
- package/src/err.ts +37 -17
- package/src/lang.ts +113 -23
- package/src/tsconfig.json +2 -1
- package/src/type.ts +5 -0
- package/src/unify.ts +390 -64
- package/src/utility.ts +5 -2
- package/src/val/BagVal.ts +6 -7
- package/src/val/ConjunctVal.ts +133 -15
- package/src/val/CopyFuncVal.ts +3 -2
- package/src/val/DisjunctVal.ts +43 -11
- package/src/val/ExpectVal.ts +19 -5
- package/src/val/FuncBaseVal.ts +2 -2
- package/src/val/IntegerVal.ts +1 -1
- package/src/val/JunctionVal.ts +5 -1
- package/src/val/KeyFuncVal.ts +0 -3
- package/src/val/ListVal.ts +40 -86
- package/src/val/MapVal.ts +78 -119
- package/src/val/MoveFuncVal.ts +79 -14
- package/src/val/NilVal.ts +17 -1
- package/src/val/OpBaseVal.ts +1 -1
- package/src/val/PathFuncVal.ts +29 -4
- package/src/val/PathVal.ts +435 -0
- package/src/val/PrefVal.ts +21 -8
- package/src/val/{RefVal.ts → RefVal.ts.old} +31 -20
- package/src/val/SpreadVal.ts +275 -0
- package/src/val/Val.ts +141 -50
- package/src/val/VarVal.ts +3 -3
- package/dist/val/RefVal.js.map +0 -1
package/src/val/MapVal.ts
CHANGED
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
DONE,
|
|
11
|
-
SPREAD,
|
|
12
11
|
} from '../type'
|
|
13
12
|
|
|
14
13
|
import { AontuContext } from '../ctx'
|
|
@@ -28,13 +27,13 @@ import {
|
|
|
28
27
|
} from './top'
|
|
29
28
|
|
|
30
29
|
|
|
31
|
-
import { ConjunctVal } from './ConjunctVal'
|
|
32
30
|
import { NilVal } from './NilVal'
|
|
33
31
|
import { BagVal } from './BagVal'
|
|
34
32
|
|
|
35
33
|
|
|
36
34
|
class MapVal extends BagVal {
|
|
37
35
|
isMap = true
|
|
36
|
+
_canonCache?: string
|
|
38
37
|
|
|
39
38
|
constructor(
|
|
40
39
|
spec: ValSpec,
|
|
@@ -48,23 +47,6 @@ class MapVal extends BagVal {
|
|
|
48
47
|
|
|
49
48
|
this.mark.type = !!spec.mark?.type
|
|
50
49
|
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)
|
|
68
50
|
}
|
|
69
51
|
|
|
70
52
|
|
|
@@ -75,6 +57,23 @@ class MapVal extends BagVal {
|
|
|
75
57
|
|
|
76
58
|
const TOP = top()
|
|
77
59
|
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
|
+
|
|
78
77
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Map', this, peer)
|
|
79
78
|
|
|
80
79
|
let done: boolean = true
|
|
@@ -84,13 +83,12 @@ class MapVal extends BagVal {
|
|
|
84
83
|
let out: MapVal | NilVal = (peer.isTop ? this : new MapVal({ peg: {} }, ctx))
|
|
85
84
|
|
|
86
85
|
out.closed = this.closed
|
|
87
|
-
out.optionalKeys = [...this.optionalKeys]
|
|
88
|
-
out.spread.cj = this.spread.cj
|
|
86
|
+
out.optionalKeys = 0 < this.optionalKeys.length ? [...this.optionalKeys] : this.optionalKeys
|
|
89
87
|
out.site = this.site
|
|
90
88
|
|
|
91
89
|
if (peer instanceof MapVal) {
|
|
92
90
|
if (!this.closed && peer.closed) {
|
|
93
|
-
out = peer.unify(this, ctx.clone({ explain: ec(te, 'PMC') })) as MapVal
|
|
91
|
+
out = peer.unify(this, te ? ctx.clone({ explain: ec(te, 'PMC') }) : ctx) as MapVal
|
|
94
92
|
exit = true
|
|
95
93
|
}
|
|
96
94
|
|
|
@@ -105,56 +103,50 @@ class MapVal extends BagVal {
|
|
|
105
103
|
&& peerkeys.join('~') < selfkeys.join('~')
|
|
106
104
|
)
|
|
107
105
|
) {
|
|
108
|
-
out = peer.unify(this, ctx.clone({ explain: ec(te, 'SPC') })) as MapVal
|
|
106
|
+
out = peer.unify(this, te ? ctx.clone({ explain: ec(te, 'SPC') }) : ctx) as MapVal
|
|
109
107
|
exit = true
|
|
110
108
|
}
|
|
111
|
-
|
|
112
109
|
}
|
|
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(ctx.clone({ explain: ec(te, 'SPR') }),
|
|
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)
|
|
126
110
|
}
|
|
127
111
|
|
|
128
112
|
|
|
129
113
|
if (!exit) {
|
|
130
114
|
out.dc = this.dc + 1
|
|
131
115
|
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
116
|
+
// Fast path: self-unify with TOP.
|
|
117
|
+
// If all children are already done, the map is fully converged.
|
|
118
|
+
if (peer.isTop) {
|
|
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
|
+
}
|
|
135
132
|
|
|
136
|
-
//
|
|
133
|
+
// Unify own children
|
|
137
134
|
for (let key in this.peg) {
|
|
138
|
-
const keyctx = ctx.descend(key)
|
|
139
|
-
|
|
140
|
-
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
141
135
|
const child = this.peg[key]
|
|
136
|
+
const keyctx = ctx.descend(key)
|
|
142
137
|
|
|
143
138
|
propagateMarks(this, child)
|
|
144
139
|
|
|
145
140
|
out.peg[key] =
|
|
146
|
-
undefined === child ?
|
|
141
|
+
undefined === child ? top() :
|
|
147
142
|
child.isNil ? child :
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
child
|
|
151
|
-
unite(keyctx.clone({ explain: ec(te, 'KEY:' + key) }),
|
|
152
|
-
child, key_spread_cj, 'map-own')
|
|
143
|
+
child.done ? child :
|
|
144
|
+
unite(te ? keyctx.clone({ explain: ec(te, 'KEY:' + key) }) : keyctx,
|
|
145
|
+
child, top(), 'map-own')
|
|
153
146
|
|
|
154
147
|
done = (done && DONE === out.peg[key].dc)
|
|
155
148
|
}
|
|
156
149
|
|
|
157
|
-
const allowedKeys: string[] = this.closed ? Object.keys(this.peg) : []
|
|
158
150
|
let bad: NilVal | undefined = undefined
|
|
159
151
|
|
|
160
152
|
if (peer instanceof MapVal) {
|
|
@@ -165,12 +157,14 @@ class MapVal extends BagVal {
|
|
|
165
157
|
for (let peerkey in upeer.peg) {
|
|
166
158
|
let peerchild = upeer.peg[peerkey]
|
|
167
159
|
|
|
168
|
-
if (this.closed && !
|
|
160
|
+
if (this.closed && !(peerkey in this.peg)) {
|
|
169
161
|
bad = makeNilErr(ctx, 'closed', peerchild, undefined)
|
|
170
162
|
}
|
|
171
163
|
|
|
172
164
|
// key optionality is additive
|
|
173
|
-
if (
|
|
165
|
+
if (0 < upeer.optionalKeys.length
|
|
166
|
+
&& upeer.optionalKeys.includes(peerkey)
|
|
167
|
+
&& !out.optionalKeys.includes(peerkey)) {
|
|
174
168
|
out.optionalKeys.push(peerkey)
|
|
175
169
|
}
|
|
176
170
|
|
|
@@ -180,19 +174,11 @@ class MapVal extends BagVal {
|
|
|
180
174
|
|
|
181
175
|
let oval = out.peg[peerkey] =
|
|
182
176
|
undefined === child ? this.handleExpectedVal(peerkey, peerchild, this, ctx) :
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
}
|
|
177
|
+
child.isTop && peerchild.done ? peerchild :
|
|
178
|
+
child.isNil ? child :
|
|
179
|
+
peerchild.isNil ? peerchild :
|
|
180
|
+
unite(te ? peerctx.clone({ explain: ec(te, 'CHD') }) : peerctx,
|
|
181
|
+
child, peerchild, 'map-peer')
|
|
196
182
|
|
|
197
183
|
propagateMarks(this, oval)
|
|
198
184
|
|
|
@@ -213,58 +199,41 @@ class MapVal extends BagVal {
|
|
|
213
199
|
out.dc = done ? DONE : out.dc
|
|
214
200
|
propagateMarks(peer, out)
|
|
215
201
|
propagateMarks(this, out)
|
|
202
|
+
|
|
216
203
|
}
|
|
217
204
|
}
|
|
218
205
|
|
|
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
|
-
|
|
227
206
|
ctx.explain && explainClose(te, out)
|
|
228
207
|
|
|
229
208
|
return out
|
|
230
209
|
}
|
|
231
210
|
|
|
232
211
|
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
// N x M allocations for maps with N keys and M spread fields.
|
|
236
|
-
// Spread clone: when all children are ScalarKindVal (simple type
|
|
237
|
-
// constraints like `string`, `number`), share them directly to avoid
|
|
238
|
-
// N x M allocations. ScalarKindVal is safe to share: it is immutable,
|
|
239
|
-
// always done, never path-dependent, and never has marks mutated.
|
|
240
|
-
// For anything more complex, fall back to full deep clone.
|
|
212
|
+
// Optimized clone for use as a spread constraint: share
|
|
213
|
+
// path-independent children, clone only path-dependent ones.
|
|
241
214
|
spreadClone(ctx: AontuContext): Val {
|
|
242
|
-
|
|
243
|
-
for (let key in this.peg) {
|
|
244
|
-
if (!(this.peg[key] as any)?.isScalarKind) {
|
|
245
|
-
allScalarKind = false
|
|
246
|
-
break
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (!allScalarKind) {
|
|
251
|
-
return this.clone(ctx)
|
|
252
|
-
}
|
|
215
|
+
if (!this.isPathDependent) return this
|
|
253
216
|
|
|
254
217
|
let out = (super.clone(ctx) as MapVal)
|
|
255
218
|
out.peg = {}
|
|
256
219
|
|
|
257
220
|
for (let entry of Object.entries(this.peg)) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
221
|
+
const child = entry[1] as Val
|
|
222
|
+
if (child?.isVal && child.isPathDependent) {
|
|
223
|
+
out.peg[entry[0]] = child.clone(ctx, { path: [...out.path, entry[0]] })
|
|
224
|
+
}
|
|
225
|
+
else if (child?.isVal) {
|
|
226
|
+
const wrapper = Object.create(child)
|
|
227
|
+
wrapper.mark = { ...child.mark }
|
|
228
|
+
out.peg[entry[0]] = wrapper
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
out.peg[entry[0]] = child
|
|
232
|
+
}
|
|
264
233
|
}
|
|
265
234
|
|
|
266
235
|
out.closed = this.closed
|
|
267
|
-
out.optionalKeys = [...this.optionalKeys]
|
|
236
|
+
out.optionalKeys = 0 < this.optionalKeys.length ? [...this.optionalKeys] : this.optionalKeys
|
|
268
237
|
|
|
269
238
|
return out
|
|
270
239
|
}
|
|
@@ -277,36 +246,25 @@ class MapVal extends BagVal {
|
|
|
277
246
|
for (let entry of Object.entries(this.peg)) {
|
|
278
247
|
out.peg[entry[0]] =
|
|
279
248
|
(entry[1] as any)?.isVal ?
|
|
280
|
-
// (entry[1] as Val).clone(ctx, spec?.mark ? { mark: spec.mark } : {}) :
|
|
281
249
|
(entry[1] as Val).clone(ctx, {
|
|
282
250
|
mark: spec?.mark ?? {},
|
|
283
251
|
path: [...out.path, entry[0]]
|
|
284
252
|
}) :
|
|
285
253
|
entry[1]
|
|
286
254
|
}
|
|
287
|
-
if (this.spread.cj) {
|
|
288
|
-
out.spread.cj = this.spread.cj.clone(ctx, spec?.mark ? { mark: spec.mark } : {})
|
|
289
|
-
}
|
|
290
255
|
|
|
291
256
|
out.closed = this.closed
|
|
292
257
|
out.optionalKeys = [...this.optionalKeys]
|
|
293
258
|
|
|
294
|
-
// out.from = this.from
|
|
295
|
-
|
|
296
|
-
// console.log('MAPVAL-CLONE', this.canon, '->', out.canon)
|
|
297
259
|
return out
|
|
298
260
|
}
|
|
299
261
|
|
|
300
262
|
|
|
301
263
|
get canon() {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
// (this.mark.type ? '<type>' : '') +
|
|
306
|
-
// (this.id + '=') +
|
|
264
|
+
if (this._canonCache !== undefined) return this._canonCache
|
|
265
|
+
let keys = Object.keys(this.peg).sort()
|
|
266
|
+
const c = '' +
|
|
307
267
|
'{' +
|
|
308
|
-
(this.spread.cj ? '&:' + this.spread.cj.canon +
|
|
309
|
-
(0 < keys.length ? ',' : '') : '') +
|
|
310
268
|
keys
|
|
311
269
|
.map(k => [
|
|
312
270
|
JSON.stringify(k) +
|
|
@@ -315,18 +273,19 @@ class MapVal extends BagVal {
|
|
|
315
273
|
(this.peg[k]?.canon ?? this.peg[k])
|
|
316
274
|
])
|
|
317
275
|
.join(',') +
|
|
318
|
-
'}'
|
|
319
|
-
|
|
276
|
+
'}'
|
|
277
|
+
if (this.done) this._canonCache = c
|
|
278
|
+
return c
|
|
320
279
|
}
|
|
321
280
|
|
|
322
281
|
|
|
323
|
-
inspection(
|
|
324
|
-
return
|
|
282
|
+
inspection(_d?: number) {
|
|
283
|
+
return ''
|
|
325
284
|
}
|
|
326
285
|
|
|
327
286
|
}
|
|
328
287
|
|
|
329
288
|
|
|
330
289
|
export {
|
|
331
|
-
MapVal
|
|
290
|
+
MapVal,
|
|
332
291
|
}
|
package/src/val/MoveFuncVal.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { makeNilErr } from '../err'
|
|
14
14
|
|
|
15
15
|
import { NilVal } from '../val/NilVal'
|
|
16
|
+
import { PathVal } from '../val/PathVal'
|
|
16
17
|
|
|
17
18
|
import {
|
|
18
19
|
walk
|
|
@@ -26,6 +27,60 @@ import { PrefFuncVal } from './PrefFuncVal'
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
|
|
30
|
+
// Navigate the tree using a PathVal's resolved path and hide the source.
|
|
31
|
+
function hideAtPath(root: Val, pv: PathVal) {
|
|
32
|
+
// Compute the refpath the same way PathVal.find does
|
|
33
|
+
const parts: string[] = []
|
|
34
|
+
for (const part of pv.peg) {
|
|
35
|
+
if ('string' === typeof part) parts.push(part)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let refpath: string[]
|
|
39
|
+
if (pv.absolute) {
|
|
40
|
+
refpath = parts
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
refpath = pv.path.slice(0, -1).concat(parts)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Walk to the source, handling conjuncts/disjuncts
|
|
47
|
+
let node: any = root
|
|
48
|
+
for (let i = 0; i < refpath.length; i++) {
|
|
49
|
+
const part = refpath[i]
|
|
50
|
+
if (node?.isMap || node?.isList) {
|
|
51
|
+
node = node.peg[part]
|
|
52
|
+
}
|
|
53
|
+
else if (node?.isConjunct || node?.isDisjunct) {
|
|
54
|
+
// Search junction terms for the key
|
|
55
|
+
let found = null
|
|
56
|
+
const stack = [...node.peg]
|
|
57
|
+
while (stack.length > 0) {
|
|
58
|
+
const term = stack.pop()
|
|
59
|
+
if (term?.isConjunct || term?.isDisjunct) {
|
|
60
|
+
stack.push(...term.peg)
|
|
61
|
+
}
|
|
62
|
+
else if ((term?.isMap || term?.isList) && term.peg[part] != null) {
|
|
63
|
+
found = term.peg[part]
|
|
64
|
+
break
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
node = found
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
if (node == null) return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Mark the source value hidden
|
|
76
|
+
node.mark.hide = true
|
|
77
|
+
walk(node, (_key: string | number | undefined, val: Val) => {
|
|
78
|
+
val.mark.hide = true
|
|
79
|
+
return val
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
29
84
|
class MoveFuncVal extends FuncBaseVal {
|
|
30
85
|
isMoveFunc = true
|
|
31
86
|
|
|
@@ -50,30 +105,40 @@ class MoveFuncVal extends FuncBaseVal {
|
|
|
50
105
|
}
|
|
51
106
|
|
|
52
107
|
resolve(ctx: AontuContext, args: Val[]) {
|
|
53
|
-
let
|
|
108
|
+
let arg = args[0] ?? makeNilErr(ctx, 'arg', this)
|
|
109
|
+
if (arg.isNil) return arg
|
|
54
110
|
|
|
55
|
-
|
|
111
|
+
let src: Val
|
|
56
112
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
113
|
+
if (arg instanceof PathVal) {
|
|
114
|
+
// Get clone for the destination
|
|
115
|
+
src = arg.find(ctx) as Val
|
|
116
|
+
if (src == null || src.isNil) return makeNilErr(ctx, 'arg', this)
|
|
59
117
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
118
|
+
// Hide the source in the tree by navigating to it
|
|
119
|
+
hideAtPath(ctx.root as Val, arg)
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
src = arg.clone(ctx)
|
|
63
123
|
|
|
64
|
-
|
|
124
|
+
// Hide the original
|
|
125
|
+
arg.mark.hide = true
|
|
126
|
+
walk(arg, (_key: string | number | undefined, val: Val) => {
|
|
65
127
|
val.mark.hide = true
|
|
66
128
|
return val
|
|
67
129
|
})
|
|
68
|
-
|
|
69
|
-
// out = new CopyFuncVal({ peg: [src] }, ctx)
|
|
70
|
-
out = new PrefFuncVal({ peg: [src] }, ctx)
|
|
71
|
-
// out = src
|
|
72
130
|
}
|
|
73
131
|
|
|
74
|
-
//
|
|
132
|
+
// Clear marks on the clone (like copy)
|
|
133
|
+
src.mark.type = false
|
|
134
|
+
src.mark.hide = false
|
|
135
|
+
walk(src, (_key: string | number | undefined, val: Val) => {
|
|
136
|
+
val.mark.type = false
|
|
137
|
+
val.mark.hide = false
|
|
138
|
+
return val
|
|
139
|
+
})
|
|
75
140
|
|
|
76
|
-
return
|
|
141
|
+
return new PrefFuncVal({ peg: [src] }, ctx)
|
|
77
142
|
}
|
|
78
143
|
}
|
|
79
144
|
|
package/src/val/NilVal.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
|
|
17
17
|
import { Val, EMPTY_ERR } from './Val'
|
|
18
18
|
|
|
19
|
-
import { AontuError } from '../err'
|
|
19
|
+
import { AontuError, descErr } from '../err'
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class NilVal extends Val {
|
|
@@ -142,6 +142,9 @@ class NilVal extends Val {
|
|
|
142
142
|
ctx.adderr(this)
|
|
143
143
|
|
|
144
144
|
if (!ctx.collect) {
|
|
145
|
+
if (null == this.msg || '' === this.msg) {
|
|
146
|
+
descErr(this, ctx)
|
|
147
|
+
}
|
|
145
148
|
const err = new AontuError(this.msg, [this])
|
|
146
149
|
throw err
|
|
147
150
|
}
|
|
@@ -162,6 +165,19 @@ class NilVal extends Val {
|
|
|
162
165
|
}
|
|
163
166
|
|
|
164
167
|
|
|
168
|
+
// Shared sentinel for transient "this unification branch failed"
|
|
169
|
+
// markers. Used by DisjunctVal.unify to flag failed member trials
|
|
170
|
+
// (and to dedup results) without allocating a fresh NilVal per
|
|
171
|
+
// failure. The sentinel is filtered out before the disjunct result
|
|
172
|
+
// is constructed, so its .why / .site / .primary fields are never
|
|
173
|
+
// inspected by user-visible code.
|
|
174
|
+
//
|
|
175
|
+
// Do NOT use this sentinel for errors that may surface: those need
|
|
176
|
+
// real NilVals with proper site/path info for descErr formatting.
|
|
177
|
+
const TRIAL_NIL = new NilVal({ why: '|:trial-nil' })
|
|
178
|
+
|
|
179
|
+
|
|
165
180
|
export {
|
|
166
181
|
NilVal,
|
|
182
|
+
TRIAL_NIL,
|
|
167
183
|
}
|
package/src/val/OpBaseVal.ts
CHANGED
|
@@ -117,7 +117,7 @@ class OpBaseVal extends FeatureVal {
|
|
|
117
117
|
}
|
|
118
118
|
else {
|
|
119
119
|
out = result.done && peer.isTop ? result :
|
|
120
|
-
unite(ctx.clone({ explain: ec(te, 'RES') }), result, peer, 'op')
|
|
120
|
+
unite(te ? ctx.clone({ explain: ec(te, 'RES') }) : ctx, result, peer, 'op')
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
out.dc = DONE === out.dc ? DONE : this.dc + 1
|
package/src/val/PathFuncVal.ts
CHANGED
|
@@ -6,6 +6,10 @@ import type {
|
|
|
6
6
|
ValSpec,
|
|
7
7
|
} from '../type'
|
|
8
8
|
|
|
9
|
+
import {
|
|
10
|
+
DONE,
|
|
11
|
+
} from '../type'
|
|
12
|
+
|
|
9
13
|
import {
|
|
10
14
|
AontuContext,
|
|
11
15
|
} from '../ctx'
|
|
@@ -13,7 +17,7 @@ import {
|
|
|
13
17
|
import { makeNilErr } from '../err'
|
|
14
18
|
|
|
15
19
|
import { NilVal } from '../val/NilVal'
|
|
16
|
-
import {
|
|
20
|
+
import { PathVal } from '../val/PathVal'
|
|
17
21
|
import { FuncBaseVal } from './FuncBaseVal'
|
|
18
22
|
|
|
19
23
|
|
|
@@ -45,12 +49,26 @@ class PathFuncVal extends FuncBaseVal {
|
|
|
45
49
|
let arg = args[0]
|
|
46
50
|
|
|
47
51
|
if (0 === this.prepared) {
|
|
48
|
-
if (arg
|
|
49
|
-
|
|
52
|
+
if (arg instanceof PathVal) {
|
|
53
|
+
// PathVal from dotted arg — resolve via find().
|
|
54
|
+
const found = arg.find(ctx)
|
|
55
|
+
if (found != null && !found.isNil) {
|
|
56
|
+
arg = found
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
arg.dc = DONE
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (arg.isScalar && arg.peg != null && arg.peg !== ''
|
|
63
|
+
&& ('string' === typeof arg.peg || arg.isNumber)) {
|
|
64
|
+
// String or number arg like path("foo") or path(0.2) — create a path value
|
|
65
|
+
arg = this.place(new PathVal({ peg: [arg], absolute: false })) as PathVal
|
|
66
|
+
arg.dc = DONE
|
|
50
67
|
}
|
|
51
|
-
else if (
|
|
68
|
+
else if (arg.isNil || (arg.isScalar && (arg.peg === '' || arg.peg == null))) {
|
|
52
69
|
arg = makeNilErr(ctx, 'invalid-arg', this)
|
|
53
70
|
}
|
|
71
|
+
// else: already resolved by preprocessing — pass through
|
|
54
72
|
}
|
|
55
73
|
|
|
56
74
|
args[0] = arg
|
|
@@ -64,6 +82,13 @@ class PathFuncVal extends FuncBaseVal {
|
|
|
64
82
|
resolve(ctx: AontuContext, args: Val[]) {
|
|
65
83
|
let out = args[0] ?? makeNilErr(ctx, 'arg', this)
|
|
66
84
|
|
|
85
|
+
if (out instanceof PathVal) {
|
|
86
|
+
const found = out.find(ctx)
|
|
87
|
+
if (found != null && !found.isNil) {
|
|
88
|
+
out = found
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
67
92
|
return out
|
|
68
93
|
}
|
|
69
94
|
|