aontu 0.61.0 → 0.63.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 +4 -4
- package/dist/agentsmd.d.ts +1 -0
- package/dist/agentsmd.js +7 -28
- package/dist/agentsmd.js.map +1 -1
- package/dist/alias.js.map +1 -1
- package/dist/allow.d.ts +23 -0
- package/dist/allow.js +138 -0
- package/dist/allow.js.map +1 -0
- package/dist/aontu.d.ts +4 -2
- package/dist/aontu.js +4 -80
- package/dist/aontu.js.map +1 -1
- package/dist/aontumodel.d.ts +4 -0
- package/dist/aontumodel.js +33 -0
- package/dist/aontumodel.js.map +1 -0
- package/dist/cli.d.ts +10 -1
- package/dist/cli.js +877 -479
- package/dist/cli.js.map +1 -1
- package/dist/ctx.js +0 -48
- package/dist/ctx.js.map +1 -1
- package/dist/diff.js +0 -32
- package/dist/diff.js.map +1 -1
- package/dist/err.js +0 -40
- package/dist/err.js.map +1 -1
- package/dist/escape.js +0 -45
- package/dist/escape.js.map +1 -1
- package/dist/exactjson.d.ts +0 -35
- package/dist/exactjson.js +0 -131
- package/dist/exactjson.js.map +1 -1
- package/dist/format.js +55 -189
- package/dist/format.js.map +1 -1
- package/dist/grammar.d.ts +9 -0
- package/dist/grammar.js +54 -0
- package/dist/grammar.js.map +1 -0
- package/dist/graph.js +0 -26
- package/dist/graph.js.map +1 -1
- package/dist/hcanon.js +0 -82
- package/dist/hcanon.js.map +1 -1
- package/dist/helpdoc.d.ts +16 -0
- package/dist/helpdoc.js +59 -0
- package/dist/helpdoc.js.map +1 -0
- package/dist/hints.d.ts +0 -6
- package/dist/hints.js +59 -47
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.js +0 -114
- package/dist/jsonschema.js.map +1 -1
- package/dist/keyorder.d.ts +0 -7
- package/dist/keyorder.js +0 -41
- package/dist/keyorder.js.map +1 -1
- package/dist/lang.js +32 -877
- package/dist/lang.js.map +1 -1
- package/dist/lower.d.ts +3 -0
- package/dist/lower.js +14 -61
- package/dist/lower.js.map +1 -1
- package/dist/lsp-server.js +0 -16
- package/dist/lsp-server.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/lsp.js +12 -159
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.js +0 -26
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp.js +0 -113
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +0 -130
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.js +0 -162
- package/dist/mod.js.map +1 -1
- package/dist/patch.js +0 -217
- package/dist/patch.js.map +1 -1
- package/dist/provenance.js +0 -140
- package/dist/provenance.js.map +1 -1
- package/dist/query.js +0 -75
- package/dist/query.js.map +1 -1
- package/dist/reach.js +0 -43
- package/dist/reach.js.map +1 -1
- package/dist/relation.d.ts +2 -0
- package/dist/relation.js +3 -58
- package/dist/relation.js.map +1 -1
- package/dist/render.js +33 -143
- package/dist/render.js.map +1 -1
- package/dist/report-sarif.d.ts +0 -11
- package/dist/report-sarif.js +0 -28
- package/dist/report-sarif.js.map +1 -1
- package/dist/sig.js +0 -35
- package/dist/sig.js.map +1 -1
- package/dist/sigdecl.js +1 -1
- package/dist/sigdecl.js.map +1 -1
- package/dist/siggate.js +0 -4
- package/dist/siggate.js.map +1 -1
- package/dist/site.js +3 -29
- package/dist/site.js.map +1 -1
- package/dist/subsume.d.ts +0 -10
- package/dist/subsume.js +0 -137
- package/dist/subsume.js.map +1 -1
- package/dist/template.d.ts +2 -1
- package/dist/template.js +58 -138
- package/dist/template.js.map +1 -1
- package/dist/trim.js +0 -41
- package/dist/trim.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.js.map +1 -1
- package/dist/unify.js +12 -242
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +0 -22
- package/dist/utility.js.map +1 -1
- package/dist/val/AbnfFuncVal.d.ts +18 -0
- package/dist/val/AbnfFuncVal.js +132 -0
- package/dist/val/AbnfFuncVal.js.map +1 -0
- package/dist/val/AbsentVal.d.ts +11 -0
- package/dist/val/AbsentVal.js +30 -0
- package/dist/val/AbsentVal.js.map +1 -0
- package/dist/val/AggFuncVal.d.ts +10 -1
- package/dist/val/AggFuncVal.js +104 -116
- package/dist/val/AggFuncVal.js.map +1 -1
- package/dist/val/ArithFuncVal.js +0 -12
- package/dist/val/ArithFuncVal.js.map +1 -1
- package/dist/val/BagVal.js +1 -78
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/BigDecimalVal.js +0 -16
- package/dist/val/BigDecimalVal.js.map +1 -1
- package/dist/val/BigIntegerVal.js +0 -16
- package/dist/val/BigIntegerVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +0 -9
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/CmpFuncVal.d.ts +20 -0
- package/dist/val/CmpFuncVal.js +188 -0
- package/dist/val/CmpFuncVal.js.map +1 -0
- package/dist/val/ConjunctVal.js +0 -29
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.js +0 -500
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.js +0 -2
- package/dist/val/ContainerKindVal.js.map +1 -1
- package/dist/val/CopyFuncVal.js +0 -3
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.js +0 -179
- package/dist/val/Decimal.js.map +1 -1
- package/dist/val/DeprecateFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.js +0 -152
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/EachFuncVal.d.ts +1 -2
- package/dist/val/EachFuncVal.js +12 -29
- package/dist/val/EachFuncVal.js.map +1 -1
- package/dist/val/EmitFuncVal.d.ts +1 -1
- package/dist/val/EmitFuncVal.js +6 -119
- package/dist/val/EmitFuncVal.js.map +1 -1
- package/dist/val/ExpectVal.js +0 -62
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FilterFuncVal.js +0 -25
- package/dist/val/FilterFuncVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +7 -127
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.js +0 -15
- package/dist/val/GraphAtomVal.js.map +1 -1
- package/dist/val/HideFuncVal.js +0 -13
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/IntegerVal.js +0 -61
- package/dist/val/IntegerVal.js.map +1 -1
- package/dist/val/JunctionVal.js +0 -20
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.js +0 -46
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +0 -57
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js +11 -6
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +0 -151
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.js +0 -27
- package/dist/val/MatchFuncVal.js.map +1 -1
- package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
- package/dist/val/MaybeFuncVal.js +50 -0
- package/dist/val/MaybeFuncVal.js.map +1 -0
- package/dist/val/MoveFuncVal.js +0 -18
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +2 -36
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/NomFuncVal.d.ts +12 -0
- package/dist/val/NomFuncVal.js +153 -0
- package/dist/val/NomFuncVal.js.map +1 -0
- package/dist/val/NumberVal.js +0 -15
- package/dist/val/NumberVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -0
- package/dist/val/OpBaseVal.js +3 -15
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/PackFuncVal.js +0 -34
- package/dist/val/PackFuncVal.js.map +1 -1
- package/dist/val/PathFuncVal.js +0 -6
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.js +0 -41
- package/dist/val/PathVal.js.map +1 -1
- package/dist/val/PlaceVal.js +0 -25
- package/dist/val/PlaceVal.js.map +1 -1
- package/dist/val/PlusOpVal.d.ts +1 -7
- package/dist/val/PlusOpVal.js +13 -74
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js +0 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.js +0 -167
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.js +0 -55
- package/dist/val/RecurseVal.js.map +1 -1
- package/dist/val/RefVal.js +0 -282
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.js +0 -232
- package/dist/val/ReferFuncVal.js.map +1 -1
- package/dist/val/ScalarKindVal.js +0 -49
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/ScalarVal.js +0 -11
- package/dist/val/ScalarVal.js.map +1 -1
- package/dist/val/StrFuncVal.js +0 -18
- package/dist/val/StrFuncVal.js.map +1 -1
- package/dist/val/SuperFuncVal.js +0 -32
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.js +0 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TranslateFuncVal.d.ts +12 -0
- package/dist/val/TranslateFuncVal.js +99 -0
- package/dist/val/TranslateFuncVal.js.map +1 -0
- package/dist/val/UpperFuncVal.js +11 -6
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +1 -0
- package/dist/val/Val.js +2 -133
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +0 -12
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/arith.js +0 -37
- package/dist/val/arith.js.map +1 -1
- package/dist/val/caserange.d.ts +3 -0
- package/dist/val/caserange.js +49 -0
- package/dist/val/caserange.js.map +1 -0
- package/dist/val/members.js +0 -6
- package/dist/val/members.js.map +1 -1
- package/dist/val/numcmp.js +0 -11
- package/dist/val/numcmp.js.map +1 -1
- package/dist/val/numkind.js +0 -145
- package/dist/val/numkind.js.map +1 -1
- package/dist/val/valutil.js +0 -16
- package/dist/val/valutil.js.map +1 -1
- package/dist/vet.d.ts +12 -0
- package/dist/vet.js +159 -412
- package/dist/vet.js.map +1 -1
- package/dist/view.js +0 -414
- package/dist/view.js.map +1 -1
- package/dist/walk.js +0 -41
- package/dist/walk.js.map +1 -1
- package/grammar/aontu.abnf +9 -7
- package/grammar/aontu.gbnf +5 -5
- package/grammar/aontu.lark +5 -5
- package/grammar/aontu.tmLanguage.json +1 -1
- package/package.json +4 -2
- package/skill/SKILL.md +8 -0
- package/skill/init/check.sh +28 -0
- package/skill/init/data.aon +12 -0
- package/skill/init/model.aon +19 -0
- package/skill/tasks.md +151 -0
- package/src/agentsmd.ts +8 -32
- package/src/alias.ts +0 -39
- package/src/allow.ts +221 -0
- package/src/aontu.ts +10 -108
- package/src/aontumodel.ts +32 -0
- package/src/cli.ts +1009 -540
- package/src/ctx.ts +0 -103
- package/src/diff.ts +0 -40
- package/src/err.ts +0 -40
- package/src/escape.ts +0 -46
- package/src/exactjson.ts +0 -131
- package/src/format.ts +63 -234
- package/src/grammar.ts +72 -0
- package/src/graph.ts +0 -61
- package/src/hcanon.ts +0 -82
- package/src/helpdoc.ts +77 -0
- package/src/hints.ts +72 -49
- package/src/jsonschema.ts +0 -123
- package/src/keyorder.ts +0 -42
- package/src/lang.ts +39 -895
- package/src/lower.ts +15 -65
- package/src/lsp-server.ts +0 -16
- package/src/lsp.ts +12 -180
- package/src/mcp-server.ts +0 -31
- package/src/mcp.ts +0 -130
- package/src/mod-tool.ts +0 -158
- package/src/mod.ts +0 -178
- package/src/patch.ts +0 -232
- package/src/provenance.ts +0 -183
- package/src/query.ts +0 -84
- package/src/reach.ts +0 -53
- package/src/relation.ts +7 -71
- package/src/render.ts +33 -180
- package/src/report-sarif.ts +0 -48
- package/src/sig.ts +0 -35
- package/src/sigdecl.ts +1 -1
- package/src/siggate.ts +0 -30
- package/src/site.ts +3 -29
- package/src/subsume.ts +1 -161
- package/src/template.ts +69 -140
- package/src/trim.ts +0 -53
- package/src/type.ts +2 -45
- package/src/unify.ts +13 -251
- package/src/utility.ts +0 -31
- package/src/val/AbnfFuncVal.ts +181 -0
- package/src/val/AbsentVal.ts +54 -0
- package/src/val/AggFuncVal.ts +152 -188
- package/src/val/ArithFuncVal.ts +0 -20
- package/src/val/BagVal.ts +1 -78
- package/src/val/BigDecimalVal.ts +0 -16
- package/src/val/BigIntegerVal.ts +0 -16
- package/src/val/CloseFuncVal.ts +0 -9
- package/src/val/CmpFuncVal.ts +249 -0
- package/src/val/ConjunctVal.ts +0 -33
- package/src/val/ConstraintVal.ts +2 -537
- package/src/val/ContainerKindVal.ts +0 -18
- package/src/val/CopyFuncVal.ts +0 -5
- package/src/val/Decimal.ts +1 -185
- package/src/val/DeprecateFuncVal.ts +0 -10
- package/src/val/DisjunctVal.ts +0 -157
- package/src/val/EachFuncVal.ts +12 -53
- package/src/val/EmitFuncVal.ts +8 -208
- package/src/val/ExpectVal.ts +0 -62
- package/src/val/FilterFuncVal.ts +0 -55
- package/src/val/FuncBaseVal.ts +9 -130
- package/src/val/GraphAtomVal.ts +0 -42
- package/src/val/HideFuncVal.ts +0 -15
- package/src/val/IntegerVal.ts +0 -61
- package/src/val/JunctionVal.ts +0 -20
- package/src/val/KeyFuncVal.ts +0 -48
- package/src/val/ListVal.ts +0 -59
- package/src/val/LowerFuncVal.ts +12 -7
- package/src/val/MapVal.ts +0 -151
- package/src/val/MatchFuncVal.ts +0 -59
- package/src/val/MaybeFuncVal.ts +86 -0
- package/src/val/MoveFuncVal.ts +0 -20
- package/src/val/NilVal.ts +2 -36
- package/src/val/NomFuncVal.ts +200 -0
- package/src/val/NumberVal.ts +0 -16
- package/src/val/OpBaseVal.ts +4 -17
- package/src/val/PackFuncVal.ts +0 -63
- package/src/val/PathFuncVal.ts +0 -32
- package/src/val/PathVal.ts +0 -66
- package/src/val/PlaceVal.ts +0 -45
- package/src/val/PlusOpVal.ts +18 -75
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +0 -179
- package/src/val/RecurseVal.ts +0 -81
- package/src/val/RefVal.ts +1 -285
- package/src/val/ReferFuncVal.ts +0 -255
- package/src/val/ScalarKindVal.ts +0 -50
- package/src/val/ScalarVal.ts +0 -12
- package/src/val/StrFuncVal.ts +0 -44
- package/src/val/SuperFuncVal.ts +0 -42
- package/src/val/TopVal.ts +0 -1
- package/src/val/TranslateFuncVal.ts +132 -0
- package/src/val/UpperFuncVal.ts +12 -7
- package/src/val/Val.ts +3 -192
- package/src/val/VarVal.ts +0 -15
- package/src/val/arith.ts +0 -92
- package/src/val/caserange.ts +53 -0
- package/src/val/members.ts +0 -23
- package/src/val/numcmp.ts +1 -27
- package/src/val/numkind.ts +0 -149
- package/src/val/valutil.ts +0 -16
- package/src/vet.ts +209 -504
- package/src/view.ts +0 -507
- package/src/walk.ts +0 -41
- package/dist/std.d.ts +0 -3
- package/dist/std.js +0 -637
- package/dist/std.js.map +0 -1
- package/dist/val/FormFuncVal.js +0 -55
- package/dist/val/FormFuncVal.js.map +0 -1
- package/src/std.ts +0 -648
- package/src/val/FormFuncVal.ts +0 -119
package/src/val/EachFuncVal.ts
CHANGED
|
@@ -1,26 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
|
-
// GENERATION: `each(data, tmpl)` (G8 phase 1,
|
|
4
|
-
// docs/capability-review/g8-generation.md). One element of the result
|
|
5
|
-
// list per child of `data`, each of them that child met with `tmpl`.
|
|
6
|
-
// Written with one argument, `each(m)` is a map's children as a list.
|
|
7
|
-
//
|
|
8
|
-
// ports: {http: 80, https: 443}
|
|
9
|
-
// open: each($.ports, integer) -> [80, 443]
|
|
10
|
-
//
|
|
11
|
-
// ORDER IS FIXED, and fixed the way canon already fixes it: source
|
|
12
|
-
// order for a list, sorted-key order for a map (`cmpCodePoint`, the
|
|
13
|
-
// comparator `MapVal.canon` and the Go port's marshalling use). A
|
|
14
|
-
// generated list whose order depended on insertion history would differ
|
|
15
|
-
// between two runs of the same document, and between the two ports --
|
|
16
|
-
// the one thing the shared spec exists to prevent.
|
|
17
|
-
//
|
|
18
|
-
// The element is the source child CLONED, not shared: it is a second
|
|
19
|
-
// position holding that value, and a position is where path-dependent
|
|
20
|
-
// content resolves. What the clone keeps is the identity, if the child
|
|
21
|
-
// carries one (G4 phase 1) -- a listed entity is still that entity, and
|
|
22
|
-
// the merge that follows is the point.
|
|
23
|
-
|
|
24
3
|
import type {
|
|
25
4
|
Val,
|
|
26
5
|
ValSpec,
|
|
@@ -30,7 +9,6 @@ import {
|
|
|
30
9
|
AontuContext,
|
|
31
10
|
} from '../ctx'
|
|
32
11
|
|
|
33
|
-
import { unite } from '../unify'
|
|
34
12
|
import { makeNilErr } from '../err'
|
|
35
13
|
import { ListVal } from './ListVal'
|
|
36
14
|
import { FuncBaseVal } from './FuncBaseVal'
|
|
@@ -39,19 +17,11 @@ import { fillPlace } from './PlaceVal'
|
|
|
39
17
|
import { memberVals } from './members'
|
|
40
18
|
|
|
41
19
|
|
|
42
|
-
// The members a data bag holds, in the order the result must carry
|
|
43
|
-
// them -- what generation would emit (./members.ts, BUGS.md §79) --
|
|
44
|
-
// or the code naming what is wrong with the argument.
|
|
45
|
-
function dataValues(data: Val | undefined, ctx: AontuContext): Val[] | string {
|
|
46
|
-
const vals = memberVals(data, ctx)
|
|
47
|
-
return undefined === vals ? 'each_data' : vals
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
20
|
class EachFuncVal extends FuncBaseVal {
|
|
52
21
|
isEachFunc = true
|
|
53
22
|
|
|
54
|
-
// THE STAGING RULE, for the reason given in PackFuncVal
|
|
23
|
+
// THE STAGING RULE, for the reason given in PackFuncVal: the data
|
|
24
|
+
// is not settled merely by being `done` once.
|
|
55
25
|
staged = true
|
|
56
26
|
|
|
57
27
|
constructor(
|
|
@@ -62,7 +32,6 @@ class EachFuncVal extends FuncBaseVal {
|
|
|
62
32
|
}
|
|
63
33
|
|
|
64
34
|
|
|
65
|
-
|
|
66
35
|
funcname() {
|
|
67
36
|
return 'each'
|
|
68
37
|
}
|
|
@@ -76,8 +45,7 @@ class EachFuncVal extends FuncBaseVal {
|
|
|
76
45
|
|
|
77
46
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
78
47
|
// ONE argument is driven: the data. The template is not (see
|
|
79
|
-
// prepare above)
|
|
80
|
-
// settled -- the other half of "ready to fire".
|
|
48
|
+
// prepare above).
|
|
81
49
|
if (!this.stagedReady(peer, ctx, 1)) {
|
|
82
50
|
return this.residuate(peer, ctx)
|
|
83
51
|
}
|
|
@@ -87,37 +55,28 @@ class EachFuncVal extends FuncBaseVal {
|
|
|
87
55
|
|
|
88
56
|
|
|
89
57
|
resolve(ctx: AontuContext, args: Val[]) {
|
|
90
|
-
const vals =
|
|
91
|
-
if (
|
|
92
|
-
return makeNilErr(ctx,
|
|
58
|
+
const vals = memberVals(args?.[0], ctx)
|
|
59
|
+
if (undefined === vals) {
|
|
60
|
+
return makeNilErr(ctx, 'each_data', this)
|
|
93
61
|
}
|
|
94
62
|
|
|
95
|
-
|
|
63
|
+
// Arity is checked at parse (funcArity), so the template is here.
|
|
64
|
+
const tmpl: Val = args[1]
|
|
96
65
|
const peg: Val[] = []
|
|
97
66
|
|
|
98
67
|
for (let i = 0; i < vals.length; i++) {
|
|
99
68
|
const elctx = ctx.descend(String(i))
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// `_` inside the template binds the source child (G8 phase 3),
|
|
104
|
-
// which for `each` is the element itself.
|
|
105
|
-
let inst: Val | undefined = undefined
|
|
106
|
-
if (undefined !== tmpl) {
|
|
107
|
-
inst = tmpl.clone(elctx, { dup: true })
|
|
108
|
-
repathInstance(inst, inst.path)
|
|
109
|
-
}
|
|
110
|
-
peg.push(undefined === inst ? el :
|
|
111
|
-
unite(elctx, el, fillPlace(inst, vals[i], elctx), 'each'))
|
|
69
|
+
const inst = tmpl.clone(elctx, { dup: true })
|
|
70
|
+
repathInstance(inst, inst.path)
|
|
71
|
+
peg.push(fillPlace(inst, vals[i], elctx))
|
|
112
72
|
}
|
|
113
73
|
|
|
114
74
|
return new ListVal({ peg }, ctx)
|
|
115
75
|
}
|
|
116
76
|
|
|
117
|
-
} /* node:coverage ignore next
|
|
77
|
+
} /* node:coverage ignore next 6 */
|
|
118
78
|
|
|
119
79
|
|
|
120
80
|
export {
|
|
121
|
-
dataValues,
|
|
122
81
|
EachFuncVal,
|
|
123
82
|
}
|
package/src/val/EmitFuncVal.ts
CHANGED
|
@@ -1,86 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
|
-
// TRANSFORMATION: `emit(select, table)` (G9 phase 6,
|
|
4
|
-
// docs/design/EMIT.0.md). Apply-templates, with the dispatch in the
|
|
5
|
-
// engine and none of it in user space.
|
|
6
|
-
//
|
|
7
|
-
// emit($.services, [
|
|
8
|
-
// {match: {kind: sqs}, body: [`listen(` + .pin + `)`]}
|
|
9
|
-
// {match: {kind: http}, body: [`serve(` + .path + `)`]}
|
|
10
|
-
// ])
|
|
11
|
-
//
|
|
12
|
-
// For every node of `select`, in order, the first template whose
|
|
13
|
-
// `match` the node unifies with is taken and its `body` instantiated
|
|
14
|
-
// AGAINST THAT NODE. The result is one flat list.
|
|
15
|
-
//
|
|
16
|
-
// WHY THIS CANNOT BE WRITTEN IN THE DOCUMENT (EMIT.0.md, "What it
|
|
17
|
-
// takes"). A rule table held as a value cannot be dispatched against:
|
|
18
|
-
// a body referenced by path resolves its relative references AT THE
|
|
19
|
-
// DEFINITION SITE, and the positional resolution that does exist is a
|
|
20
|
-
// dot COUNT that does not survive being consumed by a second dispatch.
|
|
21
|
-
// The builtin instantiates a body at the node it matched -- a NAMED
|
|
22
|
-
// origin -- which is the whole capability.
|
|
23
|
-
//
|
|
24
|
-
// THE BODY'S RELATIVE REFERENCES ARE BOUND TO THE NODE. `.pin` inside
|
|
25
|
-
// a body is the matched node's `pin`, and `_` is the node itself, as
|
|
26
|
-
// it is in every other generator. The binding is done HERE rather than
|
|
27
|
-
// left to path resolution: a relative path is a COUNT taken wherever
|
|
28
|
-
// the value comes to rest, and the nodes of a computed selection
|
|
29
|
-
// (`filter(...)`) come to rest nowhere -- there is no position for a
|
|
30
|
-
// count to be taken from. An ABSOLUTE reference is untouched and still
|
|
31
|
-
// reads the document root.
|
|
32
|
-
//
|
|
33
|
-
// The binding stops at a nested generator's own binding argument
|
|
34
|
-
// (boundArgStart): a rule table nested in a body is the INNER emit's
|
|
35
|
-
// to bind, so `.x` inside it is the inner node. What crosses the
|
|
36
|
-
// boundary is the nested call's SELECTOR, which is argument 0 and is
|
|
37
|
-
// bound here -- the selector is the channel.
|
|
38
|
-
//
|
|
39
|
-
// THE RESULT IS FLAT, and that is a constraint rather than a
|
|
40
|
-
// convenience: the fragment algebra is flat because the nested
|
|
41
|
-
// spelling refuses even a valid instance in both ports, so a dispatch
|
|
42
|
-
// returning a tree would undo that ruling. A body element that is
|
|
43
|
-
// itself a list SPLICES, which is what makes a nested emit compose.
|
|
44
|
-
//
|
|
45
|
-
// A VALUE REACHES THE BODY THROUGH `replace`, NOT A DELIMITER
|
|
46
|
-
// (docs/design/TEMPLATE.0.md D3, D4; RENDER.0.md P6). A template may
|
|
47
|
-
// carry a `replace` map whose key is an exact string the body already
|
|
48
|
-
// holds as ordinary target text and whose value is evaluated against
|
|
49
|
-
// the matched node, and an `esc` naming the convention every value is
|
|
50
|
-
// escaped by -- the C/JSON escape when absent, `none` the one opt-out.
|
|
51
|
-
// Three rules: a single left-to-right scan of a literal line taking
|
|
52
|
-
// the longest key at each position; a substituted value is never
|
|
53
|
-
// re-scanned, so no value can introduce a key; and a template's
|
|
54
|
-
// replacements touch its own literal text only, never a result spliced
|
|
55
|
-
// in from a nested dispatch. Two checks run on the template before any
|
|
56
|
-
// node: a key inside another key (replace_overlap) and a key the body
|
|
57
|
-
// does not hold (replace_unused). There is no hole syntax, and that is
|
|
58
|
-
// the point: any inline delimiter is somebody's syntax.
|
|
59
|
-
//
|
|
60
|
-
// NO MATCH IS AN ERROR (`emit_none`). XSLT's built-in rule copies an
|
|
61
|
-
// unhandled node's string value into the result, which for code output
|
|
62
|
-
// means model data landing silently in the middle of a source file.
|
|
63
|
-
// That is the single worst default in the prior art and it is refused.
|
|
64
|
-
// An EMPTY selection, by contrast, emits nothing -- which is the whole
|
|
65
|
-
// conditional mechanism, and why no `when` directive exists.
|
|
66
|
-
//
|
|
67
|
-
// A NAMED TABLE IS A PLACEHELD `emit` (`%wire = emit(_, T)`). A table
|
|
68
|
-
// written at a document position is DRIVEN there, so its bodies'
|
|
69
|
-
// relative references resolve against wherever it sits and miss;
|
|
70
|
-
// nothing in the language holds a value unevaluated at such a
|
|
71
|
-
// position, and what does hold one is a CALL's template argument.
|
|
72
|
-
// `emit(.listen, %wire)` follows the reference and reads the table out
|
|
73
|
-
// of the placeheld call; `.listen & %wire` fills the hole. Both are
|
|
74
|
-
// the same dispatch, and it is what lets a rule set name ITSELF.
|
|
75
|
-
//
|
|
76
|
-
// TERMINATION IS THE SELECTION'S. Unlike `pack` and `each`, this one
|
|
77
|
-
// recurses -- a nested model walked into nested output is the
|
|
78
|
-
// capability the rule layer exists to add -- so the bound is not "it
|
|
79
|
-
// cannot call itself" but "each dispatch descends into a finite bag
|
|
80
|
-
// that already exists, and a selection that empties emits nothing". A
|
|
81
|
-
// rule set that walks into itself WITHOUT descending is charged to the
|
|
82
|
-
// depth budget and refused as `unify_cycle`, like any other runaway
|
|
83
|
-
// descent.
|
|
84
3
|
|
|
85
4
|
import type {
|
|
86
5
|
Val,
|
|
@@ -106,12 +25,6 @@ import { plusText } from './PlusOpVal'
|
|
|
106
25
|
import { bagMembers } from './members'
|
|
107
26
|
|
|
108
27
|
|
|
109
|
-
// One entry of the rule table: the pattern to try, the body to
|
|
110
|
-
// instantiate, and -- TEMPLATE.0.md D3 and D4 -- the `replace` map and
|
|
111
|
-
// the `esc` convention its values take, with the literal spots of the
|
|
112
|
-
// body the replacements are written into. A table is a LIST of these;
|
|
113
|
-
// a single template map is that list of one, told apart by kind,
|
|
114
|
-
// exactly as match() tells its patterns apart.
|
|
115
28
|
type Template = {
|
|
116
29
|
match: Val,
|
|
117
30
|
body: Val,
|
|
@@ -125,8 +38,8 @@ type Template = {
|
|
|
125
38
|
|
|
126
39
|
|
|
127
40
|
// One literal string of a body: element `i`, and within a map element
|
|
128
|
-
// the `
|
|
129
|
-
type LitSpot = { i: number,
|
|
41
|
+
// the `n` index or the `text` key, with the text itself.
|
|
42
|
+
type LitSpot = { i: number, n?: number, text?: boolean, s: string }
|
|
130
43
|
|
|
131
44
|
|
|
132
45
|
// What is wrong with a table, with the detail the message carries.
|
|
@@ -148,15 +61,6 @@ function isRefusal(x: any): x is Refusal {
|
|
|
148
61
|
function tableTemplates(table: Val | undefined): Template[] | Refusal {
|
|
149
62
|
const t: any = table
|
|
150
63
|
|
|
151
|
-
// A NAMED TABLE IS A PLACEHELD `emit`, and its table is the table.
|
|
152
|
-
// A table written at a document position is DRIVEN there -- a body's
|
|
153
|
-
// relative references resolve against wherever it sits and miss --
|
|
154
|
-
// so the position that holds one unevaluated is the one position the
|
|
155
|
-
// language already never drives: a call's template argument.
|
|
156
|
-
// `%wire = emit(_, [ … ])` is that position with the selection left
|
|
157
|
-
// open, and it reads as what it is, an apply-templates waiting for
|
|
158
|
-
// its nodes: `emit(.listen, %wire)` passes them, `.listen & %wire`
|
|
159
|
-
// fills the hole, and both are the same dispatch.
|
|
160
64
|
if (true === t?.isEmitFunc) {
|
|
161
65
|
return tableTemplates(t.peg[1])
|
|
162
66
|
}
|
|
@@ -186,12 +90,6 @@ function tableTemplates(table: Val | undefined): Template[] | Refusal {
|
|
|
186
90
|
}
|
|
187
91
|
|
|
188
92
|
|
|
189
|
-
// One rule. Both keys are required: a template with no pattern would
|
|
190
|
-
// match everything by accident, and one with no body would emit
|
|
191
|
-
// nothing while claiming a node. The two optional keys -- a `replace`
|
|
192
|
-
// map and an `esc` naming the convention its values are escaped by,
|
|
193
|
-
// `none` the one opt-out -- are the template's shape too, and D3's two
|
|
194
|
-
// static checks run here, on the template alone, before any node.
|
|
195
93
|
function oneTemplate(m: any, idx: number): Template | Refusal {
|
|
196
94
|
const match: Val = m.peg.match
|
|
197
95
|
const body: any = m.peg.body
|
|
@@ -235,12 +133,6 @@ function textOf(v: any): string | undefined {
|
|
|
235
133
|
}
|
|
236
134
|
|
|
237
135
|
|
|
238
|
-
// The literal strings of a body -- a string element, and the strings
|
|
239
|
-
// written directly in a map element's `of` list or `text` -- which are
|
|
240
|
-
// the text the template wrote. A string an expression or a nested
|
|
241
|
-
// dispatch computes is not one: D3's third rule (a spliced result is
|
|
242
|
-
// finished) and its second (a substituted value is never re-scanned)
|
|
243
|
-
// both follow from substituting at these spots and nowhere else.
|
|
244
136
|
function literalSpots(elems: Val[]): LitSpot[] {
|
|
245
137
|
const out: LitSpot[] = []
|
|
246
138
|
elems.forEach((el: any, i: number) => {
|
|
@@ -252,12 +144,12 @@ function literalSpots(elems: Val[]): LitSpot[] {
|
|
|
252
144
|
if (true !== el?.isMap) {
|
|
253
145
|
return
|
|
254
146
|
}
|
|
255
|
-
const
|
|
256
|
-
if (true ===
|
|
257
|
-
(
|
|
147
|
+
const chunks: any = el.peg.n
|
|
148
|
+
if (true === chunks?.isList) {
|
|
149
|
+
(chunks.peg as any[]).forEach((p: any, j: number) => {
|
|
258
150
|
const ps = textOf(p)
|
|
259
151
|
if (undefined !== ps) {
|
|
260
|
-
out.push({ i,
|
|
152
|
+
out.push({ i, n: j, s: ps })
|
|
261
153
|
}
|
|
262
154
|
})
|
|
263
155
|
}
|
|
@@ -270,11 +162,6 @@ function literalSpots(elems: Val[]): LitSpot[] {
|
|
|
270
162
|
}
|
|
271
163
|
|
|
272
164
|
|
|
273
|
-
// D3's two static checks, on the template alone and before any node:
|
|
274
|
-
// a key inside another is ambiguous whatever the order
|
|
275
|
-
// (replace_overlap), and a key no literal holds means the template
|
|
276
|
-
// drifted from its map (replace_unused). Keys are visited in code
|
|
277
|
-
// point order, so both ports name the same pair.
|
|
278
165
|
function checkReplace(keys: string[], lits: LitSpot[]): Refusal | undefined {
|
|
279
166
|
const sorted = [...keys].sort(cmpCodePoint)
|
|
280
167
|
for (const a of sorted) {
|
|
@@ -293,10 +180,6 @@ function checkReplace(keys: string[], lits: LitSpot[]): Refusal | undefined {
|
|
|
293
180
|
}
|
|
294
181
|
|
|
295
182
|
|
|
296
|
-
// D3's first two rules as one scan: at each position the longest key
|
|
297
|
-
// that matches is taken and its value written out whole, and the scan
|
|
298
|
-
// moves past the KEY -- the value is never looked at again, so no
|
|
299
|
-
// value can introduce a key.
|
|
300
183
|
function substitute(text: string, pairs: Pair[]): string {
|
|
301
184
|
let out = ''
|
|
302
185
|
let i = 0
|
|
@@ -315,11 +198,6 @@ function substitute(text: string, pairs: Pair[]): string {
|
|
|
315
198
|
}
|
|
316
199
|
|
|
317
200
|
|
|
318
|
-
// The instance with the template's literal text at element `i`
|
|
319
|
-
// rewritten through the pairs -- on the fresh instance, where the
|
|
320
|
-
// structure is exactly the template's, and before any binding, so a
|
|
321
|
-
// value written in is never scanned again and a spliced result is
|
|
322
|
-
// never touched.
|
|
323
201
|
function substituted(
|
|
324
202
|
inst: Val, i: number, lits: LitSpot[], pairs: Pair[], ctx: AontuContext
|
|
325
203
|
): Val {
|
|
@@ -328,8 +206,8 @@ function substituted(
|
|
|
328
206
|
continue
|
|
329
207
|
}
|
|
330
208
|
const sv = new StringVal({ peg: substitute(l.s, pairs) }, ctx)
|
|
331
|
-
if (undefined !== l.
|
|
332
|
-
(inst as any).peg.
|
|
209
|
+
if (undefined !== l.n) {
|
|
210
|
+
(inst as any).peg.n.peg[l.n] = sv
|
|
333
211
|
}
|
|
334
212
|
else if (true === l.text) {
|
|
335
213
|
(inst as any).peg.text = sv
|
|
@@ -374,14 +252,6 @@ function bindNode(v: any, node: Val, ctx: AontuContext, fail: Fail): Val {
|
|
|
374
252
|
return v
|
|
375
253
|
}
|
|
376
254
|
const out = found.clone(ctx)
|
|
377
|
-
// A RELATIVE REFERENCE IS A READ TOO (RENDER.0.md P7), and the one
|
|
378
|
-
// read no reference resolution sees: the binding answers it here,
|
|
379
|
-
// from the matched node, rather than letting a path resolve at a
|
|
380
|
-
// position the body never occupies. Without this a nested rule set
|
|
381
|
-
// whose selection is `.handlers` reported its nodes at the address
|
|
382
|
-
// they came to rest, which is in the OUTPUT. A node carries an
|
|
383
|
-
// address only under an instrumented run, which is what makes the
|
|
384
|
-
// second test the whole guard.
|
|
385
255
|
if (null == (out as any).origin && null != (node as any).origin) {
|
|
386
256
|
; (out as any).origin = (node as any).origin +
|
|
387
257
|
(v.peg as string[]).map((seg: string) => '.' + seg).join('')
|
|
@@ -430,12 +300,6 @@ function bindNode(v: any, node: Val, ctx: AontuContext, fail: Fail): Val {
|
|
|
430
300
|
}
|
|
431
301
|
|
|
432
302
|
|
|
433
|
-
// The field of `node` a reference names, or undefined when it names
|
|
434
|
-
// none. Only a chain of plain NAMES is a field: a parent step has no
|
|
435
|
-
// answer at a node that is an origin rather than a position, and a
|
|
436
|
-
// variable segment is not a name until something resolves it -- both
|
|
437
|
-
// are refused here rather than left to resolve somewhere else, which
|
|
438
|
-
// is the failure mode the binding exists to remove.
|
|
439
303
|
function nodeField(ref: any, node: Val): Val | undefined {
|
|
440
304
|
let cur: any = node
|
|
441
305
|
for (const seg of ref.peg as any[]) {
|
|
@@ -455,21 +319,6 @@ function nodeField(ref: any, node: Val): Val | undefined {
|
|
|
455
319
|
}
|
|
456
320
|
|
|
457
321
|
|
|
458
|
-
// The address of one matched node: its own read address when it has
|
|
459
|
-
// one, else the SELECTION's read address and the node's key under it
|
|
460
|
-
// -- a selection is read once and walked, so its members carry no read
|
|
461
|
-
// of their own.
|
|
462
|
-
//
|
|
463
|
-
// A COMPUTED SELECTION HAS NO ADDRESS, AND THE TRACE SAYS SO: an empty
|
|
464
|
-
// node. `filter(...)` builds a bag no path in the document names, and
|
|
465
|
-
// the only other thing to report is where the bag came to REST -- a
|
|
466
|
-
// position inside a template instance, which is not in the document,
|
|
467
|
-
// and which the two ports number differently. Publishing that would
|
|
468
|
-
// have made the trace a parity break as well as a fiction. The rule
|
|
469
|
-
// address answers the same way: `<table>#<index>` for a table a
|
|
470
|
-
// reference reached, and `#<index>` alone for one written inline at the
|
|
471
|
-
// call site, which has no address of its own. `#` is in no path, so a
|
|
472
|
-
// rule's address can never be read as one.
|
|
473
322
|
function nodeAddr(sel: string | undefined, key: string, node: any): string {
|
|
474
323
|
if (null != node.origin) {
|
|
475
324
|
return node.origin
|
|
@@ -534,22 +383,11 @@ class EmitFuncVal extends FuncBaseVal {
|
|
|
534
383
|
|
|
535
384
|
|
|
536
385
|
resolve(ctx: AontuContext, args: Val[]) {
|
|
537
|
-
// THE MEMBERS WITH THEIR KEYS, read through the one helper every
|
|
538
|
-
// fold reads a bag by (./members.ts): source order for a list,
|
|
539
|
-
// sorted-key order for a map, a hidden child and an unfilled
|
|
540
|
-
// optional left out. The KEY is what the trace addresses a node by
|
|
541
|
-
// -- it is the node's key IN THE SELECTION, which is the only
|
|
542
|
-
// thing a walk of a computed bag knows about where a node sits.
|
|
543
386
|
const nodes = bagMembers(args?.[0], ctx)
|
|
544
387
|
if (undefined === nodes) {
|
|
545
388
|
return makeNilErr(ctx, 'emit_data', this)
|
|
546
389
|
}
|
|
547
390
|
|
|
548
|
-
// A NAMED TABLE IS REACHED BY REFERENCE, and the reference -- not
|
|
549
|
-
// the table -- is what is followed. Followed HERE rather than in
|
|
550
|
-
// the staged drive, which waits for a SETTLED target: a table is a
|
|
551
|
-
// template, a template holding a hole never settles, and waiting
|
|
552
|
-
// for one would mean the dispatch never fires.
|
|
553
391
|
let table: any = args?.[1]
|
|
554
392
|
if (true === table?.isRef) {
|
|
555
393
|
table = table.unify(top(), ctx)
|
|
@@ -560,10 +398,6 @@ class EmitFuncVal extends FuncBaseVal {
|
|
|
560
398
|
return this.refuse(ctx, templates)
|
|
561
399
|
}
|
|
562
400
|
|
|
563
|
-
// THE TRACE'S TWO ADDRESSES (RENDER.0.md D11, P7), computed once
|
|
564
|
-
// per dispatch and only when the run is instrumented: the table's
|
|
565
|
-
// own, which every rule of it is numbered under, and the
|
|
566
|
-
// selection's, which every node of it is keyed under.
|
|
567
401
|
const rec = undefined !== ctx.reads
|
|
568
402
|
const tableAddr = rec ? ((table as any)?.origin ?? '') : ''
|
|
569
403
|
const selAddr = rec ? (args?.[0] as any)?.origin : undefined
|
|
@@ -582,11 +416,6 @@ class EmitFuncVal extends FuncBaseVal {
|
|
|
582
416
|
const fail: Fail = {}
|
|
583
417
|
let mark: EmitOrigin | undefined = undefined
|
|
584
418
|
if (rec) {
|
|
585
|
-
// THE NODE KEEPS ITS ADDRESS (P7). A body passes the node on
|
|
586
|
-
// through `_`, and a nested rule set dispatching over it can
|
|
587
|
-
// then say where it came from -- otherwise the node arrives as
|
|
588
|
-
// an element of a list the body wrote, and the only address
|
|
589
|
-
// left is where that list came to rest.
|
|
590
419
|
const naddr = nodeAddr(selAddr, member.key, node)
|
|
591
420
|
if ('' !== naddr && null == (node as any).origin) {
|
|
592
421
|
; (node as any).origin = naddr
|
|
@@ -643,14 +472,6 @@ class EmitFuncVal extends FuncBaseVal {
|
|
|
643
472
|
}
|
|
644
473
|
|
|
645
474
|
|
|
646
|
-
// The replacement pairs for one node: the template's `replace` map
|
|
647
|
-
// instantiated at the node -- bound, filled and driven as a body is
|
|
648
|
-
// -- each value as text by the one number-to-text rule (`plusText`,
|
|
649
|
-
// the rule `+` and `join` share), escaped by the template's
|
|
650
|
-
// convention unless that is `none`, and sorted longest key first so
|
|
651
|
-
// the scan takes the longest match at every position (D3's first
|
|
652
|
-
// rule). A value that is not text, or has not settled, is
|
|
653
|
-
// replace_value.
|
|
654
475
|
replacements(ctx: AontuContext, node: Val, tmpl: Template, fail: Fail): Pair[] | undefined {
|
|
655
476
|
if (undefined === tmpl.replace) {
|
|
656
477
|
return undefined
|
|
@@ -676,13 +497,6 @@ class EmitFuncVal extends FuncBaseVal {
|
|
|
676
497
|
}
|
|
677
498
|
|
|
678
499
|
|
|
679
|
-
// Instantiate one body at the node and SPLICE its pieces into the
|
|
680
|
-
// output. A full instance to the leaves (`dup`, ADR-005), because a
|
|
681
|
-
// bare clone shares the inner structure of any call in the body and
|
|
682
|
-
// the first node's resolution would answer for every node; the
|
|
683
|
-
// template's replacements written into the instance's literal text;
|
|
684
|
-
// then the two bindings, relative references and the hole, both to
|
|
685
|
-
// the node.
|
|
686
500
|
instantiate(ctx: AontuContext, node: Val, tmpl: Template,
|
|
687
501
|
out: Val[], fail: Fail, mark?: EmitOrigin): void {
|
|
688
502
|
const pairs = this.replacements(ctx, node, tmpl, fail)
|
|
@@ -700,24 +514,10 @@ class EmitFuncVal extends FuncBaseVal {
|
|
|
700
514
|
}
|
|
701
515
|
let piece = fillPlace(bindNode(inst, node, elctx, fail), node, elctx)
|
|
702
516
|
|
|
703
|
-
// A NESTED DISPATCH IS DRIVEN HERE, not left for the next pass.
|
|
704
|
-
// Its selection is bound and the model has settled, so it has
|
|
705
|
-
// everything it needs -- and it must answer NOW, because what
|
|
706
|
-
// makes the result flat is splicing its pieces into this one.
|
|
707
|
-
// Left standing, a nested `emit` resolved a pass later, as a
|
|
708
|
-
// list INSIDE the list, and the fragment algebra is flat.
|
|
709
|
-
// Through `unite` rather than by hand: a rule set that walks
|
|
710
|
-
// into itself for ever is charged to the depth budget and
|
|
711
|
-
// refused as `unify_cycle`, like any other runaway descent.
|
|
712
517
|
if (!piece.done) {
|
|
713
518
|
piece = unite(elctx, piece, top(), 'emit')
|
|
714
519
|
}
|
|
715
520
|
|
|
716
|
-
// THE INNERMOST DISPATCH OWNS THE PIECE (P7). A body element
|
|
717
|
-
// that is a nested rule set has already stamped what it emitted,
|
|
718
|
-
// and those pieces are spliced into this result here: the rule
|
|
719
|
-
// that WROTE a line is the one the trace names, so a stamp is
|
|
720
|
-
// written only where there is none.
|
|
721
521
|
const at = out.length
|
|
722
522
|
splice(piece, out)
|
|
723
523
|
if (undefined !== mark) {
|
package/src/val/ExpectVal.ts
CHANGED
|
@@ -34,22 +34,6 @@ class ExpectVal extends FeatureVal {
|
|
|
34
34
|
parent?: Val
|
|
35
35
|
key?: string
|
|
36
36
|
|
|
37
|
-
// An expectation canons as THE EXPECTATION ITSELF -- the peg the peer
|
|
38
|
-
// must satisfy. Val.canon's default was the empty string, which
|
|
39
|
-
// rendered a key with no value (`{"r":}`): text that is not a document
|
|
40
|
-
// and could not be reparsed, breaking canon's round-trip contract in
|
|
41
|
-
// both engines (issue #43).
|
|
42
|
-
//
|
|
43
|
-
// Not `top`, which was the first fix here and was wrong. An ExpectVal
|
|
44
|
-
// is created for EVERY peer-introduced non-generable key, not just for
|
|
45
|
-
// `&:` spread children -- `m:{x:1} m:{y:string}` makes one at `y` with
|
|
46
|
-
// no spread in sight -- so rendering `top` erased the `string` and the
|
|
47
|
-
// canon reparsed into a document that accepts values the original
|
|
48
|
-
// rejects. A canon that silently drops a constraint is worse than one
|
|
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.
|
|
53
37
|
get canon() { return this.peg.canon }
|
|
54
38
|
|
|
55
39
|
constructor(
|
|
@@ -59,41 +43,15 @@ class ExpectVal extends FeatureVal {
|
|
|
59
43
|
super(spec, ctx)
|
|
60
44
|
}
|
|
61
45
|
|
|
62
|
-
// PURE, deliberately (the unequal-spread crosswire, BUGS.md §6-§7).
|
|
63
|
-
// The old body accumulated `this.peer` IN PLACE, which was invisible
|
|
64
|
-
// while an expectation only ever lived at one destination -- but the
|
|
65
|
-
// spread-combination meet (MapVal.unify's 'map-self' unite) bakes an
|
|
66
|
-
// ExpectVal INTO the combined template, and a path-independent
|
|
67
|
-
// template is SHARED across every destination (spreadClone tier 1).
|
|
68
|
-
// One stateful node in a shared template unified each sibling's own
|
|
69
|
-
// data with the next sibling's ($.w.y.r: "Cannot unify value: 6 with
|
|
70
|
-
// value: 5", both values sibling data). An expectation now answers
|
|
71
|
-
// with a NEW node when it must keep accumulated state, so a shared
|
|
72
|
-
// template's expect stays exactly what was written.
|
|
73
46
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
74
47
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Expect', this, peer)
|
|
75
48
|
|
|
76
49
|
let out: Val = this
|
|
77
50
|
|
|
78
51
|
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
52
|
const peeru =
|
|
88
53
|
unite(te ? ctx.clone({ explain: ec(te, 'EXPECT') }) : ctx, peer, this.peg, 'expect-self')
|
|
89
54
|
|
|
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.
|
|
97
55
|
const acc = undefined === this.peer ? peer :
|
|
98
56
|
unite(te ? ctx.clone({ explain: ec(te, 'PEER') }) : ctx, this.peer, peer, 'expect-peer')
|
|
99
57
|
|
|
@@ -101,26 +59,6 @@ class ExpectVal extends FeatureVal {
|
|
|
101
59
|
out = peeru
|
|
102
60
|
}
|
|
103
61
|
else {
|
|
104
|
-
// Still an expectation: carry the accumulated peer forward in a
|
|
105
|
-
// fresh node stored at THIS destination by the caller, leaving
|
|
106
|
-
// `this` -- possibly a shared template's child -- untouched.
|
|
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
62
|
const e = new ExpectVal({ peg: peeru }, ctx)
|
|
125
63
|
e.key = this.key
|
|
126
64
|
e.parent = this.parent
|
package/src/val/FilterFuncVal.ts
CHANGED
|
@@ -1,35 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
|
-
// GENERATION: `filter(data, cond)` (G8 phase 2,
|
|
4
|
-
// docs/capability-review/g8-generation.md). The children of `data`
|
|
5
|
-
// that unify with `cond`, keys preserved for a map and order for a
|
|
6
|
-
// list; the children that do not are DROPPED, not refused.
|
|
7
|
-
//
|
|
8
|
-
// debugged: filter($.services, {debug: true})
|
|
9
|
-
// sidecars: pack($.debugged, {image: "acme/debug:1.0"})
|
|
10
|
-
//
|
|
11
|
-
// A CHILD IS KEPT WHEN THE CONDITION CHANGES NOTHING: the meet
|
|
12
|
-
// succeeds AND its answer is the child itself, which is to say the
|
|
13
|
-
// child ALREADY satisfies the condition. Mere unifiability is not the
|
|
14
|
-
// test, and cannot be: a map is open, so `{p:2}` unifies with
|
|
15
|
-
// `{debug:true}` perfectly well by GAINING the key -- and a filter
|
|
16
|
-
// that keeps everything that could be made to match keeps everything.
|
|
17
|
-
// The design named unifiability; its own example
|
|
18
|
-
// (`filter($.services, {debug:true})`) is unsatisfiable under it.
|
|
19
|
-
//
|
|
20
|
-
// There is no predicate language here and there will not be one:
|
|
21
|
-
// `cond` is an ordinary Aontu value, so the constraint atoms compose
|
|
22
|
-
// with it for free (`filter($.deploy, {replicas: min(3)})`), and a
|
|
23
|
-
// document that can filter can be read by anything that can read a
|
|
24
|
-
// document.
|
|
25
|
-
//
|
|
26
|
-
// A FAILED CHILD IS AN ANSWER, not an error. The meet runs in TRIAL
|
|
27
|
-
// MODE -- the mechanism disjunction already uses to try each member
|
|
28
|
-
// against a peer (trialUnify in FuncBaseVal) -- so a child that does
|
|
29
|
-
// not match costs nothing and reports nothing.
|
|
30
|
-
//
|
|
31
|
-
// TOTALITY. `filter` iterates a finite, settled bag and cannot call
|
|
32
|
-
// itself, exactly as `pack` and `each` cannot.
|
|
33
3
|
|
|
34
4
|
import type {
|
|
35
5
|
Val,
|
|
@@ -72,15 +42,6 @@ class FilterFuncVal extends FuncBaseVal {
|
|
|
72
42
|
}
|
|
73
43
|
|
|
74
44
|
|
|
75
|
-
// Neither argument is driven by the base: `unify` below drives the
|
|
76
|
-
// DATA by hand, because a staged func must advance the argument it
|
|
77
|
-
// is waiting on every pass rather than only on the one it fires.
|
|
78
|
-
//
|
|
79
|
-
// The CONDITION is not driven at all, and that is deliberate: it is
|
|
80
|
-
// a template, tested against each child at that child's position,
|
|
81
|
-
// so it may hold a `_` (G8 phase 3, the child it is being tested
|
|
82
|
-
// against) or a relative reference — neither of which has an answer
|
|
83
|
-
// at the call site. Driving it there would freeze both.
|
|
84
45
|
prepare(_ctx: AontuContext, _args: Val[]) {
|
|
85
46
|
return null
|
|
86
47
|
}
|
|
@@ -99,19 +60,7 @@ class FilterFuncVal extends FuncBaseVal {
|
|
|
99
60
|
const data: any = args[0]
|
|
100
61
|
const cond: Val = args[1]
|
|
101
62
|
|
|
102
|
-
// The trial is run against CLONES: `unite` refines a bag in place,
|
|
103
|
-
// and a child that failed the test must reach the result -- when
|
|
104
|
-
// it passes -- exactly as it was written.
|
|
105
|
-
//
|
|
106
|
-
// Canon is the comparison because canon is what "the same value"
|
|
107
|
-
// MEANS in this language: it is the form the two ports agree on,
|
|
108
|
-
// the form `aontu diff` compares, and the form a hash is taken of.
|
|
109
63
|
const keeps = (child: Val, kctx: AontuContext): boolean => {
|
|
110
|
-
// `_` inside the condition binds the child being tested (G8
|
|
111
|
-
// phase 3), so a condition can be about the child as a whole
|
|
112
|
-
// rather than only about its shape. The condition is cloned as
|
|
113
|
-
// a FULL instance per trial (`dup`, ADR-005) — a bare clone
|
|
114
|
-
// shares call/pref innards across trials (see PackFuncVal).
|
|
115
64
|
const inst = cond.clone(kctx, { dup: true })
|
|
116
65
|
repathInstance(inst, inst.path)
|
|
117
66
|
const test = fillPlace(inst, child, kctx)
|
|
@@ -136,10 +85,6 @@ class FilterFuncVal extends FuncBaseVal {
|
|
|
136
85
|
if (true === data?.isList) {
|
|
137
86
|
const peg: Val[] = []
|
|
138
87
|
for (const { val: el } of bagMembers(data, ctx) as Member[]) {
|
|
139
|
-
// The element context is the position it will END UP at, which
|
|
140
|
-
// is its index in the RESULT: dropping the third of five moves
|
|
141
|
-
// the fourth up, and a kept element must be pathed where it
|
|
142
|
-
// lands rather than where it came from.
|
|
143
88
|
const ectx = ctx.descend(String(peg.length))
|
|
144
89
|
if (keeps(el, ectx)) {
|
|
145
90
|
peg.push(el.clone(ectx))
|