aontu 0.45.1 → 0.48.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.js +5 -0
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +203 -0
- package/dist/cli.js.map +1 -0
- package/dist/err.js +1 -1
- package/dist/err.js.map +1 -1
- package/dist/hints.js +1 -0
- package/dist/hints.js.map +1 -1
- package/dist/lang.d.ts +1 -1
- package/dist/lang.js +45 -18
- package/dist/lang.js.map +1 -1
- package/dist/lsp-server.d.ts +14 -0
- package/dist/lsp-server.js +87 -0
- package/dist/lsp-server.js.map +1 -0
- package/dist/lsp.d.ts +71 -0
- package/dist/lsp.js +375 -0
- package/dist/lsp.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +1 -1
- package/dist/unify.js +31 -4
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +9 -2
- package/dist/utility.js.map +1 -1
- package/dist/val/BagVal.js +20 -2
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/DisjunctVal.js +25 -16
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/IntegerVal.js +1 -0
- package/dist/val/IntegerVal.js.map +1 -1
- package/dist/val/LowerFuncVal.d.ts +1 -1
- package/dist/val/LowerFuncVal.js +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +127 -16
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/NumberVal.js +7 -2
- package/dist/val/NumberVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -1
- package/dist/val/OpBaseVal.js +1 -1
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/ScalarVal.js +3 -1
- package/dist/val/ScalarVal.js.map +1 -1
- package/dist/val/Val.d.ts +2 -0
- package/dist/val/Val.js +16 -1
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +5 -3
- package/dist/val/VarVal.js.map +1 -1
- package/package.json +25 -13
- package/src/aontu.ts +5 -0
- package/src/cli.ts +193 -0
- package/src/err.ts +1 -1
- package/src/hints.ts +2 -0
- package/src/lang.ts +46 -18
- package/src/lsp-server.ts +109 -0
- package/src/lsp.ts +486 -0
- package/src/type.ts +1 -1
- package/src/unify.ts +33 -4
- package/src/utility.ts +11 -2
- package/src/val/BagVal.ts +22 -2
- package/src/val/DisjunctVal.ts +27 -18
- package/src/val/IntegerVal.ts +1 -0
- package/src/val/LowerFuncVal.ts +1 -1
- package/src/val/MapVal.ts +138 -23
- package/src/val/NumberVal.ts +7 -2
- package/src/val/OpBaseVal.ts +1 -1
- package/src/val/ScalarVal.ts +3 -1
- package/src/val/Val.ts +18 -1
- package/src/val/VarVal.ts +6 -4
package/src/lang.ts
CHANGED
|
@@ -5,42 +5,43 @@
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
Jsonic,
|
|
8
|
+
Tabnas,
|
|
8
9
|
Plugin,
|
|
9
10
|
Rule,
|
|
10
11
|
RuleSpec,
|
|
11
12
|
Context as JsonicContext,
|
|
12
13
|
JsonicError,
|
|
13
|
-
} from 'jsonic'
|
|
14
|
+
} from '@tabnas/jsonic'
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
import { Debug } from '
|
|
17
|
+
import { Debug } from '@tabnas/debug'
|
|
17
18
|
|
|
18
19
|
import {
|
|
19
20
|
MultiSource
|
|
20
|
-
} from '@
|
|
21
|
+
} from '@tabnas/multisource'
|
|
21
22
|
|
|
22
|
-
// TODO: @
|
|
23
|
+
// TODO: @tabnas/multisource should support virtual fs
|
|
23
24
|
|
|
24
25
|
import {
|
|
25
26
|
makeFileResolver
|
|
26
|
-
} from '@
|
|
27
|
+
} from '@tabnas/multisource/resolver/file'
|
|
27
28
|
|
|
28
29
|
import {
|
|
29
30
|
makePkgResolver
|
|
30
|
-
} from '@
|
|
31
|
+
} from '@tabnas/multisource/resolver/pkg'
|
|
31
32
|
|
|
32
33
|
import {
|
|
33
34
|
makeMemResolver
|
|
34
|
-
} from '@
|
|
35
|
+
} from '@tabnas/multisource/resolver/mem'
|
|
35
36
|
|
|
36
37
|
import {
|
|
37
38
|
Expr,
|
|
38
39
|
Op,
|
|
39
|
-
} from '@
|
|
40
|
+
} from '@tabnas/expr'
|
|
40
41
|
|
|
41
42
|
import {
|
|
42
43
|
Path
|
|
43
|
-
} from '@
|
|
44
|
+
} from '@tabnas/path'
|
|
44
45
|
|
|
45
46
|
import type {
|
|
46
47
|
Val,
|
|
@@ -93,9 +94,11 @@ import { OpenFuncVal } from './val/OpenFuncVal'
|
|
|
93
94
|
import { SuperFuncVal } from './val/SuperFuncVal'
|
|
94
95
|
|
|
95
96
|
|
|
97
|
+
const asPlugin = (p: unknown): Plugin => p as Plugin
|
|
98
|
+
|
|
96
99
|
let AontuJsonic: Plugin = function AontuLang(jsonic: Jsonic) {
|
|
97
100
|
|
|
98
|
-
jsonic.use(Path)
|
|
101
|
+
jsonic.use(asPlugin(Path))
|
|
99
102
|
|
|
100
103
|
// TODO: refactor Val constructor
|
|
101
104
|
// let addsite = (v: Val, p: string[]) => (v.path = [...(p || [])], v)
|
|
@@ -250,6 +253,8 @@ help isolate the syntax error.`,
|
|
|
250
253
|
'negative-prefix': (r: Rule, ctx: JsonicContext, _op: Op, terms: any) => {
|
|
251
254
|
let val = terms[0]
|
|
252
255
|
val.peg = -1 * val.peg
|
|
256
|
+
// Normalize -0 to 0 (keeps the AST and canon free of negative zero).
|
|
257
|
+
if (0 === val.peg) val.peg = 0
|
|
253
258
|
return addsite(val, r, ctx)
|
|
254
259
|
},
|
|
255
260
|
|
|
@@ -277,7 +282,7 @@ help isolate the syntax error.`,
|
|
|
277
282
|
|
|
278
283
|
|
|
279
284
|
jsonic
|
|
280
|
-
.use(Expr, {
|
|
285
|
+
.use(asPlugin(Expr), {
|
|
281
286
|
op: {
|
|
282
287
|
// disjunct < conjunct: c & b | a -> (c & b) | a
|
|
283
288
|
'conjunct': {
|
|
@@ -374,13 +379,23 @@ help isolate the syntax error.`,
|
|
|
374
379
|
|
|
375
380
|
rs
|
|
376
381
|
.open([
|
|
377
|
-
{
|
|
382
|
+
{
|
|
383
|
+
s: [CJ, CL], p: 'map', b: 2, n: { pk: 1 },
|
|
384
|
+
// @tabnas seeds a descended rule's node from its parent; without
|
|
385
|
+
// a fresh node here the nested spread map (`a:&:{x:1}`) would
|
|
386
|
+
// share the parent map's node object and self-reference.
|
|
387
|
+
a: (r: Rule) => { r.node = {} },
|
|
388
|
+
g: 'spread'
|
|
389
|
+
},
|
|
378
390
|
|
|
379
391
|
{
|
|
380
392
|
s: [OPTKEY, QM],
|
|
381
393
|
c: (r) => 0 == r.d,
|
|
382
394
|
p: 'map',
|
|
383
395
|
b: 2,
|
|
396
|
+
// Fresh node (see spread alt above): the optional dive descends
|
|
397
|
+
// to a map and must not share the parent's node object.
|
|
398
|
+
a: (r: Rule) => { r.node = {} },
|
|
384
399
|
g: 'pair,jsonic,top,aontu-optional',
|
|
385
400
|
},
|
|
386
401
|
|
|
@@ -389,12 +404,13 @@ help isolate the syntax error.`,
|
|
|
389
404
|
p: 'map',
|
|
390
405
|
b: 2,
|
|
391
406
|
n: { pk: 1 },
|
|
407
|
+
a: (r: Rule) => { r.node = {} },
|
|
392
408
|
g: 'pair,jsonic,top,dive,aontu-optional',
|
|
393
409
|
},
|
|
394
410
|
|
|
395
411
|
])
|
|
396
412
|
|
|
397
|
-
.
|
|
413
|
+
.ac((r: Rule, ctx: JsonicContext) => {
|
|
398
414
|
|
|
399
415
|
let valnode: Val = r.node
|
|
400
416
|
let valtype = typeof valnode
|
|
@@ -555,7 +571,7 @@ help isolate the syntax error.`,
|
|
|
555
571
|
}
|
|
556
572
|
])
|
|
557
573
|
|
|
558
|
-
// NOTE: manually adjust path - @
|
|
574
|
+
// NOTE: manually adjust path - @tabnas/path ignores as not pair:true
|
|
559
575
|
.ao((r) => {
|
|
560
576
|
if (0 < r.d && r.u.spread) {
|
|
561
577
|
r.child.k.path = [...r.k.path, '&']
|
|
@@ -640,6 +656,13 @@ help isolate the syntax error.`,
|
|
|
640
656
|
|
|
641
657
|
|
|
642
658
|
|
|
659
|
+
// SECURITY: the default resolver reads any file/package the process can
|
|
660
|
+
// reach — @"path" follows relative paths (`@"../../etc/passwd"`) and
|
|
661
|
+
// symlinks with no containment check, and @"pkg" can require() arbitrary
|
|
662
|
+
// installed modules. This is intentional for the CLI, but it means a
|
|
663
|
+
// `.aon` source can read referenced files; the LSP uses this same
|
|
664
|
+
// resolver, so treat opening an untrusted source as running it. Pass a
|
|
665
|
+
// confined `options.resolver` to restrict reads in less-trusted contexts.
|
|
643
666
|
function makeModelResolver(options: any) {
|
|
644
667
|
const useRequire = options.require || require
|
|
645
668
|
|
|
@@ -662,7 +685,7 @@ function makeModelResolver(options: any) {
|
|
|
662
685
|
popts: any,
|
|
663
686
|
rule: Rule,
|
|
664
687
|
ctx: JsonicContext,
|
|
665
|
-
jsonic:
|
|
688
|
+
jsonic: Tabnas
|
|
666
689
|
) {
|
|
667
690
|
|
|
668
691
|
let path = 'string' === typeof spec ? spec : spec?.peg
|
|
@@ -711,20 +734,25 @@ class Lang {
|
|
|
711
734
|
this.jsonic = Jsonic.make()
|
|
712
735
|
|
|
713
736
|
if (this.opts.debug) {
|
|
714
|
-
this.jsonic.use(Debug, {
|
|
737
|
+
this.jsonic.use(asPlugin(Debug), {
|
|
715
738
|
trace: this.opts.trace
|
|
716
739
|
})
|
|
717
740
|
}
|
|
718
741
|
|
|
719
742
|
this.jsonic
|
|
720
|
-
.use(
|
|
721
|
-
.use(MultiSource, {
|
|
743
|
+
.use(asPlugin(MultiSource), {
|
|
722
744
|
resolver: options?.resolver || modelResolver,
|
|
745
|
+
// `.aon` is the preferred Aontu source extension; `.aontu` also
|
|
746
|
+
// works. `.jsonic` is retired (no longer auto-resolved); the
|
|
747
|
+
// default `['jsonic','jsc','json','js']` is overridden here.
|
|
748
|
+
// (Upstream option name is the misspelled `implictExt`.)
|
|
749
|
+
implictExt: ['aon', 'aontu'],
|
|
723
750
|
processor: {
|
|
724
751
|
aontu: 'jsonic',
|
|
725
752
|
aon: 'jsonic',
|
|
726
753
|
}
|
|
727
754
|
})
|
|
755
|
+
.use(AontuJsonic)
|
|
728
756
|
}
|
|
729
757
|
|
|
730
758
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
3
|
+
|
|
4
|
+
// Aontu Language Server (stdio).
|
|
5
|
+
//
|
|
6
|
+
// aontu-lsp
|
|
7
|
+
//
|
|
8
|
+
// Speaks LSP over stdio (JSON-RPC with Content-Length framing) and
|
|
9
|
+
// publishes unification diagnostics as `.aontu` files are edited. This
|
|
10
|
+
// binary is intentionally thin: all protocol logic lives in the reusable
|
|
11
|
+
// library ./lsp (LspHandler + computeDiagnostics). See docs/lsp.md for
|
|
12
|
+
// editor configuration.
|
|
13
|
+
|
|
14
|
+
import { LspHandler, Message, OutMessage } from './lsp'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// A byte-level LSP framing codec: feed it incoming chunks, give it a
|
|
18
|
+
// handler, and it decodes Content-Length frames, dispatches them, and
|
|
19
|
+
// writes framed replies. Kept transport-injectable (write/onExit) so it
|
|
20
|
+
// can be unit-tested without real stdio.
|
|
21
|
+
class FrameCodec {
|
|
22
|
+
private buffer = Buffer.alloc(0)
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
private handler: LspHandler,
|
|
26
|
+
private write: (chunk: Buffer) => void,
|
|
27
|
+
private onExit: (code: number) => void,
|
|
28
|
+
) { }
|
|
29
|
+
|
|
30
|
+
// Feed a chunk of incoming bytes; processes any complete frames.
|
|
31
|
+
push(chunk: Buffer) {
|
|
32
|
+
this.buffer = Buffer.concat([this.buffer, chunk])
|
|
33
|
+
this.drain()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Called when the input stream ends.
|
|
37
|
+
end() {
|
|
38
|
+
this.onExit(this.handler.exitCode)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private drain() {
|
|
42
|
+
for (; ;) {
|
|
43
|
+
const headerEnd = this.buffer.indexOf('\r\n\r\n')
|
|
44
|
+
if (headerEnd < 0) return
|
|
45
|
+
|
|
46
|
+
const header = this.buffer.subarray(0, headerEnd).toString('ascii')
|
|
47
|
+
const match = /Content-Length:\s*(\d+)/i.exec(header)
|
|
48
|
+
if (null == match) {
|
|
49
|
+
// Malformed header block: skip past it and continue.
|
|
50
|
+
this.buffer = this.buffer.subarray(headerEnd + 4)
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const length = parseInt(match[1], 10)
|
|
55
|
+
const bodyStart = headerEnd + 4
|
|
56
|
+
if (this.buffer.length < bodyStart + length) return // need more bytes
|
|
57
|
+
|
|
58
|
+
const body = this.buffer.subarray(bodyStart, bodyStart + length).toString('utf8')
|
|
59
|
+
this.buffer = this.buffer.subarray(bodyStart + length)
|
|
60
|
+
|
|
61
|
+
let msg: Message
|
|
62
|
+
try {
|
|
63
|
+
msg = JSON.parse(body)
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
continue // ignore unparseable frame
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const out of this.handler.handle(msg)) {
|
|
70
|
+
this.send(out)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (this.handler.shouldExit) {
|
|
74
|
+
this.onExit(this.handler.exitCode)
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private send(out: OutMessage) {
|
|
81
|
+
const body = Buffer.from(JSON.stringify(out), 'utf8')
|
|
82
|
+
this.write(Buffer.from('Content-Length: ' + body.length + '\r\n\r\n', 'ascii'))
|
|
83
|
+
this.write(body)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
function main() {
|
|
89
|
+
const handler = new LspHandler()
|
|
90
|
+
const codec = new FrameCodec(
|
|
91
|
+
handler,
|
|
92
|
+
(chunk) => process.stdout.write(chunk),
|
|
93
|
+
(code) => process.exit(code),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
process.stdin.on('data', (chunk: Buffer) => codec.push(chunk))
|
|
97
|
+
process.stdin.on('end', () => codec.end())
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
// Only auto-run when invoked as a program, not when imported by tests.
|
|
102
|
+
if (require.main === module) {
|
|
103
|
+
main()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
export {
|
|
108
|
+
FrameCodec,
|
|
109
|
+
}
|