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
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
Val,
|
|
6
|
+
ValSpec,
|
|
7
|
+
} from '../type'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
DONE,
|
|
11
|
+
} from '../type'
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
walk,
|
|
15
|
+
} from '../utility'
|
|
16
|
+
|
|
17
|
+
import { AontuContext } from '../ctx'
|
|
18
|
+
import { unite } from '../unify'
|
|
19
|
+
|
|
20
|
+
import { makeNilErr } from '../err'
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
top
|
|
24
|
+
} from './top'
|
|
25
|
+
|
|
26
|
+
import { StringVal } from './StringVal'
|
|
27
|
+
import { IntegerVal } from './IntegerVal'
|
|
28
|
+
import { NumberVal } from './NumberVal'
|
|
29
|
+
import { VarVal } from './VarVal'
|
|
30
|
+
import { ConjunctVal } from './ConjunctVal'
|
|
31
|
+
import { DisjunctVal } from './DisjunctVal'
|
|
32
|
+
import { FeatureVal } from './FeatureVal'
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PathVal extends FeatureVal {
|
|
36
|
+
isPath = true
|
|
37
|
+
isGenable = true
|
|
38
|
+
cjo = 32500
|
|
39
|
+
|
|
40
|
+
absolute: boolean = false
|
|
41
|
+
prefix: boolean = false
|
|
42
|
+
_resolved: Val | undefined = undefined
|
|
43
|
+
|
|
44
|
+
constructor(
|
|
45
|
+
spec: {
|
|
46
|
+
peg: any[],
|
|
47
|
+
absolute?: boolean,
|
|
48
|
+
prefix?: boolean
|
|
49
|
+
},
|
|
50
|
+
ctx?: AontuContext
|
|
51
|
+
) {
|
|
52
|
+
super(spec, ctx)
|
|
53
|
+
this.peg = []
|
|
54
|
+
|
|
55
|
+
this.absolute = true === this.absolute ? true : // absolute sticks
|
|
56
|
+
true === spec.absolute ? true : false
|
|
57
|
+
|
|
58
|
+
this.prefix = true === spec.prefix
|
|
59
|
+
|
|
60
|
+
for (let pI = 0; pI < spec.peg.length; pI++) {
|
|
61
|
+
this.append(spec.peg[pI])
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
append(part: any) {
|
|
67
|
+
let partval
|
|
68
|
+
|
|
69
|
+
if ('string' === typeof part) {
|
|
70
|
+
partval = part
|
|
71
|
+
this.peg.push(partval)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
else if (part instanceof StringVal) {
|
|
75
|
+
partval = part.peg
|
|
76
|
+
this.peg.push(partval)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
else if (part instanceof IntegerVal) {
|
|
80
|
+
partval = part.src
|
|
81
|
+
this.peg.push(partval)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
else if (part instanceof NumberVal) {
|
|
85
|
+
let partvals: string[] = part.src.split('.')
|
|
86
|
+
this.peg.push(...partvals)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
else if (part instanceof VarVal) {
|
|
90
|
+
partval = part
|
|
91
|
+
this.peg.push(partval)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
else if (part instanceof PathVal) {
|
|
95
|
+
if (part.absolute) {
|
|
96
|
+
this.absolute = true
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (this.prefix) {
|
|
100
|
+
if (part.prefix) {
|
|
101
|
+
this.peg.push('.')
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
if (part.prefix) {
|
|
106
|
+
if (0 === this.peg.length) {
|
|
107
|
+
this.prefix = true
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
else if (0 < this.peg.length) {
|
|
111
|
+
this.peg.push('.')
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.peg.push(...part.peg)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
unify(peer: Val, ctx: AontuContext): Val {
|
|
122
|
+
peer = peer ?? top()
|
|
123
|
+
|
|
124
|
+
// Already resolved (e.g. path value from path() function) — skip find
|
|
125
|
+
if (this.done) return this
|
|
126
|
+
|
|
127
|
+
let out: Val = this
|
|
128
|
+
const found = this.find(ctx)
|
|
129
|
+
|
|
130
|
+
if (found != null && !found.isNil) {
|
|
131
|
+
out = unite(ctx, found, peer, 'path')
|
|
132
|
+
}
|
|
133
|
+
else if (found?.isNil) {
|
|
134
|
+
out = found
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// Not yet resolvable — increment dc to signal not done
|
|
138
|
+
this.dc = DONE === this.dc ? DONE : this.dc + 1
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return out
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
find(ctx: AontuContext) {
|
|
146
|
+
let out: Val | undefined = undefined
|
|
147
|
+
|
|
148
|
+
// Check if self.path starts with peg (cycle detection).
|
|
149
|
+
// Element-by-element comparison avoids string join+startsWith allocations.
|
|
150
|
+
let isprefixpath = this.peg.length <= this.path.length
|
|
151
|
+
if (isprefixpath) {
|
|
152
|
+
for (let i = 0; i < this.peg.length; i++) {
|
|
153
|
+
if (this.peg[i] !== this.path[i]) {
|
|
154
|
+
isprefixpath = false
|
|
155
|
+
break
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Degenerate case: peg is all empty strings (e.g. path("")) and path is empty.
|
|
160
|
+
if (!isprefixpath && this.peg.length > 0 && this.path.length === 0) {
|
|
161
|
+
let allEmpty = true
|
|
162
|
+
for (let i = 0; i < this.peg.length; i++) {
|
|
163
|
+
if ('' !== this.peg[i]) { allEmpty = false; break }
|
|
164
|
+
}
|
|
165
|
+
isprefixpath = allEmpty
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let refpath: string[] = []
|
|
169
|
+
let pI = 0
|
|
170
|
+
// let descent = ''
|
|
171
|
+
|
|
172
|
+
if (isprefixpath) {
|
|
173
|
+
// console.log('SELFPATH', selfpath, 'PEGPATH', pegpath)
|
|
174
|
+
out = makeNilErr(ctx, 'path_cycle', this)
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
|
|
178
|
+
let parts: string[] = []
|
|
179
|
+
|
|
180
|
+
let modes: string[] = []
|
|
181
|
+
|
|
182
|
+
for (let pI = 0; pI < this.peg.length; pI++) {
|
|
183
|
+
let part = this.peg[pI]
|
|
184
|
+
if (part instanceof VarVal) {
|
|
185
|
+
let strval = (part as VarVal).peg
|
|
186
|
+
let name = strval ? '' + strval.peg : ''
|
|
187
|
+
|
|
188
|
+
if ('KEY' === name) {
|
|
189
|
+
if (pI === this.peg.length - 1) {
|
|
190
|
+
modes.push(name)
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
// TODO: return a Nil explaining error
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if ('SELF' === name) {
|
|
199
|
+
if (pI === 0) {
|
|
200
|
+
modes.push(name)
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// TODO: return a Nil explaining error
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if ('PARENT' === name) {
|
|
208
|
+
if (pI === 0) {
|
|
209
|
+
modes.push(name)
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// TODO: return a Nil explaining error
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else if (0 === modes.length) {
|
|
217
|
+
part = (part as VarVal).unify(top(), ctx)
|
|
218
|
+
if (part.isNil) {
|
|
219
|
+
// TODO: var not found, so can't find path
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
part = '' + part.peg
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
parts.push(part)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (this.absolute) {
|
|
233
|
+
refpath = parts
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// TODO: deprecate $KEY, etc
|
|
237
|
+
refpath = this.path.slice(
|
|
238
|
+
0,
|
|
239
|
+
(
|
|
240
|
+
modes.includes('SELF') ? 0 :
|
|
241
|
+
modes.includes('PARENT') ? -1 :
|
|
242
|
+
-1 // siblings
|
|
243
|
+
)
|
|
244
|
+
).concat(parts)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let sep = '.'
|
|
248
|
+
refpath = refpath
|
|
249
|
+
.reduce(((a: string[], p: string) =>
|
|
250
|
+
(p === sep ? a.length = a.length - 1 : a.push(p), a)), [])
|
|
251
|
+
|
|
252
|
+
if (modes.includes('KEY')) {
|
|
253
|
+
let key = this.path[this.path.length - 2]
|
|
254
|
+
let sv = new StringVal({ peg: null == key ? '' : key }, ctx)
|
|
255
|
+
|
|
256
|
+
// TODO: other props?
|
|
257
|
+
sv.dc = DONE
|
|
258
|
+
sv.path = this.path
|
|
259
|
+
|
|
260
|
+
return sv
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
let node: Val | null = ctx.root as Val
|
|
264
|
+
|
|
265
|
+
let nopath = false
|
|
266
|
+
|
|
267
|
+
if (null != node) {
|
|
268
|
+
for (; pI < refpath.length; pI++) {
|
|
269
|
+
let part = refpath[pI]
|
|
270
|
+
// console.log('PART', pI, part, node)
|
|
271
|
+
|
|
272
|
+
// descent += (' | ' + pI + '=' + node.canon) // Util.inspect(node))
|
|
273
|
+
|
|
274
|
+
if (node.isMap) {
|
|
275
|
+
node = node.peg[part]
|
|
276
|
+
}
|
|
277
|
+
else if (node.isList) {
|
|
278
|
+
node = node.peg[part]
|
|
279
|
+
}
|
|
280
|
+
else if (node.isConjunct || node.isDisjunct) {
|
|
281
|
+
// Collect matching children from all junction terms,
|
|
282
|
+
// flattening nested conjuncts and disjuncts.
|
|
283
|
+
// Spreads match any key — their peg is always included.
|
|
284
|
+
const matches: Val[] = []
|
|
285
|
+
const stack = [...node.peg]
|
|
286
|
+
while (stack.length > 0) {
|
|
287
|
+
const term = stack.pop()!
|
|
288
|
+
if (term.isConjunct || term.isDisjunct) {
|
|
289
|
+
stack.push(...term.peg)
|
|
290
|
+
}
|
|
291
|
+
else if (term.isSpread) {
|
|
292
|
+
matches.push(term.peg)
|
|
293
|
+
}
|
|
294
|
+
else if ((term.isMap || term.isList) && term.peg[part] != null) {
|
|
295
|
+
matches.push(term.peg[part])
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (matches.length === 1) {
|
|
299
|
+
node = matches[0]
|
|
300
|
+
}
|
|
301
|
+
else if (matches.length > 1) {
|
|
302
|
+
node = node.isConjunct
|
|
303
|
+
? new ConjunctVal({ peg: matches })
|
|
304
|
+
: new DisjunctVal({ peg: matches })
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
node = null
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (node.done) {
|
|
311
|
+
nopath = true
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (null == node) {
|
|
319
|
+
nopath = true
|
|
320
|
+
break
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// console.log('REFPATH', ctx.cc, pI, refpath, nopath, ctx.root, node)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
if (nopath) {
|
|
330
|
+
out = makeNilErr(ctx, 'no_path', this)
|
|
331
|
+
}
|
|
332
|
+
else if (pI === refpath.length && node != null) {
|
|
333
|
+
out = node
|
|
334
|
+
|
|
335
|
+
// Types and hidden values are cloned and made concrete
|
|
336
|
+
if (null != out) { // && (out.mark.type || out.mark.hide)) {
|
|
337
|
+
|
|
338
|
+
// console.log('FOUND-A', out)
|
|
339
|
+
|
|
340
|
+
if (this.mark.type || this.mark.hide) {
|
|
341
|
+
out.mark.type = this.mark.type
|
|
342
|
+
out.mark.hide = this.mark.hide
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (this.mark._hide_found) {
|
|
346
|
+
out.mark.hide = true
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Cache clone+walk results per (ref, target) per iteration.
|
|
350
|
+
const cacheKey = this.id + '|' + out.id
|
|
351
|
+
const cache = ctx._refCloneCache
|
|
352
|
+
const cached = cache?.get(cacheKey)
|
|
353
|
+
if (cached !== undefined) {
|
|
354
|
+
out = cached
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
out = out.clone(ctx)
|
|
358
|
+
out.mark.type = false
|
|
359
|
+
out.mark.hide = false
|
|
360
|
+
|
|
361
|
+
walk(out, (_key: string | number | undefined, val: Val) => {
|
|
362
|
+
val.mark.type = false
|
|
363
|
+
val.mark.hide = false
|
|
364
|
+
return val
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
cache?.set(cacheKey, out)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// console.log('REF-FIND', ctx.cc, this.id, selfpath, 'PEG=', pegpath, 'RP', pI, refpath.join('.'), descent, 'O=', out?.id, out?.canon, out?.done)
|
|
374
|
+
|
|
375
|
+
return out
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
same(peer: Val): boolean {
|
|
381
|
+
return null == peer ? false : this.peg === peer.peg
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
386
|
+
let out = (super.clone(ctx, {
|
|
387
|
+
peg: this.peg,
|
|
388
|
+
absolute: this.absolute,
|
|
389
|
+
...(spec || {})
|
|
390
|
+
}) as PathVal)
|
|
391
|
+
return out
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
get canon() {
|
|
396
|
+
let str =
|
|
397
|
+
(this.absolute ? '$' : '') +
|
|
398
|
+
(0 < this.peg.length ? '.' : '') +
|
|
399
|
+
this.peg.map((p: any) => '.' === p ? '' :
|
|
400
|
+
(p.isVal ? p.canon : '' + p))
|
|
401
|
+
.join('.')
|
|
402
|
+
return str
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
gen(ctx: AontuContext) {
|
|
407
|
+
let nil = makeNilErr(
|
|
408
|
+
ctx,
|
|
409
|
+
'ref',
|
|
410
|
+
this,
|
|
411
|
+
undefined,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
nil.path = this.path
|
|
415
|
+
nil.site.url = this.site.url
|
|
416
|
+
nil.site.row = this.site.row
|
|
417
|
+
nil.site.col = this.site.col
|
|
418
|
+
|
|
419
|
+
return undefined
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
inspection() {
|
|
424
|
+
return [
|
|
425
|
+
this.absolute ? 'absolute' : '',
|
|
426
|
+
this.prefix ? 'prefix' : '',
|
|
427
|
+
].filter(p => '' != p).join(',')
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
export {
|
|
434
|
+
PathVal,
|
|
435
|
+
}
|
package/src/val/PrefVal.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
|
|
23
23
|
import { top } from './top'
|
|
24
24
|
|
|
25
|
+
import { ConjunctVal } from './ConjunctVal'
|
|
25
26
|
import { FeatureVal } from './FeatureVal'
|
|
26
27
|
|
|
27
28
|
|
|
@@ -62,12 +63,15 @@ class PrefVal extends FeatureVal {
|
|
|
62
63
|
let why = ''
|
|
63
64
|
|
|
64
65
|
if (!this.peg.done) {
|
|
65
|
-
const resolved = unite(ctx.clone({ explain:
|
|
66
|
+
const resolved = unite(te ? ctx.clone({ explain: ec(te, 'RES') }) : ctx,
|
|
66
67
|
this.peg, top(), 'pref/resolve')
|
|
67
|
-
// console.log('PREF-RESOLVED', this.peg.canon, '->', resolved)
|
|
68
68
|
this.peg = resolved
|
|
69
69
|
this.superpeg = this.peg.superior()
|
|
70
70
|
}
|
|
71
|
+
else if (this.superpeg.isTop && !this.peg.isTop) {
|
|
72
|
+
// Stale superpeg from pre-resolved PathVal — recalculate
|
|
73
|
+
this.superpeg = this.peg.superior()
|
|
74
|
+
}
|
|
71
75
|
|
|
72
76
|
if (peer instanceof PrefVal) {
|
|
73
77
|
why += 'pref-'
|
|
@@ -96,7 +100,7 @@ class PrefVal extends FeatureVal {
|
|
|
96
100
|
// peer.peg.id, peer.peg, peer.peg.done,
|
|
97
101
|
// )
|
|
98
102
|
|
|
99
|
-
let peg = unite(ctx.clone({ explain:
|
|
103
|
+
let peg = unite(te ? ctx.clone({ explain: ec(te, 'PREF-PEER') }) : ctx,
|
|
100
104
|
this.peg, peer.peg, 'pref-peer/' + this.id)
|
|
101
105
|
out = new PrefVal({ peg }, ctx)
|
|
102
106
|
// console.log('PREF-RANK-SAME-OUT', peg, peg.done, out, out.done)
|
|
@@ -106,11 +110,20 @@ class PrefVal extends FeatureVal {
|
|
|
106
110
|
else if (!peer.isTop) {
|
|
107
111
|
why += 'super-'
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
out = this
|
|
113
|
-
|
|
113
|
+
// If peg is unresolved (e.g. deferred ref), don't decide yet —
|
|
114
|
+
// preserve both sides so a later pass can resolve.
|
|
115
|
+
if (!this.peg.done) {
|
|
116
|
+
out = new ConjunctVal({ peg: [this, peer] }, ctx)
|
|
117
|
+
done = false
|
|
118
|
+
why += 'defer'
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
out = unite(te ? ctx.clone({ explain: ec(te, 'SUPER') }) : ctx,
|
|
122
|
+
this.superpeg, peer, 'pref-super/' + this.id)
|
|
123
|
+
if (out.same(this.superpeg)) {
|
|
124
|
+
out = this.peg
|
|
125
|
+
why += 'same'
|
|
126
|
+
}
|
|
114
127
|
}
|
|
115
128
|
|
|
116
129
|
// }
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/* Copyright (c) 2021-2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
import Util from 'node:util'
|
|
5
|
-
|
|
6
4
|
import {
|
|
7
5
|
walk,
|
|
8
6
|
explainOpen,
|
|
@@ -16,6 +14,7 @@ import type {
|
|
|
16
14
|
ValSpec,
|
|
17
15
|
} from '../type'
|
|
18
16
|
|
|
17
|
+
|
|
19
18
|
import {
|
|
20
19
|
DONE,
|
|
21
20
|
} from '../type'
|
|
@@ -137,10 +136,23 @@ class RefVal extends FeatureVal {
|
|
|
137
136
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
138
137
|
peer = peer ?? top()
|
|
139
138
|
|
|
139
|
+
// TEMPORARY: nerf RefVals to verify spread-first resolution
|
|
140
|
+
return makeNilErr(ctx, 'ref_test_block', this, peer)
|
|
141
|
+
|
|
140
142
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Ref', this, peer)
|
|
141
143
|
let out: Val = this
|
|
142
144
|
let why = 'id'
|
|
143
145
|
|
|
146
|
+
// Defer ref resolution on first pass and while spreads remain
|
|
147
|
+
if (0 === ctx.cc || 0 < ctx.sc) {
|
|
148
|
+
if (!peer.isTop && this.id !== peer.id) {
|
|
149
|
+
out = new ConjunctVal({ peg: [this, peer] }, ctx)
|
|
150
|
+
}
|
|
151
|
+
out.dc = DONE === out.dc ? DONE : this.dc + 1
|
|
152
|
+
explainClose(te, out)
|
|
153
|
+
return out
|
|
154
|
+
}
|
|
155
|
+
|
|
144
156
|
if (this.id !== peer.id) {
|
|
145
157
|
|
|
146
158
|
// TODO: not resolved when all Vals in path are done is an error
|
|
@@ -177,7 +189,7 @@ class RefVal extends FeatureVal {
|
|
|
177
189
|
}
|
|
178
190
|
}
|
|
179
191
|
else {
|
|
180
|
-
out = unite(ctx.clone({ explain: ec(te, 'RES') }), resolved, peer, 'ref')
|
|
192
|
+
out = unite(te ? ctx.clone({ explain: ec(te, 'RES') }) : ctx, resolved, peer, 'ref')
|
|
181
193
|
why = 'u'
|
|
182
194
|
}
|
|
183
195
|
|
|
@@ -359,31 +371,30 @@ class RefVal extends FeatureVal {
|
|
|
359
371
|
if (this.mark.type || this.mark.hide) {
|
|
360
372
|
out.mark.type = this.mark.type
|
|
361
373
|
out.mark.hide = this.mark.hide
|
|
362
|
-
|
|
363
|
-
// walk(out, (_key: string | number | undefined, val: Val) => {
|
|
364
|
-
// val.mark.type = this.mark.type
|
|
365
|
-
// val.mark.hide = this.mark.hide
|
|
366
|
-
// return val
|
|
367
|
-
// })
|
|
368
374
|
}
|
|
369
375
|
|
|
370
376
|
if (this.mark._hide_found) {
|
|
371
377
|
out.mark.hide = true
|
|
372
378
|
}
|
|
373
379
|
|
|
374
|
-
//
|
|
375
|
-
|
|
376
|
-
|
|
380
|
+
// Cache clone+walk results per (ref, target) per iteration.
|
|
381
|
+
const cacheKey = this.id + '|' + out.id
|
|
382
|
+
const cache = ctx._refCloneCache
|
|
383
|
+
const cached = cache?.get(cacheKey)
|
|
384
|
+
if (cached !== undefined) {
|
|
385
|
+
out = cached
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
out = out.clone(ctx)
|
|
377
389
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
})
|
|
384
|
-
//}
|
|
390
|
+
walk(out, (_key: string | number | undefined, val: Val) => {
|
|
391
|
+
val.mark.type = false
|
|
392
|
+
val.mark.hide = false
|
|
393
|
+
return val
|
|
394
|
+
})
|
|
385
395
|
|
|
386
|
-
|
|
396
|
+
cache?.set(cacheKey, out)
|
|
397
|
+
}
|
|
387
398
|
}
|
|
388
399
|
}
|
|
389
400
|
}
|