aontu 0.53.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aontu.d.ts +3 -2
- package/dist/aontu.js +36 -7
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +500 -8
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +5 -0
- package/dist/ctx.js +1 -0
- package/dist/ctx.js.map +1 -1
- package/dist/diff.js.map +1 -1
- package/dist/err.js +7 -1
- package/dist/err.js.map +1 -1
- package/dist/graph.d.ts +2 -5
- package/dist/graph.js +83 -46
- package/dist/graph.js.map +1 -1
- package/dist/hcanon.js +9 -10
- package/dist/hcanon.js.map +1 -1
- package/dist/hints.js +94 -26
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.js +34 -0
- package/dist/jsonschema.js.map +1 -1
- package/dist/lang.js +593 -191
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/lsp.js +86 -6
- package/dist/lsp.js.map +1 -1
- package/dist/mcp.js +153 -6
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +42 -8
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.d.ts +4 -0
- package/dist/mod.js +97 -2
- package/dist/mod.js.map +1 -1
- package/dist/patch.d.ts +5 -0
- package/dist/patch.js +25 -25
- package/dist/patch.js.map +1 -1
- package/dist/provenance.d.ts +1 -0
- package/dist/provenance.js +2 -1
- package/dist/provenance.js.map +1 -1
- package/dist/query.js.map +1 -1
- package/dist/reach.d.ts +1 -0
- package/dist/reach.js +49 -21
- package/dist/reach.js.map +1 -1
- package/dist/relation.d.ts +4 -0
- package/dist/relation.js +125 -200
- package/dist/relation.js.map +1 -1
- package/dist/sig.d.ts +25 -0
- package/dist/sig.js +277 -0
- package/dist/sig.js.map +1 -0
- package/dist/sigdecl.d.ts +2 -0
- package/dist/sigdecl.js +11 -0
- package/dist/sigdecl.js.map +1 -0
- package/dist/siggate.d.ts +4 -0
- package/dist/siggate.js +90 -0
- package/dist/siggate.js.map +1 -0
- package/dist/std.js +75 -16
- package/dist/std.js.map +1 -1
- package/dist/subsume.js +57 -10
- package/dist/subsume.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/unify.d.ts +2 -2
- package/dist/unify.js +93 -114
- package/dist/unify.js.map +1 -1
- package/dist/utility.d.ts +1 -2
- package/dist/utility.js +7 -61
- package/dist/utility.js.map +1 -1
- package/dist/val/AggFuncVal.d.ts +12 -1
- package/dist/val/AggFuncVal.js +165 -3
- package/dist/val/AggFuncVal.js.map +1 -1
- package/dist/val/BagVal.d.ts +2 -0
- package/dist/val/BagVal.js +56 -8
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/ConstraintVal.js +33 -5
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.d.ts +35 -0
- package/dist/val/ContainerKindVal.js +99 -0
- package/dist/val/ContainerKindVal.js.map +1 -0
- package/dist/val/CopyFuncVal.js +0 -7
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.d.ts +1 -2
- package/dist/val/DisjunctVal.js +146 -39
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/ExpectVal.js +37 -2
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +19 -8
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.d.ts +39 -0
- package/dist/val/GraphAtomVal.js +184 -0
- package/dist/val/GraphAtomVal.js.map +1 -0
- package/dist/val/JunctionVal.js +22 -5
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/ListVal.js +27 -34
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/MapVal.d.ts +1 -0
- package/dist/val/MapVal.js +82 -35
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/PathFuncVal.d.ts +2 -2
- package/dist/val/PathFuncVal.js +75 -16
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.d.ts +25 -0
- package/dist/val/PathVal.js +150 -0
- package/dist/val/PathVal.js.map +1 -0
- package/dist/val/PlusOpVal.d.ts +2 -1
- package/dist/val/PlusOpVal.js +50 -35
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +2 -0
- package/dist/val/PrefVal.js +159 -32
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.d.ts +19 -0
- package/dist/val/RecurseVal.js +217 -0
- package/dist/val/RecurseVal.js.map +1 -0
- package/dist/val/RefVal.d.ts +2 -1
- package/dist/val/RefVal.js +105 -72
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.d.ts +30 -7
- package/dist/val/ReferFuncVal.js +395 -94
- package/dist/val/ReferFuncVal.js.map +1 -1
- package/dist/val/ScalarKindVal.d.ts +4 -2
- package/dist/val/ScalarKindVal.js +12 -1
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/SuperFuncVal.d.ts +4 -2
- package/dist/val/SuperFuncVal.js +118 -14
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.d.ts +1 -1
- package/dist/val/Val.d.ts +2 -3
- package/dist/val/Val.js +39 -20
- package/dist/val/Val.js.map +1 -1
- package/dist/val/arith.js +4 -1
- package/dist/val/arith.js.map +1 -1
- package/dist/vet.d.ts +1 -0
- package/dist/vet.js +32 -1
- package/dist/vet.js.map +1 -1
- package/dist/view.d.ts +90 -0
- package/dist/view.js +2168 -0
- package/dist/view.js.map +1 -0
- package/grammar/aontu.gbnf +18 -10
- package/grammar/aontu.lark +15 -10
- package/grammar/aontu.tmLanguage.json +184 -0
- package/package.json +10 -3
- package/skill/grammar-card.md +1 -2
- package/src/aontu.ts +37 -7
- package/src/cli.ts +553 -8
- package/src/ctx.ts +20 -0
- package/src/diff.ts +4 -2
- package/src/err.ts +8 -1
- package/src/graph.ts +125 -75
- package/src/hcanon.ts +9 -11
- package/src/hints.ts +112 -29
- package/src/jsonschema.ts +41 -0
- package/src/lang.ts +642 -203
- package/src/lsp.ts +75 -6
- package/src/mcp.ts +164 -6
- package/src/mod-tool.ts +48 -9
- package/src/mod.ts +110 -1
- package/src/patch.ts +31 -27
- package/src/provenance.ts +8 -1
- package/src/query.ts +4 -2
- package/src/reach.ts +52 -23
- package/src/relation.ts +139 -236
- package/src/sig.ts +345 -0
- package/src/sigdecl.ts +11 -0
- package/src/siggate.ts +144 -0
- package/src/std.ts +77 -16
- package/src/subsume.ts +59 -10
- package/src/unify.ts +102 -125
- package/src/utility.ts +7 -67
- package/src/val/AggFuncVal.ts +231 -4
- package/src/val/BagVal.ts +58 -9
- package/src/val/ConstraintVal.ts +34 -5
- package/src/val/ContainerKindVal.ts +158 -0
- package/src/val/CopyFuncVal.ts +0 -7
- package/src/val/DisjunctVal.ts +152 -40
- package/src/val/ExpectVal.ts +39 -4
- package/src/val/FuncBaseVal.ts +21 -8
- package/src/val/GraphAtomVal.ts +264 -0
- package/src/val/JunctionVal.ts +23 -6
- package/src/val/ListVal.ts +30 -37
- package/src/val/MapVal.ts +87 -39
- package/src/val/PathFuncVal.ts +107 -19
- package/src/val/PathVal.ts +221 -0
- package/src/val/PlusOpVal.ts +56 -37
- package/src/val/PrefVal.ts +186 -38
- package/src/val/RecurseVal.ts +285 -0
- package/src/val/RefVal.ts +105 -83
- package/src/val/ReferFuncVal.ts +445 -100
- package/src/val/ScalarKindVal.ts +12 -0
- package/src/val/SuperFuncVal.ts +137 -13
- package/src/val/TopVal.ts +1 -1
- package/src/val/Val.ts +44 -35
- package/src/val/arith.ts +4 -1
- package/src/vet.ts +41 -4
- package/src/view.ts +2882 -0
- package/dist/val/IdFuncVal.d.ts +0 -13
- package/dist/val/IdFuncVal.js +0 -54
- package/dist/val/IdFuncVal.js.map +0 -1
- package/src/val/IdFuncVal.ts +0 -91
package/src/sig.ts
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/* Copyright (c) 2021-2026 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// THE SIGNATURE REGISTRY (docs/design/SIGNATURES.0.md). The call
|
|
4
|
+
// surface of the built-in functions is DECLARED, in the signature
|
|
5
|
+
// syntax itself, in test/spec/signature.tsv; this module is the
|
|
6
|
+
// TypeScript half of the pair that reads it. The declaration text is
|
|
7
|
+
// inlined at build time (ts/src/sigdecl.ts, `make sig`) and parsed at
|
|
8
|
+
// initialisation by the signature grammar -- a custom tabnas grammar,
|
|
9
|
+
// the same engine the aontu grammar itself is built on -- into the
|
|
10
|
+
// registry the runtime signature checker, the error-message builder,
|
|
11
|
+
// the docs table and the LSP all consume. Neither port authors a
|
|
12
|
+
// table: go/sig.go parses the same text with the same grammar, and
|
|
13
|
+
// the shared suite round-trips every line (render(parse(line)) is the
|
|
14
|
+
// line) so the two parsers cannot drift.
|
|
15
|
+
//
|
|
16
|
+
// line = name '(' [ arg {',' arg} ] ')' ':' type
|
|
17
|
+
// arg = [mode] name ['?'] ':' type
|
|
18
|
+
// | '...' name ':' ( type | '(' [mode] type {',' [mode] type} ')' )
|
|
19
|
+
// type = word {'|' word}
|
|
20
|
+
// mode = 'capture' | 'template' | 'trial' | 'projector' | 'text'
|
|
21
|
+
//
|
|
22
|
+
// `value` mode is unmarked; the five marked modes are the vocabulary
|
|
23
|
+
// plain pseudo-TypeScript cannot say (a captured spelling is not a
|
|
24
|
+
// string value). The grammar is line-oriented: the loader strips
|
|
25
|
+
// comment and blank lines and parses each declaration line alone, so
|
|
26
|
+
// the grammar never sees line structure.
|
|
27
|
+
|
|
28
|
+
import { Tabnas } from '@tabnas/parser'
|
|
29
|
+
|
|
30
|
+
import { SIGDECL } from './sigdecl'
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
type ArgMode = 'value' | 'capture' | 'template' | 'trial' | 'projector' | 'text'
|
|
34
|
+
|
|
35
|
+
// One group member of a rest-group argument (match's pattern/result
|
|
36
|
+
// pair): a mode and a type, no name -- the group repeats.
|
|
37
|
+
type GroupSig = {
|
|
38
|
+
mode: ArgMode
|
|
39
|
+
type: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type ArgSig = {
|
|
43
|
+
name: string
|
|
44
|
+
mode: ArgMode
|
|
45
|
+
type: string
|
|
46
|
+
opt?: boolean
|
|
47
|
+
rest?: boolean
|
|
48
|
+
group?: GroupSig[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type FuncSig = {
|
|
52
|
+
name: string
|
|
53
|
+
args: ArgSig[]
|
|
54
|
+
out: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const ARG_MODES: Record<string, boolean> = {
|
|
58
|
+
capture: true, template: true, trial: true, projector: true, text: true,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// The signature grammar, as a tabnas grammar plugin. Rules: sig (the
|
|
63
|
+
// line) -> args -> arg -> argtype -> type | group -> gmember. Alts
|
|
64
|
+
// match at most two tokens, the engine's shape; lists loop the
|
|
65
|
+
// json-grammar way (the element rule replaces itself on ',' and
|
|
66
|
+
// backtracks the closer for its parent to consume).
|
|
67
|
+
function sigGrammar(tn: any) {
|
|
68
|
+
tn.options({
|
|
69
|
+
fixed: {
|
|
70
|
+
token: {
|
|
71
|
+
'#OP': '(',
|
|
72
|
+
'#CP': ')',
|
|
73
|
+
'#QM': '?',
|
|
74
|
+
'#PI': '|',
|
|
75
|
+
'#DD': '...',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
rule: { start: 'sig' },
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// Parse-level validation errors, collected by the actions: the
|
|
82
|
+
// engine's own errors cover token shape, these cover word choice (a
|
|
83
|
+
// mode that is not a mode). Read after parse by parseSigLine.
|
|
84
|
+
const errs: string[] = []
|
|
85
|
+
tn.sigErrs = errs
|
|
86
|
+
|
|
87
|
+
const mode = (word: string): ArgMode => {
|
|
88
|
+
if (true !== ARG_MODES[word]) {
|
|
89
|
+
errs.push('mode:' + word)
|
|
90
|
+
return 'value'
|
|
91
|
+
}
|
|
92
|
+
return word as ArgMode
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
tn.grammar({
|
|
96
|
+
ref: {
|
|
97
|
+
'@sig-bo': (r: any) => {
|
|
98
|
+
r.node = { name: '', args: [], out: '' }
|
|
99
|
+
r.u.words = []
|
|
100
|
+
},
|
|
101
|
+
'@signame': (r: any) => {
|
|
102
|
+
r.node.name = String(r.o0.val)
|
|
103
|
+
},
|
|
104
|
+
'@sigargs': (r: any) => {
|
|
105
|
+
r.node.args = r.child.node
|
|
106
|
+
},
|
|
107
|
+
'@sigout': (r: any) => {
|
|
108
|
+
r.node.out = r.u.words.join('|')
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
'@args-bo': (r: any) => {
|
|
112
|
+
r.node = []
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
'@arg-bo': (r: any) => {
|
|
116
|
+
r.u.sig = { name: '', mode: 'value', type: '' }
|
|
117
|
+
},
|
|
118
|
+
'@arg-rest': (r: any) => {
|
|
119
|
+
r.u.sig.rest = true
|
|
120
|
+
r.u.sig.name = String(r.o1.val)
|
|
121
|
+
},
|
|
122
|
+
'@arg-modename': (r: any) => {
|
|
123
|
+
r.u.sig.mode = mode(String(r.o0.val))
|
|
124
|
+
r.u.sig.name = String(r.o1.val)
|
|
125
|
+
},
|
|
126
|
+
'@arg-name': (r: any) => {
|
|
127
|
+
r.u.sig.name = String(r.o0.val)
|
|
128
|
+
},
|
|
129
|
+
'@arg-opt': (r: any) => {
|
|
130
|
+
r.u.sig.opt = true
|
|
131
|
+
},
|
|
132
|
+
'@arg-done': (r: any) => {
|
|
133
|
+
const sig = r.u.sig
|
|
134
|
+
const at = r.child.node
|
|
135
|
+
if (Array.isArray(at)) {
|
|
136
|
+
sig.group = at
|
|
137
|
+
sig.type = ''
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
sig.type = String(at)
|
|
141
|
+
}
|
|
142
|
+
r.node.push(sig)
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
'@argtype-bo': (r: any) => {
|
|
146
|
+
r.u.words = []
|
|
147
|
+
},
|
|
148
|
+
'@argtype-bc': (r: any) => {
|
|
149
|
+
r.node = 0 < r.u.words.length ?
|
|
150
|
+
r.u.words.join('|') : r.child.node
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
'@type-word': (r: any) => {
|
|
154
|
+
r.parent.u.words.push(String(r.o0.val))
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
'@group-bo': (r: any) => {
|
|
158
|
+
r.node = []
|
|
159
|
+
},
|
|
160
|
+
'@gm-two': (r: any) => {
|
|
161
|
+
r.u.gm = { mode: mode(String(r.o0.val)), type: String(r.o1.val) }
|
|
162
|
+
},
|
|
163
|
+
'@gm-one': (r: any) => {
|
|
164
|
+
r.u.gm = { mode: 'value', type: String(r.o0.val) }
|
|
165
|
+
},
|
|
166
|
+
'@gm-done': (r: any) => {
|
|
167
|
+
r.node.push(r.u.gm)
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
rule: {
|
|
172
|
+
sig: {
|
|
173
|
+
open: [
|
|
174
|
+
{ s: '#TX #OP', a: '@signame', p: 'args' },
|
|
175
|
+
],
|
|
176
|
+
close: [
|
|
177
|
+
{ s: '#CL', p: 'type', a: '@sigargs' },
|
|
178
|
+
{ s: '#ZZ', a: '@sigout' },
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
args: {
|
|
183
|
+
open: [
|
|
184
|
+
{ s: '#CP', b: 1 },
|
|
185
|
+
{ p: 'arg' },
|
|
186
|
+
],
|
|
187
|
+
close: [
|
|
188
|
+
{ s: '#CP' },
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
arg: {
|
|
193
|
+
open: [
|
|
194
|
+
{ s: '#DD #TX', a: '@arg-rest' },
|
|
195
|
+
{ s: '#TX #TX', a: '@arg-modename' },
|
|
196
|
+
{ s: '#TX', a: '@arg-name' },
|
|
197
|
+
],
|
|
198
|
+
close: [
|
|
199
|
+
{ s: '#QM #CL', a: '@arg-opt', p: 'argtype' },
|
|
200
|
+
{ s: '#CL', p: 'argtype' },
|
|
201
|
+
{ s: '#CA', a: '@arg-done', r: 'arg' },
|
|
202
|
+
{ s: '#CP', a: '@arg-done', b: 1 },
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
argtype: {
|
|
207
|
+
open: [
|
|
208
|
+
{ s: '#OP', p: 'group' },
|
|
209
|
+
{ p: 'type' },
|
|
210
|
+
],
|
|
211
|
+
close: [
|
|
212
|
+
{},
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
type: {
|
|
217
|
+
open: [
|
|
218
|
+
{ s: '#TX', a: '@type-word' },
|
|
219
|
+
],
|
|
220
|
+
close: [
|
|
221
|
+
{ s: '#PI', r: 'type' },
|
|
222
|
+
{},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
group: {
|
|
227
|
+
open: [
|
|
228
|
+
{ p: 'gmember' },
|
|
229
|
+
],
|
|
230
|
+
close: [
|
|
231
|
+
{ s: '#CP' },
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
gmember: {
|
|
236
|
+
open: [
|
|
237
|
+
{ s: '#TX #TX', a: '@gm-two' },
|
|
238
|
+
{ s: '#TX', a: '@gm-one' },
|
|
239
|
+
],
|
|
240
|
+
close: [
|
|
241
|
+
{ s: '#CA', a: '@gm-done', r: 'gmember' },
|
|
242
|
+
{ s: '#CP', a: '@gm-done', b: 1 },
|
|
243
|
+
],
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
let sigParser: any = undefined
|
|
251
|
+
|
|
252
|
+
function makeSigParser(): any {
|
|
253
|
+
if (undefined === sigParser) {
|
|
254
|
+
sigParser = new Tabnas({ plugins: [sigGrammar] })
|
|
255
|
+
}
|
|
256
|
+
return sigParser
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
// Parse ONE declaration line. A malformed line is an Error: the
|
|
261
|
+
// declaration is repository content, read at build and test time, so
|
|
262
|
+
// failing loudly is the right shape (the round-trip suite holds the
|
|
263
|
+
// gate).
|
|
264
|
+
function parseSigLine(line: string): FuncSig {
|
|
265
|
+
const tn = makeSigParser()
|
|
266
|
+
tn.sigErrs.length = 0
|
|
267
|
+
const out = tn.parse(line)
|
|
268
|
+
if (0 < tn.sigErrs.length) {
|
|
269
|
+
throw new Error('signature: bad declaration ' +
|
|
270
|
+
tn.sigErrs.join(',') + ': ' + line)
|
|
271
|
+
}
|
|
272
|
+
if (null == out || '' === out.name || '' === out.out) {
|
|
273
|
+
throw new Error('signature: incomplete declaration: ' + line)
|
|
274
|
+
}
|
|
275
|
+
return out as FuncSig
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
// Render one argument of a signature -- the piece the LSP's
|
|
280
|
+
// signatureHelp parameters share with the whole-line renderer.
|
|
281
|
+
function renderSigArg(a: ArgSig): string {
|
|
282
|
+
const type = undefined === a.group ? a.type :
|
|
283
|
+
'(' + a.group.map((g: GroupSig) =>
|
|
284
|
+
('value' === g.mode ? '' : g.mode + ' ') + g.type).join(', ') + ')'
|
|
285
|
+
return (true === a.rest ? '...' : '') +
|
|
286
|
+
('value' === a.mode || true === a.rest ? '' : a.mode + ' ') +
|
|
287
|
+
a.name +
|
|
288
|
+
(true === a.opt ? '?' : '') +
|
|
289
|
+
': ' + type
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
// Render the canonical line for a parsed signature -- the round-trip
|
|
294
|
+
// twin of parseSigLine, and the one renderer every consumer (hints,
|
|
295
|
+
// docs, LSP) uses.
|
|
296
|
+
function renderSig(sig: FuncSig): string {
|
|
297
|
+
return sig.name + '(' +
|
|
298
|
+
sig.args.map(renderSigArg).join(', ') + ') : ' + sig.out
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
// Parse the whole declaration text: comment (#) and blank lines are
|
|
303
|
+
// the loader's to skip, one FuncSig per remaining line, name-keyed.
|
|
304
|
+
// A duplicate name is an error for the same reason a bad line is.
|
|
305
|
+
function parseSigText(text: string): Record<string, FuncSig> {
|
|
306
|
+
const reg: Record<string, FuncSig> = {}
|
|
307
|
+
for (const rawline of text.split('\n')) {
|
|
308
|
+
const line = rawline.trim()
|
|
309
|
+
if ('' === line || line.startsWith('#')) {
|
|
310
|
+
continue
|
|
311
|
+
}
|
|
312
|
+
const sig = parseSigLine(line)
|
|
313
|
+
if (undefined !== reg[sig.name]) {
|
|
314
|
+
throw new Error('signature: duplicate declaration: ' + sig.name)
|
|
315
|
+
}
|
|
316
|
+
reg[sig.name] = sig
|
|
317
|
+
}
|
|
318
|
+
return reg
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
export type {
|
|
323
|
+
ArgMode,
|
|
324
|
+
ArgSig,
|
|
325
|
+
GroupSig,
|
|
326
|
+
FuncSig,
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// The parsed registry, built once from the inlined declaration -- the
|
|
330
|
+
// one source every consumer (the arity tables, the runtime gate, the
|
|
331
|
+
// hints, the docs table, the LSP) reads. A parse failure here throws
|
|
332
|
+
// at module load: the inlined text is repository content whose parse
|
|
333
|
+
// the round-trip suite gates, so a failure is a build defect, not a
|
|
334
|
+
// runtime condition. Twin: funcSig in go/sig.go.
|
|
335
|
+
const funcSig: Record<string, FuncSig> =
|
|
336
|
+
parseSigText(SIGDECL) /* node:coverage ignore next 9 */
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
export {
|
|
340
|
+
funcSig,
|
|
341
|
+
parseSigLine,
|
|
342
|
+
parseSigText,
|
|
343
|
+
renderSig,
|
|
344
|
+
renderSigArg,
|
|
345
|
+
}
|
package/src/sigdecl.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* Copyright (c) 2021-2026 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// GENERATED by ts/scripts/sigdecl.cjs (`make sig`) from
|
|
4
|
+
// test/spec/signature.tsv — DO NOT EDIT. The declaration is the
|
|
5
|
+
// source (docs/design/SIGNATURES.0.md); ts/test/sig.test.ts asserts
|
|
6
|
+
// this copy is identical with the shared file.
|
|
7
|
+
|
|
8
|
+
const SIGDECL: string =
|
|
9
|
+
"# The call surface: one declaration line per built-in function\n# (docs/design/SIGNATURES.0.md). THIS FILE IS THE SOURCE — both ports\n# carry a build-time-inlined copy (ts/src/sigdecl.ts, go/sigdecl.txt;\n# `make sig` regenerates both, and each port's suite asserts its copy\n# is byte-identical with this file) and parse it at initialisation\n# with the signature grammar, a tabnas grammar (ts/src/sig.ts,\n# go/sig.go). The suites also round-trip every line:\n# render(parse(line)) must be the line exactly, in both ports.\n#\n# The syntax (rendered TypeScript-ish, honest about argument MODES):\n# line = name '(' [ arg {',' arg} ] ')' ':' type\n# arg = [mode] name ['?'] ':' type\n# | '...' name ':' '(' [mode] type {',' [mode] type} ')'\n# type = word {'|' word}\n# mode = 'capture' | 'template' | 'trial' | 'projector' | 'text'\n# `value` mode is unmarked. `constraint` is the result word for\n# residuals whose meet depends on the peer; `any` is the honest type\n# where a function is a wrapper.\nupper(s: string|number) : string\nlower(s: string|number) : string\ncopy(v: any) : any\npref(v: any) : any\nsuper(t: any) : any\ntype(t: any) : any\nhide(v: any) : any\nclose(m: any) : any\nopen(m: any) : any\nmove(v: any) : any\npath(capture p?: path) : path\nmap() : map\nlist() : list\nmin(n: number|string) : constraint\nmax(n: number|string) : constraint\nabove(n: number|string) : constraint\nbelow(n: number|string) : constraint\nre(text p: string) : constraint\nlength(n: number|constraint) : constraint\nkey(up?: integer|biginteger) : string\nunique(projector k?: string) : constraint\nneq(...vals: number|string) : constraint\nmust(trial c: any, text msg: string) : constraint\ndeprecate(v: any, r?: map) : any\nacyclic() : constraint\ninverse(projector k: string) : constraint\nrefer(template t?: any) : constraint\nrel(template t?: any) : constraint\npack(d: map|list, template t: any) : map\neach(d: map|list, template t?: any) : list\nfilter(d: map|list, trial c: any) : map|list\nmatch(s: any, ...pr: (trial any, any), dflt?: any) : any\nadd(a: number, b: number) : number\nsub(a: number, b: number) : number\nmul(a: number, b: number) : number\ndiv(a: number, b: number) : number\nmod(a: number, b: number) : number\nrem(a: number, b: number) : number\nsum(d: map|list) : number\nleast(d: map|list) : number\ngreatest(d: map|list) : number\npick(d: map|list, projector k: string|integer) : any\njoin(d: map|list, sep?: string) : string\n"
|
|
10
|
+
|
|
11
|
+
export { SIGDECL }
|
package/src/siggate.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/* Copyright (c) 2021-2026 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// THE RUNTIME SIGNATURE CHECKER (docs/design/SIGNATURES.0.md). One
|
|
4
|
+
// argument gate, run by the shared function machinery
|
|
5
|
+
// (FuncBaseVal.unify) just before a call resolves, when its arguments
|
|
6
|
+
// are driven: for each VALUE-mode argument whose declared type is
|
|
7
|
+
// scalar-kind words, the driven Val must be a concrete scalar of an
|
|
8
|
+
// admitted kind. A failure refuses as `func_arg`, whose hint renders
|
|
9
|
+
// the signature line and names the offending argument -- the
|
|
10
|
+
// error-message builder the registry exists for.
|
|
11
|
+
//
|
|
12
|
+
// The gate owns exactly the argument-shape refusals that were bare
|
|
13
|
+
// `invalid-arg` at the call: the case family's operand, the
|
|
14
|
+
// arithmetic operands, join's separator, pick's key. Everything with
|
|
15
|
+
// more meaning than a shape mismatch keeps its own code: the bag
|
|
16
|
+
// arguments (`pack_data`, `each_data`, `filter_data`,
|
|
17
|
+
// `aggregate_data` -- container words are not gate words), the
|
|
18
|
+
// constraint atoms (not on this path at all -- their refusals ride
|
|
19
|
+
// the residual), `key()` (whose level meaning `key_level` names, and
|
|
20
|
+
// which is skipped here for that reason), and the capture, template,
|
|
21
|
+
// trial, projector and text modes, none of which are read as values.
|
|
22
|
+
//
|
|
23
|
+
// What the gate refuses it must POSITIVELY identify: a concrete
|
|
24
|
+
// scalar of a wrong kind, a map, a list, or a scalar KIND marker
|
|
25
|
+
// where a value belongs. Anything else -- a preference, a residual, a
|
|
26
|
+
// disjunct -- passes through to the builtin's own logic, which is
|
|
27
|
+
// what keeps arith's unpref reading and join's deferral working.
|
|
28
|
+
// Twin: sigRefuse in go/siggate.go.
|
|
29
|
+
|
|
30
|
+
import type { Val } from './type'
|
|
31
|
+
import { AontuContext } from './ctx'
|
|
32
|
+
import { makeNilErr } from './err'
|
|
33
|
+
|
|
34
|
+
import { funcSig, renderSig } from './sig'
|
|
35
|
+
import type { FuncSig, ArgSig } from './sig'
|
|
36
|
+
|
|
37
|
+
import {
|
|
38
|
+
BigDecimal,
|
|
39
|
+
BigInteger,
|
|
40
|
+
Float,
|
|
41
|
+
Integer,
|
|
42
|
+
Path,
|
|
43
|
+
kindSubsumes,
|
|
44
|
+
} from './val/ScalarKindVal'
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
// The scalar-kind words the gate enforces, each to its lattice
|
|
48
|
+
// marker. A declared type is gate-checkable only when EVERY union
|
|
49
|
+
// word is here: `any`, `constraint`, and the container words leave
|
|
50
|
+
// the argument to the builtin.
|
|
51
|
+
const SIG_KIND = new Map<string, any>([
|
|
52
|
+
['string', String],
|
|
53
|
+
['number', Number],
|
|
54
|
+
['integer', Integer],
|
|
55
|
+
['float', Float],
|
|
56
|
+
['biginteger', BigInteger],
|
|
57
|
+
['bigdecimal', BigDecimal],
|
|
58
|
+
['boolean', Boolean],
|
|
59
|
+
['path', Path],
|
|
60
|
+
])
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
function gateWords(type: string): any[] | undefined {
|
|
64
|
+
const out: any[] = []
|
|
65
|
+
for (const word of type.split('|')) {
|
|
66
|
+
const marker = SIG_KIND.get(word)
|
|
67
|
+
if (undefined === marker) {
|
|
68
|
+
return undefined
|
|
69
|
+
}
|
|
70
|
+
out.push(marker)
|
|
71
|
+
}
|
|
72
|
+
return out
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
// The declared type admits a driven Val when the Val is a concrete
|
|
77
|
+
// scalar whose leaf kind is, or sits below, one of the declared
|
|
78
|
+
// words -- the same walk subsumption makes, so `number` admits every
|
|
79
|
+
// numeric leaf and `string` admits a path value.
|
|
80
|
+
function admits(markers: any[], arg: any): boolean {
|
|
81
|
+
const leaf: any = arg.superior?.()
|
|
82
|
+
if (true !== arg.isScalar || true !== leaf?.isScalarKind) {
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
for (const marker of markers) {
|
|
86
|
+
if (marker === leaf.peg || kindSubsumes(marker, leaf.peg)) {
|
|
87
|
+
return true
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return false
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
// The gate. Answers the func_arg refusal, or undefined to let the
|
|
95
|
+
// call resolve.
|
|
96
|
+
function sigRefuse(
|
|
97
|
+
ctx: AontuContext, fn: any, args: Val[]
|
|
98
|
+
): Val | undefined {
|
|
99
|
+
const sig: FuncSig | undefined = funcSig[fn.funcname()]
|
|
100
|
+
|
|
101
|
+
// key() reads its level off the written peg and `key_level` names
|
|
102
|
+
// what is wrong with a bad one; the gate leaves the meaning where
|
|
103
|
+
// it lives.
|
|
104
|
+
if (undefined === sig || 'key' === sig.name) {
|
|
105
|
+
return undefined
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (let i = 0; i < sig.args.length; i++) {
|
|
109
|
+
const a: ArgSig = sig.args[i]
|
|
110
|
+
if (true === a.rest) {
|
|
111
|
+
break
|
|
112
|
+
}
|
|
113
|
+
if ('value' !== a.mode) {
|
|
114
|
+
continue
|
|
115
|
+
}
|
|
116
|
+
const markers = gateWords(a.type)
|
|
117
|
+
if (undefined === markers) {
|
|
118
|
+
continue
|
|
119
|
+
}
|
|
120
|
+
const arg: any = args[i]
|
|
121
|
+
if (undefined === arg || true === arg.isNil || true !== arg.done) {
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
const shaped = (true === arg.isScalar) ||
|
|
125
|
+
(true === arg.isMap) || (true === arg.isList) ||
|
|
126
|
+
(true === arg.isScalarKind)
|
|
127
|
+
if (shaped && !admits(markers, arg)) {
|
|
128
|
+
return makeNilErr(ctx, 'func_arg', fn, arg, undefined, {
|
|
129
|
+
func: sig.name,
|
|
130
|
+
sig: renderSig(sig),
|
|
131
|
+
arg: a.name,
|
|
132
|
+
argn: '' + (i + 1),
|
|
133
|
+
got: arg.canon,
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return undefined
|
|
139
|
+
} /* node:coverage ignore next 5 */
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
export {
|
|
143
|
+
sigRefuse,
|
|
144
|
+
}
|
package/src/std.ts
CHANGED
|
@@ -32,9 +32,9 @@ std: {
|
|
|
32
32
|
protocol?: string
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
# A node with ports.
|
|
36
|
-
# component OF
|
|
37
|
-
#
|
|
35
|
+
# A node with ports. Where a Component sits in the tree is what it
|
|
36
|
+
# is a component OF -- containment is the document's own structure
|
|
37
|
+
# and needs no mark of its own.
|
|
38
38
|
Component: type({
|
|
39
39
|
ports?: {&: $.std.Port}
|
|
40
40
|
})
|
|
@@ -49,25 +49,86 @@ std: {
|
|
|
49
49
|
ports?: {&: $.std.Port}
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
# (The Relation schema that used to sit here is retired with the
|
|
53
|
+
# relations: magic key, RELATIONS.0.md P2: a relation is declared
|
|
54
|
+
# by the graph atoms at its field -- rel(t) & acyclic() &
|
|
55
|
+
# inverse(name) -- and the target half is rel(t)'s flow.)
|
|
56
|
+
}
|
|
57
|
+
`
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
const STD_VIEW = `# std/view --- the FIGURE VOCABULARY (VIEWS.0.md, "6. The view
|
|
61
|
+
# document"). A view document declares its figures as data, and a
|
|
62
|
+
# declaration is just a map: this is the schema for one, so a typo is
|
|
63
|
+
# refused where every other mistake in an Aontu document is refused --
|
|
64
|
+
# at evaluation, by unification -- rather than by the verb that reads
|
|
65
|
+
# it afterwards.
|
|
66
|
+
#
|
|
67
|
+
# @"std/view"
|
|
68
|
+
# @"./system.aon"
|
|
69
|
+
#
|
|
70
|
+
# views: {&: $.view.Figure} & {
|
|
71
|
+
# arch: {kind: matrix, order: partition, out: "docs/arch.dsm.txt"}
|
|
72
|
+
# }
|
|
73
|
+
#
|
|
74
|
+
# The keys ARE the view options: the command-line flags without the
|
|
75
|
+
# dashes, one vocabulary for the CLI, the library and the file. The
|
|
76
|
+
# poset is not among the kinds, because a view document declares
|
|
77
|
+
# figures of the ONE document it includes and the poset compares
|
|
78
|
+
# several.
|
|
79
|
+
#
|
|
80
|
+
# EXPERIMENTAL until the distribution layer can version it by
|
|
81
|
+
# canon-hash. This file carries no backtick: it is one string literal
|
|
82
|
+
# per port, and Go raw strings have no escape.
|
|
83
|
+
|
|
84
|
+
view: {
|
|
85
|
+
|
|
86
|
+
# One declared figure. The kind says what to draw and out says where
|
|
87
|
+
# it belongs; everything else narrows the drawing, and each option
|
|
88
|
+
# belongs to the kinds that read it.
|
|
89
|
+
Figure: type({
|
|
90
|
+
kind: doc | tree | matrix | graph | layer | sets | layers | ladder
|
|
91
|
+
out: string
|
|
92
|
+
|
|
93
|
+
# Every kind.
|
|
94
|
+
as?: text | mermaid | dot | er | svg
|
|
95
|
+
at?: string
|
|
96
|
+
maxRows?: integer & min(0)
|
|
97
|
+
|
|
98
|
+
# doc: how many levels of key to draw.
|
|
99
|
+
depth?: integer & min(0)
|
|
100
|
+
|
|
101
|
+
# tree, matrix, layer: the relation drawn. graph: the predicates
|
|
102
|
+
# kept. tree: the subtrees drawn.
|
|
103
|
+
relation?: string
|
|
104
|
+
relations?: [&: string]
|
|
105
|
+
roots?: [&: string]
|
|
106
|
+
|
|
107
|
+
# matrix.
|
|
108
|
+
order?: canon | partition
|
|
109
|
+
closure?: boolean
|
|
110
|
+
|
|
111
|
+
# graph, layer.
|
|
112
|
+
groupBy?: string
|
|
113
|
+
label?: string
|
|
114
|
+
layers?: [&: string]
|
|
115
|
+
edges?: upward | all | none
|
|
116
|
+
|
|
117
|
+
# sets, layers.
|
|
118
|
+
sets?: string
|
|
119
|
+
member?: string
|
|
120
|
+
universe?: string
|
|
121
|
+
minDegree?: integer & min(0)
|
|
122
|
+
maxCols?: integer & min(0)
|
|
123
|
+
minSize?: integer & min(0)
|
|
62
124
|
})
|
|
63
125
|
}
|
|
64
126
|
`
|
|
65
127
|
|
|
66
128
|
|
|
67
|
-
// The bundled sources, by the name a document writes. Both the bare
|
|
68
|
-
// name and the `.aon` spelling resolve, because both are what an
|
|
69
|
-
// author reaches for.
|
|
70
129
|
export const STD_SOURCES: Record<string, string> = {
|
|
71
130
|
'std/system': STD_SYSTEM,
|
|
72
131
|
'std/system.aon': STD_SYSTEM,
|
|
132
|
+
'std/view': STD_VIEW,
|
|
133
|
+
'std/view.aon': STD_VIEW,
|
|
73
134
|
}
|