aontu 0.52.1 → 0.54.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 +15 -3
- package/dist/aontu.js +126 -5
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +45 -1
- package/dist/cli.js +2845 -69
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +18 -0
- package/dist/ctx.js +44 -0
- package/dist/ctx.js.map +1 -1
- package/dist/diff.d.ts +22 -0
- package/dist/diff.js +141 -0
- package/dist/diff.js.map +1 -0
- package/dist/err.d.ts +3 -1
- package/dist/err.js +45 -8
- package/dist/err.js.map +1 -1
- package/dist/graph.d.ts +13 -0
- package/dist/graph.js +110 -0
- package/dist/graph.js.map +1 -0
- package/dist/hcanon.d.ts +3 -0
- package/dist/hcanon.js +145 -0
- package/dist/hcanon.js.map +1 -0
- package/dist/hints.js +235 -8
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.d.ts +20 -0
- package/dist/jsonschema.js +425 -0
- package/dist/jsonschema.js.map +1 -0
- package/dist/lang.js +955 -110
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +9 -2
- package/dist/lsp.js +343 -48
- 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 +941 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mod-tool.d.ts +58 -0
- package/dist/mod-tool.js +532 -0
- package/dist/mod-tool.js.map +1 -0
- package/dist/mod.d.ts +35 -0
- package/dist/mod.js +345 -0
- package/dist/mod.js.map +1 -0
- package/dist/patch.d.ts +49 -0
- package/dist/patch.js +506 -0
- package/dist/patch.js.map +1 -0
- package/dist/provenance.d.ts +41 -0
- package/dist/provenance.js +336 -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 +15 -0
- package/dist/reach.js +168 -0
- package/dist/reach.js.map +1 -0
- package/dist/relation.d.ts +23 -0
- package/dist/relation.js +230 -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/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/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 +129 -0
- package/dist/std.js.map +1 -0
- package/dist/subsume.d.ts +39 -0
- package/dist/subsume.js +573 -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 +234 -38
- package/dist/unify.js.map +1 -1
- package/dist/utility.d.ts +8 -1
- package/dist/utility.js +68 -1
- package/dist/utility.js.map +1 -1
- package/dist/val/AggFuncVal.d.ts +44 -0
- package/dist/val/AggFuncVal.js +364 -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 +7 -0
- package/dist/val/BagVal.js +150 -11
- 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 +523 -45
- 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.d.ts +1 -2
- 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.d.ts +1 -2
- package/dist/val/DisjunctVal.js +269 -53
- 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 +62 -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 +7 -1
- package/dist/val/FuncBaseVal.js +183 -2
- 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/HideFuncVal.js.map +1 -1
- package/dist/val/JunctionVal.js +24 -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 +94 -14
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.d.ts +1 -0
- package/dist/val/MapVal.js +146 -14
- 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.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/PlaceVal.d.ts +13 -0
- package/dist/val/PlaceVal.js +131 -0
- package/dist/val/PlaceVal.js.map +1 -0
- package/dist/val/PlusOpVal.d.ts +2 -1
- package/dist/val/PlusOpVal.js +61 -37
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +4 -2
- package/dist/val/PrefVal.js +223 -41
- 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 +3 -2
- package/dist/val/RefVal.js +181 -66
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.d.ts +59 -0
- package/dist/val/ReferFuncVal.js +604 -0
- package/dist/val/ReferFuncVal.js.map +1 -0
- package/dist/val/ScalarKindVal.d.ts +4 -3
- package/dist/val/ScalarKindVal.js +12 -12
- 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/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 +7 -1
- package/dist/val/Val.js +170 -2
- 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 +173 -0
- package/dist/val/arith.js.map +1 -0
- package/dist/vet.d.ts +45 -0
- package/dist/vet.js +802 -0
- package/dist/vet.js.map +1 -0
- package/dist/view.d.ts +85 -0
- package/dist/view.js +1948 -0
- package/dist/view.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 +138 -0
- package/grammar/aontu.lark +118 -0
- package/grammar/aontu.tmLanguage.json +184 -0
- package/package.json +30 -8
- package/skill/SKILL.md +37 -0
- package/skill/error-codes.md +62 -0
- package/skill/examples.md +99 -0
- package/skill/grammar-card.md +56 -0
- package/src/agentsmd.ts +135 -0
- package/src/aontu.ts +166 -5
- package/src/cli.ts +3324 -72
- package/src/ctx.ts +93 -1
- package/src/diff.ts +198 -0
- package/src/err.ts +50 -8
- package/src/graph.ts +185 -0
- package/src/hcanon.ts +167 -0
- package/src/hints.ts +291 -8
- package/src/jsonschema.ts +552 -0
- package/src/lang.ts +1049 -110
- package/src/lsp.ts +351 -49
- package/src/mcp-server.ts +187 -0
- package/src/mcp.ts +1130 -0
- package/src/mod-tool.ts +718 -0
- package/src/mod.ts +453 -0
- package/src/patch.ts +628 -0
- package/src/provenance.ts +437 -0
- package/src/query.ts +381 -0
- package/src/reach.ts +213 -0
- package/src/relation.ts +298 -0
- package/src/report-sarif.ts +137 -0
- package/src/sig.ts +345 -0
- package/src/sigdecl.ts +11 -0
- package/src/siggate.ts +144 -0
- package/src/site.ts +36 -1
- package/src/std.ts +131 -0
- package/src/subsume.ts +739 -0
- package/src/trim.ts +195 -0
- package/src/tsconfig.json +10 -4
- package/src/type.ts +51 -2
- package/src/unify.ts +253 -38
- package/src/utility.ts +79 -1
- package/src/val/AggFuncVal.ts +546 -0
- package/src/val/ArithFuncVal.ts +108 -0
- package/src/val/BagVal.ts +158 -12
- package/src/val/CloseFuncVal.ts +9 -1
- package/src/val/ConjunctVal.ts +20 -0
- package/src/val/ConstraintVal.ts +576 -48
- package/src/val/ContainerKindVal.ts +158 -0
- package/src/val/CopyFuncVal.ts +0 -1
- package/src/val/Decimal.ts +15 -0
- package/src/val/DeprecateFuncVal.ts +84 -0
- package/src/val/DisjunctVal.ts +282 -59
- package/src/val/EachFuncVal.ts +133 -0
- package/src/val/ExpectVal.ts +65 -8
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FilterFuncVal.ts +154 -0
- package/src/val/FuncBaseVal.ts +206 -2
- package/src/val/GraphAtomVal.ts +264 -0
- package/src/val/HideFuncVal.ts +0 -2
- package/src/val/JunctionVal.ts +24 -1
- package/src/val/KeyFuncVal.ts +39 -35
- package/src/val/ListVal.ts +101 -15
- package/src/val/LowerFuncVal.ts +0 -1
- package/src/val/MapVal.ts +153 -14
- 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 +107 -20
- package/src/val/PathVal.ts +221 -0
- package/src/val/PlaceVal.ts +193 -0
- package/src/val/PlusOpVal.ts +67 -39
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +251 -60
- package/src/val/RecurseVal.ts +285 -0
- package/src/val/RefVal.ts +183 -78
- package/src/val/ReferFuncVal.ts +732 -0
- package/src/val/ScalarKindVal.ts +12 -13
- package/src/val/SuperFuncVal.ts +137 -13
- package/src/val/TopVal.ts +1 -2
- package/src/val/TypeFuncVal.ts +0 -2
- package/src/val/UpperFuncVal.ts +0 -1
- package/src/val/Val.ts +216 -4
- package/src/val/VarVal.ts +0 -1
- package/src/val/arith.ts +319 -0
- package/src/vet.ts +1025 -0
- package/src/view.ts +2563 -0
- package/src/walk.ts +99 -0
package/src/unify.ts
CHANGED
|
@@ -8,8 +8,10 @@ import { AontuContext } from './ctx'
|
|
|
8
8
|
import { DONE } from './type'
|
|
9
9
|
|
|
10
10
|
import { makeNilErr } from './err'
|
|
11
|
+
import { findAt } from './val/ReferFuncVal'
|
|
11
12
|
|
|
12
13
|
import { NilVal } from './val/NilVal'
|
|
14
|
+
import { hasPlace } from './val/PlaceVal'
|
|
13
15
|
|
|
14
16
|
import {
|
|
15
17
|
Lang
|
|
@@ -26,27 +28,27 @@ import {
|
|
|
26
28
|
} from './val/top'
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
// terms through both engines as the regression guard.
|
|
36
|
-
const MAXCYCLE = 999
|
|
37
|
-
|
|
38
|
-
// Structural recursion budget: how deep `unite` may nest before the
|
|
39
|
-
// evaluator reports `unify_cycle`. SHARED LANGUAGE SURFACE -- Go's
|
|
40
|
-
// maxUniteDepth (go/unify.go) carries the same number, and
|
|
41
|
-
// test/spec/budget.tsv pins the boundary in both, so changing it is a
|
|
42
|
-
// spec-visible change in both ports at once.
|
|
31
|
+
// The evaluation budgets live on the context (ctx.budget: passes,
|
|
32
|
+
// revisits, depth), defaulted there to the shared spec-visible
|
|
33
|
+
// constants test/spec/budget.tsv pins in both ports (9 / 999 / 1000)
|
|
34
|
+
// and configurable through the trust profile (G5, docs/trust.md) —
|
|
35
|
+
// deterministically: a budget is an integer count of engine events,
|
|
36
|
+
// never wall-clock.
|
|
43
37
|
//
|
|
44
|
-
// Why
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
38
|
+
// Why the revisit default is 999: how many times one (Val, path) pair
|
|
39
|
+
// may be re-unified within a single fixpoint pass before the evaluator
|
|
40
|
+
// calls it non-convergence (`unify_cycle`). The old false positive here
|
|
41
|
+
// -- a legal model with many sibling conjunct terms at one path, each
|
|
42
|
+
// re-running the TOP self-unify -- is fixed by the per-pass memo below
|
|
43
|
+
// (_tcc/_tpi); test/spec/budget.tsv drives 1200 sibling terms through
|
|
44
|
+
// both engines as the regression guard.
|
|
45
|
+
//
|
|
46
|
+
// Why the depth default is 1000: the whole shared suite peaks at 603
|
|
47
|
+
// (the deliberately extreme 1200-sibling-term fixture; ordinary
|
|
48
|
+
// documents are two orders below), and V8 exhausts its call stack
|
|
49
|
+
// somewhere past depth ~1500 in this evaluator. 1000 sits above every
|
|
50
|
+
// real document and below the host limit, so the budget -- not the
|
|
51
|
+
// host -- decides the verdict.
|
|
50
52
|
|
|
51
53
|
// Charge a DIRECT `Val.unify` recursion to the same depth budget that
|
|
52
54
|
// `unite` enforces. Function and operator arguments evaluate through
|
|
@@ -59,7 +61,7 @@ const MAXDEPTH = 1000
|
|
|
59
61
|
const withDepth = (
|
|
60
62
|
ctx: AontuContext, a: any, b: any, run: () => any
|
|
61
63
|
): any => {
|
|
62
|
-
if (
|
|
64
|
+
if (ctx.budget.depth <= ctx._depth.n) {
|
|
63
65
|
return makeNilErr(ctx, 'unify_cycle', a, b)
|
|
64
66
|
}
|
|
65
67
|
ctx._depth.n++
|
|
@@ -89,14 +91,46 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
|
|
|
89
91
|
if (a === b) {
|
|
90
92
|
if (a.done) return a
|
|
91
93
|
}
|
|
92
|
-
|
|
94
|
+
// ... and NOT on an instrumented run (G7 provenance). Both arms
|
|
95
|
+
// below answer with one operand and never reach the recorder at
|
|
96
|
+
// the tail, so an equal pair — two positions of one entity that
|
|
97
|
+
// agree, a clone meeting its source — contributed silently and
|
|
98
|
+
// `why` named one site where the Go port, whose recorder wraps the
|
|
99
|
+
// whole dispatcher, named both. Instrumented runs pay the slow
|
|
100
|
+
// path knowingly; uninstrumented ones pay one undefined check.
|
|
101
|
+
else if (b !== undefined && b !== null && undefined === ctx.prov) {
|
|
93
102
|
if (a.done && b.done) {
|
|
94
|
-
if (a.id === b.id)
|
|
103
|
+
if (a.id === b.id) {
|
|
104
|
+
// The deprecation record survives the fast path (G3).
|
|
105
|
+
if (null == a.deprecation && null != b.deprecation) {
|
|
106
|
+
a.deprecation = b.deprecation
|
|
107
|
+
}
|
|
108
|
+
return a
|
|
109
|
+
}
|
|
95
110
|
if (a.constructor === b.constructor && a.peg === b.peg
|
|
96
111
|
&& !a.isNil && !b.isNil
|
|
97
112
|
&& !a.isMap && !a.isList
|
|
98
113
|
&& !a.isConjunct && !a.isDisjunct
|
|
99
|
-
&& !a.isRef && !a.isPref && !a.isFunc && !a.isExpect
|
|
114
|
+
&& !a.isRef && !a.isPref && !a.isFunc && !a.isExpect
|
|
115
|
+
// NOT two TOPs: every top has the same (absent) peg, so
|
|
116
|
+
// this path would treat any two as the same value and
|
|
117
|
+
// return one of them whole — dropping a rider the other
|
|
118
|
+
// carries. The slow path answers the same thing for two
|
|
119
|
+
// plain tops, so nothing is lost by declining the shortcut.
|
|
120
|
+
&& !a.isTop && !b.isTop
|
|
121
|
+
// NOT two rel residuals (RELATIONS P1) for the same
|
|
122
|
+
// reason: a settled rel is DONE with an absent peg, so
|
|
123
|
+
// any two matched here — dropping one side's type and
|
|
124
|
+
// held constraints. RelVal.unify merges them instead.
|
|
125
|
+
// NOT two graph atoms (P2) either: acyclic() and
|
|
126
|
+
// inverse(x) share a constructor and an absent peg
|
|
127
|
+
// without being the same declaration.
|
|
128
|
+
&& !a.isRel && !a.isGraphAtom && !a.isRecurse) {
|
|
129
|
+
// The deprecation record survives the fast path too (G3):
|
|
130
|
+
// `deprecate(5) & 5` short-circuits here.
|
|
131
|
+
if (null == a.deprecation && null != b.deprecation) {
|
|
132
|
+
a.deprecation = b.deprecation
|
|
133
|
+
}
|
|
100
134
|
return a
|
|
101
135
|
}
|
|
102
136
|
}
|
|
@@ -119,7 +153,7 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
|
|
|
119
153
|
// NOTE: if this error occurs "unreasonably", attemp to avoid unnecesary unification
|
|
120
154
|
// See for example PrefVal peg.id equality inspection.
|
|
121
155
|
const sawCount = ctx.seen[saw] ?? 0
|
|
122
|
-
if (
|
|
156
|
+
if (ctx.budget.depth <= ctx._depth.n) {
|
|
123
157
|
// Structural recursion budget. Without it, deep nesting exhausts the
|
|
124
158
|
// V8 call stack and the catch-all below reports a RangeError as
|
|
125
159
|
// `internal` — a verdict that depends on the host's stack size
|
|
@@ -128,7 +162,7 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
|
|
|
128
162
|
// makes it a stated budget error, like the pass budget.
|
|
129
163
|
out = makeNilErr(ctx, 'unify_cycle', a, b)
|
|
130
164
|
}
|
|
131
|
-
else if (
|
|
165
|
+
else if (ctx.budget.revisits < sawCount) {
|
|
132
166
|
// console.log('SAW', sawCount, saw, a?.id, a?.canon, b?.id, b?.canon, ctx.cc)
|
|
133
167
|
out = makeNilErr(ctx, 'unify_cycle', a, b)
|
|
134
168
|
}
|
|
@@ -184,14 +218,36 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
|
|
|
184
218
|
|| b.isVar
|
|
185
219
|
|| b.isFunc
|
|
186
220
|
|| b.isExpect
|
|
221
|
+
// The refer residual (G4 phase 2) DRIVES, like the other
|
|
222
|
+
// residuals here: its peer is a plain string, which knows
|
|
223
|
+
// nothing about entity addresses, so letting the string drive
|
|
224
|
+
// dropped the address and left the constraint standing.
|
|
225
|
+
|| b.isRefer
|
|
226
|
+
// An operator holding a HOLE (G8 phase 3) drives for the same
|
|
227
|
+
// reason: its peer is what FILLS it, and a scalar asked to
|
|
228
|
+
// unify with `_ + 2` sees an operator rather than a hole and
|
|
229
|
+
// refuses it on kind. Narrow to placeheld operators on
|
|
230
|
+
// purpose -- every other operator meets its peer the way it
|
|
231
|
+
// always has, through the conjunct fold that drives it.
|
|
232
|
+
|| (b.isOp && hasPlace(b))
|
|
233
|
+
// A graph atom DRIVES (RELATIONS P2): its peer is the value
|
|
234
|
+
// it rides beside -- a container, a rel, a scalar -- and none
|
|
235
|
+
// of them know the atom; the atom knows to residuate.
|
|
236
|
+
|| b.isGraphAtom
|
|
237
|
+
// The recursive residual DRIVES for the same reason: its peer
|
|
238
|
+
// is the concrete structure it expands against.
|
|
239
|
+
|| b.isRecurse
|
|
187
240
|
) {
|
|
188
241
|
out = b.unify(a, te ? ctx.clone({ explain: ec(te, 'BW') }) : ctx)
|
|
189
242
|
unified = true
|
|
190
243
|
why = 'bv'
|
|
191
244
|
}
|
|
192
245
|
// Exactly equal scalars (not caught by early fast-path — e.g.
|
|
193
|
-
// because a or b isn't .done yet).
|
|
194
|
-
|
|
246
|
+
// because a or b isn't .done yet). Rel residuals are excluded
|
|
247
|
+
// exactly as in the fast path: their pegs are equally absent
|
|
248
|
+
// without the values being the same relation.
|
|
249
|
+
else if (a.constructor === b.constructor && a.peg === b.peg
|
|
250
|
+
&& !a.isRel && !a.isGraphAtom && !a.isRecurse) {
|
|
195
251
|
out = update(a, b)
|
|
196
252
|
why = 'up'
|
|
197
253
|
}
|
|
@@ -251,6 +307,29 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
|
|
|
251
307
|
|
|
252
308
|
ctx.explain && explainClose(te, out)
|
|
253
309
|
|
|
310
|
+
// The provenance record (G7 phase 3), at the one place every meet
|
|
311
|
+
// passes through — the same reason the deprecation rider below lives
|
|
312
|
+
// here. Off by default: an uninstrumented run pays this one property
|
|
313
|
+
// load, and an instrumented one pays site materialisation knowingly.
|
|
314
|
+
if (undefined !== ctx.prov) {
|
|
315
|
+
ctx.prov.record(ctx.path, a, b, out)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// The deprecation record survives EVERY meet (G3 phase 4): the
|
|
319
|
+
// boolean marks have their own sweeps (ConjunctVal, the bag walks),
|
|
320
|
+
// but a record lost in one meet shape is a use the tooling never
|
|
321
|
+
// warns about, so it rides here, at the one place all meets pass
|
|
322
|
+
// through. First record wins; TOP and nil stay clean (TOP is the
|
|
323
|
+
// unit, and an error needs no deprecation).
|
|
324
|
+
if (null != out && true === (out as any).isVal &&
|
|
325
|
+
!out.isTop && !out.isNil && null == out.deprecation) {
|
|
326
|
+
const dep = (null != a ? a.deprecation : undefined) ??
|
|
327
|
+
(null != b ? b.deprecation : undefined)
|
|
328
|
+
if (null != dep) {
|
|
329
|
+
out.deprecation = dep
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
254
333
|
return out
|
|
255
334
|
}
|
|
256
335
|
|
|
@@ -285,6 +364,72 @@ function residuePaths(v: Val, max: number): string[] {
|
|
|
285
364
|
}
|
|
286
365
|
|
|
287
366
|
|
|
367
|
+
// THE TYPE FLOW, APPLIED (G4 phase 2). `refer(t)` unifies `t` INTO the
|
|
368
|
+
// node it addresses, which is a write at a position the meet is not
|
|
369
|
+
// currently at -- the one non-local effect in the evaluator.
|
|
370
|
+
//
|
|
371
|
+
// It cannot be only a write made during the pass. A pass BUILDS a new
|
|
372
|
+
// tree from the old one, and `ctx.root` during pass N is pass N-1's
|
|
373
|
+
// result; a subtree rebuilt by pass N (which is exactly what happens
|
|
374
|
+
// when the link sits inside its own target, or when two nodes link at
|
|
375
|
+
// each other) drops a write made into the previous one. So each flow is
|
|
376
|
+
// also RECORDED, keyed by the target's path, and re-applied to the
|
|
377
|
+
// pass's own result here.
|
|
378
|
+
//
|
|
379
|
+
// Keyed by PATH, so there is no registry of names to collide in
|
|
380
|
+
// (ADR-014) -- the key is the position the address resolved to, and
|
|
381
|
+
// re-uniting the same type at the same position is idempotent, which is
|
|
382
|
+
// what makes replaying every recorded flow every pass correct rather
|
|
383
|
+
// than merely cheap.
|
|
384
|
+
//
|
|
385
|
+
// The pass loop is its only caller; it is EXPORTED for the test that
|
|
386
|
+
// pins the unresolved-path guard below (see there).
|
|
387
|
+
function applyFlows(ctx: AontuContext, root: Val): Val {
|
|
388
|
+
const flows: Map<string, Val> | undefined = (ctx as any).referflows
|
|
389
|
+
// NOTHING TO APPLY is the common case -- a document with no links
|
|
390
|
+
// pays one property load per pass, and the walk never runs.
|
|
391
|
+
if (null == flows || 0 === flows.size) {
|
|
392
|
+
return root
|
|
393
|
+
}
|
|
394
|
+
// Sorted, so two flows landing at overlapping positions arrive in the
|
|
395
|
+
// same order in both ports.
|
|
396
|
+
for (const key of [...flows.keys()].sort()) {
|
|
397
|
+
const path = key.split('\x00')
|
|
398
|
+
// The SHARED resolver, the one `refer` itself uses: a second
|
|
399
|
+
// descent written here would be a second answer to "what does this
|
|
400
|
+
// path name", and the two would drift (the Go twin calls the same
|
|
401
|
+
// findAt, arm for arm -- ADR-001).
|
|
402
|
+
//
|
|
403
|
+
// A RECORDED PATH THAT NO LONGER RESOLVES is skipped rather than
|
|
404
|
+
// refused: the record outliving its position is a question about
|
|
405
|
+
// the tree, and the link that named it answers it
|
|
406
|
+
// (test/spec/refer.tsv, `flow-target-moved-away`).
|
|
407
|
+
//
|
|
408
|
+
// NO DOCUMENT REACHES IT: a record is written only for a path that
|
|
409
|
+
// HAD resolved, and unification never takes a node back out of the
|
|
410
|
+
// tree — `move` copies and hides its source rather than removing
|
|
411
|
+
// it, which is the one rearrangement that looked like it would
|
|
412
|
+
// (probed in both ports: the flow still resolves on every pass,
|
|
413
|
+
// `flow-lands-then-its-parent-moves`). The guard is the contract
|
|
414
|
+
// for a rearrangement that does, and it is pinned by a direct call
|
|
415
|
+
// (`apply-flows-skips-a-record-that-stops-resolving` in
|
|
416
|
+
// ts/test/coverage3.test.ts) rather than by an ignore marker: node's
|
|
417
|
+
// `coverage ignore` drops LINES, and the gate reads BRANCH records,
|
|
418
|
+
// which survive it. The Go twin in go/unify.go can use the marker
|
|
419
|
+
// because that gate counts statements.
|
|
420
|
+
const found = findAt(root, path)
|
|
421
|
+
if (undefined === found) {
|
|
422
|
+
continue
|
|
423
|
+
}
|
|
424
|
+
const { parent, key: pkey, val: node } = found
|
|
425
|
+
const merged = unite(ctx.descend(pkey as string), node,
|
|
426
|
+
flows.get(key) as Val, 'refer-flow')
|
|
427
|
+
parent.peg[pkey as string] = merged
|
|
428
|
+
}
|
|
429
|
+
return root
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
|
|
288
433
|
class Unify {
|
|
289
434
|
root: Val
|
|
290
435
|
res: Val
|
|
@@ -339,27 +484,96 @@ class Unify {
|
|
|
339
484
|
// keyed by ref canon + source site, shared across all passes.
|
|
340
485
|
; (uctx as any).snapmap = new Map()
|
|
341
486
|
|
|
487
|
+
// The RECORDED TYPE FLOWS (G4 phase 2): target path -> the type
|
|
488
|
+
// `refer(t)` unified into it, replayed onto each pass's result by
|
|
489
|
+
// applyFlows. Seeded HERE, on the unify root, for the reason the
|
|
490
|
+
// snapshot map above is: a descended context is Object.create'd
|
|
491
|
+
// from its parent, so a `??=` in the descendant would make its
|
|
492
|
+
// OWN map and the root would never see what was recorded.
|
|
493
|
+
; (uctx as any).referflows = new Map()
|
|
494
|
+
|
|
495
|
+
// The re-entrancy guard for those flows: the set of target paths
|
|
496
|
+
// a flow is currently inside. Same placement, same reason.
|
|
497
|
+
; (uctx as any)._referflow = new Set()
|
|
498
|
+
|
|
342
499
|
const explain = null == ctx?.explain ? undefined : ctx?.explain
|
|
343
500
|
const te = explain && explainOpen(uctx, explain, 'root', res)
|
|
344
501
|
|
|
345
502
|
// NOTE: if true === res.done already, then this loop never needs to run.
|
|
346
|
-
let maxcc =
|
|
503
|
+
let maxcc = uctx.budget.passes
|
|
347
504
|
let prevCanon: string | undefined = undefined
|
|
505
|
+
let lastCanon: string | undefined = undefined
|
|
506
|
+
let settle = false
|
|
348
507
|
for (; this.cc < maxcc && DONE !== res.dc; this.cc++) {
|
|
349
508
|
// console.log('CC', this.cc, res.canon)
|
|
350
509
|
uctx.cc = this.cc
|
|
351
510
|
uctx.seen = {}
|
|
352
|
-
res = unite(te ? uctx.clone({ explain: ec(te, 'run') }) : uctx, res, top(), 'unify')
|
|
353
511
|
|
|
354
|
-
|
|
355
|
-
|
|
512
|
+
// THE STAGING RULE (G8 phase 0,
|
|
513
|
+
// docs/capability-review/g8-generation.md), stated once, here,
|
|
514
|
+
// for every value whose answer depends on WHERE IT IS. Such a
|
|
515
|
+
// value residuates while the model is still moving and fires on
|
|
516
|
+
// the first pass whose input is IDENTICAL to the previous
|
|
517
|
+
// pass's input: nothing moved, so nothing will move it again,
|
|
518
|
+
// and the position it reports is the position it ends at.
|
|
519
|
+
//
|
|
520
|
+
// Why the whole model and not the value's own path. A spread, a
|
|
521
|
+
// reference or a `move` can place a value under a path it has
|
|
522
|
+
// already been driven at and THEN change what encloses it --
|
|
523
|
+
// `move` hides its source one pass AFTER it copies it, and a
|
|
524
|
+
// `key()` that answered on the strength of its path alone would
|
|
525
|
+
// answer for the ghost. Stability of the model is the only
|
|
526
|
+
// signal that says every such rearrangement is finished.
|
|
527
|
+
uctx.settle = settle
|
|
528
|
+
|
|
529
|
+
// Snapshot BEFORE the final pass (the loop condition has
|
|
530
|
+
// already established the tree is not done), so exhaustion can
|
|
531
|
+
// tell "still refining" from "stable residue" below. Taken at
|
|
532
|
+
// the final pass's ENTRY rather than the previous pass's exit
|
|
533
|
+
// — the same value when the budget allows two passes, and the
|
|
534
|
+
// only possible value when the trust profile sets passes to 1,
|
|
535
|
+
// where the old placement (cc === maxcc - 2, never true) made
|
|
536
|
+
// exhaustion silent, exactly the truncation docs/trust.md
|
|
537
|
+
// forbids. `lastCanon` IS that entry canon whenever a previous
|
|
538
|
+
// pass rendered one, so this costs nothing extra.
|
|
539
|
+
if (this.cc === maxcc - 1) {
|
|
540
|
+
prevCanon = lastCanon ?? res.canon
|
|
356
541
|
}
|
|
357
542
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
|
|
543
|
+
res = unite(te ? uctx.clone({ explain: ec(te, 'run') }) : uctx, res, top(), 'unify')
|
|
544
|
+
|
|
545
|
+
// MULTI-ERROR COLLECTION (G2 phase 6): the pass loop CONTINUES
|
|
546
|
+
// past an erroring pass, so independent failures a later pass
|
|
547
|
+
// would reach are collected in the same run — the break that
|
|
548
|
+
// stood here made every multi-error report truncated at the
|
|
549
|
+
// first erroring pass.
|
|
550
|
+
//
|
|
551
|
+
// What controls the cascade the design feared: a nil is
|
|
552
|
+
// ABSORBING (unite's isNil arms return the existing nil, no new
|
|
553
|
+
// error), so one failure stays ONE NilVal however many later
|
|
554
|
+
// meets touch it — a reference resolving to a failed target
|
|
555
|
+
// takes the same nil identity, which is exactly what lets the
|
|
556
|
+
// report layer dedup by identity. The probes that established
|
|
557
|
+
// this (fan-in refs, spread templates, disjunct trials, nested
|
|
558
|
+
// conjuncts) are pinned as vet.tsv's multi-* rows in both
|
|
559
|
+
// ports.
|
|
560
|
+
|
|
561
|
+
// The recorded type flows, re-applied to the tree THIS pass
|
|
562
|
+
// built: a pass rebuilds subtrees, and a flow written into the
|
|
563
|
+
// previous pass's tree does not survive that.
|
|
564
|
+
res = applyFlows(uctx, res)
|
|
565
|
+
|
|
566
|
+
// The staging signal for the NEXT pass, rendered here rather
|
|
567
|
+
// than at the top of the loop so a model that is FINISHED is
|
|
568
|
+
// never rendered at all: canon walks references, and the only
|
|
569
|
+
// trees that close a cycle are hand-built ones (the pass loop
|
|
570
|
+
// is what a test drives them through), which converge in one
|
|
571
|
+
// pass and must not be walked to decide a question that no
|
|
572
|
+
// longer arises.
|
|
573
|
+
if (DONE !== res.dc) {
|
|
574
|
+
const nowCanon = res.canon
|
|
575
|
+
settle = undefined !== lastCanon && lastCanon === nowCanon
|
|
576
|
+
lastCanon = nowCanon
|
|
363
577
|
}
|
|
364
578
|
|
|
365
579
|
uctx = uctx.clone({ root: res })
|
|
@@ -389,7 +603,7 @@ class Unify {
|
|
|
389
603
|
|
|
390
604
|
this.res = res
|
|
391
605
|
}
|
|
392
|
-
} /* node:coverage ignore next
|
|
606
|
+
} /* node:coverage ignore next 10 */
|
|
393
607
|
|
|
394
608
|
|
|
395
609
|
|
|
@@ -398,4 +612,5 @@ export {
|
|
|
398
612
|
Unify,
|
|
399
613
|
unite,
|
|
400
614
|
withDepth,
|
|
615
|
+
applyFlows,
|
|
401
616
|
}
|
package/src/utility.ts
CHANGED
|
@@ -25,6 +25,80 @@ function propagateMarks(source: Val, target: Val): void {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
// Collect every value in the tree carrying the deprecation record (G3
|
|
29
|
+
// phase 4), with its path — the one walk behind vet's `deprecated`
|
|
30
|
+
// warnings and the LSP's Deprecated tags. The record travels on meets
|
|
31
|
+
// (the unite rider) and clones, so this sees the declaration and every
|
|
32
|
+
// use resolving through it. The non-Val guard is for a bag's raw peg
|
|
33
|
+
// entries, which degenerate parses can leave behind.
|
|
34
|
+
function collectDeprecations(
|
|
35
|
+
root: Val): Array<{ val: Val, path: string[] }> {
|
|
36
|
+
const out: Array<{ val: Val, path: string[] }> = []
|
|
37
|
+
walkBagVals(root, (v: any, path) => {
|
|
38
|
+
if (null != v.deprecation) {
|
|
39
|
+
out.push({ val: v, path })
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
return out
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
// Visit every Val reachable through bag children, with its path — the
|
|
47
|
+
// walk under collectDeprecations and vet's default-validity lint. The
|
|
48
|
+
// non-Val guard is for a bag's raw peg entries, which degenerate
|
|
49
|
+
// parses can leave behind (pinned by the collect-deprecations direct
|
|
50
|
+
// test, ts/test/coverage3.test.ts).
|
|
51
|
+
function walkBagVals(
|
|
52
|
+
root: Val, fn: (v: Val, path: string[]) => void): void {
|
|
53
|
+
const walk = (v: any, path: string[]): void => {
|
|
54
|
+
if (null == v || true !== v.isVal) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
fn(v, path)
|
|
58
|
+
if ((true === v.isMap || true === v.isList) && null != v.peg) {
|
|
59
|
+
for (const k of Object.keys(v.peg)) {
|
|
60
|
+
walk(v.peg[k], [...path, k])
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
walk(root, [])
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
// The one-line prose for a deprecation record, shared by vet's warning
|
|
69
|
+
// findings and the LSP's tagged diagnostics.
|
|
70
|
+
function deprecationMessage(d: Record<string, string>): string {
|
|
71
|
+
const msg = 'string' === typeof d.msg ? d.msg : ''
|
|
72
|
+
return 'deprecated' + ('' === msg ? '' : ': ' + msg) +
|
|
73
|
+
('string' === typeof d.use ? ' (use ' + d.use + ')' : '') +
|
|
74
|
+
('string' === typeof d.since ? ' (since ' + d.since + ')' : '')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// The canonical form of a value, wrapped in the RIDER it carries —
|
|
79
|
+
// the deprecation record (G3 phase 4) — reparseably, so
|
|
80
|
+
// `deprecate(x, m)` survives canon. Bags render their children through
|
|
81
|
+
// this (MapVal/ListVal canon), which is where a marked FIELD — the
|
|
82
|
+
// realistic case — lives.
|
|
83
|
+
//
|
|
84
|
+
// The rider renders HERE and not in the value's own `canon` for the
|
|
85
|
+
// same reason the guard at the MapVal call site tests the isVal flag:
|
|
86
|
+
// a bag's canon recursion visits each child once, and a child that
|
|
87
|
+
// wrapped itself as well would render its subtree twice per level —
|
|
88
|
+
// 2^depth on a nested document.
|
|
89
|
+
function canonRiders(v: Val): string {
|
|
90
|
+
const c = v.canon
|
|
91
|
+
const d = v.deprecation
|
|
92
|
+
if (null == d) {
|
|
93
|
+
return c
|
|
94
|
+
}
|
|
95
|
+
const keys = Object.keys(d).sort()
|
|
96
|
+
const rec = keys.map((k) =>
|
|
97
|
+
JSON.stringify(k) + ':' + JSON.stringify(d[k])).join(',')
|
|
98
|
+
return 'deprecate(' + c + ('' === rec ? '' : ',{' + rec + '}') + ')'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
28
102
|
function formatPath(path: Val | string[], absolute?: boolean) {
|
|
29
103
|
let parts: string[]
|
|
30
104
|
if (Array.isArray(path)) {
|
|
@@ -188,12 +262,16 @@ function items(o: any) {
|
|
|
188
262
|
else {
|
|
189
263
|
return []
|
|
190
264
|
}
|
|
191
|
-
} /* node:coverage ignore next
|
|
265
|
+
} /* node:coverage ignore next 18 */
|
|
192
266
|
|
|
193
267
|
|
|
194
268
|
export {
|
|
195
269
|
items,
|
|
196
270
|
propagateMarks,
|
|
271
|
+
canonRiders,
|
|
272
|
+
collectDeprecations,
|
|
273
|
+
walkBagVals,
|
|
274
|
+
deprecationMessage,
|
|
197
275
|
formatPath,
|
|
198
276
|
walk,
|
|
199
277
|
WalkApply,
|