@algosail/lang 0.2.12 → 0.5.1

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.
Files changed (145) hide show
  1. package/bin/sail.mjs +4 -0
  2. package/cli/run-cli.js +176 -0
  3. package/index.js +12 -2
  4. package/lib/codegen/README.md +230 -0
  5. package/lib/codegen/codegen-diagnostics.js +164 -0
  6. package/lib/codegen/compile-graph.js +107 -0
  7. package/lib/codegen/emit-adt.js +177 -0
  8. package/lib/codegen/emit-body.js +1265 -0
  9. package/lib/codegen/emit-builtin.js +371 -0
  10. package/lib/codegen/emit-jsdoc-sail.js +383 -0
  11. package/lib/codegen/emit-module.js +498 -0
  12. package/lib/codegen/esm-imports.js +26 -0
  13. package/lib/codegen/index.js +69 -0
  14. package/lib/codegen/out-layout.js +102 -0
  15. package/lib/ffi/extract-jsdoc-sail.js +34 -0
  16. package/lib/io-node/index.js +4 -0
  17. package/lib/io-node/package-root.js +18 -0
  18. package/lib/io-node/read-file.js +12 -0
  19. package/lib/io-node/resolve-package.js +24 -0
  20. package/lib/io-node/resolve-sail-names-from-disk.js +21 -0
  21. package/lib/ir/assert-json-serializable.js +30 -0
  22. package/lib/ir/attach-call-effects.js +108 -0
  23. package/lib/ir/bind-values.js +594 -0
  24. package/lib/ir/build-module-ir.js +290 -0
  25. package/lib/ir/index.js +31 -0
  26. package/lib/ir/lower-body-steps.js +170 -0
  27. package/lib/ir/module-metadata.js +65 -0
  28. package/lib/ir/schema-version.js +15 -0
  29. package/lib/ir/serialize.js +202 -0
  30. package/lib/ir/stitch-types.js +92 -0
  31. package/lib/names/adt-autogen.js +22 -0
  32. package/lib/names/import-path.js +28 -0
  33. package/lib/names/index.js +1 -0
  34. package/lib/names/local-declarations.js +127 -0
  35. package/lib/names/lower-first.js +6 -0
  36. package/lib/names/module-scope.js +120 -0
  37. package/lib/names/resolve-sail.js +365 -0
  38. package/lib/names/walk-ast-refs.js +91 -0
  39. package/lib/parse/ast-build.js +51 -0
  40. package/lib/parse/ast-spec.js +212 -0
  41. package/lib/parse/builtins-set.js +12 -0
  42. package/lib/parse/diagnostics.js +180 -0
  43. package/lib/parse/index.js +46 -0
  44. package/lib/parse/lexer.js +390 -0
  45. package/lib/parse/parse-source.js +912 -0
  46. package/lib/typecheck/adt-autogen-sigs.js +345 -0
  47. package/lib/typecheck/build-type-env.js +148 -0
  48. package/lib/typecheck/builtin-signatures.js +183 -0
  49. package/lib/typecheck/check-word-body.js +1021 -0
  50. package/lib/typecheck/effect-decl.js +124 -0
  51. package/lib/typecheck/index.js +55 -0
  52. package/lib/typecheck/normalize-sig.js +369 -0
  53. package/lib/typecheck/stack-step-snapshots.js +56 -0
  54. package/lib/typecheck/unify-type.js +665 -0
  55. package/lib/typecheck/validate-adt.js +201 -0
  56. package/package.json +4 -9
  57. package/scripts/regen-demo-full-syntax-ast.mjs +22 -0
  58. package/test/cli/sail-cli.test.js +64 -0
  59. package/test/codegen/compile-bracket-ffi-e2e.test.js +64 -0
  60. package/test/codegen/compile-stage0.test.js +128 -0
  61. package/test/codegen/compile-stage4-layout.test.js +124 -0
  62. package/test/codegen/e2e-prelude-ffi-adt/app/extra.sail +6 -0
  63. package/test/codegen/e2e-prelude-ffi-adt/app/lib.sail +34 -0
  64. package/test/codegen/e2e-prelude-ffi-adt/app/main.sail +28 -0
  65. package/test/codegen/e2e-prelude-ffi-adt/artifacts/.gitignore +2 -0
  66. package/test/codegen/e2e-prelude-ffi-adt/ffi/helpers.js +27 -0
  67. package/test/codegen/e2e-prelude-ffi-adt.test.js +100 -0
  68. package/test/codegen/emit-adt-stage6.test.js +168 -0
  69. package/test/codegen/emit-async-stage5.test.js +164 -0
  70. package/test/codegen/emit-body-stage2.test.js +139 -0
  71. package/test/codegen/emit-body.test.js +163 -0
  72. package/test/codegen/emit-builtins-stage7.test.js +258 -0
  73. package/test/codegen/emit-diagnostics-stage9.test.js +90 -0
  74. package/test/codegen/emit-jsdoc-stage8.test.js +113 -0
  75. package/test/codegen/emit-module-stage3.test.js +78 -0
  76. package/test/conformance/conformance-ir-l4.test.js +38 -0
  77. package/test/conformance/conformance-l5-codegen.test.js +111 -0
  78. package/test/conformance/conformance-runner.js +91 -0
  79. package/test/conformance/conformance-suite-l3.test.js +32 -0
  80. package/test/ffi/prelude-jsdoc.test.js +49 -0
  81. package/test/fixtures/demo-full-syntax.ast.json +1471 -0
  82. package/test/fixtures/demo-full-syntax.sail +35 -0
  83. package/test/fixtures/io-node-ffi-adt/ffi.js +7 -0
  84. package/test/fixtures/io-node-ffi-adt/use.sail +4 -0
  85. package/test/fixtures/io-node-mini/dep.sail +2 -0
  86. package/test/fixtures/io-node-mini/entry.sail +4 -0
  87. package/test/fixtures/io-node-prelude/entry.sail +4 -0
  88. package/test/fixtures/io-node-reexport-chain/a.sail +4 -0
  89. package/test/fixtures/io-node-reexport-chain/b.sail +2 -0
  90. package/test/fixtures/io-node-reexport-chain/c.sail +2 -0
  91. package/test/io-node/resolve-disk.test.js +59 -0
  92. package/test/ir/bind-values.test.js +84 -0
  93. package/test/ir/build-module-ir.test.js +100 -0
  94. package/test/ir/call-effects.test.js +97 -0
  95. package/test/ir/ffi-bracket-ir.test.js +59 -0
  96. package/test/ir/full-ir-document.test.js +51 -0
  97. package/test/ir/ir-document-assert.js +67 -0
  98. package/test/ir/lower-body-steps.test.js +90 -0
  99. package/test/ir/module-metadata.test.js +42 -0
  100. package/test/ir/serialization-model.test.js +172 -0
  101. package/test/ir/stitch-types.test.js +74 -0
  102. package/test/names/l2-resolve-adt-autogen.test.js +155 -0
  103. package/test/names/l2-resolve-bracket-ffi.test.js +108 -0
  104. package/test/names/l2-resolve-declaration-and-bracket-errors.test.js +276 -0
  105. package/test/names/l2-resolve-graph.test.js +105 -0
  106. package/test/names/l2-resolve-single-file.test.js +79 -0
  107. package/test/parse/ast-spec.test.js +56 -0
  108. package/test/parse/ast.test.js +476 -0
  109. package/test/parse/contract.test.js +37 -0
  110. package/test/parse/fixtures-full-syntax.test.js +24 -0
  111. package/test/parse/helpers.js +27 -0
  112. package/test/parse/l0-lex-diagnostics-matrix.test.js +59 -0
  113. package/test/parse/l0-lex.test.js +40 -0
  114. package/test/parse/l1-diagnostics.test.js +77 -0
  115. package/test/parse/l1-import.test.js +28 -0
  116. package/test/parse/l1-parse-diagnostics-matrix.test.js +32 -0
  117. package/test/parse/l1-top-level.test.js +47 -0
  118. package/test/parse/l1-types.test.js +31 -0
  119. package/test/parse/l1-words.test.js +49 -0
  120. package/test/parse/l2-diagnostics-contract.test.js +67 -0
  121. package/test/parse/l3-diagnostics-contract.test.js +66 -0
  122. package/test/typecheck/adt-decl-stage2.test.js +83 -0
  123. package/test/typecheck/container-contract-e1309.test.js +258 -0
  124. package/test/typecheck/ffi-bracket-l3.test.js +61 -0
  125. package/test/typecheck/l3-diagnostics-matrix.test.js +248 -0
  126. package/test/typecheck/l3-partial-pipeline.test.js +74 -0
  127. package/test/typecheck/opaque-ffi-type.test.js +78 -0
  128. package/test/typecheck/sig-type-stage3.test.js +190 -0
  129. package/test/typecheck/stack-check-stage4.test.js +149 -0
  130. package/test/typecheck/stack-check-stage5.test.js +74 -0
  131. package/test/typecheck/stack-check-stage6.test.js +56 -0
  132. package/test/typecheck/stack-check-stage7.test.js +160 -0
  133. package/test/typecheck/stack-check-stage8.test.js +146 -0
  134. package/test/typecheck/stack-check-stage9.test.js +105 -0
  135. package/test/typecheck/typecheck-env.test.js +53 -0
  136. package/test/typecheck/typecheck-pipeline.test.js +37 -0
  137. package/README.md +0 -37
  138. package/cli/sail.js +0 -151
  139. package/cli/typecheck.js +0 -39
  140. package/docs/ARCHITECTURE.md +0 -50
  141. package/docs/CHANGELOG.md +0 -18
  142. package/docs/FFI-GUIDE.md +0 -65
  143. package/docs/RELEASE.md +0 -36
  144. package/docs/TESTING.md +0 -86
  145. package/test/integration.test.js +0 -61
