aontu 0.58.0 → 0.59.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.d.ts +1 -1
- package/dist/aontu.js +2 -1
- package/dist/aontu.js.map +1 -1
- package/dist/cli.js +11 -1
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +2 -0
- package/dist/ctx.js +2 -0
- package/dist/ctx.js.map +1 -1
- package/dist/err.js +6 -3
- package/dist/err.js.map +1 -1
- package/dist/lang.js +55 -1
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +2 -0
- package/dist/type.js.map +1 -1
- package/dist/val/DisjunctVal.js +33 -2
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/FuncBaseVal.js +36 -13
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/ListVal.js +9 -1
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/PlaceVal.js +5 -1
- package/dist/val/PlaceVal.js.map +1 -1
- package/dist/val/RefVal.js +25 -1
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/Val.d.ts +1 -0
- package/dist/val/Val.js +27 -0
- package/dist/val/Val.js.map +1 -1
- package/package.json +1 -1
- package/src/aontu.ts +2 -1
- package/src/cli.ts +11 -1
- package/src/ctx.ts +5 -0
- package/src/err.ts +6 -3
- package/src/lang.ts +47 -1
- package/src/type.ts +10 -1
- package/src/val/DisjunctVal.ts +33 -2
- package/src/val/FuncBaseVal.ts +36 -13
- package/src/val/ListVal.ts +9 -1
- package/src/val/PlaceVal.ts +5 -1
- package/src/val/RefVal.ts +25 -1
- package/src/val/Val.ts +33 -3
package/src/aontu.ts
CHANGED
|
@@ -38,7 +38,7 @@ export type { LintFinding, FormatReport, FormatOptions } from './format'
|
|
|
38
38
|
// Kept in step with package.json by the `version` npm lifecycle script,
|
|
39
39
|
// which runs on `npm version` / `npm run repo-bump`. version.test.ts
|
|
40
40
|
// fails if the two ever drift.
|
|
41
|
-
const VERSION = '0.
|
|
41
|
+
const VERSION = '0.59.0'
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
// A module file's VALUE, as far as it goes. COLLECTED, not raised: a
|
|
@@ -103,6 +103,7 @@ class Aontu {
|
|
|
103
103
|
ctx(cfg?: AontuContextConfig): AontuContext {
|
|
104
104
|
cfg = cfg ?? {}
|
|
105
105
|
cfg.fs = cfg.fs ?? this.opts.fs
|
|
106
|
+
;(cfg as any).errfs = (cfg as any).errfs ?? (this.opts as any).errfs
|
|
106
107
|
// The trust profile rides the instance (its resolver is built once,
|
|
107
108
|
// in the Lang constructor); the context needs it too, for the
|
|
108
109
|
// budgets (G5, docs/trust.md).
|
package/src/cli.ts
CHANGED
|
@@ -603,7 +603,17 @@ function runFile(file: string, mode: Mode, trust: TrustArg): number {
|
|
|
603
603
|
}
|
|
604
604
|
|
|
605
605
|
const path = resolve(file)
|
|
606
|
-
|
|
606
|
+
// `fs` IS WHAT MAKES A FRAME EXCERPT THE FILE IT NAMES. Without it,
|
|
607
|
+
// err.ts's resolveSrc falls back to the ENTRY text, so a frame whose
|
|
608
|
+
// arrow says `lib/types.aon:2:6` printed the entry's line 2 under it
|
|
609
|
+
// -- a real file name over another file's line, which
|
|
610
|
+
// docs/reference-api.md forbids in the same words it uses to require
|
|
611
|
+
// the name.
|
|
612
|
+
const aontu = new Aontu({
|
|
613
|
+
path,
|
|
614
|
+
errfs: { existsSync, readFileSync },
|
|
615
|
+
...trustOpts(trust, dirname(path)),
|
|
616
|
+
})
|
|
607
617
|
const res = evalSource(aontu, src, mode)
|
|
608
618
|
;(res.ok ? process.stdout : process.stderr).write(res.text + '\n')
|
|
609
619
|
return res.ok ? 0 : 1
|
package/src/ctx.ts
CHANGED
|
@@ -35,6 +35,7 @@ type AontuContextConfig = {
|
|
|
35
35
|
// (Val.origin, Val.emitted), so one flag turns the whole record on.
|
|
36
36
|
reads?: Set<string>
|
|
37
37
|
fs?: any
|
|
38
|
+
errfs?: any
|
|
38
39
|
path?: string[]
|
|
39
40
|
root?: Val
|
|
40
41
|
seen?: Record<string, number>
|
|
@@ -77,6 +78,8 @@ class AontuContext {
|
|
|
77
78
|
vars: Record<string, Val> = {}
|
|
78
79
|
src?: string
|
|
79
80
|
fs?: FST
|
|
81
|
+
// The error renderer's own reader; see type.ts's `errfs`.
|
|
82
|
+
errfs?: FST
|
|
80
83
|
|
|
81
84
|
seenI: number
|
|
82
85
|
seen: Record<string, number>
|
|
@@ -199,6 +202,7 @@ class AontuContext {
|
|
|
199
202
|
this.explain = Array.isArray(cfg.explain) ? cfg.explain : null
|
|
200
203
|
|
|
201
204
|
this.fs = cfg.fs ?? null
|
|
205
|
+
this.errfs = cfg.errfs ?? null
|
|
202
206
|
|
|
203
207
|
// Multiple unify passes will keep incrementing Val counter.
|
|
204
208
|
this.vc = null == cfg.vc ? 1_000_000_000 : cfg.vc
|
|
@@ -320,6 +324,7 @@ class AontuContext {
|
|
|
320
324
|
this.err = this.opts.err ?? this.err
|
|
321
325
|
this.deps = this.opts.deps ?? this.deps
|
|
322
326
|
this.fs = this.opts.fs ?? this.fs
|
|
327
|
+
this.errfs = (this.opts as any).errfs ?? this.errfs
|
|
323
328
|
this.explain = this.opts.explain ?? this.explain
|
|
324
329
|
|
|
325
330
|
this.src = ('string' === typeof this.opts.src ? this.opts.src : undefined) ?? this.src
|
package/src/err.ts
CHANGED
|
@@ -208,9 +208,12 @@ function resolveSrc(v: Val, errctx: ErrContext | undefined) {
|
|
|
208
208
|
}
|
|
209
209
|
else {
|
|
210
210
|
try {
|
|
211
|
-
|
|
211
|
+
// errfs first: the CLI gives the renderer a reader without
|
|
212
|
+
// giving the resolver one (type.ts, `errfs`).
|
|
213
|
+
const reader = errctx?.errfs ?? errctx?.fs
|
|
214
|
+
const fileExists = reader?.existsSync(url)
|
|
212
215
|
if (fileExists) {
|
|
213
|
-
src =
|
|
216
|
+
src = reader?.readFileSync(url, 'utf8') ?? undefined
|
|
214
217
|
}
|
|
215
218
|
}
|
|
216
219
|
catch (fe: any) {
|
|
@@ -228,7 +231,7 @@ function resolveSrc(v: Val, errctx: ErrContext | undefined) {
|
|
|
228
231
|
}
|
|
229
232
|
else if (errctx) {
|
|
230
233
|
src = 'SOURCE-NOT-FOUND:' + (null != url ? (' ' + url) : '') +
|
|
231
|
-
(null == errctx?.fs ? ' (NO-FS)' : '')
|
|
234
|
+
(null == (errctx?.errfs ?? errctx?.fs) ? ' (NO-FS)' : '')
|
|
232
235
|
}
|
|
233
236
|
}
|
|
234
237
|
|
package/src/lang.ts
CHANGED
|
@@ -807,6 +807,38 @@ help isolate the syntax error.`,
|
|
|
807
807
|
// Handle defered conjuncts, where MapVal does not yet
|
|
808
808
|
// exist, by creating ConjunctVal later.
|
|
809
809
|
else {
|
|
810
|
+
// AN INCLUDE UNIFIES IN PLACE. multisource calls this hook at
|
|
811
|
+
// the `@`'s own source position, so `prev` holds exactly the
|
|
812
|
+
// pairs written BEFORE it. Folding the loaded map's keys in
|
|
813
|
+
// here -- host-so-far first, arriving value second -- is what
|
|
814
|
+
// inlining the loaded bytes at the `@` does, and mirrors
|
|
815
|
+
// go/lang.go's Map.Merge, which multisource-go drives one key
|
|
816
|
+
// at a time. A non-map load has no keys to fold and stays a
|
|
817
|
+
// deferred conjunct arm.
|
|
818
|
+
if (true === (cval as any)?.isMap) {
|
|
819
|
+
const lm: any = cval
|
|
820
|
+
for (const k of Object.keys(lm.peg)) {
|
|
821
|
+
const own = (prev as any)[k]
|
|
822
|
+
;(prev as any)[k] = (null == own) ? lm.peg[k] :
|
|
823
|
+
(own?.isVal
|
|
824
|
+
? new ConjunctVal({ peg: [own, lm.peg[k]] })
|
|
825
|
+
: lm.peg[k])
|
|
826
|
+
}
|
|
827
|
+
// The loaded map's spread joins THIS map's spread list at
|
|
828
|
+
// the `@`'s position: the parse pushes each `&:` onto the
|
|
829
|
+
// node as it is read, so `prev[SPREAD].v` already holds the
|
|
830
|
+
// spreads written before the `@` and nothing after it.
|
|
831
|
+
if (null != lm.spread?.cj) {
|
|
832
|
+
;(prev as any)[SPREAD] =
|
|
833
|
+
((prev as any)[SPREAD] || { o: '&', v: [] })
|
|
834
|
+
;(prev as any)[SPREAD].v.push(lm.spread.cj)
|
|
835
|
+
}
|
|
836
|
+
prev.___optional = (prev.___optional || [])
|
|
837
|
+
for (const k of lm.optionalKeys) { prev.___optional.push(k) }
|
|
838
|
+
prev.___alias = (prev.___alias || [])
|
|
839
|
+
for (const k of lm.aliasKeys) { prev.___alias.push(k) }
|
|
840
|
+
return prev
|
|
841
|
+
}
|
|
810
842
|
prev.___merge = (prev.___merge || [])
|
|
811
843
|
prev.___merge.push(curr)
|
|
812
844
|
return prev
|
|
@@ -1436,7 +1468,8 @@ help isolate the syntax error.`,
|
|
|
1436
1468
|
// nested pair, which the val rule does produce -- and neither is
|
|
1437
1469
|
// a trailing comma.
|
|
1438
1470
|
for (const k in mo) {
|
|
1439
|
-
if (null == mo[k] && '___merge' !== k
|
|
1471
|
+
if (null == mo[k] && '___merge' !== k &&
|
|
1472
|
+
'___optional' !== k && '___alias' !== k) {
|
|
1440
1473
|
// Pathed at the KEY, not at the enclosing map. addsite takes
|
|
1441
1474
|
// the rule's path, which here is the map's, so the error
|
|
1442
1475
|
// would otherwise name the container and leave the reader to
|
|
@@ -1497,6 +1530,19 @@ help isolate the syntax error.`,
|
|
|
1497
1530
|
mo[key] = en
|
|
1498
1531
|
}
|
|
1499
1532
|
|
|
1533
|
+
// Marks carried over from a map include folded in the merge
|
|
1534
|
+
// hook above, applied here where the MapVal is built.
|
|
1535
|
+
if (mo.___optional || mo.___alias) {
|
|
1536
|
+
for (const k of (mo.___optional || [])) {
|
|
1537
|
+
if (!optionalKeys.includes(k)) { optionalKeys.push(k) }
|
|
1538
|
+
}
|
|
1539
|
+
for (const k of (mo.___alias || [])) {
|
|
1540
|
+
if (!aliasKeys.includes(k)) { aliasKeys.push(k) }
|
|
1541
|
+
}
|
|
1542
|
+
delete mo.___optional
|
|
1543
|
+
delete mo.___alias
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1500
1546
|
// Handle defered conjuncts, e.g. `{x:1 @"foo"}`
|
|
1501
1547
|
if (mo.___merge) {
|
|
1502
1548
|
let mop = { ...mo }
|
package/src/type.ts
CHANGED
|
@@ -61,6 +61,14 @@ type AontuOptions = {
|
|
|
61
61
|
debug?: boolean
|
|
62
62
|
trace?: boolean
|
|
63
63
|
fs?: FST
|
|
64
|
+
// errfs READS FOR THE ERROR RENDERER ONLY, never for resolution.
|
|
65
|
+
// A frame excerpts the file its arrow names, which means reading
|
|
66
|
+
// that file -- but handing the same reader to `fs` would change
|
|
67
|
+
// which leg the include RESOLVER takes (its file leg reads through
|
|
68
|
+
// the host filesystem when one is given, so a package hit can
|
|
69
|
+
// become a file hit), and a diagnostic must not move the boundary
|
|
70
|
+
// it is describing.
|
|
71
|
+
errfs?: FST
|
|
64
72
|
deps?: any
|
|
65
73
|
log?: any
|
|
66
74
|
idcount?: number
|
|
@@ -103,7 +111,8 @@ type ValList = Val[]
|
|
|
103
111
|
|
|
104
112
|
type ErrContext = {
|
|
105
113
|
src?: string,
|
|
106
|
-
fs?: FST
|
|
114
|
+
fs?: FST,
|
|
115
|
+
errfs?: FST
|
|
107
116
|
} /* node:coverage ignore next 24 */
|
|
108
117
|
|
|
109
118
|
export type {
|
package/src/val/DisjunctVal.ts
CHANGED
|
@@ -101,6 +101,27 @@ class DisjunctVal extends JunctionVal {
|
|
|
101
101
|
// before return.
|
|
102
102
|
const savedErr = ctx.err
|
|
103
103
|
const savedTrialMode = ctx._trialMode
|
|
104
|
+
// THE SANDBOX MUST NOT OUTLIVE THE TRIAL AS AN OWN PROPERTY.
|
|
105
|
+
// Contexts are made with Object.create(parent) and CACHED per
|
|
106
|
+
// (parent, key) by AontuContext.descend, so `err` and `_trialMode`
|
|
107
|
+
// are normally INHERITED -- and assigning them here, the restore
|
|
108
|
+
// included, creates own properties that shadow the ancestor on
|
|
109
|
+
// every later pass. A child that has run a trial of its own then
|
|
110
|
+
// cannot see the trial its PARENT is running: makeNilErr allocates
|
|
111
|
+
// a real NilVal instead of TRIAL_NIL, the refusal lands on the
|
|
112
|
+
// meet's real error list, and the losing member is kept as though
|
|
113
|
+
// it had survived -- with the nil inside it. A vet run then
|
|
114
|
+
// reported the conflicts of arms that should have dropped out, and
|
|
115
|
+
// called the document invalid where it is incomplete.
|
|
116
|
+
//
|
|
117
|
+
// So the restore DELETES what was inherited rather than writing it
|
|
118
|
+
// back. Both arms of both guards are live: the root meet context
|
|
119
|
+
// has an own `err`, a descended child does not, and `_trialMode`
|
|
120
|
+
// is own exactly when a disjunction is tried inside another
|
|
121
|
+
// disjunction's trial on the same context.
|
|
122
|
+
const ownErr = Object.prototype.hasOwnProperty.call(ctx, 'err')
|
|
123
|
+
const ownTrialMode =
|
|
124
|
+
Object.prototype.hasOwnProperty.call(ctx, '_trialMode')
|
|
104
125
|
// A MEMBER'S TYPE FLOW IS PART OF THAT MEMBER. `refer(t)`/`rel(t)`
|
|
105
126
|
// assert `t` on ANOTHER node, and the assertion may only take
|
|
106
127
|
// effect if the member that makes it survives: committing every
|
|
@@ -194,8 +215,18 @@ class DisjunctVal extends JunctionVal {
|
|
|
194
215
|
}
|
|
195
216
|
}
|
|
196
217
|
finally {
|
|
197
|
-
|
|
198
|
-
|
|
218
|
+
if (ownTrialMode) {
|
|
219
|
+
ctx._trialMode = savedTrialMode
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
delete (ctx as any)._trialMode
|
|
223
|
+
}
|
|
224
|
+
if (ownErr) {
|
|
225
|
+
ctx.err = savedErr
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
delete (ctx as any).err
|
|
229
|
+
}
|
|
199
230
|
;(ctx as any).referflows = savedFlows
|
|
200
231
|
}
|
|
201
232
|
|
package/src/val/FuncBaseVal.ts
CHANGED
|
@@ -46,6 +46,13 @@ import { hasPlace, fillPlace } from '../val/PlaceVal'
|
|
|
46
46
|
function trialUnify(ctx: AontuContext, a: Val, b: Val): Val | undefined {
|
|
47
47
|
const savedErr = ctx.err
|
|
48
48
|
const savedTrial = ctx._trialMode
|
|
49
|
+
// Restored by DELETION where they were inherited, for the reason
|
|
50
|
+
// DisjunctVal.unify's own sandbox gives at length: contexts are
|
|
51
|
+
// Object.create(parent) and cached per (parent, key), so writing
|
|
52
|
+
// these back leaves own properties that shadow the ancestor and make
|
|
53
|
+
// a later trial invisible to the value running inside it.
|
|
54
|
+
const ownErr = Object.prototype.hasOwnProperty.call(ctx, 'err')
|
|
55
|
+
const ownTrial = Object.prototype.hasOwnProperty.call(ctx, '_trialMode')
|
|
49
56
|
const trialErr: any[] = []
|
|
50
57
|
|
|
51
58
|
ctx.err = trialErr
|
|
@@ -56,8 +63,18 @@ function trialUnify(ctx: AontuContext, a: Val, b: Val): Val | undefined {
|
|
|
56
63
|
out = unite(ctx, a, b, 'trial')
|
|
57
64
|
}
|
|
58
65
|
finally {
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
if (ownErr) {
|
|
67
|
+
ctx.err = savedErr
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
delete (ctx as any).err
|
|
71
|
+
}
|
|
72
|
+
if (ownTrial) {
|
|
73
|
+
ctx._trialMode = savedTrial
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
delete (ctx as any)._trialMode
|
|
77
|
+
}
|
|
61
78
|
}
|
|
62
79
|
|
|
63
80
|
return 0 < trialErr.length || out.isNil ? undefined : out
|
|
@@ -158,22 +175,28 @@ class FuncBaseVal extends FeatureVal {
|
|
|
158
175
|
|
|
159
176
|
|
|
160
177
|
// THE PER-DESTINATION INSTANTIATION RULE (ADR-005). The default
|
|
161
|
-
// clone shares the argument array AND the argument Vals —
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
178
|
+
// clone shares the argument array AND the argument Vals — the
|
|
179
|
+
// residuation clone, which stays at one position and wants the
|
|
180
|
+
// sharing, and the reference copy of a target that still holds a
|
|
181
|
+
// staged call, which pins the move()/copy() ghost artifacts
|
|
182
|
+
// (test/spec/func.tsv, ghost-*-innard-canon; ADR-025) — but a clone
|
|
183
|
+
// that is an INSTANCE must own the full inner structure: with the
|
|
184
|
+
// args shared, `pack($.names, close({name: key()}))` resolved key()
|
|
185
|
+
// once inside the one shared inner map and stamped the FIRST
|
|
186
|
+
// child's key on every child (use-cases/BUGS.md §8). The `dup` spec
|
|
187
|
+
// flag asks for that depth; everything else keeps the sharing it
|
|
188
|
+
// has always had.
|
|
169
189
|
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
170
190
|
const out = super.clone(ctx, spec) as FuncBaseVal
|
|
171
191
|
if (true === spec?.dup && Array.isArray(this.peg)) {
|
|
172
192
|
// Every argument is a Val by construction (the parser builds
|
|
173
193
|
// them; make() rebuilds from driven Vals), as the Go twin's
|
|
174
|
-
// []Val typing states outright. The
|
|
175
|
-
// normalise every path in the clone
|
|
176
|
-
// argument-shaped parse paths never
|
|
194
|
+
// []Val typing states outright. The generator and spread
|
|
195
|
+
// instantiation sites then normalise every path in the clone
|
|
196
|
+
// (repathInstance), so the argument-shaped parse paths never
|
|
197
|
+
// leak into an instance; the reference copy takes the paths
|
|
198
|
+
// this rebasing gives, which is what an absolute address in a
|
|
199
|
+
// copied model already expects (ADR-014).
|
|
177
200
|
out.peg = this.peg.map((a: Val) => a.clone(ctx, { dup: true }))
|
|
178
201
|
}
|
|
179
202
|
return out
|
package/src/val/ListVal.ts
CHANGED
|
@@ -335,7 +335,15 @@ class ListVal extends BagVal {
|
|
|
335
335
|
{ mark: spec?.mark, dup: spec?.dup } : {}
|
|
336
336
|
for (let entry of Object.entries(this.peg)) {
|
|
337
337
|
out.peg[entry[0]] =
|
|
338
|
-
(entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx,
|
|
338
|
+
(entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx, {
|
|
339
|
+
...childspec,
|
|
340
|
+
// AN ELEMENT IS A POSITION, exactly as a map's child is
|
|
341
|
+
// (MapVal.clone). Without this an explicitly pathed clone
|
|
342
|
+
// rebased the list and left every element at its source
|
|
343
|
+
// path -- the Go twin descends by index (go/clone.go, the
|
|
344
|
+
// *ListVal arm of clonePathKind).
|
|
345
|
+
path: [...out.path, entry[0]],
|
|
346
|
+
}) : entry[1]
|
|
339
347
|
}
|
|
340
348
|
if (this.spread.cj) {
|
|
341
349
|
out.spread.cj = this.spread.cj.clone(ctx, childspec)
|
package/src/val/PlaceVal.ts
CHANGED
|
@@ -133,7 +133,11 @@ function hasPlace(v: Val): boolean {
|
|
|
133
133
|
// generator's to fill with its OWN source children when it fires.
|
|
134
134
|
function fillPlace(v: Val, fill: Val, ctx: AontuContext): Val {
|
|
135
135
|
if (true === (v as any).isPlace) {
|
|
136
|
-
|
|
136
|
+
// A FILL IS A POSITION. The hole knows where it sits in the
|
|
137
|
+
// instance; the datum arriving in it does not, and inserted as it
|
|
138
|
+
// stands it keeps the paths it had at its SOURCE, so every finding
|
|
139
|
+
// under it names a path that does not exist.
|
|
140
|
+
return fill.clone(ctx, { path: [...(v as any).path] })
|
|
137
141
|
}
|
|
138
142
|
|
|
139
143
|
const peg: any = (v as any).peg
|
package/src/val/RefVal.ts
CHANGED
|
@@ -653,7 +653,31 @@ class RefVal extends FeatureVal {
|
|
|
653
653
|
const lifted = true !== (ctx as any).argsnap
|
|
654
654
|
|| true === out.mark.type || true === out.mark.hide
|
|
655
655
|
|
|
656
|
-
|
|
656
|
+
// A REFERENCE'S COPY OWNS ITS ARGUMENTS (ADR-025). The copy
|
|
657
|
+
// is a per-destination instance exactly as a spread's or a
|
|
658
|
+
// generator's is, so ADR-005's rule holds here too: nothing
|
|
659
|
+
// path-dependent may be shared between two destinations, or
|
|
660
|
+
// the first destination's resolution answers for them all.
|
|
661
|
+
// The shallow clone shared a call's ARGUMENTS -- so
|
|
662
|
+
// `items: [&: $.entities.User]` over a `close({...})` target
|
|
663
|
+
// gave every element the one inner map, whose path each
|
|
664
|
+
// element rebased in turn, and the constraint that failed at
|
|
665
|
+
// element 2 reported element 0's path (use-cases GAP 8).
|
|
666
|
+
//
|
|
667
|
+
// A STAGED CALL IS THE EXCEPTION, because it has not decided
|
|
668
|
+
// yet. Its arguments are still being driven AT ITS OWN SITE
|
|
669
|
+
// (the staging rule, G8 phase 0), and a copy that owned them
|
|
670
|
+
// would drive its own set at the referring position instead:
|
|
671
|
+
// the relative `.side_effect` in a `match()` would read the
|
|
672
|
+
// referring field's siblings (use-cases/09-agent-tools), and
|
|
673
|
+
// an alias naming an `emit` rule table -- a template, which
|
|
674
|
+
// is exactly a value copied before it resolves -- would read
|
|
675
|
+
// its recursive `%w` as a self-reference. A staged call
|
|
676
|
+
// ANYWHERE in the target counts: what is referenced is
|
|
677
|
+
// usually the conjunct the call sits in, not the call.
|
|
678
|
+
// The copy shares what the source is still settling, and
|
|
679
|
+
// owns the rest.
|
|
680
|
+
out = out.clone(ctx, { dup: !out.holdsStaged })
|
|
657
681
|
|
|
658
682
|
if (lifted) {
|
|
659
683
|
walk(out, (_key: string | number | undefined, val: Val) => {
|
package/src/val/Val.ts
CHANGED
|
@@ -44,9 +44,12 @@ type ValSpec = {
|
|
|
44
44
|
// depth explicitly: `dup: true` makes FuncBaseVal, PrefVal and
|
|
45
45
|
// OpBaseVal clone their inner Vals too, and the bag/junction clones
|
|
46
46
|
// carry the flag down. Set by pack/each template instantiation,
|
|
47
|
-
// filter condition testing,
|
|
48
|
-
// ListVal.spreadClone)
|
|
49
|
-
//
|
|
47
|
+
// filter condition testing, spread application (MapVal/
|
|
48
|
+
// ListVal.spreadClone), and REFERENCE RESOLUTION of a target that
|
|
49
|
+
// holds no staged call, whose copy is a per-destination instance
|
|
50
|
+
// too (ADR-025) — never by the residuation clone, whose sharing is
|
|
51
|
+
// pinned behaviour, and never by a copy of something still being
|
|
52
|
+
// settled at its own site, which is what keeps the ghost rows.
|
|
50
53
|
dup?: boolean,
|
|
51
54
|
|
|
52
55
|
|
|
@@ -440,6 +443,33 @@ abstract class Val {
|
|
|
440
443
|
}
|
|
441
444
|
|
|
442
445
|
|
|
446
|
+
// A STAGED CALL STANDING ANYWHERE IN THIS VALUE (the `staged` flag,
|
|
447
|
+
// G8 phase 0). Such a call has not decided: its arguments are still
|
|
448
|
+
// being driven AT ITS OWN SITE, so a REFERENCE's copy shares it
|
|
449
|
+
// rather than owning a set of arguments it would drive at the
|
|
450
|
+
// referring position instead (RefVal.find, ADR-025). Not cached:
|
|
451
|
+
// unlike isPathDependent this is a fact about the value's current
|
|
452
|
+
// state, and the whole point is that it stops being true.
|
|
453
|
+
get holdsStaged(): boolean {
|
|
454
|
+
if (true === (this as any).staged) {
|
|
455
|
+
return true
|
|
456
|
+
}
|
|
457
|
+
const peg: any = this.peg
|
|
458
|
+
if (Array.isArray(peg)) {
|
|
459
|
+
for (let i = 0; i < peg.length; i++) {
|
|
460
|
+
if (true === peg[i]?.isVal && peg[i].holdsStaged) return true
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
else if (null != peg && 'object' === typeof peg) {
|
|
464
|
+
for (const k in peg) {
|
|
465
|
+
if (true === peg[k]?.isVal && peg[k].holdsStaged) return true
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
const spreadCj = (this as any).spread?.cj as Val | undefined
|
|
469
|
+
return true === spreadCj?.isVal && (spreadCj as any).holdsStaged
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
|
|
443
473
|
// PUT A MINTED VALUE WHERE THIS ONE STANDS: the site travels, and so
|
|
444
474
|
// does provenance, because the two answer one question. A narrowed
|
|
445
475
|
// disjunction, a lifted kind, a resolved reference -- each is a
|