aontu 0.52.0 → 0.53.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/README.md +88 -0
- package/bin/aontu-mcp.js +4 -0
- package/dist/agentsmd.d.ts +16 -0
- package/dist/agentsmd.js +107 -0
- package/dist/agentsmd.js.map +1 -0
- package/dist/aontu.d.ts +14 -3
- package/dist/aontu.js +145 -4
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +44 -1
- package/dist/cli.js +2401 -44
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +16 -0
- package/dist/ctx.js +44 -0
- package/dist/ctx.js.map +1 -1
- package/dist/diff.d.ts +22 -0
- package/dist/diff.js +141 -0
- package/dist/diff.js.map +1 -0
- package/dist/err.d.ts +3 -1
- package/dist/err.js +48 -8
- package/dist/err.js.map +1 -1
- package/dist/graph.d.ts +16 -0
- package/dist/graph.js +73 -0
- package/dist/graph.js.map +1 -0
- package/dist/hcanon.d.ts +3 -0
- package/dist/hcanon.js +146 -0
- package/dist/hcanon.js.map +1 -0
- package/dist/hints.js +223 -5
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.d.ts +20 -0
- package/dist/jsonschema.js +391 -0
- package/dist/jsonschema.js.map +1 -0
- package/dist/lang.js +698 -35
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +9 -2
- package/dist/lsp.js +262 -46
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.d.ts +20 -0
- package/dist/mcp-server.js +147 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp.d.ts +42 -0
- package/dist/mcp.js +814 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mod-tool.d.ts +58 -0
- package/dist/mod-tool.js +498 -0
- package/dist/mod-tool.js.map +1 -0
- package/dist/mod.d.ts +31 -0
- package/dist/mod.js +250 -0
- package/dist/mod.js.map +1 -0
- package/dist/patch.d.ts +44 -0
- package/dist/patch.js +506 -0
- package/dist/patch.js.map +1 -0
- package/dist/provenance.d.ts +40 -0
- package/dist/provenance.js +335 -0
- package/dist/provenance.js.map +1 -0
- package/dist/query.d.ts +27 -0
- package/dist/query.js +294 -0
- package/dist/query.js.map +1 -0
- package/dist/reach.d.ts +14 -0
- package/dist/reach.js +140 -0
- package/dist/reach.js.map +1 -0
- package/dist/relation.d.ts +19 -0
- package/dist/relation.js +305 -0
- package/dist/relation.js.map +1 -0
- package/dist/report-sarif.d.ts +14 -0
- package/dist/report-sarif.js +102 -0
- package/dist/report-sarif.js.map +1 -0
- package/dist/site.d.ts +4 -0
- package/dist/site.js +31 -0
- package/dist/site.js.map +1 -1
- package/dist/std.d.ts +1 -0
- package/dist/std.js +73 -0
- package/dist/std.js.map +1 -0
- package/dist/subsume.d.ts +39 -0
- package/dist/subsume.js +526 -0
- package/dist/subsume.js.map +1 -0
- package/dist/trim.d.ts +19 -0
- package/dist/trim.js +155 -0
- package/dist/trim.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +17 -1
- package/dist/type.js.map +1 -1
- package/dist/unify.d.ts +3 -1
- package/dist/unify.js +287 -18
- package/dist/unify.js.map +1 -1
- package/dist/utility.d.ts +9 -1
- package/dist/utility.js +122 -1
- package/dist/utility.js.map +1 -1
- package/dist/val/AggFuncVal.d.ts +33 -0
- package/dist/val/AggFuncVal.js +202 -0
- package/dist/val/AggFuncVal.js.map +1 -0
- package/dist/val/ArithFuncVal.d.ts +31 -0
- package/dist/val/ArithFuncVal.js +62 -0
- package/dist/val/ArithFuncVal.js.map +1 -0
- package/dist/val/BagVal.d.ts +5 -0
- package/dist/val/BagVal.js +96 -5
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +9 -1
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/ConjunctVal.d.ts +1 -1
- package/dist/val/ConjunctVal.js +19 -0
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.d.ts +48 -1
- package/dist/val/ConstraintVal.js +1501 -110
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/CopyFuncVal.d.ts +1 -2
- package/dist/val/CopyFuncVal.js +7 -0
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.d.ts +1 -0
- package/dist/val/Decimal.js +13 -0
- package/dist/val/Decimal.js.map +1 -1
- package/dist/val/DeprecateFuncVal.d.ts +11 -0
- package/dist/val/DeprecateFuncVal.js +47 -0
- package/dist/val/DeprecateFuncVal.js.map +1 -0
- package/dist/val/DisjunctVal.js +130 -21
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/EachFuncVal.d.ts +15 -0
- package/dist/val/EachFuncVal.js +75 -0
- package/dist/val/EachFuncVal.js.map +1 -0
- package/dist/val/ExpectVal.d.ts +1 -0
- package/dist/val/ExpectVal.js +41 -4
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FeatureVal.js +1 -1
- package/dist/val/FeatureVal.js.map +1 -1
- package/dist/val/FilterFuncVal.d.ts +15 -0
- package/dist/val/FilterFuncVal.js +91 -0
- package/dist/val/FilterFuncVal.js.map +1 -0
- package/dist/val/FuncBaseVal.d.ts +6 -1
- package/dist/val/FuncBaseVal.js +178 -2
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/IdFuncVal.d.ts +13 -0
- package/dist/val/IdFuncVal.js +54 -0
- package/dist/val/IdFuncVal.js.map +1 -0
- package/dist/val/JunctionVal.js +7 -1
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.d.ts +1 -1
- package/dist/val/KeyFuncVal.js +38 -30
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +117 -17
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +102 -8
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.d.ts +15 -0
- package/dist/val/MatchFuncVal.js +107 -0
- package/dist/val/MatchFuncVal.js.map +1 -0
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +24 -0
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -1
- package/dist/val/OpBaseVal.js +24 -2
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/OpenFuncVal.js +4 -1
- package/dist/val/OpenFuncVal.js.map +1 -1
- package/dist/val/PackFuncVal.d.ts +15 -0
- package/dist/val/PackFuncVal.js +108 -0
- package/dist/val/PackFuncVal.js.map +1 -0
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PlaceVal.d.ts +13 -0
- package/dist/val/PlaceVal.js +131 -0
- package/dist/val/PlaceVal.js.map +1 -0
- package/dist/val/PlusOpVal.js +11 -2
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +2 -2
- package/dist/val/PrefVal.js +78 -23
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RefVal.d.ts +1 -1
- package/dist/val/RefVal.js +158 -30
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.d.ts +36 -0
- package/dist/val/ReferFuncVal.js +303 -0
- package/dist/val/ReferFuncVal.js.map +1 -0
- package/dist/val/ScalarKindVal.d.ts +1 -2
- package/dist/val/ScalarKindVal.js +0 -11
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TypeFuncVal.js.map +1 -1
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +9 -2
- package/dist/val/Val.js +150 -4
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/arith.d.ts +6 -0
- package/dist/val/arith.js +170 -0
- package/dist/val/arith.js.map +1 -0
- package/dist/vet.d.ts +45 -0
- package/dist/vet.js +776 -0
- package/dist/vet.js.map +1 -0
- package/dist/walk.d.ts +2 -0
- package/dist/walk.js +91 -0
- package/dist/walk.js.map +1 -0
- package/grammar/aontu.gbnf +130 -0
- package/grammar/aontu.lark +113 -0
- package/package.json +30 -15
- package/skill/SKILL.md +37 -0
- package/skill/error-codes.md +62 -0
- package/skill/examples.md +99 -0
- package/skill/grammar-card.md +57 -0
- package/src/agentsmd.ts +135 -0
- package/src/aontu.ts +192 -4
- package/src/cli.ts +2858 -71
- package/src/ctx.ts +81 -0
- package/src/diff.ts +196 -0
- package/src/err.ts +52 -8
- package/src/graph.ts +135 -0
- package/src/hcanon.ts +169 -0
- package/src/hints.ts +271 -5
- package/src/jsonschema.ts +511 -0
- package/src/lang.ts +779 -37
- package/src/lsp.ts +281 -47
- package/src/mcp-server.ts +187 -0
- package/src/mcp.ts +993 -0
- package/src/mod-tool.ts +679 -0
- package/src/mod.ts +344 -0
- package/src/patch.ts +624 -0
- package/src/provenance.ts +430 -0
- package/src/query.ts +379 -0
- package/src/reach.ts +184 -0
- package/src/relation.ts +395 -0
- package/src/report-sarif.ts +137 -0
- package/src/site.ts +36 -1
- package/src/std.ts +73 -0
- package/src/subsume.ts +690 -0
- package/src/trim.ts +195 -0
- package/src/tsconfig.json +10 -4
- package/src/type.ts +51 -2
- package/src/unify.ts +311 -16
- package/src/utility.ts +139 -1
- package/src/val/AggFuncVal.ts +319 -0
- package/src/val/ArithFuncVal.ts +108 -0
- package/src/val/BagVal.ts +101 -4
- package/src/val/CloseFuncVal.ts +9 -1
- package/src/val/ConjunctVal.ts +20 -0
- package/src/val/ConstraintVal.ts +1699 -116
- package/src/val/CopyFuncVal.ts +7 -1
- package/src/val/Decimal.ts +15 -0
- package/src/val/DeprecateFuncVal.ts +84 -0
- package/src/val/DisjunctVal.ts +139 -28
- package/src/val/EachFuncVal.ts +133 -0
- package/src/val/ExpectVal.ts +43 -6
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FilterFuncVal.ts +154 -0
- package/src/val/FuncBaseVal.ts +200 -3
- package/src/val/HideFuncVal.ts +0 -2
- package/src/val/IdFuncVal.ts +91 -0
- package/src/val/JunctionVal.ts +7 -1
- package/src/val/KeyFuncVal.ts +39 -35
- package/src/val/ListVal.ts +125 -18
- package/src/val/LowerFuncVal.ts +0 -1
- package/src/val/MapVal.ts +110 -8
- package/src/val/MatchFuncVal.ts +176 -0
- package/src/val/MoveFuncVal.ts +0 -2
- package/src/val/NilVal.ts +25 -0
- package/src/val/OpBaseVal.ts +26 -3
- package/src/val/OpenFuncVal.ts +4 -2
- package/src/val/PackFuncVal.ts +175 -0
- package/src/val/PathFuncVal.ts +0 -1
- package/src/val/PlaceVal.ts +193 -0
- package/src/val/PlusOpVal.ts +11 -2
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +79 -36
- package/src/val/RefVal.ts +163 -30
- package/src/val/ReferFuncVal.ts +387 -0
- package/src/val/ScalarKindVal.ts +0 -13
- package/src/val/TopVal.ts +0 -1
- package/src/val/TypeFuncVal.ts +0 -2
- package/src/val/UpperFuncVal.ts +0 -1
- package/src/val/Val.ts +213 -3
- package/src/val/VarVal.ts +0 -1
- package/src/val/arith.ts +316 -0
- package/src/vet.ts +992 -0
- package/src/walk.ts +99 -0
package/src/val/ListVal.ts
CHANGED
|
@@ -17,6 +17,8 @@ import { unite } from '../unify'
|
|
|
17
17
|
|
|
18
18
|
import {
|
|
19
19
|
propagateMarks,
|
|
20
|
+
canonRiders,
|
|
21
|
+
constantIdFunc,
|
|
20
22
|
explainOpen,
|
|
21
23
|
ec,
|
|
22
24
|
explainClose,
|
|
@@ -32,6 +34,8 @@ import {
|
|
|
32
34
|
import { ConjunctVal } from './ConjunctVal'
|
|
33
35
|
import { NilVal } from './NilVal'
|
|
34
36
|
import { BagVal } from './BagVal'
|
|
37
|
+
import { repathInstance } from './Val'
|
|
38
|
+
import { markSpread } from '../provenance'
|
|
35
39
|
|
|
36
40
|
|
|
37
41
|
class ListVal extends BagVal {
|
|
@@ -55,7 +59,10 @@ class ListVal extends BagVal {
|
|
|
55
59
|
if (spread) {
|
|
56
60
|
if ('&' === spread.o) {
|
|
57
61
|
|
|
58
|
-
//
|
|
62
|
+
// Multiple same-level spreads conjoin; an unequal spread from
|
|
63
|
+
// another statement meets this one in unify's combination
|
|
64
|
+
// below (see the MapVal constructor note — the combined
|
|
65
|
+
// template is stateless, BUGS.md §6-§7).
|
|
59
66
|
this.spread.cj =
|
|
60
67
|
Array.isArray(spread.v) ?
|
|
61
68
|
1 < spread.v.length ?
|
|
@@ -63,6 +70,22 @@ class ListVal extends BagVal {
|
|
|
63
70
|
spread.v[0] :
|
|
64
71
|
spread.v
|
|
65
72
|
|
|
73
|
+
// Clearing rule 3 (G4 phase 1): a CONSTANT id in the template
|
|
74
|
+
// would declare every child to be one entity. The refusal
|
|
75
|
+
// replaces the template, so it reaches every child and the
|
|
76
|
+
// bag itself (see the isNil arm where the spread is applied)
|
|
77
|
+
// as ONE nil identity — made here, once, rather than per
|
|
78
|
+
// pass, so the report names it once.
|
|
79
|
+
const idfn: any = constantIdFunc(this.spread.cj)
|
|
80
|
+
if (undefined !== idfn) {
|
|
81
|
+
const nil: any = new NilVal({ why: 'id_spread' }, ctx)
|
|
82
|
+
nil.site.row = idfn.site.row
|
|
83
|
+
nil.site.col = idfn.site.col
|
|
84
|
+
nil.site.url = idfn.site.url
|
|
85
|
+
nil.primary = idfn
|
|
86
|
+
this.spread.cj = nil
|
|
87
|
+
}
|
|
88
|
+
|
|
66
89
|
// let tmv = Array.isArray(spread.v) ? spread.v : [spread.v]
|
|
67
90
|
// this.spread.cj = new ConjunctVal({ peg: tmv }, ctx)
|
|
68
91
|
}
|
|
@@ -76,6 +99,16 @@ class ListVal extends BagVal {
|
|
|
76
99
|
const TOP = top()
|
|
77
100
|
peer = peer ?? TOP
|
|
78
101
|
|
|
102
|
+
// A sizing residual (`length`, `unique`) sorts AFTER containers in a
|
|
103
|
+
// conjunct so that it counts the MERGED list rather than the first
|
|
104
|
+
// fragment (SIZING_CJO in ConstraintVal.ts). That makes the list the
|
|
105
|
+
// accumulator and the constraint its peer, the reverse of the usual
|
|
106
|
+
// order — and the reading belongs to the constraint either way, so
|
|
107
|
+
// hand it straight back.
|
|
108
|
+
if (true === (peer as any).isConstraint) {
|
|
109
|
+
return peer.unify(this, ctx)
|
|
110
|
+
}
|
|
111
|
+
|
|
79
112
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'List', this, peer)
|
|
80
113
|
let done: boolean = true
|
|
81
114
|
let exit = false
|
|
@@ -111,24 +144,81 @@ class ListVal extends BagVal {
|
|
|
111
144
|
|
|
112
145
|
let spread_cj = out.spread.cj || TOP
|
|
113
146
|
|
|
147
|
+
// The template REFUSED at construction (clearing rule 3, G4
|
|
148
|
+
// phase 1): the bag itself is that refusal. Returning the nil
|
|
149
|
+
// here rather than only letting it reach the children is what
|
|
150
|
+
// makes an EMPTY bag with a bad template an error too — there
|
|
151
|
+
// are no children to carry it.
|
|
152
|
+
//
|
|
153
|
+
// Narrow to THIS code on purpose. A nil spread from any other
|
|
154
|
+
// cause keeps its existing behaviour of driving every key
|
|
155
|
+
// (coverage3 `nil-spread-drives-every-key`): a template that has
|
|
156
|
+
// merely not resolved yet must not permanently kill the bag that
|
|
157
|
+
// holds it.
|
|
158
|
+
if ('id_spread' === (spread_cj as any).why) {
|
|
159
|
+
return spread_cj
|
|
160
|
+
}
|
|
161
|
+
|
|
114
162
|
// Always unify children first
|
|
115
163
|
for (let key in this.peg) {
|
|
116
164
|
const keyctx = ctx.descend(key)
|
|
117
|
-
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
118
165
|
const child = this.peg[key]
|
|
119
166
|
|
|
120
167
|
propagateMarks(this, child)
|
|
121
168
|
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
169
|
+
// APPLIED ONCE PER ELEMENT, the guard MapVal has carried since
|
|
170
|
+
// the spread was written: an element that already holds this
|
|
171
|
+
// template's contribution is progressed by self-unification
|
|
172
|
+
// instead of having the template met into it a second time.
|
|
173
|
+
// Re-applying is the identity for a template that has already
|
|
174
|
+
// RESOLVED, which is why the missing guard went unnoticed here
|
|
175
|
+
// — but a template that residuates (`&: id(key(1))`, G8 phase
|
|
176
|
+
// 0) is not yet a value to be idempotent about, so each pass
|
|
177
|
+
// conjoined another copy and the element's canon DOUBLED per
|
|
178
|
+
// pass. The old `ctx.cc < 3` key delay hid it by ending the
|
|
179
|
+
// growth at three passes; the staging rule waits for the model
|
|
180
|
+
// to settle, and a model whose canon doubles every pass never
|
|
181
|
+
// does.
|
|
182
|
+
let oval: Val
|
|
183
|
+
if (!spread_cj.isTop
|
|
184
|
+
&& (child as any)._spr === (spread_cj as any).id) {
|
|
185
|
+
oval = child.done ? child :
|
|
186
|
+
unite(te ? keyctx.clone({ explain: ec(te, 'PEG:' + key) }) : keyctx,
|
|
187
|
+
child, TOP, 'list-own')
|
|
188
|
+
; (oval as any)._spr = (spread_cj as any).id
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
192
|
+
// The spread mark the provenance recorder reads (G7 phase 3),
|
|
193
|
+
// as in MapVal: this is where a template becomes a per-element
|
|
194
|
+
// contribution. Instrumented runs only.
|
|
195
|
+
if (undefined !== keyctx.prov) {
|
|
196
|
+
markSpread(key_spread_cj)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// child is non-nullish: propagateMarks above dereferences it.
|
|
200
|
+
oval =
|
|
201
|
+
child.isNil ? child :
|
|
202
|
+
key_spread_cj.isNil ? key_spread_cj :
|
|
203
|
+
// The no-op meet is SKIPPED on the normal path (it is the
|
|
204
|
+
// identity) but TAKEN while recording: a value written once
|
|
205
|
+
// and never met is still a contribution the author wants
|
|
206
|
+
// pointed at, and the Go port's unite sees that meet (G7
|
|
207
|
+
// phase 4). Instrumented runs pay knowingly.
|
|
208
|
+
key_spread_cj.isTop && child.done && undefined === keyctx.prov
|
|
209
|
+
? child :
|
|
210
|
+
child.isTop && key_spread_cj.done ? key_spread_cj :
|
|
211
|
+
unite(te ? keyctx.clone({ explain: ec(te, 'PEG:' + key) }) : keyctx,
|
|
212
|
+
child, key_spread_cj, 'list-own')
|
|
213
|
+
|
|
214
|
+
if (!spread_cj.isTop && !oval.isNil) {
|
|
215
|
+
; (oval as any)._spr = (spread_cj as any).id
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
out.peg[key] = oval
|
|
130
220
|
|
|
131
|
-
done = (done && DONE ===
|
|
221
|
+
done = (done && DONE === oval.dc)
|
|
132
222
|
}
|
|
133
223
|
|
|
134
224
|
const allowedKeys: string[] = this.closed ? Object.keys(this.peg) : []
|
|
@@ -161,6 +251,9 @@ class ListVal extends BagVal {
|
|
|
161
251
|
|
|
162
252
|
if (this.spread.cj) {
|
|
163
253
|
let key_spread_cj = spread_cj.spreadClone(peerctx)
|
|
254
|
+
if (undefined !== peerctx.prov) {
|
|
255
|
+
markSpread(key_spread_cj)
|
|
256
|
+
}
|
|
164
257
|
|
|
165
258
|
oval = out.peg[peerkey] =
|
|
166
259
|
unite(te ? peerctx.clone({ explain: ec(te, 'PSP:' + peerkey) }) : peerctx,
|
|
@@ -216,7 +309,11 @@ class ListVal extends BagVal {
|
|
|
216
309
|
}
|
|
217
310
|
|
|
218
311
|
if (!allScalarKind) {
|
|
219
|
-
|
|
312
|
+
// A full instance (`dup`, ADR-005), paths normalised to the
|
|
313
|
+
// destination: see Val.spreadClone and repathInstance.
|
|
314
|
+
const out = this.clone(ctx, { dup: true })
|
|
315
|
+
repathInstance(out, out.path)
|
|
316
|
+
return out
|
|
220
317
|
}
|
|
221
318
|
|
|
222
319
|
let out = (super.clone(ctx) as ListVal)
|
|
@@ -239,12 +336,16 @@ class ListVal extends BagVal {
|
|
|
239
336
|
|
|
240
337
|
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
241
338
|
let out = (super.clone(ctx, spec) as ListVal)
|
|
339
|
+
// The instantiation flag descends with the mark (ADR-005): a
|
|
340
|
+
// template's elements are part of the instance.
|
|
341
|
+
const childspec = spec?.mark || spec?.dup ?
|
|
342
|
+
{ mark: spec?.mark, dup: spec?.dup } : {}
|
|
242
343
|
for (let entry of Object.entries(this.peg)) {
|
|
243
344
|
out.peg[entry[0]] =
|
|
244
|
-
(entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx,
|
|
345
|
+
(entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx, childspec) : entry[1]
|
|
245
346
|
}
|
|
246
347
|
if (this.spread.cj) {
|
|
247
|
-
out.spread.cj = this.spread.cj.clone(ctx,
|
|
348
|
+
out.spread.cj = this.spread.cj.clone(ctx, childspec)
|
|
248
349
|
}
|
|
249
350
|
|
|
250
351
|
out.closed = this.closed
|
|
@@ -263,10 +364,16 @@ class ListVal extends BagVal {
|
|
|
263
364
|
'[' +
|
|
264
365
|
(this.spread.cj ? '&:' + this.spread.cj.canon +
|
|
265
366
|
(0 < keys.length ? ',' : '') : '') +
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
367
|
+
// No optional-element rendering. A list HAS no optional elements to
|
|
368
|
+
// render: a key:value pair in list position contributes no element
|
|
369
|
+
// at all, in either spelling and whatever its key (issue #40), so
|
|
370
|
+
// nothing a source can write reaches this method with an optional
|
|
371
|
+
// key. The Go port's ListVal.Canon has no such arm either, and the
|
|
372
|
+
// two canons must agree -- a canon is round-trippable, and a marker
|
|
373
|
+
// on an element the grammar cannot produce would not reparse.
|
|
374
|
+
// canonRiders, not .canon: a deprecated element renders
|
|
375
|
+
// back as its `deprecate(x, m)` call, reparseably (G3).
|
|
376
|
+
keys.map(k => canonRiders(this.peg[k])).join(',') +
|
|
270
377
|
']'
|
|
271
378
|
}
|
|
272
379
|
} /* node:coverage ignore next 8 */
|
package/src/val/LowerFuncVal.ts
CHANGED
package/src/val/MapVal.ts
CHANGED
|
@@ -16,6 +16,8 @@ import { unite } from '../unify'
|
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
18
|
propagateMarks,
|
|
19
|
+
canonRiders,
|
|
20
|
+
constantIdFunc,
|
|
19
21
|
walk,
|
|
20
22
|
explainOpen,
|
|
21
23
|
ec,
|
|
@@ -32,7 +34,9 @@ import {
|
|
|
32
34
|
import { ConjunctVal } from './ConjunctVal'
|
|
33
35
|
import { NilVal } from './NilVal'
|
|
34
36
|
import { BagVal } from './BagVal'
|
|
37
|
+
import { repathInstance } from './Val'
|
|
35
38
|
import { cmpCodePoint } from '../keyorder'
|
|
39
|
+
import { markSpread } from '../provenance'
|
|
36
40
|
|
|
37
41
|
|
|
38
42
|
// Structural snapshots of ref spreads (see MapVal.unify), keyed by the
|
|
@@ -60,7 +64,9 @@ function snapshotRefSpread(cj: any, ctx: AontuContext): Val | undefined {
|
|
|
60
64
|
const sk = spreadSnapKey(cj)
|
|
61
65
|
let snap: Val | undefined = snapmap.get(sk)
|
|
62
66
|
if (undefined === snap) {
|
|
63
|
-
|
|
67
|
+
// snap mode: the pending-mark-wrapper defer in find must not
|
|
68
|
+
// apply here — the snapshot WANTS the pre-resolution structure.
|
|
69
|
+
let tgt: Val | undefined = cj.find(ctx, true)
|
|
64
70
|
// A ref to a type() resolves to its inner template — snapshot that,
|
|
65
71
|
// so a type-wrapped ref behaves like a plain-map ref spread.
|
|
66
72
|
if (tgt && (tgt as any).isTypeFunc) tgt = (tgt as any).peg?.[0]
|
|
@@ -104,13 +110,34 @@ class MapVal extends BagVal {
|
|
|
104
110
|
|
|
105
111
|
if (spread) {
|
|
106
112
|
if ('&' === spread.o) {
|
|
107
|
-
//
|
|
113
|
+
// Multiple same-level spreads arrive as an array and conjoin;
|
|
114
|
+
// an unequal spread arriving from ANOTHER statement meets this
|
|
115
|
+
// one in unify's spread combination below — sound since the
|
|
116
|
+
// combined template became stateless (pure ExpectVal, BUGS.md
|
|
117
|
+
// §6-§7): each child meets the combined constraint
|
|
118
|
+
// independently and children never meet each other's data.
|
|
108
119
|
this.spread.cj =
|
|
109
120
|
Array.isArray(spread.v) ?
|
|
110
121
|
1 < spread.v.length ?
|
|
111
122
|
new ConjunctVal({ peg: spread.v }, ctx) :
|
|
112
123
|
spread.v[0] :
|
|
113
124
|
spread.v
|
|
125
|
+
|
|
126
|
+
// Clearing rule 3 (G4 phase 1): a CONSTANT id in the template
|
|
127
|
+
// would declare every child to be one entity. The refusal
|
|
128
|
+
// replaces the template, so it reaches every child and the
|
|
129
|
+
// bag itself (see the isNil arm where the spread is applied)
|
|
130
|
+
// as ONE nil identity — made here, once, rather than per
|
|
131
|
+
// pass, so the report names it once.
|
|
132
|
+
const idfn: any = constantIdFunc(this.spread.cj)
|
|
133
|
+
if (undefined !== idfn) {
|
|
134
|
+
const nil: any = new NilVal({ why: 'id_spread' }, ctx)
|
|
135
|
+
nil.site.row = idfn.site.row
|
|
136
|
+
nil.site.col = idfn.site.col
|
|
137
|
+
nil.site.url = idfn.site.url
|
|
138
|
+
nil.primary = idfn
|
|
139
|
+
this.spread.cj = nil
|
|
140
|
+
}
|
|
114
141
|
}
|
|
115
142
|
}
|
|
116
143
|
|
|
@@ -125,6 +152,17 @@ class MapVal extends BagVal {
|
|
|
125
152
|
|
|
126
153
|
const TOP = top()
|
|
127
154
|
peer = peer ?? TOP
|
|
155
|
+
|
|
156
|
+
// A sizing residual (`length`, `unique`) sorts AFTER containers in a
|
|
157
|
+
// conjunct so that it counts the MERGED map rather than the first
|
|
158
|
+
// fragment (SIZING_CJO in ConstraintVal.ts). That makes the map the
|
|
159
|
+
// accumulator and the constraint its peer, the reverse of the usual
|
|
160
|
+
// order — and the reading belongs to the constraint either way, so
|
|
161
|
+
// hand it straight back.
|
|
162
|
+
if (true === (peer as any).isConstraint) {
|
|
163
|
+
return peer.unify(this, ctx)
|
|
164
|
+
}
|
|
165
|
+
|
|
128
166
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Map', this, peer)
|
|
129
167
|
|
|
130
168
|
let done: boolean = true
|
|
@@ -173,6 +211,13 @@ class MapVal extends BagVal {
|
|
|
173
211
|
// combined here). unite resolves key()/path() at each destination via
|
|
174
212
|
// spreadClone below, so nested + sibling key() cases stay correct
|
|
175
213
|
// (test/spec/spread-nested-key, spread-key-all).
|
|
214
|
+
//
|
|
215
|
+
// The combined template must stay STATELESS: this meet wraps a
|
|
216
|
+
// key present in only one side as an ExpectVal, the combined
|
|
217
|
+
// map is shared across destinations when path-independent
|
|
218
|
+
// (spreadClone tier 1), and a stateful expect accumulated the
|
|
219
|
+
// first sibling's data and met it into the next (BUGS.md
|
|
220
|
+
// §6-§7). ExpectVal.unify is pure for exactly this reason.
|
|
176
221
|
out.spread.cj = null == out.spread.cj ? peer.spread.cj : (
|
|
177
222
|
null == peer.spread.cj ? out.spread.cj :
|
|
178
223
|
out.spread.cj.canon === peer.spread.cj.canon ? out.spread.cj :
|
|
@@ -193,6 +238,21 @@ class MapVal extends BagVal {
|
|
|
193
238
|
|
|
194
239
|
let spread_cj = out.spread.cj ?? TOP
|
|
195
240
|
|
|
241
|
+
// The template REFUSED at construction (clearing rule 3, G4
|
|
242
|
+
// phase 1): the bag itself is that refusal. Returning the nil
|
|
243
|
+
// here rather than only letting it reach the children is what
|
|
244
|
+
// makes an EMPTY bag with a bad template an error too — there
|
|
245
|
+
// are no children to carry it.
|
|
246
|
+
//
|
|
247
|
+
// Narrow to THIS code on purpose. A nil spread from any other
|
|
248
|
+
// cause keeps its existing behaviour of driving every key
|
|
249
|
+
// (coverage3 `nil-spread-drives-every-key`): a template that has
|
|
250
|
+
// merely not resolved yet must not permanently kill the bag that
|
|
251
|
+
// holds it.
|
|
252
|
+
if ('id_spread' === (spread_cj as any).why) {
|
|
253
|
+
return spread_cj
|
|
254
|
+
}
|
|
255
|
+
|
|
196
256
|
// Snapshot a path-dependent *ref* spread to its structural target
|
|
197
257
|
// once (while inner key()/path() funcs are still unresolved), so
|
|
198
258
|
// later fixpoint passes don't re-resolve the ref against the mutated
|
|
@@ -241,11 +301,25 @@ class MapVal extends BagVal {
|
|
|
241
301
|
else {
|
|
242
302
|
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
243
303
|
|
|
304
|
+
// The one place a spread is APPLIED, so the one place that
|
|
305
|
+
// knows a contribution came from a template rather than
|
|
306
|
+
// from the key itself (G7 phase 3). Only when someone is
|
|
307
|
+
// recording: the walk is O(template) per key per pass.
|
|
308
|
+
if (undefined !== keyctx.prov) {
|
|
309
|
+
markSpread(key_spread_cj)
|
|
310
|
+
}
|
|
311
|
+
|
|
244
312
|
// child is non-nullish: propagateMarks above dereferences it.
|
|
245
313
|
oval =
|
|
246
314
|
child.isNil ? child :
|
|
247
315
|
key_spread_cj.isNil ? key_spread_cj :
|
|
248
|
-
|
|
316
|
+
// The no-op meet is SKIPPED on the normal path (it is the
|
|
317
|
+
// identity) but TAKEN while recording: a value written once
|
|
318
|
+
// and never met is still a contribution the author wants
|
|
319
|
+
// pointed at, and the Go port's unite sees that meet (G7
|
|
320
|
+
// phase 4). Instrumented runs pay knowingly.
|
|
321
|
+
key_spread_cj.isTop && child.done && undefined === keyctx.prov
|
|
322
|
+
? child :
|
|
249
323
|
child.isTop && key_spread_cj.done ? key_spread_cj :
|
|
250
324
|
unite(te ? keyctx.clone({ explain: ec(te, 'KEY:' + key) }) : keyctx,
|
|
251
325
|
child, key_spread_cj, 'map-own')
|
|
@@ -257,6 +331,7 @@ class MapVal extends BagVal {
|
|
|
257
331
|
|
|
258
332
|
out.peg[key] = oval
|
|
259
333
|
|
|
334
|
+
|
|
260
335
|
done = (done && DONE === oval.dc)
|
|
261
336
|
}
|
|
262
337
|
|
|
@@ -285,7 +360,19 @@ class MapVal extends BagVal {
|
|
|
285
360
|
const peerctx = ctx.descend(peerkey)
|
|
286
361
|
|
|
287
362
|
let oval = out.peg[peerkey] =
|
|
288
|
-
|
|
363
|
+
// A peer-only key is CARRIED, not met — except on an
|
|
364
|
+
// instrumented run, where the identity meet is taken so
|
|
365
|
+
// the recorder sees where the value came from. The Go port
|
|
366
|
+
// unites a genable peer-only child with TOP unconditionally
|
|
367
|
+
// (go/mapval.go), and the difference was invisible until
|
|
368
|
+
// G4's identity merge brought a peer whose children the
|
|
369
|
+
// recorder counts as WRITTEN: `why $.b.k` on two positions
|
|
370
|
+
// of one entity named the site in Go and answered "nothing
|
|
371
|
+
// met here" in TypeScript.
|
|
372
|
+
undefined === child
|
|
373
|
+
? (undefined !== peerctx.prov && peerchild.isGenable
|
|
374
|
+
? unite(peerctx, peerchild, TOP, 'map-peer-only')
|
|
375
|
+
: this.handleExpectedVal(peerkey, peerchild, this, ctx)) :
|
|
289
376
|
child.isTop && peerchild.done ? peerchild :
|
|
290
377
|
child.isNil ? child :
|
|
291
378
|
peerchild.isNil ? peerchild :
|
|
@@ -371,7 +458,11 @@ class MapVal extends BagVal {
|
|
|
371
458
|
}
|
|
372
459
|
|
|
373
460
|
if (!allScalarKind) {
|
|
374
|
-
|
|
461
|
+
// A full instance (`dup`, ADR-005), paths normalised to the
|
|
462
|
+
// destination: see Val.spreadClone and repathInstance.
|
|
463
|
+
const out = this.clone(ctx, { dup: true })
|
|
464
|
+
repathInstance(out, out.path)
|
|
465
|
+
return out
|
|
375
466
|
}
|
|
376
467
|
|
|
377
468
|
let out = (super.clone(ctx) as MapVal)
|
|
@@ -403,12 +494,17 @@ class MapVal extends BagVal {
|
|
|
403
494
|
// (entry[1] as Val).clone(ctx, spec?.mark ? { mark: spec.mark } : {}) :
|
|
404
495
|
(entry[1] as Val).clone(ctx, {
|
|
405
496
|
mark: spec?.mark ?? {},
|
|
406
|
-
path: [...out.path, entry[0]]
|
|
497
|
+
path: [...out.path, entry[0]],
|
|
498
|
+
// The instantiation flag descends (ADR-005): a template's
|
|
499
|
+
// children are part of the instance.
|
|
500
|
+
dup: spec?.dup,
|
|
407
501
|
}) :
|
|
408
502
|
entry[1]
|
|
409
503
|
}
|
|
410
504
|
if (this.spread.cj) {
|
|
411
|
-
out.spread.cj = this.spread.cj.clone(ctx,
|
|
505
|
+
out.spread.cj = this.spread.cj.clone(ctx,
|
|
506
|
+
spec?.mark || spec?.dup ?
|
|
507
|
+
{ mark: spec?.mark, dup: spec?.dup } : {})
|
|
412
508
|
}
|
|
413
509
|
|
|
414
510
|
out.closed = this.closed
|
|
@@ -439,7 +535,13 @@ class MapVal extends BagVal {
|
|
|
439
535
|
JSON.stringify(k) +
|
|
440
536
|
(this.optionalKeys.includes(k) ? '?' : '') +
|
|
441
537
|
':' +
|
|
442
|
-
|
|
538
|
+
// canonRiders, not .canon: a deprecated field renders
|
|
539
|
+
// back as its `deprecate(x, m)` call, reparseably (G3). The
|
|
540
|
+
// guard is the isVal FLAG, never the canon getter: computing
|
|
541
|
+
// canon in the guard and again in the render doubles the
|
|
542
|
+
// recursion per level, which is 2^depth on a nested document.
|
|
543
|
+
(true === this.peg[k]?.isVal
|
|
544
|
+
? canonRiders(this.peg[k]) : this.peg[k])
|
|
443
545
|
])
|
|
444
546
|
.join(',') +
|
|
445
547
|
'}' // + '<' + (this.mark.hide ? 'H' : '') + '>'
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// GENERATION: `match(v, p1, r1, p2, r2, …, d?)` (G8 phase 2,
|
|
4
|
+
// docs/capability-review/g8-generation.md). A BOUNDED conditional:
|
|
5
|
+
// alternating pattern/result arguments and an optional trailing
|
|
6
|
+
// default. The first pattern IN ARGUMENT ORDER that `v` unifies with
|
|
7
|
+
// SELECTS its result, and the result is the answer.
|
|
8
|
+
//
|
|
9
|
+
// The design said the answer was `v & p & r` -- the scrutinee narrowed
|
|
10
|
+
// by the arm rather than replaced by it. That cannot be what a match
|
|
11
|
+
// is for: it makes every arm whose result is not already a `v` a
|
|
12
|
+
// contradiction, and the design's own example
|
|
13
|
+
// (`match($.tier, small, {cpu:1}, …)`, a string scrutinee and map
|
|
14
|
+
// results) cannot be evaluated at all under it. A match MAPS a value
|
|
15
|
+
// to another value; a document that wants the scrutinee kept can say
|
|
16
|
+
// so, because the scrutinee is a value it can name.
|
|
17
|
+
//
|
|
18
|
+
// size: match($.tier, small, {cpu:1}, large, {cpu:8}, {cpu:2})
|
|
19
|
+
//
|
|
20
|
+
// WHAT KEEPS IT FROM BECOMING A CONDITIONAL LANGUAGE. The scrutinee is
|
|
21
|
+
// matched by UNIFIABILITY only: no boolean guards, no comparisons
|
|
22
|
+
// beyond what the constraint atoms already are, no fallthrough (first
|
|
23
|
+
// match wins, in a spec-pinned order), and no way to write a pattern
|
|
24
|
+
// that is not an ordinary Aontu value. The whole form is total.
|
|
25
|
+
//
|
|
26
|
+
// NO MATCH AND NO DEFAULT IS AN ERROR, not an empty answer, and the
|
|
27
|
+
// report names the patterns that were tried -- the admissible-
|
|
28
|
+
// alternatives shape (G2's error contract). A default is how a
|
|
29
|
+
// document says it meant to allow the rest.
|
|
30
|
+
//
|
|
31
|
+
// A RESULT IS NOT EVALUATED UNTIL IT IS SELECTED. Only the scrutinee
|
|
32
|
+
// and the patterns are driven; an unselected result never runs, so a
|
|
33
|
+
// broken arm nobody takes is not an error the document has to carry
|
|
34
|
+
// (which multi-error collection, G2 phase 6, would otherwise report).
|
|
35
|
+
|
|
36
|
+
import type {
|
|
37
|
+
Val,
|
|
38
|
+
ValSpec,
|
|
39
|
+
} from '../type'
|
|
40
|
+
|
|
41
|
+
import {
|
|
42
|
+
AontuContext,
|
|
43
|
+
} from '../ctx'
|
|
44
|
+
|
|
45
|
+
import { makeNilErr } from '../err'
|
|
46
|
+
import { top } from './top'
|
|
47
|
+
import { prefInnerPeg } from './PrefVal'
|
|
48
|
+
import { FuncBaseVal, trialUnify } from './FuncBaseVal'
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
// THE DEFAULTED-SCRUTINEE RULE (ADR-004, use-cases/BUGS.md §5). The
|
|
52
|
+
// generation-effective view of a settled scrutinee: a preference — or
|
|
53
|
+
// a disjunction carrying one — means "this value unless something
|
|
54
|
+
// overrides it", and by resolve time the model has SETTLED (staging
|
|
55
|
+
// rule), so nothing will. The value generation is about to emit is
|
|
56
|
+
// therefore the value the patterns must be tested against. Testing
|
|
57
|
+
// against the still-open preference instead let a pattern SELECT an
|
|
58
|
+
// arm by overriding the default: `side_effect:*readonly|write|
|
|
59
|
+
// destructive` beside `match(.side_effect, destructive, true, false)`
|
|
60
|
+
// answered `true` while generating "readonly" next to it — a derived
|
|
61
|
+
// value contradicting the very value it derives from, exit 0.
|
|
62
|
+
// A pref-free scrutinee (open disjunction included) is untouched:
|
|
63
|
+
// matching by unifiability is its documented meaning.
|
|
64
|
+
// Exported for the multi-pref unit test (ADR-002, the subsumeNode
|
|
65
|
+
// precedent): rankPrefs leaves a settled disjunct at most one pref, so
|
|
66
|
+
// the min-rank scan below cannot be reached through a document.
|
|
67
|
+
export function effectiveScrutinee(v: Val): Val {
|
|
68
|
+
let out: any = v
|
|
69
|
+
if (true === out?.isDisjunct && Array.isArray(out.peg)) {
|
|
70
|
+
const prefs = out.peg.filter((m: any) => true === m?.isPref)
|
|
71
|
+
if (0 === prefs.length) {
|
|
72
|
+
return v
|
|
73
|
+
}
|
|
74
|
+
// Generation picks the LOWEST rank (effectiveDefault in
|
|
75
|
+
// subsume.ts; `a:**1|*2` generates 2). rankPrefs leaves at most
|
|
76
|
+
// one pref standing in a settled disjunct, so the scan is
|
|
77
|
+
// defensive.
|
|
78
|
+
out = prefs.reduce((a: any, b: any) => b.rank < a.rank ? b : a)
|
|
79
|
+
}
|
|
80
|
+
return prefInnerPeg(out)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class MatchFuncVal extends FuncBaseVal {
|
|
85
|
+
isMatchFunc = true
|
|
86
|
+
|
|
87
|
+
// THE STAGING RULE (G8 phase 0). A scrutinee that is still being
|
|
88
|
+
// narrowed can match an EARLIER pattern than the one it will end up
|
|
89
|
+
// matching, and the arm a match takes is not a thing to guess at.
|
|
90
|
+
staged = true
|
|
91
|
+
|
|
92
|
+
constructor(
|
|
93
|
+
spec: ValSpec,
|
|
94
|
+
ctx?: AontuContext
|
|
95
|
+
) {
|
|
96
|
+
super(spec, ctx)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
funcname() {
|
|
101
|
+
return 'match'
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
prepare(_ctx: AontuContext, _args: Val[]) {
|
|
106
|
+
return null
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
// The scrutinee is argument 0 and the patterns are the odd
|
|
111
|
+
// arguments; the results are the even ones after 0, and the last
|
|
112
|
+
// argument is a DEFAULT when the count is even. Written once, read
|
|
113
|
+
// by both the driver below and resolve.
|
|
114
|
+
hasDefault() {
|
|
115
|
+
return 0 === this.peg.length % 2
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
unify(peer: Val, ctx: AontuContext): Val {
|
|
120
|
+
// The scrutinee and the PATTERNS are driven; the results are not
|
|
121
|
+
// (see the header). driveStagedArgs takes a prefix, so the odd
|
|
122
|
+
// positions are driven one at a time.
|
|
123
|
+
let ready = this.driveStagedArgs(ctx, 1)
|
|
124
|
+
const last = this.peg.length - (this.hasDefault() ? 1 : 0)
|
|
125
|
+
for (let i = 1; i < last; i += 2) {
|
|
126
|
+
const arg: Val = this.peg[i]
|
|
127
|
+
if (!arg.done) {
|
|
128
|
+
this.peg[i] = arg.unify(top(), ctx)
|
|
129
|
+
}
|
|
130
|
+
ready = ready && true === this.peg[i].done
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!ready || !ctx.settle) {
|
|
134
|
+
return this.residuate(peer, ctx)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return super.unify(peer, ctx)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
resolve(ctx: AontuContext, args: Val[]) {
|
|
142
|
+
const scrutinee: Val = effectiveScrutinee(args[0])
|
|
143
|
+
const dflt: Val | undefined = this.hasDefault() ?
|
|
144
|
+
args[args.length - 1] : undefined
|
|
145
|
+
const last = args.length - (undefined === dflt ? 0 : 1)
|
|
146
|
+
|
|
147
|
+
const tried: string[] = []
|
|
148
|
+
|
|
149
|
+
for (let i = 1; i < last; i += 2) {
|
|
150
|
+
const pattern: Val = args[i]
|
|
151
|
+
tried.push(pattern.canon)
|
|
152
|
+
|
|
153
|
+
// The trial is against CLONES: `unite` refines a bag in place
|
|
154
|
+
// against a TOP peer, and a pattern that failed must be
|
|
155
|
+
// untouched for the next document that reads its canon.
|
|
156
|
+
if (undefined !== trialUnify(ctx, scrutinee.clone(ctx), pattern.clone(ctx))) {
|
|
157
|
+
return args[i + 1].clone(ctx)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (undefined !== dflt) {
|
|
162
|
+
return dflt.clone(ctx)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return makeNilErr(ctx, 'match_none', this, undefined, 'resolve', {
|
|
166
|
+
value: scrutinee.canon,
|
|
167
|
+
tried: tried.join(' '),
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
} /* node:coverage ignore next 5 */
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
export {
|
|
175
|
+
MatchFuncVal,
|
|
176
|
+
}
|
package/src/val/MoveFuncVal.ts
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
|
|
13
13
|
import { makeNilErr } from '../err'
|
|
14
14
|
|
|
15
|
-
import { NilVal } from '../val/NilVal'
|
|
16
15
|
|
|
17
16
|
import {
|
|
18
17
|
walk
|
|
@@ -21,7 +20,6 @@ import {
|
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
import { FuncBaseVal } from './FuncBaseVal'
|
|
24
|
-
import { CopyFuncVal } from './CopyFuncVal'
|
|
25
23
|
import { PrefFuncVal } from './PrefFuncVal'
|
|
26
24
|
|
|
27
25
|
|
package/src/val/NilVal.ts
CHANGED
|
@@ -79,6 +79,31 @@ class NilVal extends Val {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// THE PATH IS WHERE THE MEET IS, NOT WHERE THE OPERAND WAS WRITTEN
|
|
83
|
+
// (use-cases/BUGS.md §41). The operand path above decides the SITE
|
|
84
|
+
// correctly and the path only by accident: a value that arrives by
|
|
85
|
+
// REFERENCE is re-pathed to the referring field, and its children
|
|
86
|
+
// are re-pathed to that same field rather than rebased under it, so
|
|
87
|
+
// every conflict inside `q: $.M` reported `$.q` — the enclosing
|
|
88
|
+
// record, not the key to edit, and the SAME path for every one of
|
|
89
|
+
// its fields. The context has descended to the child by the time
|
|
90
|
+
// the meet fails, and Go reads the path off the tree position for
|
|
91
|
+
// exactly this reason.
|
|
92
|
+
//
|
|
93
|
+
// Only EXTENDS, never redirects: the context path is taken when the
|
|
94
|
+
// operand's path is a PREFIX of it, so a nil minted away from the
|
|
95
|
+
// descent (a func resolving an argument, a generator's own probe,
|
|
96
|
+
// an anchored `--at` run whose operand is already correctly placed)
|
|
97
|
+
// keeps the path its operand carries. Taking the context path
|
|
98
|
+
// unconditionally was tried and reverted -- it moved the closed-key,
|
|
99
|
+
// spread-template and every `--at` finding to the driving location,
|
|
100
|
+
// which is not where those belong.
|
|
101
|
+
if (null != ctx?.path && null != nil.path &&
|
|
102
|
+
nil.path.length < ctx.path.length &&
|
|
103
|
+
nil.path.every((p, i) => p === ctx.path[i])) {
|
|
104
|
+
nil.path = [...ctx.path]
|
|
105
|
+
}
|
|
106
|
+
|
|
82
107
|
if (ctx) {
|
|
83
108
|
ctx.adderr(nil)
|
|
84
109
|
}
|