package/cli/typecheck.js DELETED
@@ -1,39 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createParser } from '@algosail/parser'
3
- import { typecheck } from '@algosail/typecheck'
4
- import { readFile } from 'node:fs/promises'
5
- import { pathToFileURL } from 'node:url'
6
- import { resolve } from 'node:path'
7
-
8
- const filePath = process.argv[2]
9
-
10
- if (!filePath) {
11
- console.error('Usage: sail-typecheck <path-to-file.sail>')
12
- process.exit(1)
13
- }
14
-
15
- const absPath = resolve(process.cwd(), filePath)
16
- const uri = pathToFileURL(absPath).href
17
-
18
- let text
19
- try {
20
- text = await readFile(absPath, 'utf8')
21
- } catch (err) {
22
- console.error(`sail-typecheck: cannot read ${filePath}: ${err.message}`)
23
- process.exit(1)
24
- }
25
-
26
- const parser = await createParser()
27
- const result = await parser.parseSail(uri, text)
28
- const parseErrors = result.errors ?? []
29
- const typeErrors = typecheck(result)
30
- const errors = [...parseErrors.map((e) => ({ ...e, message: e.type === 'error' ? `Parse error: unexpected ${JSON.stringify(e.text)}` : `Parse error: missing ${JSON.stringify(e.text)}` })), ...typeErrors]
31
-
32
- if (errors.length > 0) {
33
- for (const err of errors) {
34
- const { row, column } = err.startPosition ?? {}
35
- const loc = row != null ? `:${row + 1}:${(column ?? 0) + 1}` : ''
36
- console.error(`${filePath}${loc}: ${err.message}`)
37
- }
38
- process.exit(1)
39
- }
@@ -1,50 +0,0 @@
1
- # Sail Architecture
2
-
3
- ## Pipeline
4
-
5
- ```
6
- Sail source (.sail) → [Parser] → Symbol Table → [Typecheck] → [Compiler] → JavaScript
7
- ↑ ↑ ↑
8
- FFI (.js) → [parseJsDoc] ─┘ └── modules, groups, tags, words
9
- ```
10
-
11
- 1. **Parser** (`@algosail/parser`): Builds symbol table from Sail and JS sources
12
- 2. **Typecheck** (`@algosail/typecheck`): Validates words and tags against signatures
13
- 3. **Compiler** (`@algosail/compiler`): Emits JS from validated symbol table
14
-
15
- ## Packages
16
-
17
- | Package | Role |
18
- |---------|------|
19
- | `@algosail/tree-sitter` | Grammar (grammar.js), WASM lexer/parser for Sail |
20
- | `@algosail/parser` | buildSymbolTable, parseJsDoc, Sail + JS → AST |
21
- | `@algosail/builtins` | Builtin words (DUP, SWAP, DIP, MATCH, …) with sigs |
22
- | `@algosail/shared` | getStepSignature, getStepStackEffect (used by typecheck, compiler) |
23
- | `@algosail/typecheck` | checkWord, checkTag, stack-effect validation |
24
- | `@algosail/compiler` | compile(), emitWord, emitStep → JS |
25
- | `@algosail/lsp` | LSP server (validate, completion, hover, go-to-definition) |
26
- | `@algosail/lang` | Re-exports typecheck, createParser; integration tests |
27
-
28
- ## Data Flow
29
-
30
- - **Symbol table**: `{ modules, groups, tags, words, errors, imports }`
31
- - **Word**: `{ name, sig, signature, body, doc }` — body is steps (builtin_word, word_ref, quotation, tag, …)
32
- - **Typecheck** uses `builtins` for builtin signatures; FFI words come from `parseJsDoc` (modules)
33
- - **Compiler** uses builtins for emit logic; FFI calls go through `emitStep` (CALL to imported module)
34
-
35
- ## Dependencies
36
-
37
- ```
38
- tree-sitter (grammar)
39
-
40
- parser (tree-sitter, tree-sitter-javascript, web-tree-sitter)
41
-
42
- builtins (no deps)
43
-
44
- typecheck (builtins)
45
- compiler (parser, typecheck, builtins)
46
- lsp (parser, typecheck, builtins)
47
- lang (parser, typecheck, compiler)
48
- ```
49
-
50
- **Note:** `tree-sitter` uses regex `/[A-Z][A-Z0-9_]*/` for `builtin_word` — decoupled from builtins (Phase 2.2 done).
package/docs/CHANGELOG.md DELETED
@@ -1,18 +0,0 @@
1
- # Changelog
2
-
3
- ## [Unreleased]
4
-
5
- ### Added
6
- - Integration tests (parse → typecheck → compile → run) in `lang/test/integration.test.js`
7
- - `npm test` in @algosail/lang
8
-
9
- ### Changed
10
- - Documentation: compiler README (source maps, error format, CLI options)
11
- - Documentation: LSP README (hover, definition)
12
- - Documentation: TESTING.md (integration tests section)
13
-
14
- ## [0.2.8] - previous
15
- - @algosail/lang: sail-typecheck CLI, re-exports typecheck + createParser
16
- - @algosail/compiler: source maps, JSDoc, async/await, error hints
17
- - @algosail/lsp: hover, go-to-definition
18
- - @algosail/typecheck: effects (addEffect, removeEffect)
package/docs/FFI-GUIDE.md DELETED
@@ -1,65 +0,0 @@
1
- # Sail FFI: JSDoc Format
2
-
3
- Sail reads type information from JavaScript/JS modules via JSDoc. This document describes the format.
4
-
5
- ## Overview
6
-
7
- FFI modules are JS files with `/** ... @sail ... */` blocks. The parser (`@algosail/parser`) uses `parseJsDoc` to extract groups, tags, and words. Compiled Sail output must emit the same format so it can be used as FFI by other Sail code and JS consumers.
8
-
9
- ## Word (exported function)
10
-
11
- A JSDoc block **immediately before** an `export function` declaration defines a Sail word. The function name becomes the word name when called as `~Module/wordName`.
12
-
13
- ```javascript
14
- /**
15
- * @sail
16
- * @of ( * -- Int ) ( Convert a raw value to an integer )
17
- */
18
- export function of(a) {
19
- return parseInt(a, 10)
20
- }
21
- ```
22
-
23
- **Format after `@sail`:**
24
- - `@functionName ( stack_sig ) ( description )`
25
- - `stack_sig`: `inputs -- outputs`, e.g. `( * -- Int )`, `( a b -- b a )`
26
- - `*` = raw value (untyped literal)
27
- - Types: `Int`, `Str`, `Bool`, `[a]` (list), `( a -- b )` (quotation), `&Group{Int}` (tagged union)
28
-
29
- **Full word form** (when the block starts with `@wordName`):
30
- ```
31
- @wordName ( sig ) ( doc )
32
- ```
33
- The sail parser treats everything after `@sail` as Sail source and parses it with the Sail grammar (word_def, sig, etc.).
34
-
35
- ## Groups and Tags
36
-
37
- Standalone JSDoc blocks (not before export) can define groups and tags:
38
-
39
- ```javascript
40
- /**
41
- * @sail
42
- * &Maybe a
43
- * #Just a
44
- * #Nothing
45
- */
46
- ```
47
-
48
- Parsed as Sail: `&Maybe a` (group with type param), `#Just a` and `#Nothing` (tags).
49
-
50
- ## Extraction Rules
51
-
52
- - Comment must start with `/**` and contain `@sail`
53
- - Content after `@sail` is parsed as Sail source (groups, tags, words)
54
- - For export pairs: `comment` + `export function name` → word `name` with body from JSDoc
55
- - If sailText starts with `@wordName` (e.g. `@of`), it's used as-is; else prefixed with `@functionName`
56
-
57
- ## References
58
-
59
- - Parser: `parser/lib/jsDoc.js` — `parseJsDoc`, `findExportSailPairs`, `extractSailBlock`
60
- - Examples: `zed/test/int.js`, `zed/test/buffer.js`
61
- - Builtins use a different format (JS objects with `sig`, `signature`, `docs`) — see `builtins/index.js`
62
-
63
- ## Buffer (Bare/Node)
64
-
65
- Для Bare + Hyperswarm + RocksDB: `zed/test/buffer.js` — FFI-модуль с `from`, `alloc`, `concat`.
package/docs/RELEASE.md DELETED
@@ -1,36 +0,0 @@
1
- # Release Checklist
2
-
3
- ## Pre-release
4
-
5
- 1. Run all tests:
6
- ```bash
7
- cd parser && npm test
8
- cd ../typecheck && npm test
9
- cd ../compiler && npm test
10
- cd ../lang && npm test
11
- ```
12
-
13
- 2. Ensure `npm link` for local dev (see TESTING.md)
14
-
15
- ## Version Bumps (for publish)
16
-
17
- Suggested order (dependencies first):
18
-
19
- - `@algosail/builtins` — bump if builtin sigs changed
20
- - `@algosail/shared` — bump if API changed
21
- - `@algosail/typecheck` — bump if API or behaviour changed
22
- - `@algosail/parser` — bump if API changed
23
- - `@algosail/compiler` — bump for source maps, JSDoc, async, error format
24
- - `@algosail/lsp` — bump for hover, definition
25
- - `@algosail/lang` — bump last; update deps to new versions
26
-
27
- ## Publish
28
-
29
- ```bash
30
- cd <package> && npm publish --access public
31
- ```
32
-
33
- ## Post-release
34
-
35
- - Update CHANGELOG.md with version and date
36
- - Tag release if using git tags
package/docs/TESTING.md DELETED
@@ -1,86 +0,0 @@
1
- # Sail Testing
2
-
3
- ## Framework: Brittle
4
-
5
- Sail packages use [brittle](https://github.com/holepunchto/brittle) for tests.
6
-
7
- ### Setup
8
-
9
- ```json
10
- {
11
- "scripts": {
12
- "test": "brittle \"test/**/*.test.js\""
13
- },
14
- "devDependencies": {
15
- "brittle": "^3.19.1"
16
- }
17
- }
18
- ```
19
-
20
- ### Test File Pattern
21
-
22
- - Location: `test/**/*.test.js`
23
- - Import: `import test from 'brittle'`
24
-
25
- ### Example
26
-
27
- ```javascript
28
- import test from 'brittle'
29
- import { checkWord } from '../lib/word/checkWord.js'
30
-
31
- test('word step applies callee signature', (t) => {
32
- const table = baseTable()
33
- table.words.toInt = { ... }
34
- const word = { ... }
35
- t.alike(checkWord(word, table), [])
36
- })
37
-
38
- test('DUP builtin applies sig', (t) => {
39
- // ...
40
- t.alike(checkWord(word, table), [])
41
- })
42
- ```
43
-
44
- ### Assertions
45
-
46
- - `t.ok(value)` — truthy
47
- - `t.absent(value)` — falsy
48
- - `t.alike(actual, expected)` — deep equality
49
- - `t.is(actual, expected)` — strict equality
50
-
51
- ### Running Tests
52
-
53
- ```bash
54
- # In each package
55
- cd typecheck && npm test
56
- cd parser && npm test
57
- cd compiler && npm test
58
- ```
59
-
60
- ### Local Package Linking (npm link)
61
-
62
- Для локальной разработки связывай пакеты через `npm link`:
63
-
64
- ```bash
65
- # 1. В пакете-источнике (shared, builtins и т.д.)
66
- cd shared && npm link
67
-
68
- # 2. В пакете-потребителе (compiler, typecheck и т.д.)
69
- cd ../compiler && npm link @algosail/shared
70
- cd ../typecheck && npm link @algosail/shared
71
- ```
72
-
73
- Проверка: `ls -la node_modules/@algosail/shared` должен быть symlink.
74
-
75
- ### Integration Tests
76
-
77
- Full pipeline (parse → typecheck → compile → run) is tested in `lang/test/integration.test.js`:
78
-
79
- ```bash
80
- cd lang && npm test
81
- ```
82
-
83
- Tests:
84
- - Compile a simple program (builtins only), run via dynamic import, assert result
85
- - Compile program with FFI (async_main.sail), run, assert result
86
- - Invalid program (stack underflow) produces errors
@@ -1,61 +0,0 @@
1
- /**
2
- * Integration tests: parse → typecheck → compile → run
3
- */
4
-
5
- import test from 'brittle'
6
- import { compile } from '@algosail/compiler'
7
- import { writeFile, unlink, readFile } from 'node:fs/promises'
8
- import { tmpdir } from 'node:os'
9
- import { join, dirname } from 'node:path'
10
- import { pathToFileURL, fileURLToPath } from 'node:url'
11
- import { randomUUID } from 'node:crypto'
12
-
13
- const __dirname = dirname(fileURLToPath(import.meta.url))
14
-
15
- test('full pipeline: compile simple program and run', async (t) => {
16
- const source = `
17
- @main ( Int -- Int )
18
- DUP NIP
19
- `
20
- const uri = 'file:///test/integration.sail'
21
- const { js, errors } = await compile(uri, source)
22
-
23
- t.is(errors.length, 0, `expected no errors, got: ${JSON.stringify(errors)}`)
24
- t.ok(js)
25
- t.ok(js.includes('export function main'))
26
-
27
- const tmpFile = join(tmpdir(), `sail-integration-${randomUUID()}.mjs`)
28
- await writeFile(tmpFile, js, 'utf8')
29
- try {
30
- const mod = await import(pathToFileURL(tmpFile).href)
31
- const result = mod.main(42)
32
- t.is(result, 42, 'main(42) should return 42 (DUP NIP)')
33
- } finally {
34
- await unlink(tmpFile)
35
- }
36
- })
37
-
38
- test('full pipeline: compile program with FFI', async (t) => {
39
- const fixturesDir = join(__dirname, '..', '..', 'compiler', 'test', 'fixtures')
40
- const uri = pathToFileURL(join(fixturesDir, 'async_main.sail')).href
41
- const source = await readFile(join(fixturesDir, 'async_main.sail'), 'utf8')
42
-
43
- const { js, errors } = await compile(uri, source, { outPath: fixturesDir })
44
-
45
- t.is(errors.length, 0, `expected no errors, got: ${JSON.stringify(errors)}`)
46
- t.ok(js, 'should emit JS')
47
- t.ok(js.includes('export function main') || js.includes('export async function main'), 'should export main')
48
- t.ok(/Async\.incAsync|incAsync/.test(js), 'should call FFI word')
49
- })
50
-
51
- test('full pipeline: typecheck rejects invalid program', async (t) => {
52
- const source = `
53
- @main ( Int -- Int )
54
- DUP DROP POP
55
- `
56
- const uri = 'file:///test/invalid.sail'
57
- const { js, errors } = await compile(uri, source)
58
-
59
- t.ok(errors.length > 0, 'should have typecheck/stack errors')
60
- t.ok(!js || errors.length > 0)
61
- })