aontu 0.52.1 → 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 +96 -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 +13 -0
- package/dist/ctx.js +43 -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 +38 -7
- 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 +167 -4
- 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 +512 -69
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +9 -2
- package/dist/lsp.js +262 -47
- 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 +2 -1
- package/dist/unify.js +253 -36
- 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 +7 -1
- package/dist/val/ConstraintVal.js +490 -40
- 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.js +27 -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 +171 -1
- 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 +101 -14
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +93 -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 +19 -1
- 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 +89 -7
- 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 +8 -1
- package/dist/val/Val.js +150 -1
- 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 +21 -6
- 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 +135 -4
- package/src/cli.ts +2858 -71
- package/src/ctx.ts +73 -1
- package/src/diff.ts +196 -0
- package/src/err.ts +42 -7
- package/src/graph.ts +135 -0
- package/src/hcanon.ts +169 -0
- package/src/hints.ts +208 -4
- package/src/jsonschema.ts +511 -0
- package/src/lang.ts +570 -70
- package/src/lsp.ts +281 -48
- 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 +274 -36
- 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 +542 -43
- 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 +28 -6
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FilterFuncVal.ts +154 -0
- package/src/val/FuncBaseVal.ts +192 -1
- 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 +108 -15
- package/src/val/LowerFuncVal.ts +0 -1
- package/src/val/MapVal.ts +99 -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 +20 -1
- 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 +91 -8
- 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 +205 -2
- 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
|
}
|
|
@@ -121,24 +144,81 @@ class ListVal extends BagVal {
|
|
|
121
144
|
|
|
122
145
|
let spread_cj = out.spread.cj || TOP
|
|
123
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
|
+
|
|
124
162
|
// Always unify children first
|
|
125
163
|
for (let key in this.peg) {
|
|
126
164
|
const keyctx = ctx.descend(key)
|
|
127
|
-
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
128
165
|
const child = this.peg[key]
|
|
129
166
|
|
|
130
167
|
propagateMarks(this, child)
|
|
131
168
|
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
|
140
220
|
|
|
141
|
-
done = (done && DONE ===
|
|
221
|
+
done = (done && DONE === oval.dc)
|
|
142
222
|
}
|
|
143
223
|
|
|
144
224
|
const allowedKeys: string[] = this.closed ? Object.keys(this.peg) : []
|
|
@@ -171,6 +251,9 @@ class ListVal extends BagVal {
|
|
|
171
251
|
|
|
172
252
|
if (this.spread.cj) {
|
|
173
253
|
let key_spread_cj = spread_cj.spreadClone(peerctx)
|
|
254
|
+
if (undefined !== peerctx.prov) {
|
|
255
|
+
markSpread(key_spread_cj)
|
|
256
|
+
}
|
|
174
257
|
|
|
175
258
|
oval = out.peg[peerkey] =
|
|
176
259
|
unite(te ? peerctx.clone({ explain: ec(te, 'PSP:' + peerkey) }) : peerctx,
|
|
@@ -226,7 +309,11 @@ class ListVal extends BagVal {
|
|
|
226
309
|
}
|
|
227
310
|
|
|
228
311
|
if (!allScalarKind) {
|
|
229
|
-
|
|
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
|
|
230
317
|
}
|
|
231
318
|
|
|
232
319
|
let out = (super.clone(ctx) as ListVal)
|
|
@@ -249,12 +336,16 @@ class ListVal extends BagVal {
|
|
|
249
336
|
|
|
250
337
|
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
251
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 } : {}
|
|
252
343
|
for (let entry of Object.entries(this.peg)) {
|
|
253
344
|
out.peg[entry[0]] =
|
|
254
|
-
(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]
|
|
255
346
|
}
|
|
256
347
|
if (this.spread.cj) {
|
|
257
|
-
out.spread.cj = this.spread.cj.clone(ctx,
|
|
348
|
+
out.spread.cj = this.spread.cj.clone(ctx, childspec)
|
|
258
349
|
}
|
|
259
350
|
|
|
260
351
|
out.closed = this.closed
|
|
@@ -280,7 +371,9 @@ class ListVal extends BagVal {
|
|
|
280
371
|
// key. The Go port's ListVal.Canon has no such arm either, and the
|
|
281
372
|
// two canons must agree -- a canon is round-trippable, and a marker
|
|
282
373
|
// on an element the grammar cannot produce would not reparse.
|
|
283
|
-
|
|
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(',') +
|
|
284
377
|
']'
|
|
285
378
|
}
|
|
286
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
|
|
|
@@ -184,6 +211,13 @@ class MapVal extends BagVal {
|
|
|
184
211
|
// combined here). unite resolves key()/path() at each destination via
|
|
185
212
|
// spreadClone below, so nested + sibling key() cases stay correct
|
|
186
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.
|
|
187
221
|
out.spread.cj = null == out.spread.cj ? peer.spread.cj : (
|
|
188
222
|
null == peer.spread.cj ? out.spread.cj :
|
|
189
223
|
out.spread.cj.canon === peer.spread.cj.canon ? out.spread.cj :
|
|
@@ -204,6 +238,21 @@ class MapVal extends BagVal {
|
|
|
204
238
|
|
|
205
239
|
let spread_cj = out.spread.cj ?? TOP
|
|
206
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
|
+
|
|
207
256
|
// Snapshot a path-dependent *ref* spread to its structural target
|
|
208
257
|
// once (while inner key()/path() funcs are still unresolved), so
|
|
209
258
|
// later fixpoint passes don't re-resolve the ref against the mutated
|
|
@@ -252,11 +301,25 @@ class MapVal extends BagVal {
|
|
|
252
301
|
else {
|
|
253
302
|
const key_spread_cj = spread_cj.spreadClone(keyctx)
|
|
254
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
|
+
|
|
255
312
|
// child is non-nullish: propagateMarks above dereferences it.
|
|
256
313
|
oval =
|
|
257
314
|
child.isNil ? child :
|
|
258
315
|
key_spread_cj.isNil ? key_spread_cj :
|
|
259
|
-
|
|
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 :
|
|
260
323
|
child.isTop && key_spread_cj.done ? key_spread_cj :
|
|
261
324
|
unite(te ? keyctx.clone({ explain: ec(te, 'KEY:' + key) }) : keyctx,
|
|
262
325
|
child, key_spread_cj, 'map-own')
|
|
@@ -268,6 +331,7 @@ class MapVal extends BagVal {
|
|
|
268
331
|
|
|
269
332
|
out.peg[key] = oval
|
|
270
333
|
|
|
334
|
+
|
|
271
335
|
done = (done && DONE === oval.dc)
|
|
272
336
|
}
|
|
273
337
|
|
|
@@ -296,7 +360,19 @@ class MapVal extends BagVal {
|
|
|
296
360
|
const peerctx = ctx.descend(peerkey)
|
|
297
361
|
|
|
298
362
|
let oval = out.peg[peerkey] =
|
|
299
|
-
|
|
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)) :
|
|
300
376
|
child.isTop && peerchild.done ? peerchild :
|
|
301
377
|
child.isNil ? child :
|
|
302
378
|
peerchild.isNil ? peerchild :
|
|
@@ -382,7 +458,11 @@ class MapVal extends BagVal {
|
|
|
382
458
|
}
|
|
383
459
|
|
|
384
460
|
if (!allScalarKind) {
|
|
385
|
-
|
|
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
|
|
386
466
|
}
|
|
387
467
|
|
|
388
468
|
let out = (super.clone(ctx) as MapVal)
|
|
@@ -414,12 +494,17 @@ class MapVal extends BagVal {
|
|
|
414
494
|
// (entry[1] as Val).clone(ctx, spec?.mark ? { mark: spec.mark } : {}) :
|
|
415
495
|
(entry[1] as Val).clone(ctx, {
|
|
416
496
|
mark: spec?.mark ?? {},
|
|
417
|
-
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,
|
|
418
501
|
}) :
|
|
419
502
|
entry[1]
|
|
420
503
|
}
|
|
421
504
|
if (this.spread.cj) {
|
|
422
|
-
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 } : {})
|
|
423
508
|
}
|
|
424
509
|
|
|
425
510
|
out.closed = this.closed
|
|
@@ -450,7 +535,13 @@ class MapVal extends BagVal {
|
|
|
450
535
|
JSON.stringify(k) +
|
|
451
536
|
(this.optionalKeys.includes(k) ? '?' : '') +
|
|
452
537
|
':' +
|
|
453
|
-
|
|
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])
|
|
454
545
|
])
|
|
455
546
|
.join(',') +
|
|
456
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
|
}
|
package/src/val/OpBaseVal.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
|
|
32
32
|
import { ConjunctVal } from './ConjunctVal'
|
|
33
33
|
import { FeatureVal } from './FeatureVal'
|
|
34
|
+
import { hasPlace, fillPlace } from './PlaceVal'
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
|
|
@@ -66,6 +67,17 @@ class OpBaseVal extends FeatureVal {
|
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
70
|
+
|
|
71
|
+
// THE PLACEHOLDER (G8 phase 3, see PlaceVal), on the operator side:
|
|
72
|
+
// `x: {&: {m: _ + 2}}` meeting `1` is `3`. Same rule as
|
|
73
|
+
// FuncBaseVal's -- the peer fills the hole and the operation is
|
|
74
|
+
// what answers.
|
|
75
|
+
if (!peer.isTop && !peer.isNil && this.id !== peer.id && hasPlace(this)) {
|
|
76
|
+
if (hasPlace(peer)) {
|
|
77
|
+
return makeNilErr(ctx, 'place_pair', this, peer)
|
|
78
|
+
}
|
|
79
|
+
return fillPlace(this, peer, ctx).unify(top(), ctx)
|
|
80
|
+
}
|
|
69
81
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Op:' + this.opname(), this, peer)
|
|
70
82
|
// Declared without an initial value: every arm below assigns it, and
|
|
71
83
|
// seeding it with `this` made the two arms that stand the op read as
|
|
@@ -165,10 +177,17 @@ class OpBaseVal extends FeatureVal {
|
|
|
165
177
|
}
|
|
166
178
|
|
|
167
179
|
|
|
168
|
-
clone(ctx: AontuContext,
|
|
180
|
+
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
169
181
|
let out = (super.clone(ctx, {
|
|
170
182
|
peg: this.peg,
|
|
171
183
|
}) as OpBaseVal)
|
|
184
|
+
// THE PER-DESTINATION INSTANTIATION RULE (ADR-005): an operation
|
|
185
|
+
// inside a template clones its operands as instances — the
|
|
186
|
+
// default clone shares them (see FuncBaseVal.clone). Every
|
|
187
|
+
// operand is a Val by construction, as in the Go twin's []Val.
|
|
188
|
+
if (true === spec?.dup) {
|
|
189
|
+
out.peg = this.peg.map((a: Val) => a.clone(ctx, { dup: true }))
|
|
190
|
+
}
|
|
172
191
|
return out
|
|
173
192
|
}
|
|
174
193
|
|