aontu 0.53.0 → 0.55.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 +3 -2
- package/dist/aontu.js +36 -7
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +500 -8
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +5 -0
- package/dist/ctx.js +1 -0
- package/dist/ctx.js.map +1 -1
- package/dist/diff.js.map +1 -1
- package/dist/err.js +7 -1
- package/dist/err.js.map +1 -1
- package/dist/graph.d.ts +2 -5
- package/dist/graph.js +83 -46
- package/dist/graph.js.map +1 -1
- package/dist/hcanon.js +9 -10
- package/dist/hcanon.js.map +1 -1
- package/dist/hints.js +94 -26
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.js +34 -0
- package/dist/jsonschema.js.map +1 -1
- package/dist/lang.js +593 -191
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/lsp.js +86 -6
- package/dist/lsp.js.map +1 -1
- package/dist/mcp.js +153 -6
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +42 -8
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.d.ts +4 -0
- package/dist/mod.js +97 -2
- package/dist/mod.js.map +1 -1
- package/dist/patch.d.ts +5 -0
- package/dist/patch.js +25 -25
- package/dist/patch.js.map +1 -1
- package/dist/provenance.d.ts +1 -0
- package/dist/provenance.js +2 -1
- package/dist/provenance.js.map +1 -1
- package/dist/query.js.map +1 -1
- package/dist/reach.d.ts +1 -0
- package/dist/reach.js +49 -21
- package/dist/reach.js.map +1 -1
- package/dist/relation.d.ts +4 -0
- package/dist/relation.js +125 -200
- package/dist/relation.js.map +1 -1
- package/dist/sig.d.ts +25 -0
- package/dist/sig.js +277 -0
- package/dist/sig.js.map +1 -0
- package/dist/sigdecl.d.ts +2 -0
- package/dist/sigdecl.js +11 -0
- package/dist/sigdecl.js.map +1 -0
- package/dist/siggate.d.ts +4 -0
- package/dist/siggate.js +90 -0
- package/dist/siggate.js.map +1 -0
- package/dist/std.js +75 -16
- package/dist/std.js.map +1 -1
- package/dist/subsume.js +57 -10
- package/dist/subsume.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/unify.d.ts +2 -2
- package/dist/unify.js +93 -114
- package/dist/unify.js.map +1 -1
- package/dist/utility.d.ts +1 -2
- package/dist/utility.js +7 -61
- package/dist/utility.js.map +1 -1
- package/dist/val/AggFuncVal.d.ts +12 -1
- package/dist/val/AggFuncVal.js +165 -3
- package/dist/val/AggFuncVal.js.map +1 -1
- package/dist/val/BagVal.d.ts +2 -0
- package/dist/val/BagVal.js +56 -8
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/ConstraintVal.js +33 -5
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.d.ts +35 -0
- package/dist/val/ContainerKindVal.js +99 -0
- package/dist/val/ContainerKindVal.js.map +1 -0
- package/dist/val/CopyFuncVal.js +0 -7
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.d.ts +1 -2
- package/dist/val/DisjunctVal.js +146 -39
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/ExpectVal.js +37 -2
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +19 -8
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.d.ts +39 -0
- package/dist/val/GraphAtomVal.js +184 -0
- package/dist/val/GraphAtomVal.js.map +1 -0
- package/dist/val/JunctionVal.js +22 -5
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/ListVal.js +27 -34
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/MapVal.d.ts +1 -0
- package/dist/val/MapVal.js +82 -35
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/PathFuncVal.d.ts +2 -2
- package/dist/val/PathFuncVal.js +75 -16
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.d.ts +25 -0
- package/dist/val/PathVal.js +150 -0
- package/dist/val/PathVal.js.map +1 -0
- package/dist/val/PlusOpVal.d.ts +2 -1
- package/dist/val/PlusOpVal.js +50 -35
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +2 -0
- package/dist/val/PrefVal.js +159 -32
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.d.ts +19 -0
- package/dist/val/RecurseVal.js +217 -0
- package/dist/val/RecurseVal.js.map +1 -0
- package/dist/val/RefVal.d.ts +2 -1
- package/dist/val/RefVal.js +105 -72
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.d.ts +30 -7
- package/dist/val/ReferFuncVal.js +395 -94
- package/dist/val/ReferFuncVal.js.map +1 -1
- package/dist/val/ScalarKindVal.d.ts +4 -2
- package/dist/val/ScalarKindVal.js +12 -1
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/SuperFuncVal.d.ts +4 -2
- package/dist/val/SuperFuncVal.js +118 -14
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.d.ts +1 -1
- package/dist/val/Val.d.ts +2 -3
- package/dist/val/Val.js +39 -20
- package/dist/val/Val.js.map +1 -1
- package/dist/val/arith.js +4 -1
- package/dist/val/arith.js.map +1 -1
- package/dist/vet.d.ts +1 -0
- package/dist/vet.js +32 -1
- package/dist/vet.js.map +1 -1
- package/dist/view.d.ts +90 -0
- package/dist/view.js +2168 -0
- package/dist/view.js.map +1 -0
- package/grammar/aontu.gbnf +18 -10
- package/grammar/aontu.lark +15 -10
- package/grammar/aontu.tmLanguage.json +184 -0
- package/package.json +10 -3
- package/skill/grammar-card.md +1 -2
- package/src/aontu.ts +37 -7
- package/src/cli.ts +553 -8
- package/src/ctx.ts +20 -0
- package/src/diff.ts +4 -2
- package/src/err.ts +8 -1
- package/src/graph.ts +125 -75
- package/src/hcanon.ts +9 -11
- package/src/hints.ts +112 -29
- package/src/jsonschema.ts +41 -0
- package/src/lang.ts +642 -203
- package/src/lsp.ts +75 -6
- package/src/mcp.ts +164 -6
- package/src/mod-tool.ts +48 -9
- package/src/mod.ts +110 -1
- package/src/patch.ts +31 -27
- package/src/provenance.ts +8 -1
- package/src/query.ts +4 -2
- package/src/reach.ts +52 -23
- package/src/relation.ts +139 -236
- package/src/sig.ts +345 -0
- package/src/sigdecl.ts +11 -0
- package/src/siggate.ts +144 -0
- package/src/std.ts +77 -16
- package/src/subsume.ts +59 -10
- package/src/unify.ts +102 -125
- package/src/utility.ts +7 -67
- package/src/val/AggFuncVal.ts +231 -4
- package/src/val/BagVal.ts +58 -9
- package/src/val/ConstraintVal.ts +34 -5
- package/src/val/ContainerKindVal.ts +158 -0
- package/src/val/CopyFuncVal.ts +0 -7
- package/src/val/DisjunctVal.ts +152 -40
- package/src/val/ExpectVal.ts +39 -4
- package/src/val/FuncBaseVal.ts +21 -8
- package/src/val/GraphAtomVal.ts +264 -0
- package/src/val/JunctionVal.ts +23 -6
- package/src/val/ListVal.ts +30 -37
- package/src/val/MapVal.ts +87 -39
- package/src/val/PathFuncVal.ts +107 -19
- package/src/val/PathVal.ts +221 -0
- package/src/val/PlusOpVal.ts +56 -37
- package/src/val/PrefVal.ts +186 -38
- package/src/val/RecurseVal.ts +285 -0
- package/src/val/RefVal.ts +105 -83
- package/src/val/ReferFuncVal.ts +445 -100
- package/src/val/ScalarKindVal.ts +12 -0
- package/src/val/SuperFuncVal.ts +137 -13
- package/src/val/TopVal.ts +1 -1
- package/src/val/Val.ts +44 -35
- package/src/val/arith.ts +4 -1
- package/src/vet.ts +41 -4
- package/src/view.ts +2882 -0
- package/dist/val/IdFuncVal.d.ts +0 -13
- package/dist/val/IdFuncVal.js +0 -54
- package/dist/val/IdFuncVal.js.map +0 -1
- package/src/val/IdFuncVal.ts +0 -91
package/src/val/DisjunctVal.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { AontuContext } from '../ctx'
|
|
15
15
|
|
|
16
16
|
import { AontuError, descErr, makeNilErr } from '../err'
|
|
17
|
+
import { exactJSON } from '../exactjson'
|
|
17
18
|
import { unite } from '../unify'
|
|
18
19
|
|
|
19
20
|
import {
|
|
@@ -70,7 +71,12 @@ class DisjunctVal extends JunctionVal {
|
|
|
70
71
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Disjunct', this, peer)
|
|
71
72
|
|
|
72
73
|
if (!this.prefsRanked) {
|
|
73
|
-
this.rankPrefs(ctx)
|
|
74
|
+
const ranked = this.rankPrefs(ctx)
|
|
75
|
+
// A clash between equal-rank defaults refuses for the whole
|
|
76
|
+
// disjunction (R2): the disagreement IS the answer.
|
|
77
|
+
if (null != ranked && ranked.isNil) {
|
|
78
|
+
return ranked
|
|
79
|
+
}
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
// // // console.log('DISJUNCT-unify-A', this.id, this.canon)
|
|
@@ -95,6 +101,16 @@ class DisjunctVal extends JunctionVal {
|
|
|
95
101
|
// before return.
|
|
96
102
|
const savedErr = ctx.err
|
|
97
103
|
const savedTrialMode = ctx._trialMode
|
|
104
|
+
// A MEMBER'S TYPE FLOW IS PART OF THAT MEMBER. `refer(t)`/`rel(t)`
|
|
105
|
+
// assert `t` on ANOTHER node, and the assertion may only take
|
|
106
|
+
// effect if the member that makes it survives: committing every
|
|
107
|
+
// member's flow puts `t_A & t_B` on the target, which no reading
|
|
108
|
+
// of `A | B` licenses and which leaves the target MORE constrained
|
|
109
|
+
// than either alternative. The flow record is therefore staged per
|
|
110
|
+
// trial, like `ctx.err`, and only the survivors' records are
|
|
111
|
+
// merged into the real one below.
|
|
112
|
+
const savedFlows: Map<string, Val> | undefined = (ctx as any).referflows
|
|
113
|
+
const staged: (Map<string, Val> | undefined)[] = []
|
|
98
114
|
// C1-inner: tell `makeNilErr` to return TRIAL_NIL in this scope
|
|
99
115
|
// instead of allocating per-failure NilVals. Save/restore so
|
|
100
116
|
// nested DisjunctVal trials (and the outer non-trial code) are
|
|
@@ -108,6 +124,10 @@ class DisjunctVal extends JunctionVal {
|
|
|
108
124
|
const v = this.peg[vI]
|
|
109
125
|
const trialErr: any[] = []
|
|
110
126
|
ctx.err = trialErr
|
|
127
|
+
if (undefined !== savedFlows) {
|
|
128
|
+
staged[vI] = new Map()
|
|
129
|
+
;(ctx as any).referflows = staged[vI]
|
|
130
|
+
}
|
|
111
131
|
|
|
112
132
|
oval[vI] = unite(te ? ctx.clone({ explain: ec(te, 'DIST:' + vI) }) : ctx, v, peer, 'dj-peer')
|
|
113
133
|
|
|
@@ -140,7 +160,7 @@ class DisjunctVal extends JunctionVal {
|
|
|
140
160
|
// plus `k:'autoo'` answered "autoo", and `*8080|(integer&neq(80))`
|
|
141
161
|
// admitted 80 (use-cases/BUGS.md §1-2). An inadmissible override
|
|
142
162
|
// now fails the pref member's trial, and when every member is
|
|
143
|
-
// gone the meet is the existing
|
|
163
|
+
// gone the meet is the existing `empty` refusal.
|
|
144
164
|
//
|
|
145
165
|
// SCALAR preferred values only, exactly the kind gate's own
|
|
146
166
|
// boundary (test/spec/pref.tsv, "THE GATE IS A SCALAR GATE"): a
|
|
@@ -176,6 +196,7 @@ class DisjunctVal extends JunctionVal {
|
|
|
176
196
|
finally {
|
|
177
197
|
ctx._trialMode = savedTrialMode
|
|
178
198
|
ctx.err = savedErr
|
|
199
|
+
;(ctx as any).referflows = savedFlows
|
|
179
200
|
}
|
|
180
201
|
|
|
181
202
|
// // // console.log('DISJUNCT-unify-B', this.id, oval.map(v => v.canon))
|
|
@@ -224,6 +245,31 @@ class DisjunctVal extends JunctionVal {
|
|
|
224
245
|
for (let kI = vI + 1; kI < oval.length; kI++) {
|
|
225
246
|
if (oval[kI].same(oval[vI])) {
|
|
226
247
|
oval[kI] = TRIAL_NIL
|
|
248
|
+
continue
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// TWO PREFERENCES OVER ONE VALUE ARE ONE PREFERENCE, and
|
|
252
|
+
// the lower rank is the one that generates: `*1 | **1` is
|
|
253
|
+
// `*1`. Ranking folds EQUAL ranks (R2); this folds the rest,
|
|
254
|
+
// which R5 stopped discarding.
|
|
255
|
+
//
|
|
256
|
+
// A PLAIN arm holding that same value is NOT a duplicate of
|
|
257
|
+
// it and must not be folded away: it is the sibling that
|
|
258
|
+
// ADMITS an override under ADR-004's gate, which is the
|
|
259
|
+
// whole point of writing `*x | x`. Folding it turned that
|
|
260
|
+
// idiom's own default into a `pref_not_instance` finding,
|
|
261
|
+
// and `*top | top` is pinned as its control.
|
|
262
|
+
const a: any = oval[vI]
|
|
263
|
+
const b: any = oval[kI]
|
|
264
|
+
if (true === a.isPref && true === b.isPref
|
|
265
|
+
&& prefInnerPeg(a).same(prefInnerPeg(b))) {
|
|
266
|
+
if ((a as PrefVal).rank <= (b as PrefVal).rank) {
|
|
267
|
+
oval[kI] = TRIAL_NIL
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
oval[vI] = TRIAL_NIL
|
|
271
|
+
break
|
|
272
|
+
}
|
|
227
273
|
}
|
|
228
274
|
}
|
|
229
275
|
}
|
|
@@ -231,9 +277,27 @@ class DisjunctVal extends JunctionVal {
|
|
|
231
277
|
// // // console.log('DISJUNCT-unify-D', this.id, oval.map(v => v.canon))
|
|
232
278
|
}
|
|
233
279
|
|
|
280
|
+
// THE SURVIVORS' FLOWS, AND ONLY THEIRS. Members knocked out by
|
|
281
|
+
// the trial, by the admission gate or by the dedup above are all
|
|
282
|
+
// nil here, so this runs after every one of those and before the
|
|
283
|
+
// filter that drops them.
|
|
284
|
+
if (undefined !== savedFlows) {
|
|
285
|
+
for (let vI = 0; vI < staged.length; vI++) {
|
|
286
|
+
const st = staged[vI]
|
|
287
|
+
if (undefined === st || true === oval[vI]?.isNil) {
|
|
288
|
+
continue
|
|
289
|
+
}
|
|
290
|
+
for (const [k, fv] of st) {
|
|
291
|
+
const prev = savedFlows.get(k)
|
|
292
|
+
savedFlows.set(k, undefined === prev ? fv
|
|
293
|
+
: unite(ctx, prev, fv, 'refer-flow-record'))
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
234
298
|
// Outside the 1<length block: a SINGLE-member disjunction (e.g. a
|
|
235
299
|
// rankPrefs collapse) whose one member fails the trial or the
|
|
236
|
-
// admission gate must reach the
|
|
300
|
+
// admission gate must reach the `empty` refusal below, not
|
|
237
301
|
// return the trial sentinel as if it were the answer.
|
|
238
302
|
oval = oval.filter(v => !v.isNil)
|
|
239
303
|
|
|
@@ -243,7 +307,7 @@ class DisjunctVal extends JunctionVal {
|
|
|
243
307
|
out = oval[0]
|
|
244
308
|
}
|
|
245
309
|
else if (0 == oval.length) {
|
|
246
|
-
return makeNilErr(ctx, '
|
|
310
|
+
return makeNilErr(ctx, 'empty', this, peer)
|
|
247
311
|
}
|
|
248
312
|
else {
|
|
249
313
|
out = new DisjunctVal({ peg: oval }, ctx)
|
|
@@ -268,52 +332,61 @@ class DisjunctVal extends JunctionVal {
|
|
|
268
332
|
}
|
|
269
333
|
|
|
270
334
|
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
335
|
+
// RANK ORDERS THE SURVIVORS, IT DOES NOT DISCARD AT PARSE (ADR-011
|
|
336
|
+
// R5, docs/design/DEFAULTS.0.md). Every rank is KEPT here, and
|
|
337
|
+
// generation takes the lowest-rank preference still standing -- so
|
|
338
|
+
// eliminating the lower arm PROMOTES the next instead of taking the
|
|
339
|
+
// whole ladder with it. This ran once, before the member trials,
|
|
340
|
+
// and discarded every arm but the lowest: `*1 | **2` met by
|
|
341
|
+
// `neq(1)` lost the default entirely and refused, where the ladder
|
|
342
|
+
// exists precisely to answer 2. Rank is a preference order over
|
|
343
|
+
// WHAT SURVIVES, which is not knowable until the trials have run.
|
|
344
|
+
//
|
|
345
|
+
// Only EQUAL ranks fold, because two defaults at one rank are one
|
|
346
|
+
// decision: compatible pegs merge, and a disagreement is the
|
|
347
|
+
// `pref_rank_clash` refusal (R2), which belongs to the whole
|
|
348
|
+
// disjunction -- there is no alternative to fall back to.
|
|
349
|
+
//
|
|
350
|
+
// Answers the sole surviving preference when the disjunction holds
|
|
351
|
+
// exactly one -- which the RECURSIVE call below consumes to lift a
|
|
352
|
+
// nested disjunct's winner into this one -- or the clash refusal.
|
|
353
|
+
rankPrefs(ctx: AontuContext): Val | undefined {
|
|
354
|
+
// The kept index per rank, so an equal-rank twin folds into the
|
|
355
|
+
// arm already standing for that rank.
|
|
356
|
+
const atRank: Record<number, number> = {}
|
|
278
357
|
|
|
279
358
|
// // // console.log('RP-A', this.peg.map((p: Val) => p.canon))
|
|
280
359
|
|
|
281
360
|
for (let vI = 0; vI < this.peg.length; vI++) {
|
|
282
361
|
const v = this.peg[vI]
|
|
362
|
+
let pref: PrefVal | undefined = undefined
|
|
363
|
+
|
|
283
364
|
if (v instanceof PrefVal) {
|
|
284
|
-
|
|
285
|
-
if (v.rank === lastpref.rank) {
|
|
286
|
-
const pref = v.unify(lastpref, ctx) as PrefVal
|
|
287
|
-
if (pref.isNil) {
|
|
288
|
-
return pref
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
this.peg[lastprefI] = pref
|
|
292
|
-
lastpref = pref
|
|
293
|
-
this.peg[vI] = null
|
|
294
|
-
}
|
|
295
|
-
// return Nil.make(ctx, '|:prefs', lastpref, v, 'associate')
|
|
296
|
-
}
|
|
297
|
-
else if (v.rank < lastpref.rank) {
|
|
298
|
-
this.peg[lastprefI] = null
|
|
299
|
-
lastpref = v
|
|
300
|
-
lastprefI = vI
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
this.peg[vI] = null
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
lastpref = v
|
|
308
|
-
lastprefI = vI
|
|
309
|
-
}
|
|
365
|
+
pref = v
|
|
310
366
|
}
|
|
311
367
|
else if (v.isDisjunct) {
|
|
312
368
|
const subrank = (v as DisjunctVal).rankPrefs(ctx)
|
|
369
|
+
if (null != subrank && subrank.isNil) {
|
|
370
|
+
return subrank
|
|
371
|
+
}
|
|
313
372
|
if (subrank instanceof PrefVal) {
|
|
314
373
|
this.peg[vI] = subrank
|
|
315
|
-
|
|
316
|
-
|
|
374
|
+
pref = subrank
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (undefined !== pref) {
|
|
379
|
+
const at = atRank[pref.rank]
|
|
380
|
+
if (undefined === at) {
|
|
381
|
+
atRank[pref.rank] = vI
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
const folded = pref.unify(this.peg[at], ctx)
|
|
385
|
+
if (folded.isNil) {
|
|
386
|
+
return folded
|
|
387
|
+
}
|
|
388
|
+
this.peg[at] = folded
|
|
389
|
+
this.peg[vI] = null
|
|
317
390
|
}
|
|
318
391
|
}
|
|
319
392
|
}
|
|
@@ -373,6 +446,33 @@ class DisjunctVal extends JunctionVal {
|
|
|
373
446
|
|
|
374
447
|
const prefs = this.peg.filter((v: Val) => v instanceof PrefVal)
|
|
375
448
|
|
|
449
|
+
// ALTERNATIVES THAT GENERATE THE SAME VALUE ARE RESOLVED
|
|
450
|
+
// (ADR-007's rule, asked at the moment it matters): `[] | [&:
|
|
451
|
+
// T]` met by an empty list keeps both arms -- they differ as
|
|
452
|
+
// SCHEMAS, which is what stops the dedup collapsing the
|
|
453
|
+
// template away (BUGS.md §52 regime 4) -- but both generate
|
|
454
|
+
// the empty list, and one generated value is one value.
|
|
455
|
+
if (0 === prefs.length && 1 < this.peg.length) {
|
|
456
|
+
const gctx = ctx.clone({ err: [], collect: true })
|
|
457
|
+
let firstOut: any
|
|
458
|
+
let allSame = true
|
|
459
|
+
for (let gI = 0; gI < this.peg.length && allSame; gI++) {
|
|
460
|
+
const gout = this.peg[gI].gen(gctx)
|
|
461
|
+
if (0 < gctx.err.length || undefined === gout) {
|
|
462
|
+
allSame = false
|
|
463
|
+
}
|
|
464
|
+
else if (0 === gI) {
|
|
465
|
+
firstOut = gout
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
allSame = exactJSON(gout) === exactJSON(firstOut)
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (allSame) {
|
|
472
|
+
return firstOut
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
376
476
|
if (0 === prefs.length && 1 < this.peg.length) {
|
|
377
477
|
const nerr = makeNilErr(ctx, 'disjunct_no_gen', this)
|
|
378
478
|
descErr(nerr, ctx)
|
|
@@ -385,7 +485,19 @@ class DisjunctVal extends JunctionVal {
|
|
|
385
485
|
return undefined
|
|
386
486
|
}
|
|
387
487
|
|
|
388
|
-
|
|
488
|
+
// THE LOWEST-RANK SURVIVOR (R5). Ranking no longer discards the
|
|
489
|
+
// weaker arms, so the choice is made here, over what is left:
|
|
490
|
+
// `*1 | **2` answers 1, and answers 2 once `*1` is gone.
|
|
491
|
+
let best: any = this.peg[0]
|
|
492
|
+
if (0 < prefs.length) {
|
|
493
|
+
best = prefs[0]
|
|
494
|
+
for (const p of prefs) {
|
|
495
|
+
if ((p as PrefVal).rank < best.rank) {
|
|
496
|
+
best = p
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return best.gen(ctx)
|
|
389
501
|
}
|
|
390
502
|
|
|
391
503
|
return super.gen(ctx)
|
package/src/val/ExpectVal.ts
CHANGED
|
@@ -47,6 +47,9 @@ class ExpectVal extends FeatureVal {
|
|
|
47
47
|
// canon reparsed into a document that accepts values the original
|
|
48
48
|
// rejects. A canon that silently drops a constraint is worse than one
|
|
49
49
|
// that fails to parse. Go's ExpectVal.Canon renders the same peg.
|
|
50
|
+
//
|
|
51
|
+
// Which is why `peg` is kept the WHOLE expectation as peers arrive
|
|
52
|
+
// (BUGS.md §48) rather than only what was first written: see unify.
|
|
50
53
|
get canon() { return this.peg.canon }
|
|
51
54
|
|
|
52
55
|
constructor(
|
|
@@ -73,12 +76,27 @@ class ExpectVal extends FeatureVal {
|
|
|
73
76
|
let out: Val = this
|
|
74
77
|
|
|
75
78
|
if (!peer.isTop) {
|
|
79
|
+
// THE PEER MEETS THE WHOLE EXPECTATION. `peg` already carries
|
|
80
|
+
// every peer met so far (see below), so meeting the incoming peer
|
|
81
|
+
// against the ACCUMULATED `peer` first -- as this did -- refused
|
|
82
|
+
// against only the atom that happened to reject. A conflict with
|
|
83
|
+
// `peg` is a conflict with the accumulation too, since peg
|
|
84
|
+
// subsumes it, so nothing stops being refused: only the sentence
|
|
85
|
+
// changes, to the residual the error's own hint promises
|
|
86
|
+
// (BUGS.md §48).
|
|
87
|
+
const peeru =
|
|
88
|
+
unite(te ? ctx.clone({ explain: ec(te, 'EXPECT') }) : ctx, peer, this.peg, 'expect-self')
|
|
89
|
+
|
|
90
|
+
// Accumulated for the `expect` finding's operand. Computed BEFORE
|
|
91
|
+
// the escape below, where it has always been: an expectation that
|
|
92
|
+
// escapes still passed through here, and moving it after the
|
|
93
|
+
// escape leaves the accumulating arm reachable only by a node
|
|
94
|
+
// that both carries an accumulation AND fails to escape -- which
|
|
95
|
+
// the suite never produces, so it reads as dead code against the
|
|
96
|
+
// ADR-002 gate. Go's ExpectVal.Unify keeps the same order.
|
|
76
97
|
const acc = undefined === this.peer ? peer :
|
|
77
98
|
unite(te ? ctx.clone({ explain: ec(te, 'PEER') }) : ctx, this.peer, peer, 'expect-peer')
|
|
78
99
|
|
|
79
|
-
const peeru =
|
|
80
|
-
unite(te ? ctx.clone({ explain: ec(te, 'EXPECT') }) : ctx, acc, this.peg, 'expect-self')
|
|
81
|
-
|
|
82
100
|
if (peeru.isGenable) {
|
|
83
101
|
out = peeru
|
|
84
102
|
}
|
|
@@ -86,7 +104,24 @@ class ExpectVal extends FeatureVal {
|
|
|
86
104
|
// Still an expectation: carry the accumulated peer forward in a
|
|
87
105
|
// fresh node stored at THIS destination by the caller, leaving
|
|
88
106
|
// `this` -- possibly a shared template's child -- untouched.
|
|
89
|
-
|
|
107
|
+
//
|
|
108
|
+
// THE MEET IS THE NEW PEG (BUGS.md §48). An expectation that
|
|
109
|
+
// has met a peer without being freed by it stands for `peg &
|
|
110
|
+
// peer` from then on -- that is what a later peer must satisfy,
|
|
111
|
+
// and what canon has to state. Rebuilding from the ORIGINAL peg
|
|
112
|
+
// dropped the peer everywhere the node was later copied (the
|
|
113
|
+
// bag re-wrap, Val.clone), so `b:{z:1} b:{u8:min(0)}
|
|
114
|
+
// a:$.b.u8&max(15)` -- whose reference resolves a pass late, so
|
|
115
|
+
// `max(15)` arrives as a peer -- canoned as `min(0)`. That text
|
|
116
|
+
// reparses into a document admitting 20, which the original
|
|
117
|
+
// rejects, and hashed differently in each port. Storing the
|
|
118
|
+
// meet in `peg` needs no new field and no carrying: every copy
|
|
119
|
+
// site already preserves `peg`.
|
|
120
|
+
//
|
|
121
|
+
// Purity is untouched -- this is a NEW node, so a shared
|
|
122
|
+
// template's own expectation keeps the peg it was written with
|
|
123
|
+
// (§6-§7).
|
|
124
|
+
const e = new ExpectVal({ peg: peeru }, ctx)
|
|
90
125
|
e.key = this.key
|
|
91
126
|
e.parent = this.parent
|
|
92
127
|
e.peer = acc
|
package/src/val/FuncBaseVal.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from '../utility'
|
|
23
23
|
|
|
24
24
|
import { makeNilErr, AontuError } from '../err'
|
|
25
|
+
import { sigRefuse } from '../siggate'
|
|
25
26
|
|
|
26
27
|
import {
|
|
27
28
|
top
|
|
@@ -271,16 +272,17 @@ class FuncBaseVal extends FeatureVal {
|
|
|
271
272
|
|
|
272
273
|
// console.log('FUNCBASE-PEG', this.id, pegdone, this.peg.map((p: any) => p?.canon))
|
|
273
274
|
|
|
274
|
-
if (pegdone) {
|
|
275
|
-
|
|
275
|
+
if (pegdone && !this.deferResolve(ctx, newpeg)) {
|
|
276
|
+
// THE SIGNATURE GATE (docs/design/SIGNATURES.0.md): the
|
|
277
|
+
// driven arguments against the declared signature, before
|
|
278
|
+
// the builtin's own logic sees them. See siggate.ts for
|
|
279
|
+
// what the gate owns and what stays with the builtins.
|
|
280
|
+
const resolved = sigRefuse(ctx, this, newpeg) ??
|
|
281
|
+
this.resolve(ctx, newpeg)
|
|
276
282
|
// console.log('FUNC-RESOLVED', ctx.cc, resolved?.canon)
|
|
277
283
|
|
|
278
|
-
// The TOP peer is DROPPED as the unit it is
|
|
279
|
-
|
|
280
|
-
// than the unit: `id(x) & id(y)` resolves both sides to a
|
|
281
|
-
// top, and taking this shortcut would silently keep one
|
|
282
|
-
// name and lose the other instead of refusing the pair.
|
|
283
|
-
out = resolved.done && peer.isTop && null == peer.entity ? resolved :
|
|
284
|
+
// The TOP peer is DROPPED as the unit it is.
|
|
285
|
+
out = resolved.done && peer.isTop ? resolved :
|
|
284
286
|
unite(te ? ctx.clone({ explain: ec(te, 'PEG') }) : ctx,
|
|
285
287
|
resolved, peer, 'func-' + this.funcname() + '/' + this.id)
|
|
286
288
|
propagateMarks(this, out)
|
|
@@ -393,6 +395,17 @@ class FuncBaseVal extends FeatureVal {
|
|
|
393
395
|
}
|
|
394
396
|
|
|
395
397
|
|
|
398
|
+
// A function may hold its resolution for a later pass even with its
|
|
399
|
+
// arguments settled -- it then rides the ordinary args-not-done
|
|
400
|
+
// path, residuating as any unresolved call does. super() defers on a
|
|
401
|
+
// recursion residual argument (SuperFuncVal), which is why the DRIVEN
|
|
402
|
+
// arguments are passed: this.peg still holds the undriven originals
|
|
403
|
+
// at the decision point.
|
|
404
|
+
deferResolve(_ctx: AontuContext, _args?: Val[]): boolean {
|
|
405
|
+
return false
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
|
|
396
409
|
} /* node:coverage ignore next 6 */
|
|
397
410
|
|
|
398
411
|
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// THE GRAPH ATOMS (RELATIONS.0.md §3.3): `acyclic()` and
|
|
4
|
+
// `inverse(name)`, conjoined at the same field as the `rel()` they
|
|
5
|
+
// govern. Their model is the sizing atoms -- a property that cannot be
|
|
6
|
+
// decided while information can still arrive is HELD during
|
|
7
|
+
// unification and DECIDED at generation, where no more can.
|
|
8
|
+
//
|
|
9
|
+
// During unification they are lattice-inert: both properties are
|
|
10
|
+
// global and non-monotone (one more edge can make an acyclic graph
|
|
11
|
+
// cyclic), and the lattice guarantee -- more information never
|
|
12
|
+
// falsifies what has been observed -- forbids a constraint that could
|
|
13
|
+
// answer true and then false. So the atoms only RESIDUATE: they ride
|
|
14
|
+
// the field through meets, dedup additively, appear in canon and reach
|
|
15
|
+
// the `aon1-` hash, and REGISTER the declaration on the context. The
|
|
16
|
+
// predicate they govern is the key they sit on, evaluation-global,
|
|
17
|
+
// additive across declarations.
|
|
18
|
+
//
|
|
19
|
+
// The verdict lands at generation (relationVerdict,
|
|
20
|
+
// ts/src/relation.ts) and is reported identically by the `relations`
|
|
21
|
+
// verb -- one decision, two surfaces.
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
Val,
|
|
25
|
+
ValSpec,
|
|
26
|
+
} from '../type'
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
DONE,
|
|
30
|
+
} from '../type'
|
|
31
|
+
|
|
32
|
+
import {
|
|
33
|
+
AontuContext,
|
|
34
|
+
} from '../ctx'
|
|
35
|
+
|
|
36
|
+
import { makeNilErr } from '../err'
|
|
37
|
+
|
|
38
|
+
import { FuncBaseVal } from './FuncBaseVal'
|
|
39
|
+
import { FeatureVal } from './FeatureVal'
|
|
40
|
+
import { unite } from '../unify'
|
|
41
|
+
import { propagateMarks } from '../utility'
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
// The declarations one evaluation accumulates: predicate -> what its
|
|
45
|
+
// atoms said. Additive, exactly as two statements of one map are. The
|
|
46
|
+
// map lives on the CONTEXT (created in the constructor, like the
|
|
47
|
+
// _depth box), so every clone shares one registry.
|
|
48
|
+
export type RelDecl = {
|
|
49
|
+
acyclic?: boolean
|
|
50
|
+
inverses: Set<string>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function relDecls(ctx: any): Map<string, RelDecl> {
|
|
54
|
+
return ctx._reldecls
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class GraphAtomVal extends FeatureVal {
|
|
59
|
+
isGraphAtom = true
|
|
60
|
+
isGenable = true
|
|
61
|
+
// AFTER rel() (45000): the atoms say nothing about the value.
|
|
62
|
+
cjo = 46000
|
|
63
|
+
|
|
64
|
+
akind: 'acyclic' | 'inverse'
|
|
65
|
+
invname?: string
|
|
66
|
+
// The value the atom rides on -- the sizing-constraint shape: the
|
|
67
|
+
// atom ABSORBS its fold neighbours (the rel, the container, another
|
|
68
|
+
// atom) and carries them, so the fold's pairwise walk still merges
|
|
69
|
+
// the value across it. Absent until the atom meets one.
|
|
70
|
+
held?: Val
|
|
71
|
+
|
|
72
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
73
|
+
super(spec, ctx)
|
|
74
|
+
this.akind = (spec as any).akind ?? 'acyclic'
|
|
75
|
+
this.invname = (spec as any).invname
|
|
76
|
+
this.held = (spec as any).held
|
|
77
|
+
// A settled residual, like an unmet rel(): the bare atom is its
|
|
78
|
+
// own value, and a type() body carrying one must settle. Holding
|
|
79
|
+
// an unsettled value, it is exactly as done as the value.
|
|
80
|
+
this.dc = undefined === this.held || true === this.held.done
|
|
81
|
+
? DONE : 0
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
85
|
+
const out: any = super.clone(ctx, spec)
|
|
86
|
+
out.akind = this.akind
|
|
87
|
+
out.invname = this.invname
|
|
88
|
+
out.held = this.held
|
|
89
|
+
out.dc = this.dc
|
|
90
|
+
return out
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// A rebuilt atom around a new held, at this atom's position.
|
|
94
|
+
private carry(ctx: AontuContext, held: Val): Val {
|
|
95
|
+
const out: any = new GraphAtomVal(
|
|
96
|
+
{ akind: this.akind, invname: this.invname, held } as any, ctx)
|
|
97
|
+
propagateMarks(this, out)
|
|
98
|
+
out.site = this.site
|
|
99
|
+
out.path = this.path
|
|
100
|
+
return out
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// The predicate is the key the atom sits on -- and a predicate is a
|
|
104
|
+
// D-1 NAME, by exactly fieldkey's rule: an atom landed anywhere
|
|
105
|
+
// else declares nothing. Registration is idempotent (the
|
|
106
|
+
// declaration set is a set) and happens at every drive, so
|
|
107
|
+
// whichever pass first sees the atom at its landed position records
|
|
108
|
+
// it.
|
|
109
|
+
register(ctx: AontuContext): void {
|
|
110
|
+
const seg = this.path[this.path.length - 1]
|
|
111
|
+
if ('string' !== typeof seg || !GRAPH_ATOM_NAME.test(seg)) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
const decls = relDecls(ctx)
|
|
115
|
+
let d = decls.get(seg)
|
|
116
|
+
if (undefined === d) {
|
|
117
|
+
d = { inverses: new Set() }
|
|
118
|
+
decls.set(seg, d)
|
|
119
|
+
}
|
|
120
|
+
if ('acyclic' === this.akind) {
|
|
121
|
+
d.acyclic = true
|
|
122
|
+
}
|
|
123
|
+
else if (undefined !== this.invname) {
|
|
124
|
+
d.inverses.add(this.invname)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
unify(peer: Val, ctx: AontuContext): Val {
|
|
129
|
+
const p: any = peer
|
|
130
|
+
this.register(ctx)
|
|
131
|
+
|
|
132
|
+
// The self-drive: unite's tail calls unify(top) directly on any
|
|
133
|
+
// not-done result, and the held is what still has work to do.
|
|
134
|
+
// (A null/nil peer never arrives -- unite's ladder absorbs both.)
|
|
135
|
+
if (null == peer || true === p.isTop) {
|
|
136
|
+
if (undefined === this.held) {
|
|
137
|
+
return this
|
|
138
|
+
}
|
|
139
|
+
if (true === this.held.done) {
|
|
140
|
+
// Doneness is monotone, so recording it in place is safe --
|
|
141
|
+
// and without it the bag walk keeps asking and generation
|
|
142
|
+
// refuses a finished value.
|
|
143
|
+
this.dc = DONE
|
|
144
|
+
return this
|
|
145
|
+
}
|
|
146
|
+
// The self-drive refines IN PLACE (the MapVal top-peer
|
|
147
|
+
// pattern): a fresh atom per pass changes object identity, so
|
|
148
|
+
// spread apply-once stamps and the entity merge's fast paths
|
|
149
|
+
// stop holding, and the enclosing bags re-open every pass --
|
|
150
|
+
// the service catalog never converged.
|
|
151
|
+
const held = unite(ctx, this.held, undefined, 'atom-drive')
|
|
152
|
+
if (true === held.isNil) {
|
|
153
|
+
return held
|
|
154
|
+
}
|
|
155
|
+
this.held = held
|
|
156
|
+
if (true === held.done) {
|
|
157
|
+
this.dc = DONE
|
|
158
|
+
}
|
|
159
|
+
return this
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// The SAME declaration twice is one declaration; their helds
|
|
163
|
+
// merge.
|
|
164
|
+
if (true === p.isGraphAtom &&
|
|
165
|
+
p.akind === this.akind && p.invname === this.invname) {
|
|
166
|
+
const held = undefined === this.held ? p.held
|
|
167
|
+
: undefined === p.held ? this.held
|
|
168
|
+
: unite(ctx, this.held, p.held, 'atom-dup')
|
|
169
|
+
if (undefined !== held && true === held.isNil) {
|
|
170
|
+
return held
|
|
171
|
+
}
|
|
172
|
+
return undefined === held ? this : this.carry(ctx, held)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Anything else -- the rel, the container, a different atom -- is
|
|
176
|
+
// ABSORBED: the atom carries the value and the fold's pairwise
|
|
177
|
+
// walk merges across it.
|
|
178
|
+
const held = undefined === this.held ? peer
|
|
179
|
+
: unite(ctx, this.held, peer, 'atom-held')
|
|
180
|
+
return true === held.isNil ? held : this.carry(ctx, held)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
get canon(): string {
|
|
184
|
+
const own = 'acyclic' === this.akind
|
|
185
|
+
? 'acyclic()'
|
|
186
|
+
: 'inverse(' + JSON.stringify(this.invname) + ')'
|
|
187
|
+
return undefined === this.held ? own : this.held.canon + '&' + own
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
gen(ctx: AontuContext) {
|
|
191
|
+
// The atom is transparent at generation -- its verdict is global
|
|
192
|
+
// (relationVerdict), never a value at this field -- and a BARE
|
|
193
|
+
// atom is silent, exactly as an unmet rel() is.
|
|
194
|
+
return undefined === this.held ? undefined : this.held.gen(ctx)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
// D-1 (docs/design/RELATIONS.0.md): the name grammar shared by entity
|
|
200
|
+
// names, edge predicates and inverse names.
|
|
201
|
+
const GRAPH_ATOM_NAME = /^[_a-zA-Z][-_a-zA-Z0-9]*$/
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class AcyclicFuncVal extends FuncBaseVal {
|
|
205
|
+
isAcyclicFunc = true
|
|
206
|
+
|
|
207
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
208
|
+
super(spec, ctx)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
make(_ctx: AontuContext, spec: ValSpec): Val {
|
|
212
|
+
return new AcyclicFuncVal(spec)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
funcname() {
|
|
216
|
+
return 'acyclic'
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
resolve(ctx: AontuContext, _args: Val[]) {
|
|
220
|
+
const out: any = new GraphAtomVal({ akind: 'acyclic' } as any, ctx)
|
|
221
|
+
out.site = this.site
|
|
222
|
+
out.path = this.path
|
|
223
|
+
return out
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class InverseFuncVal extends FuncBaseVal {
|
|
229
|
+
isInverseFunc = true
|
|
230
|
+
|
|
231
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
232
|
+
super(spec, ctx)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
make(_ctx: AontuContext, spec: ValSpec): Val {
|
|
236
|
+
return new InverseFuncVal(spec)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
funcname() {
|
|
240
|
+
return 'inverse'
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
resolve(ctx: AontuContext, args: Val[]) {
|
|
244
|
+
const a: any = args[0]
|
|
245
|
+
// The mirroring predicate is a NAME -- D-1, spelled bare or
|
|
246
|
+
// quoted. A relation is a vocabulary term, not an address.
|
|
247
|
+
if (true !== a?.isScalar || 'string' !== typeof a.peg
|
|
248
|
+
|| !GRAPH_ATOM_NAME.test(a.peg)) {
|
|
249
|
+
return makeNilErr(ctx, 'inverse_name', this, undefined, 'inverse')
|
|
250
|
+
}
|
|
251
|
+
const out: any = new GraphAtomVal(
|
|
252
|
+
{ akind: 'inverse', invname: a.peg } as any, ctx)
|
|
253
|
+
out.site = this.site
|
|
254
|
+
out.path = this.path
|
|
255
|
+
return out
|
|
256
|
+
}
|
|
257
|
+
} /* node:coverage ignore next 7 */
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
export {
|
|
261
|
+
GraphAtomVal,
|
|
262
|
+
AcyclicFuncVal,
|
|
263
|
+
InverseFuncVal,
|
|
264
|
+
}
|