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
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// CHECKED, TYPED, LINK-SHAPED REFERENCES (G4 phase 2,
|
|
4
|
+
// docs/capability-review/g4-identity-relations.md): `refer(t)` is a
|
|
5
|
+
// constraint on a string-valued field. The string must be an ENTITY
|
|
6
|
+
// ADDRESS, the addressed node must exist in the evaluation, and — when
|
|
7
|
+
// `t` is given — `t` is unified INTO the target. The field's own value
|
|
8
|
+
// stays the address string: a LINK, not an embedding.
|
|
9
|
+
//
|
|
10
|
+
// This is the piece a plain reference cannot be. `$.a.b` resolves by
|
|
11
|
+
// CLONING its target into place, so `dependsOn: [$.services.auth]`
|
|
12
|
+
// generates a full copy of the auth node where the author meant a
|
|
13
|
+
// name. `refer` leaves the name and checks it.
|
|
14
|
+
//
|
|
15
|
+
// Constraint FLOW rather than a check: `refer(t)` does not merely test
|
|
16
|
+
// the target against `t`, it unifies `t` into it. Referring to
|
|
17
|
+
// something as a Service MAKES it one, and if it cannot be, the
|
|
18
|
+
// conflict is an ordinary located error. Check-only semantics would be
|
|
19
|
+
// non-monotone — true, then false as the target grows — and the
|
|
20
|
+
// lattice guarantee is that more information never falsifies what has
|
|
21
|
+
// been observed.
|
|
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 {
|
|
40
|
+
Address,
|
|
41
|
+
PathVal,
|
|
42
|
+
parseAddress,
|
|
43
|
+
prefixMeet,
|
|
44
|
+
} from './PathVal'
|
|
45
|
+
import { FeatureVal } from './FeatureVal'
|
|
46
|
+
import { ConjunctVal } from './ConjunctVal'
|
|
47
|
+
import { unite } from '../unify'
|
|
48
|
+
import { top } from './top'
|
|
49
|
+
import { propagateMarks, walk } from '../utility'
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// A RELATION PREDICATE is still a declared D-1 name
|
|
53
|
+
// (docs/design/RELATIONS.0.md §3.2). Entity names are gone with
|
|
54
|
+
// ADR-014; predicate names are not -- a relation is a vocabulary term,
|
|
55
|
+
// not an address.
|
|
56
|
+
const PREDICATE_NAME = /^[_a-zA-Z][-_a-zA-Z0-9]*$/
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// The tree path an address resolves to from `at` -- the position of
|
|
60
|
+
// the link itself -- or undefined when a relative address climbs off
|
|
61
|
+
// the top of the tree.
|
|
62
|
+
export function addressPath(
|
|
63
|
+
addr: Address, at: (string | number)[]
|
|
64
|
+
): string[] | undefined {
|
|
65
|
+
if (addr.absolute) {
|
|
66
|
+
return addr.parts
|
|
67
|
+
}
|
|
68
|
+
// The SIBLING scope: drop the link's own key, then take the parent
|
|
69
|
+
// steps. A link at `$.a.b.dep` spelling `.other` means `$.a.b.other`.
|
|
70
|
+
const cut = at.length - 1 - addr.up
|
|
71
|
+
if (cut < 0) {
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
74
|
+
return at.slice(0, cut).map(String).concat(addr.parts)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// The node a tree path names, with the parent and key that hold it so
|
|
79
|
+
// a type flow can be written back. Pending is not failure: the target
|
|
80
|
+
// may be introduced by a later conjunct, include or spread, so `refer`
|
|
81
|
+
// residuates exactly as a forward reference does.
|
|
82
|
+
export function findAt(
|
|
83
|
+
root: Val | undefined, path: string[]
|
|
84
|
+
): { parent?: any, key?: string, val: Val } | undefined {
|
|
85
|
+
if (null == root || 0 === path.length) {
|
|
86
|
+
return undefined
|
|
87
|
+
}
|
|
88
|
+
let parent: any = undefined
|
|
89
|
+
let key: string | undefined = undefined
|
|
90
|
+
let val: any = root
|
|
91
|
+
for (const seg of path) {
|
|
92
|
+
if (true !== val?.isMap && true !== val?.isList) {
|
|
93
|
+
return undefined
|
|
94
|
+
}
|
|
95
|
+
const next = val.peg[seg]
|
|
96
|
+
if (null == next) {
|
|
97
|
+
return undefined
|
|
98
|
+
}
|
|
99
|
+
parent = val
|
|
100
|
+
key = seg
|
|
101
|
+
val = next
|
|
102
|
+
}
|
|
103
|
+
return { parent, key, val }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
// concreteFlow is `t` as it enters the target: a copy with the
|
|
108
|
+
// type/hide marks cleared at every depth. The clone matters as much as
|
|
109
|
+
// the clearing — `t` is shared by every position that refers to the
|
|
110
|
+
// same thing, and clearing in place would unmark the schema itself.
|
|
111
|
+
function concreteFlow(ctx: AontuContext, t: Val): Val {
|
|
112
|
+
let marked = false
|
|
113
|
+
walk(t, (_key: string | number | undefined, v: Val) => {
|
|
114
|
+
marked = marked || v.mark.type || v.mark.hide
|
|
115
|
+
return v
|
|
116
|
+
})
|
|
117
|
+
// An unmarked flow type is passed THROUGH: cloning one anyway would
|
|
118
|
+
// move the site an error names, and a conflict has to point at what
|
|
119
|
+
// the author wrote.
|
|
120
|
+
if (!marked) {
|
|
121
|
+
return t
|
|
122
|
+
}
|
|
123
|
+
const out = t.clone(ctx)
|
|
124
|
+
walk(out, (_key: string | number | undefined, v: Val) => {
|
|
125
|
+
v.mark.type = false
|
|
126
|
+
v.mark.hide = false
|
|
127
|
+
return v
|
|
128
|
+
})
|
|
129
|
+
return out
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
// ReferVal is what `refer(t)` RESOLVES to: the residual constraint,
|
|
134
|
+
// carrying the type to flow and — once it has met a string — the
|
|
135
|
+
// address to flow it into. A separate value from the function for the
|
|
136
|
+
// reason every residual is: the function is written once and the
|
|
137
|
+
// constraint is met many times, and only the constraint has state
|
|
138
|
+
// worth carrying.
|
|
139
|
+
class ReferVal extends FeatureVal {
|
|
140
|
+
isRefer = true
|
|
141
|
+
isGenable = true
|
|
142
|
+
// AFTER the plain values (base 99999), BEFORE the sizing atoms
|
|
143
|
+
// (LATE_CJO): sibling path values fold together first under the
|
|
144
|
+
// prefix rule, and the residual then meets ONE merged address --
|
|
145
|
+
// without this, `refer() & path($.a) & path($.a.b)` settled on the
|
|
146
|
+
// first path and the second met the finished link too late.
|
|
147
|
+
cjo = 120000
|
|
148
|
+
|
|
149
|
+
// The type to flow into the target; TOP when `refer()` was written
|
|
150
|
+
// with no argument.
|
|
151
|
+
tval: Val
|
|
152
|
+
// The address, once a string has been met.
|
|
153
|
+
addr?: Address
|
|
154
|
+
// The address AS WRITTEN, for canon and for the error message.
|
|
155
|
+
addrsrc?: string
|
|
156
|
+
// Constraints met while the address was still pending — a kind, a
|
|
157
|
+
// regex, a preference. They meet the LINK once there is one.
|
|
158
|
+
held?: Val
|
|
159
|
+
// The PREDICATE the produced link belongs to, when this residual was
|
|
160
|
+
// minted by `rel()` on a field: the field's key, stamped onto the
|
|
161
|
+
// link so the graph reports the edge under a DECLARED relation
|
|
162
|
+
// rather than inferring one from the path (RELATIONS.0.md §3.2).
|
|
163
|
+
relkey?: string
|
|
164
|
+
// The codes this residual refuses with: refer() keeps its own,
|
|
165
|
+
// rel()-minted residuals carry rel_address/rel_unresolved.
|
|
166
|
+
addrcode: string = 'refer_address'
|
|
167
|
+
unresolvedcode: string = 'refer_unresolved'
|
|
168
|
+
|
|
169
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
170
|
+
super(spec, ctx)
|
|
171
|
+
this.tval = (spec as any).tval ?? top()
|
|
172
|
+
this.addr = (spec as any).addr
|
|
173
|
+
this.addrsrc = (spec as any).addrsrc
|
|
174
|
+
this.held = (spec as any).held
|
|
175
|
+
this.dc = 0
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// The residual's own state — the type to flow, the address it has
|
|
179
|
+
// met, the constraints it holds — TRAVELS with the clone. A spread
|
|
180
|
+
// template holds the FUNCTION, so a template never needs this; a
|
|
181
|
+
// REFERENCE to a value that already contains a resolved link does
|
|
182
|
+
// (`z: {u: refer() & "$.a"}` then `s: $.z`). Without it the
|
|
183
|
+
// clone came back as a bare `refer()` — the address silently
|
|
184
|
+
// dropped, and the copied link resolving to nothing.
|
|
185
|
+
//
|
|
186
|
+
// No path-dependence hook, though: a residual is minted at its
|
|
187
|
+
// destination, so `key()` inside a template resolves there already.
|
|
188
|
+
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
189
|
+
const out: any = super.clone(ctx, spec)
|
|
190
|
+
out.tval = this.tval
|
|
191
|
+
out.addr = this.addr
|
|
192
|
+
out.addrsrc = this.addrsrc
|
|
193
|
+
out.held = this.held
|
|
194
|
+
out.relkey = this.relkey
|
|
195
|
+
out.addrcode = this.addrcode
|
|
196
|
+
out.unresolvedcode = this.unresolvedcode
|
|
197
|
+
return out
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
unify(peer: Val, ctx: AontuContext): Val {
|
|
201
|
+
const p: any = peer
|
|
202
|
+
|
|
203
|
+
// Another `refer` at the same position: one constraint, both
|
|
204
|
+
// types. `refer(A) & refer(B)` is a target that must be both.
|
|
205
|
+
if (true === p?.isRefer) {
|
|
206
|
+
return this.with(ctx, {
|
|
207
|
+
tval: unite(ctx, this.tval, p.tval, 'refer-t'),
|
|
208
|
+
addr: this.addr ?? p.addr,
|
|
209
|
+
addrsrc: this.addrsrc ?? p.addrsrc,
|
|
210
|
+
held: null == this.held ? p.held
|
|
211
|
+
: null == p.held ? this.held
|
|
212
|
+
: unite(ctx, this.held, p.held, 'refer-held'),
|
|
213
|
+
}, this)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (null == peer || true === p.isTop) {
|
|
217
|
+
return this.settle(ctx, this)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (true === p.isNil) {
|
|
221
|
+
return peer
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// A PATH VALUE is the ADDRESS, when there is not one yet. Only a
|
|
225
|
+
// path value can be one (PATHS.0.md, amended): a bare string is
|
|
226
|
+
// never a path -- `path("...")` is the one string conversion, and
|
|
227
|
+
// it happens at the call, not here. The peg is pre-validated by
|
|
228
|
+
// the capture, so no parse can fail.
|
|
229
|
+
if (undefined === this.addr && true === p.isPath) {
|
|
230
|
+
const addr = parseAddress(p.peg) as Address
|
|
231
|
+
return this.with(ctx, { addr, addrsrc: p.peg }, peer)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// A SECOND path peer refines the address by the prefix rule: the
|
|
235
|
+
// longer of the two when one opens the other, exactly as two path
|
|
236
|
+
// values meet on their own. Two incomparable addresses are the
|
|
237
|
+
// same conflict two unequal scalars are.
|
|
238
|
+
if (undefined !== this.addr && true === p.isPath) {
|
|
239
|
+
const merged = prefixMeet(this.addrsrc as string, p.peg)
|
|
240
|
+
if (undefined === merged) {
|
|
241
|
+
return makeNilErr(ctx, 'scalar_value', this, peer)
|
|
242
|
+
}
|
|
243
|
+
return this.with(ctx,
|
|
244
|
+
{ addr: parseAddress(merged) as Address, addrsrc: merged }, peer)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// A value that can never BE a path cannot be the address, and no
|
|
248
|
+
// later pass can repair it — so this arm refuses rather than
|
|
249
|
+
// defers. A bare STRING is in it now (PATHS.0.md, amended):
|
|
250
|
+
// `path("...")` is the one conversion, at the call. A KIND or a
|
|
251
|
+
// constraint is not in it: `string`, `re("^svc_")` and the like
|
|
252
|
+
// are perfectly good constraints on an address, and are held
|
|
253
|
+
// below until there is one to apply them to.
|
|
254
|
+
if ((true === p.isScalar && true !== p.isPath)
|
|
255
|
+
|| true === p.isMap || true === p.isList) {
|
|
256
|
+
return makeNilErr(ctx, this.addrcode, this, peer, 'refer')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// HELD: everything else waits for the address. Carried on the
|
|
260
|
+
// residual rather than parked in a conjunct, because a conjunct
|
|
261
|
+
// rebuilt every pass grows a level every pass; the held constraint
|
|
262
|
+
// meets the link the moment the address resolves, so
|
|
263
|
+
// `refer() & re("a") & re("b") & path($.z)` still applies both and
|
|
264
|
+
// `refer() & string & path($.z)` still passes.
|
|
265
|
+
return this.with(ctx, {
|
|
266
|
+
held: null == this.held ? peer : unite(ctx, this.held, peer, 'refer-held'),
|
|
267
|
+
}, this)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// with is the residual reshaped: every arm above answers a NEW
|
|
271
|
+
// ReferVal rather than mutating this one, because a spread template's
|
|
272
|
+
// residual is shared by every child it is applied to.
|
|
273
|
+
with(ctx: AontuContext, spec: any, site: Val): Val {
|
|
274
|
+
const out = new ReferVal({}, ctx)
|
|
275
|
+
out.tval = spec.tval ?? this.tval
|
|
276
|
+
out.addr = spec.addr ?? this.addr
|
|
277
|
+
out.addrsrc = spec.addrsrc ?? this.addrsrc
|
|
278
|
+
out.held = spec.held ?? this.held
|
|
279
|
+
out.relkey = this.relkey
|
|
280
|
+
out.addrcode = this.addrcode
|
|
281
|
+
out.unresolvedcode = this.unresolvedcode
|
|
282
|
+
propagateMarks(this, out)
|
|
283
|
+
out.site = site.site
|
|
284
|
+
out.path = this.path
|
|
285
|
+
return out.settle(ctx, site)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// settle answers the address if the evaluation can, and stays
|
|
289
|
+
// pending if it cannot YET. `site` is the value whose position the
|
|
290
|
+
// resolved string should take.
|
|
291
|
+
settle(ctx: AontuContext, site: Val): Val {
|
|
292
|
+
if (undefined === this.addr) {
|
|
293
|
+
// NOT DONE, unlike `string` or `min(1)`. A refer without an
|
|
294
|
+
// address has not done its work — it exists to check one — and
|
|
295
|
+
// the pass loop must keep offering it the chance. The cost is
|
|
296
|
+
// that a SCHEMA mentioning a link never resolves either, so
|
|
297
|
+
// `type({from: refer($.std.Port)})` is not expressible today;
|
|
298
|
+
// G4 phase 4 records why, and what it would take.
|
|
299
|
+
this.dc = 0
|
|
300
|
+
return this
|
|
301
|
+
}
|
|
302
|
+
// The address is a TREE PATH, resolved from the link's own
|
|
303
|
+
// position for a relative one. A climb off the top of the tree can
|
|
304
|
+
// never be repaired by a later pass, so it refuses at once.
|
|
305
|
+
const target = addressPath(this.addr, this.path)
|
|
306
|
+
if (undefined === target) {
|
|
307
|
+
return makeNilErr(ctx, this.unresolvedcode, this, undefined, 'refer',
|
|
308
|
+
{ addr: this.addrsrc as string })
|
|
309
|
+
}
|
|
310
|
+
const found = findAt(ctx?.root, target)
|
|
311
|
+
if (undefined === found) {
|
|
312
|
+
// PENDING, not failed — until the last pass. The target may be
|
|
313
|
+
// introduced by a later conjunct, include or spread, so `refer`
|
|
314
|
+
// residuates as a forward reference does; but within ONE
|
|
315
|
+
// evaluation the document-set is fixed, so existence IS
|
|
316
|
+
// decidable, and the final pass is where it is decided. A
|
|
317
|
+
// pending refer keeps the tree not-done, so the pass loop always
|
|
318
|
+
// reaches that pass when there is one to decide.
|
|
319
|
+
if (ctx.cc + 1 >= ctx.budget.passes) {
|
|
320
|
+
return makeNilErr(ctx, this.unresolvedcode, this, undefined, 'refer',
|
|
321
|
+
{ addr: this.addrsrc as string })
|
|
322
|
+
}
|
|
323
|
+
this.dc = 0
|
|
324
|
+
return this
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// THE FLOW. `t` is unified into the target and written back at the
|
|
328
|
+
// target's own position — one position, because the tree is the
|
|
329
|
+
// namespace and a path names exactly one node.
|
|
330
|
+
//
|
|
331
|
+
// RE-ENTRANT ONLY ONCE PER TARGET (use-cases/BUGS.md §19). Uniting
|
|
332
|
+
// the target drives the target's OWN subtree, and if the target
|
|
333
|
+
// links back — `a` typed-refers `b`, `b` typed-refers `a`, the
|
|
334
|
+
// shape every inverse pair has — that drives this target again,
|
|
335
|
+
// and the two flow into each other until the depth budget or the
|
|
336
|
+
// host stack ends it. `unify_cycle` on a model whose meet plainly
|
|
337
|
+
// converges: `{k:1}` meeting `{k:1}` is a fixpoint, and the
|
|
338
|
+
// evaluator never got far enough to notice.
|
|
339
|
+
//
|
|
340
|
+
// The guard is the set of paths a flow is currently inside, on the
|
|
341
|
+
// context. A flow that would re-enter one has its MEET skipped:
|
|
342
|
+
// the outer flow it is nested in is already uniting that node, and
|
|
343
|
+
// re-entering is what runs the host stack out.
|
|
344
|
+
//
|
|
345
|
+
// ITS RECORD IS STILL WRITTEN. The skip used to take the record
|
|
346
|
+
// with it, on the reasoning that "the same information arrives by
|
|
347
|
+
// the same channel one frame up" -- true of the outer flow's TYPE,
|
|
348
|
+
// and false of a nested flow carrying a DIFFERENT one. The outer
|
|
349
|
+
// flow delivers only its own type, the residual is consumed into a
|
|
350
|
+
// settled link in the same breath, and nothing re-offers it: the
|
|
351
|
+
// nested type was lost for good, and which of two flows was the
|
|
352
|
+
// nested one depended on which link the evaluator happened to
|
|
353
|
+
// reach first. A layering rule declared on one field and reached
|
|
354
|
+
// through another module's mirror therefore held in one
|
|
355
|
+
// declaration order and not in the other (BUGS.md 69).
|
|
356
|
+
//
|
|
357
|
+
// Recording it DEFERS the meet to `applyFlows`, which runs at the
|
|
358
|
+
// top of the tree with no flow in flight and so cannot re-enter
|
|
359
|
+
// anything -- the channel this record already exists to be.
|
|
360
|
+
const guard = target.join('.')
|
|
361
|
+
// Seeded on the unify root (ts/src/unify.ts): a `??=` here would
|
|
362
|
+
// make a fresh set on whichever descended context asked first.
|
|
363
|
+
const flowing: Set<string> = (ctx as any)._referflow ?? new Set<string>()
|
|
364
|
+
if (!this.tval.isTop) {
|
|
365
|
+
// The flowed type is CONCRETE at the target: a schema flowing
|
|
366
|
+
// into a value must not make the value a schema. Same reasoning
|
|
367
|
+
// as a reference's clone clearing marks — `refer($.std.Service)`
|
|
368
|
+
// says the target IS a Service, not that it is the definition
|
|
369
|
+
// of one — and without it the target silently stopped
|
|
370
|
+
// generating.
|
|
371
|
+
const flow = concreteFlow(ctx, this.tval)
|
|
372
|
+
|
|
373
|
+
// THE RECORD, keyed by the target's path, replayed onto every
|
|
374
|
+
// later pass by applyFlows in ts/src/unify.ts. A pass rebuilds
|
|
375
|
+
// subtrees, so the write below does not survive one when the
|
|
376
|
+
// link sits inside its own target or two nodes link at each
|
|
377
|
+
// other; the record is what makes the flow reach the result
|
|
378
|
+
// rather than the tree it was computed from.
|
|
379
|
+
const flows: Map<string, Val> = (ctx as any).referflows ??
|
|
380
|
+
new Map<string, Val>()
|
|
381
|
+
const key = target.join('\x00')
|
|
382
|
+
const prev = flows.get(key)
|
|
383
|
+
flows.set(key, null == prev ? flow : unite(ctx, prev, flow,
|
|
384
|
+
'refer-flow-record'))
|
|
385
|
+
|
|
386
|
+
if (!flowing.has(guard)) {
|
|
387
|
+
flowing.add(guard)
|
|
388
|
+
try {
|
|
389
|
+
const merged = unite(ctx, found.val, flow, 'refer-flow')
|
|
390
|
+
if (true === (merged as any).isNil) {
|
|
391
|
+
return merged
|
|
392
|
+
}
|
|
393
|
+
// The write into THIS pass's view, so the rest of the pass
|
|
394
|
+
// sees it. findAt refuses the empty path, so a resolved
|
|
395
|
+
// target always has a parent holding it.
|
|
396
|
+
//
|
|
397
|
+
// NOT FROM INSIDE A TRIAL. A disjunction member is a
|
|
398
|
+
// HYPOTHESIS, and writing its flow into the live tree
|
|
399
|
+
// asserts the member's type on another node before the
|
|
400
|
+
// member is known to survive. The `unite` above still runs:
|
|
401
|
+
// its nil is how a member legitimately fails. Only the
|
|
402
|
+
// COMMIT waits, and the surviving member's flow reaches the
|
|
403
|
+
// tree on the next pass, from the record DisjunctVal stages
|
|
404
|
+
// and merges for survivors alone.
|
|
405
|
+
if (true !== (ctx as any)._trialMode) {
|
|
406
|
+
found.parent.peg[found.key as string] = merged
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
finally {
|
|
410
|
+
flowing.delete(guard)
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// The value IS the address, as a PATH VALUE (ADR-016): a link,
|
|
416
|
+
// not an embedding -- and re-stating or refining the address
|
|
417
|
+
// still meets it, which a string link could not do under the
|
|
418
|
+
// strict rules.
|
|
419
|
+
const out: any = new PathVal({ peg: this.addrsrc as string }, ctx)
|
|
420
|
+
out.dc = DONE
|
|
421
|
+
// STAMPED as a link (G4 phase 3): the value is the address string,
|
|
422
|
+
// so without this nothing downstream could tell a checked link from
|
|
423
|
+
// a literal that happens to look like one. The edge set is exactly
|
|
424
|
+
// the set of these stamps. A rel()-minted link also carries its
|
|
425
|
+
// PREDICATE (the rel field's key), so the graph reports a declared
|
|
426
|
+
// relation rather than inferring one from the path.
|
|
427
|
+
//
|
|
428
|
+
// The stamp is the RESOLVED path, not the written one: a relative
|
|
429
|
+
// address means a different node from each position it is written
|
|
430
|
+
// at, and an edge set whose far ends were spellings rather than
|
|
431
|
+
// nodes could not be traversed. The VALUE stays what the author
|
|
432
|
+
// wrote --- the link is what it says, the edge is where it goes.
|
|
433
|
+
out.link = '$.' + target.join('.')
|
|
434
|
+
if (undefined !== this.relkey) {
|
|
435
|
+
out.relkey = this.relkey
|
|
436
|
+
}
|
|
437
|
+
propagateMarks(this, out)
|
|
438
|
+
out.site = site.site
|
|
439
|
+
out.path = this.path
|
|
440
|
+
return null == this.held ? out : unite(ctx, out, this.held, 'refer-held')
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
get canon() {
|
|
444
|
+
const t = this.tval.isTop ? '' : this.tval.canon
|
|
445
|
+
const call = 'refer(' + t + ')' +
|
|
446
|
+
(null == this.held ? '' : '&' + this.held.canon)
|
|
447
|
+
// The address renders as the path call: a bare string address no
|
|
448
|
+
// longer reparses (PATHS.0.md, amended), and canon must.
|
|
449
|
+
return undefined === this.addrsrc
|
|
450
|
+
? call : call + '&path(' + this.addrsrc + ')'
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
// RelVal is what `rel(t?)` RESOLVES to (RELATIONS.0.md §3.2): the
|
|
456
|
+
// relation constraint, sited on the FIELD the way the sizing atoms sit
|
|
457
|
+
// on containers. Its value may be one address, a LIST of addresses, or
|
|
458
|
+
// a MAP whose string leaves are addresses -- the container shapes are
|
|
459
|
+
// rewritten leaf by leaf through the refer machinery, so pending
|
|
460
|
+
// resolution, type flow and link stamping are the one battle-tested
|
|
461
|
+
// path, and the data side stays plain strings. The PREDICATE of every
|
|
462
|
+
// edge produced is the key the rel() sits on -- declared once, in the
|
|
463
|
+
// schema, never inferred from the path.
|
|
464
|
+
class RelVal extends FeatureVal {
|
|
465
|
+
isRel = true
|
|
466
|
+
isGenable = true
|
|
467
|
+
cjo = 45000
|
|
468
|
+
|
|
469
|
+
// The type to flow into each target; TOP when `rel()` has none.
|
|
470
|
+
tval: Val
|
|
471
|
+
// Container-level constraints met before the container arrived
|
|
472
|
+
// (`rel() & length(min(1)) & [...]`): they meet the REWRITTEN
|
|
473
|
+
// container, exactly as refer's held meets the link.
|
|
474
|
+
held?: Val
|
|
475
|
+
|
|
476
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
477
|
+
super(spec, ctx)
|
|
478
|
+
this.tval = (spec as any).tval ?? top()
|
|
479
|
+
this.held = (spec as any).held
|
|
480
|
+
// DONE while unmet, deliberately -- the property refer() lacks and
|
|
481
|
+
// G4 phase 4 records the cost of: a type() body holding a rel()
|
|
482
|
+
// must SETTLE, or the schema idiom (`dependsOn?: rel($.T)` inside
|
|
483
|
+
// a vocabulary) leaves the type unresolved and every reference to
|
|
484
|
+
// it deferring forever. An unmet rel is its own settled residual,
|
|
485
|
+
// like `min(1)`; the meet re-activates it whenever a value
|
|
486
|
+
// arrives, because map merges build the conjunct regardless.
|
|
487
|
+
this.dc = DONE
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
491
|
+
const out: any = super.clone(ctx, spec)
|
|
492
|
+
out.tval = this.tval
|
|
493
|
+
out.held = this.held
|
|
494
|
+
return out
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// The predicate: the last segment of the field path the constraint
|
|
498
|
+
// is being APPLIED at -- when that segment is a D-1 NAME. A relation
|
|
499
|
+
// predicate is a declared name (RELATIONS.0.md §3.2), so a list
|
|
500
|
+
// index or a key outside the name grammar produces unlabelled
|
|
501
|
+
// links, and the graph falls back to its old inference. The D-1
|
|
502
|
+
// test is also what keeps the two ports' edges identical: a list
|
|
503
|
+
// index is a number here and a string in Go.
|
|
504
|
+
//
|
|
505
|
+
// THE PATH COMES FROM THE CONTEXT, not from `this.path`. The val's
|
|
506
|
+
// own path records where this constraint was CLONED FROM, and the
|
|
507
|
+
// two part company the moment a second document merges into an
|
|
508
|
+
// entity: the field's constraint is then driven at the ENTITY, and
|
|
509
|
+
// `this.path` names the entity while the context names the field.
|
|
510
|
+
// The predicate became the entity's own key, every link under it
|
|
511
|
+
// minted an edge starting one level too high, and `inverse(n)`
|
|
512
|
+
// reported a mirror that was written as missing.
|
|
513
|
+
fieldkey(ctx: AontuContext): string | undefined {
|
|
514
|
+
const path: any[] = (ctx as any).path
|
|
515
|
+
const seg = path[path.length - 1]
|
|
516
|
+
return 'string' === typeof seg && PREDICATE_NAME.test(seg) ? seg : undefined
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// One leaf's residual: the refer machinery carrying rel's codes,
|
|
520
|
+
// predicate and type. The predicate is passed IN, because the field
|
|
521
|
+
// it names is decided where the rewrite starts and must not be
|
|
522
|
+
// re-read on the way down (see `rewriteUnder`).
|
|
523
|
+
leafRefer(ctx: AontuContext, relkey: string | undefined): ReferVal {
|
|
524
|
+
const rv = new ReferVal({ tval: this.tval } as any, ctx)
|
|
525
|
+
rv.addrcode = 'rel_address'
|
|
526
|
+
rv.unresolvedcode = 'rel_unresolved'
|
|
527
|
+
rv.relkey = relkey
|
|
528
|
+
rv.site = this.site
|
|
529
|
+
rv.path = this.path
|
|
530
|
+
return rv
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// The container, every string leaf wrapped as a link. Nested
|
|
534
|
+
// containers descend; a leaf already STAMPED as a link is left
|
|
535
|
+
// alone, which is what makes a second application (a template
|
|
536
|
+
// re-applied, a later pass) a no-op.
|
|
537
|
+
rewrite(ctx: AontuContext, container: any): Val {
|
|
538
|
+
return this.rewriteUnder(ctx, container, this.fieldkey(ctx))
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// The rewrite proper, carrying the predicate decided at the field.
|
|
542
|
+
// It is decided ONCE, at the top: a map-valued relation
|
|
543
|
+
// (`dependsOn: {primary: [...]}`) descends through the inner label
|
|
544
|
+
// and must still report `dependsOn`, which is the whole reason a
|
|
545
|
+
// link carries a declared predicate rather than letting the graph
|
|
546
|
+
// infer one from its position.
|
|
547
|
+
rewriteUnder(
|
|
548
|
+
ctx: AontuContext, container: any, relkey: string | undefined
|
|
549
|
+
): Val {
|
|
550
|
+
const out: any = container.clone(ctx)
|
|
551
|
+
const peg: any = out.peg
|
|
552
|
+
const keys: any[] = Array.isArray(peg)
|
|
553
|
+
? peg.map((_v: any, i: number) => i) : Object.keys(peg)
|
|
554
|
+
let pending = false
|
|
555
|
+
let nested = false
|
|
556
|
+
for (const k of keys) {
|
|
557
|
+
// Children here are always Vals: the parse builds Vals, elision
|
|
558
|
+
// builds a NilVal, and clone preserved whatever the container
|
|
559
|
+
// held.
|
|
560
|
+
const child: any = peg[k]
|
|
561
|
+
if (true === child.isMap || true === child.isList) {
|
|
562
|
+
nested = true
|
|
563
|
+
const sub: any = this.rewriteUnder(ctx.descend('' + k), child, relkey)
|
|
564
|
+
peg[k] = sub
|
|
565
|
+
pending = pending || true !== sub.done
|
|
566
|
+
}
|
|
567
|
+
else if (undefined === child.link) {
|
|
568
|
+
let leaf = unite(ctx.descend('' + k), this.leafRefer(ctx, relkey),
|
|
569
|
+
child, 'rel-leaf')
|
|
570
|
+
// The held constraints apply PER LEAF: a re() on the relation
|
|
571
|
+
// constrains every address, never the container that holds
|
|
572
|
+
// them (found by the service catalog, whose re("^svc_") met
|
|
573
|
+
// the whole list and refused it).
|
|
574
|
+
if (null != this.held) {
|
|
575
|
+
leaf = unite(ctx.descend('' + k), leaf, this.held, 'rel-held')
|
|
576
|
+
}
|
|
577
|
+
peg[k] = leaf
|
|
578
|
+
pending = pending || true !== leaf.done
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
// The rewrite holds its PENDING leaves open (an address whose
|
|
582
|
+
// entity a later statement declares), so the pass loop keeps
|
|
583
|
+
// driving the container until every link settles. A rewrite that
|
|
584
|
+
// minted NOTHING pending -- every leaf already linked or settled
|
|
585
|
+
// in place -- keeps the clone's doneness: re-applying a template
|
|
586
|
+
// over a settled value must converge in the same pass, or the
|
|
587
|
+
// enclosing bags reopen forever (the service catalog, where the
|
|
588
|
+
// entity merge drops the spread stamp each pass).
|
|
589
|
+
if (pending) {
|
|
590
|
+
out.dc = 0
|
|
591
|
+
}
|
|
592
|
+
// Elements that arrive AFTER this rewrite -- another statement of
|
|
593
|
+
// the list, a patch position of the entity -- must convert too, so
|
|
594
|
+
// the rewrite installs its own leaf constraint as the container's
|
|
595
|
+
// ELEMENT SPREAD, exactly the machinery the old per-element
|
|
596
|
+
// `[&: refer()]` idiom used. Only on a FLAT address container (a
|
|
597
|
+
// labelled map's sub-containers get their own spread from the
|
|
598
|
+
// recursion above; a leaf template meeting a map child would
|
|
599
|
+
// refuse it), and only where no spread already stands: a schema's
|
|
600
|
+
// own template is not this rewrite's to clobber.
|
|
601
|
+
if (!nested && null == (out as any).spread.cj) {
|
|
602
|
+
let tmpl: Val = this.leafRefer(ctx, relkey)
|
|
603
|
+
if (null != this.held) {
|
|
604
|
+
tmpl = new ConjunctVal({ peg: [tmpl, this.held] }, ctx)
|
|
605
|
+
}
|
|
606
|
+
; (out as any).spread.cj = tmpl
|
|
607
|
+
}
|
|
608
|
+
return out
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
unify(peer: Val, ctx: AontuContext): Val {
|
|
612
|
+
const p: any = peer
|
|
613
|
+
|
|
614
|
+
// Two rel() at one field: one relation, both types.
|
|
615
|
+
if (true === p?.isRel) {
|
|
616
|
+
const out: any = new RelVal({}, ctx)
|
|
617
|
+
out.tval = unite(ctx, this.tval, p.tval, 'rel-t')
|
|
618
|
+
out.held = null == this.held ? p.held
|
|
619
|
+
: null == p.held ? this.held
|
|
620
|
+
: unite(ctx, this.held, p.held, 'rel-held')
|
|
621
|
+
propagateMarks(this, out)
|
|
622
|
+
out.site = this.site
|
|
623
|
+
out.path = this.path
|
|
624
|
+
return out
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// No null/top/nil arms: unite's dispatch ladder absorbs those
|
|
628
|
+
// peers before any Val's own unify is consulted (a null or top
|
|
629
|
+
// peer returns this side; a nil peer returns the nil), and unite
|
|
630
|
+
// is the only entrance -- the container hand-offs pass the
|
|
631
|
+
// container itself.
|
|
632
|
+
|
|
633
|
+
// ONE ADDRESS: the scalar-valued field, refer's own shape. A path
|
|
634
|
+
// value only -- a bare string is never an address (PATHS.0.md,
|
|
635
|
+
// amended); the scalar arm below refuses it.
|
|
636
|
+
if (true === p.isPath) {
|
|
637
|
+
const out = unite(ctx, this.leafRefer(ctx, this.fieldkey(ctx)), peer,
|
|
638
|
+
'rel-scalar')
|
|
639
|
+
return null == this.held ? out
|
|
640
|
+
: unite(ctx, out, this.held, 'rel-held')
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// A SET OF LINKS: list or map, rewritten leaf by leaf; the held
|
|
644
|
+
// constraints ride into each leaf inside the rewrite.
|
|
645
|
+
if (true === p.isMap || true === p.isList) {
|
|
646
|
+
return this.rewrite(ctx, peer)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// A scalar that can never be an address.
|
|
650
|
+
if (true === p.isScalar) {
|
|
651
|
+
return makeNilErr(ctx, 'rel_address', this, peer, 'refer')
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Everything else -- a reference still resolving, a kind, a
|
|
655
|
+
// container constraint -- waits for the value, as refer's held
|
|
656
|
+
// does.
|
|
657
|
+
const out: any = new RelVal({}, ctx)
|
|
658
|
+
out.tval = this.tval
|
|
659
|
+
out.held = null == this.held ? peer
|
|
660
|
+
: unite(ctx, this.held, peer, 'rel-held')
|
|
661
|
+
propagateMarks(this, out)
|
|
662
|
+
out.site = this.site
|
|
663
|
+
out.path = this.path
|
|
664
|
+
return out
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
get canon() {
|
|
668
|
+
const t = this.tval.isTop ? '' : this.tval.canon
|
|
669
|
+
return 'rel(' + t + ')' +
|
|
670
|
+
(null == this.held ? '' : '&' + this.held.canon)
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
class RelFuncVal extends FuncBaseVal {
|
|
676
|
+
isRelFunc = true
|
|
677
|
+
|
|
678
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
679
|
+
super(spec, ctx)
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
make(_ctx: AontuContext, spec: ValSpec): Val {
|
|
683
|
+
return new RelFuncVal(spec)
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
funcname() {
|
|
687
|
+
return 'rel'
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
resolve(ctx: AontuContext, args: Val[]) {
|
|
691
|
+
const out = new RelVal({}, ctx)
|
|
692
|
+
out.tval = 0 < args.length ? args[0] : top()
|
|
693
|
+
out.site = this.site
|
|
694
|
+
out.path = this.path
|
|
695
|
+
return out
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
class ReferFuncVal extends FuncBaseVal {
|
|
701
|
+
isReferFunc = true
|
|
702
|
+
|
|
703
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
704
|
+
super(spec, ctx)
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
make(_ctx: AontuContext, spec: ValSpec): Val {
|
|
708
|
+
return new ReferFuncVal(spec)
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
funcname() {
|
|
712
|
+
return 'refer'
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
resolve(ctx: AontuContext, args: Val[]) {
|
|
716
|
+
const out = new ReferVal({}, ctx)
|
|
717
|
+
out.tval = 0 < args.length ? args[0] : top()
|
|
718
|
+
out.site = this.site
|
|
719
|
+
out.path = this.path
|
|
720
|
+
return out
|
|
721
|
+
}
|
|
722
|
+
} /* node:coverage ignore next 10 */
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
// The address machinery itself (Address, parseAddress, prefixMeet)
|
|
726
|
+
// lives in PathVal, its home since ADR-016 -- import it from there.
|
|
727
|
+
export {
|
|
728
|
+
ReferFuncVal,
|
|
729
|
+
ReferVal,
|
|
730
|
+
RelFuncVal,
|
|
731
|
+
RelVal,
|
|
732
|
+
}
|