@algosail/lang 0.2.11 → 0.5.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/bin/sail.mjs +4 -0
- package/cli/run-cli.js +176 -0
- package/index.js +11 -2
- package/lib/codegen/README.md +230 -0
- package/lib/codegen/codegen-diagnostics.js +164 -0
- package/lib/codegen/compile-graph.js +107 -0
- package/lib/codegen/emit-adt.js +177 -0
- package/lib/codegen/emit-body.js +1265 -0
- package/lib/codegen/emit-builtin.js +371 -0
- package/lib/codegen/emit-jsdoc-sail.js +383 -0
- package/lib/codegen/emit-module.js +498 -0
- package/lib/codegen/esm-imports.js +26 -0
- package/lib/codegen/index.js +69 -0
- package/lib/codegen/out-layout.js +102 -0
- package/lib/ffi/extract-jsdoc-sail.js +34 -0
- package/lib/io-node/index.js +4 -0
- package/lib/io-node/package-root.js +18 -0
- package/lib/io-node/read-file.js +12 -0
- package/lib/io-node/resolve-package.js +24 -0
- package/lib/io-node/resolve-sail-names-from-disk.js +21 -0
- package/lib/ir/assert-json-serializable.js +30 -0
- package/lib/ir/attach-call-effects.js +108 -0
- package/lib/ir/bind-values.js +594 -0
- package/lib/ir/build-module-ir.js +290 -0
- package/lib/ir/index.js +31 -0
- package/lib/ir/lower-body-steps.js +170 -0
- package/lib/ir/module-metadata.js +65 -0
- package/lib/ir/schema-version.js +15 -0
- package/lib/ir/serialize.js +202 -0
- package/lib/ir/stitch-types.js +92 -0
- package/lib/names/adt-autogen.js +22 -0
- package/lib/names/import-path.js +28 -0
- package/lib/names/index.js +1 -0
- package/lib/names/local-declarations.js +127 -0
- package/lib/names/lower-first.js +6 -0
- package/lib/names/module-scope.js +120 -0
- package/lib/names/resolve-sail.js +365 -0
- package/lib/names/walk-ast-refs.js +91 -0
- package/lib/parse/ast-build.js +51 -0
- package/lib/parse/ast-spec.js +212 -0
- package/lib/parse/builtins-set.js +12 -0
- package/lib/parse/diagnostics.js +180 -0
- package/lib/parse/index.js +46 -0
- package/lib/parse/lexer.js +390 -0
- package/lib/parse/parse-source.js +912 -0
- package/lib/typecheck/adt-autogen-sigs.js +345 -0
- package/lib/typecheck/build-type-env.js +148 -0
- package/lib/typecheck/builtin-signatures.js +183 -0
- package/lib/typecheck/check-word-body.js +1021 -0
- package/lib/typecheck/effect-decl.js +124 -0
- package/lib/typecheck/index.js +55 -0
- package/lib/typecheck/normalize-sig.js +369 -0
- package/lib/typecheck/stack-step-snapshots.js +56 -0
- package/lib/typecheck/unify-type.js +665 -0
- package/lib/typecheck/validate-adt.js +201 -0
- package/package.json +4 -9
- package/scripts/regen-demo-full-syntax-ast.mjs +22 -0
- package/test/cli/sail-cli.test.js +64 -0
- package/test/codegen/compile-bracket-ffi-e2e.test.js +64 -0
- package/test/codegen/compile-stage0.test.js +128 -0
- package/test/codegen/compile-stage4-layout.test.js +124 -0
- package/test/codegen/e2e-prelude-ffi-adt/app/extra.sail +6 -0
- package/test/codegen/e2e-prelude-ffi-adt/app/lib.sail +33 -0
- package/test/codegen/e2e-prelude-ffi-adt/app/main.sail +28 -0
- package/test/codegen/e2e-prelude-ffi-adt/artifacts/.gitignore +2 -0
- package/test/codegen/e2e-prelude-ffi-adt/ffi/helpers.js +27 -0
- package/test/codegen/e2e-prelude-ffi-adt.test.js +100 -0
- package/test/codegen/emit-adt-stage6.test.js +168 -0
- package/test/codegen/emit-async-stage5.test.js +164 -0
- package/test/codegen/emit-body-stage2.test.js +139 -0
- package/test/codegen/emit-body.test.js +163 -0
- package/test/codegen/emit-builtins-stage7.test.js +258 -0
- package/test/codegen/emit-diagnostics-stage9.test.js +90 -0
- package/test/codegen/emit-jsdoc-stage8.test.js +113 -0
- package/test/codegen/emit-module-stage3.test.js +78 -0
- package/test/conformance/conformance-ir-l4.test.js +38 -0
- package/test/conformance/conformance-l5-codegen.test.js +111 -0
- package/test/conformance/conformance-runner.js +91 -0
- package/test/conformance/conformance-suite-l3.test.js +32 -0
- package/test/ffi/prelude-jsdoc.test.js +49 -0
- package/test/fixtures/demo-full-syntax.ast.json +1471 -0
- package/test/fixtures/demo-full-syntax.sail +35 -0
- package/test/fixtures/io-node-ffi-adt/ffi.js +7 -0
- package/test/fixtures/io-node-ffi-adt/use.sail +4 -0
- package/test/fixtures/io-node-mini/dep.sail +2 -0
- package/test/fixtures/io-node-mini/entry.sail +4 -0
- package/test/fixtures/io-node-prelude/entry.sail +4 -0
- package/test/fixtures/io-node-reexport-chain/a.sail +4 -0
- package/test/fixtures/io-node-reexport-chain/b.sail +2 -0
- package/test/fixtures/io-node-reexport-chain/c.sail +2 -0
- package/test/io-node/resolve-disk.test.js +59 -0
- package/test/ir/bind-values.test.js +84 -0
- package/test/ir/build-module-ir.test.js +100 -0
- package/test/ir/call-effects.test.js +97 -0
- package/test/ir/ffi-bracket-ir.test.js +59 -0
- package/test/ir/full-ir-document.test.js +51 -0
- package/test/ir/ir-document-assert.js +67 -0
- package/test/ir/lower-body-steps.test.js +90 -0
- package/test/ir/module-metadata.test.js +42 -0
- package/test/ir/serialization-model.test.js +172 -0
- package/test/ir/stitch-types.test.js +74 -0
- package/test/names/l2-resolve-adt-autogen.test.js +155 -0
- package/test/names/l2-resolve-bracket-ffi.test.js +108 -0
- package/test/names/l2-resolve-declaration-and-bracket-errors.test.js +276 -0
- package/test/names/l2-resolve-graph.test.js +105 -0
- package/test/names/l2-resolve-single-file.test.js +79 -0
- package/test/parse/ast-spec.test.js +56 -0
- package/test/parse/ast.test.js +476 -0
- package/test/parse/contract.test.js +37 -0
- package/test/parse/fixtures-full-syntax.test.js +24 -0
- package/test/parse/helpers.js +27 -0
- package/test/parse/l0-lex-diagnostics-matrix.test.js +59 -0
- package/test/parse/l0-lex.test.js +40 -0
- package/test/parse/l1-diagnostics.test.js +77 -0
- package/test/parse/l1-import.test.js +28 -0
- package/test/parse/l1-parse-diagnostics-matrix.test.js +32 -0
- package/test/parse/l1-top-level.test.js +47 -0
- package/test/parse/l1-types.test.js +31 -0
- package/test/parse/l1-words.test.js +49 -0
- package/test/parse/l2-diagnostics-contract.test.js +67 -0
- package/test/parse/l3-diagnostics-contract.test.js +66 -0
- package/test/typecheck/adt-decl-stage2.test.js +83 -0
- package/test/typecheck/container-contract-e1309.test.js +258 -0
- package/test/typecheck/ffi-bracket-l3.test.js +61 -0
- package/test/typecheck/l3-diagnostics-matrix.test.js +248 -0
- package/test/typecheck/l3-partial-pipeline.test.js +74 -0
- package/test/typecheck/opaque-ffi-type.test.js +78 -0
- package/test/typecheck/sig-type-stage3.test.js +190 -0
- package/test/typecheck/stack-check-stage4.test.js +149 -0
- package/test/typecheck/stack-check-stage5.test.js +74 -0
- package/test/typecheck/stack-check-stage6.test.js +56 -0
- package/test/typecheck/stack-check-stage7.test.js +160 -0
- package/test/typecheck/stack-check-stage8.test.js +146 -0
- package/test/typecheck/stack-check-stage9.test.js +105 -0
- package/test/typecheck/typecheck-env.test.js +53 -0
- package/test/typecheck/typecheck-pipeline.test.js +37 -0
- package/README.md +0 -37
- package/cli/sail.js +0 -151
- package/cli/typecheck.js +0 -39
- package/docs/ARCHITECTURE.md +0 -50
- package/docs/CHANGELOG.md +0 -18
- package/docs/FFI-GUIDE.md +0 -65
- package/docs/RELEASE.md +0 -36
- package/docs/TESTING.md +0 -86
- package/test/integration.test.js +0 -61
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sail AST shape for RFC-0.1 §12.2 (phrase structure). Normative grammar is RFC;
|
|
3
|
+
* this file is the implementation contract for parse output.
|
|
4
|
+
*
|
|
5
|
+
* ## Spans
|
|
6
|
+
* Every node has `span: SourceSpan`. Positions match lexer (1-based line/column).
|
|
7
|
+
* `end` is the cursor after the last consumed character (exclusive end offset).
|
|
8
|
+
*
|
|
9
|
+
* ## Documentation (`doc`, RFC-0.1 п.4.3, грамматика `doc_block` п.12.2)
|
|
10
|
+
* Where the grammar requires `doc_block` (zero or more `-- … --` each followed by `ws`),
|
|
11
|
+
* the AST exposes `doc: string[]`: each entry is the inner `comment_text` of one block,
|
|
12
|
+
* in source order. Use `[]` when the block is empty.
|
|
13
|
+
* Applies to: leading doc on an import; after sum/product header and type parameters;
|
|
14
|
+
* after each sum tag and each product field; after the word signature and before the body.
|
|
15
|
+
*
|
|
16
|
+
* ## Other comments (AST v1)
|
|
17
|
+
* Leading `-- … --` before `+` / `&` / `@` are folded into the next declaration’s `doc`;
|
|
18
|
+
* they are not separate `items` entries. Comments inside a word or quotation body are not
|
|
19
|
+
* represented as dedicated `word_step` nodes in AST v1 (RFC-0.1 п.12.3).
|
|
20
|
+
*
|
|
21
|
+
* @typedef {{ offset: number, line: number, column: number }} SourcePos
|
|
22
|
+
* @typedef {{ start: SourcePos, end: SourcePos }} SourceSpan
|
|
23
|
+
*
|
|
24
|
+
* @typedef {Object} AstSourceFile
|
|
25
|
+
* @property {'source_file'} kind
|
|
26
|
+
* @property {SourceSpan} span
|
|
27
|
+
* @property {AstTopLevel[]} items
|
|
28
|
+
*
|
|
29
|
+
* @typedef {AstImport|AstSumType|AstProductType|AstWord} AstTopLevel
|
|
30
|
+
*
|
|
31
|
+
* @typedef {Object} AstImport
|
|
32
|
+
* @property {'import'} kind
|
|
33
|
+
* @property {SourceSpan} span
|
|
34
|
+
* @property {string} module
|
|
35
|
+
* @property {string} path
|
|
36
|
+
* @property {{ words: string[], types: string[] } | null} [bracket] bracket import list, or null for simple import
|
|
37
|
+
* @property {string[]} doc `-- … --` blocks immediately before this import (RFC-0.1 п.4.3)
|
|
38
|
+
*
|
|
39
|
+
* @typedef {Object} AstSumType
|
|
40
|
+
* @property {'sum_type'} kind
|
|
41
|
+
* @property {SourceSpan} span
|
|
42
|
+
* @property {string} name
|
|
43
|
+
* @property {string[]} typeParams
|
|
44
|
+
* @property {string[]} doc after `&TypeName` and type parameters, before first `|` (RFC-0.1 п.12.2 `sum_type_decl`)
|
|
45
|
+
* @property {{ name: string, payload: AstTypeExpr | null, span: SourceSpan, doc: string[] }[]} tags
|
|
46
|
+
*
|
|
47
|
+
* @typedef {Object} AstProductType
|
|
48
|
+
* @property {'product_type'} kind
|
|
49
|
+
* @property {SourceSpan} span
|
|
50
|
+
* @property {string} name
|
|
51
|
+
* @property {string[]} typeParams
|
|
52
|
+
* @property {string[]} doc after header and type parameters, before first field (RFC-0.1 п.12.2 `product_type_decl`)
|
|
53
|
+
* @property {{ name: string, type: AstTypeExpr, span: SourceSpan, doc: string[] }[]} fields
|
|
54
|
+
*
|
|
55
|
+
* @typedef {Object} AstWord
|
|
56
|
+
* @property {'word'} kind
|
|
57
|
+
* @property {SourceSpan} span
|
|
58
|
+
* @property {string} name
|
|
59
|
+
* @property {AstSignature} signature
|
|
60
|
+
* @property {string[]} doc after signature, before first `word_step` (RFC-0.1 п.12.2 `word_decl`, п.4.3)
|
|
61
|
+
* @property {AstWordStep[]} body
|
|
62
|
+
*
|
|
63
|
+
* @typedef {Object} AstSignature
|
|
64
|
+
* @property {'signature'} kind
|
|
65
|
+
* @property {SourceSpan} span
|
|
66
|
+
* @property {AstSigStackItem[]} left stack slots only (RFC-0.1 п.12.2 `sig_item` except `effect_add` / `effect_remove`)
|
|
67
|
+
* @property {AstSigStackItem[]} right
|
|
68
|
+
* @property {AstSigEffectAdd[]} effectsAdd `+EffectName` (RFC-0.1 п.5.7, `effect_add`); order = source order (`span.start`)
|
|
69
|
+
* @property {AstSigEffectRemove[]} effectsRemove `-EffectName` (`effect_remove`); same ordering
|
|
70
|
+
*
|
|
71
|
+
* @typedef {AstSigStackVar|AstSigQuotation|AstSigNamedQuotation|AstSigTypeExpr} AstSigStackItem
|
|
72
|
+
* Stack-context variables `~s`, `~b`, … are **AstSigStackVar** (RFC-0.1 п.12.2 `stack_var`), not `AstTypeVar`.
|
|
73
|
+
*
|
|
74
|
+
* @typedef {Object} AstSigEffectAdd
|
|
75
|
+
* @property {'sig_effect_add'} kind
|
|
76
|
+
* @property {string} name Async | Fail
|
|
77
|
+
* @property {SourceSpan} span
|
|
78
|
+
* @property {'left'|'right'} side of `->` this marker belongs to
|
|
79
|
+
*
|
|
80
|
+
* @typedef {Object} AstSigEffectRemove
|
|
81
|
+
* @property {'sig_effect_remove'} kind
|
|
82
|
+
* @property {string} name Async | Fail
|
|
83
|
+
* @property {SourceSpan} span
|
|
84
|
+
* @property {'left'|'right'} side of `->` this marker belongs to
|
|
85
|
+
*
|
|
86
|
+
* @typedef {Object} AstSigStackVar
|
|
87
|
+
* Stack type / stack-context variable: source form `~` + `LowerIdent` (RFC-0.1 п.12.2 `stack_var`, п.12.3 п.10–11).
|
|
88
|
+
* Examples: `~s`, `~b`, `~rest`. Distinct from `~Module/Type` (**AstModuleTypeRef**) and from type parameters like `a` in `Maybe a` (**AstTypeVar** in **AstTypeExpr**).
|
|
89
|
+
* @property {'stack_var'} kind
|
|
90
|
+
* @property {string} name `LowerIdent` only, **without** the leading `~` (e.g. `"s"` for `~s`)
|
|
91
|
+
* @property {SourceSpan} span
|
|
92
|
+
*
|
|
93
|
+
* @typedef {Object} AstSigQuotation
|
|
94
|
+
* @property {'quotation_sig'} kind
|
|
95
|
+
* @property {SourceSpan} span
|
|
96
|
+
* @property {AstSignature} inner same shape as top-level `signature` (left/right stack items + effectsAdd/effectsRemove)
|
|
97
|
+
*
|
|
98
|
+
* @typedef {Object} AstSigNamedQuotation
|
|
99
|
+
* @property {'named_quotation_sig'} kind
|
|
100
|
+
* @property {string} prefix
|
|
101
|
+
* @property {AstSigQuotation} quotation
|
|
102
|
+
* @property {SourceSpan} span
|
|
103
|
+
*
|
|
104
|
+
* @typedef {Object} AstSigTypeExpr
|
|
105
|
+
* @property {'sig_type_expr'} kind
|
|
106
|
+
* @property {AstTypeExpr} type
|
|
107
|
+
* @property {SourceSpan} span
|
|
108
|
+
*
|
|
109
|
+
* @typedef {Object} AstQuotationType
|
|
110
|
+
* Типовое выражение `Quote ( In -> Out )` / вложенная сигнатура в аргументе (напр. `Maybe ( Num -> Str )`).
|
|
111
|
+
* @property {'quotation_type'} kind
|
|
112
|
+
* @property {AstSignature} inner та же форма, что `quotation_sig.inner`
|
|
113
|
+
*
|
|
114
|
+
* @typedef {AstTypeName|AstTypeVar|AstModuleTypeRef|AstParenType|AstTypeApp|AstQuotationType} AstTypeExpr
|
|
115
|
+
*
|
|
116
|
+
* @typedef {Object} AstTypeName
|
|
117
|
+
* @property {'type_name'} kind
|
|
118
|
+
* @property {string} name
|
|
119
|
+
*
|
|
120
|
+
* @typedef {Object} AstTypeVar
|
|
121
|
+
* Type parameter in `type_expr` / `sig_type_expr` (RFC-0.1 `TypeVar`), not a stack slot `~name` — that is **AstSigStackVar** in **AstSigStackItem**.
|
|
122
|
+
* @property {'type_var'} kind
|
|
123
|
+
* @property {string} name
|
|
124
|
+
*
|
|
125
|
+
* @typedef {Object} AstModuleTypeRef
|
|
126
|
+
* @property {'module_type_ref'} kind
|
|
127
|
+
* @property {string} module
|
|
128
|
+
* @property {string} type
|
|
129
|
+
*
|
|
130
|
+
* @typedef {Object} AstParenType
|
|
131
|
+
* @property {'paren_type'} kind
|
|
132
|
+
* @property {AstTypeExpr} inner
|
|
133
|
+
*
|
|
134
|
+
* @typedef {Object} AstTypeApp
|
|
135
|
+
* @property {'type_app'} kind
|
|
136
|
+
* @property {string} ctor List | Dict | Map or generic head name
|
|
137
|
+
* @property {AstTypeExpr[]} args
|
|
138
|
+
*
|
|
139
|
+
* @typedef {AstLiteral|AstWordRef|AstModuleWordRef|AstBuiltin|AstQuotation|AstListLiteral|AstSlotWrite|AstSlotRead} AstWordStep
|
|
140
|
+
*
|
|
141
|
+
* @typedef {Object} AstLiteral
|
|
142
|
+
* @property {'literal'} kind
|
|
143
|
+
* @property {SourceSpan} span
|
|
144
|
+
* @property {'string'|'number'|'bigint'|'regexp'|'nil'|'bool'} litKind
|
|
145
|
+
* @property {string} raw lexer text
|
|
146
|
+
*
|
|
147
|
+
* @typedef {Object} AstWordRef
|
|
148
|
+
* @property {'word_ref'} kind
|
|
149
|
+
* @property {SourceSpan} span
|
|
150
|
+
* @property {string} name
|
|
151
|
+
*
|
|
152
|
+
* @typedef {Object} AstModuleWordRef
|
|
153
|
+
* @property {'module_word_ref'} kind
|
|
154
|
+
* @property {SourceSpan} span
|
|
155
|
+
* @property {string} module
|
|
156
|
+
* @property {string} word
|
|
157
|
+
*
|
|
158
|
+
* @typedef {Object} AstBuiltin
|
|
159
|
+
* @property {'builtin'} kind
|
|
160
|
+
* @property {SourceSpan} span
|
|
161
|
+
* @property {string} name
|
|
162
|
+
*
|
|
163
|
+
* @typedef {Object} AstQuotation
|
|
164
|
+
* @property {'quotation'} kind
|
|
165
|
+
* @property {SourceSpan} span
|
|
166
|
+
* @property {AstWordStep[]} body
|
|
167
|
+
*
|
|
168
|
+
* @typedef {Object} AstListLiteral
|
|
169
|
+
* @property {'list_literal'} kind
|
|
170
|
+
* @property {SourceSpan} span
|
|
171
|
+
* @property {AstLiteral[]} elements
|
|
172
|
+
*
|
|
173
|
+
* @typedef {Object} AstSlotWrite
|
|
174
|
+
* @property {'slot_write'} kind
|
|
175
|
+
* @property {SourceSpan} span
|
|
176
|
+
* @property {string} name
|
|
177
|
+
*
|
|
178
|
+
* @typedef {Object} AstSlotRead
|
|
179
|
+
* @property {'slot_read'} kind
|
|
180
|
+
* @property {SourceSpan} span
|
|
181
|
+
* @property {string} name
|
|
182
|
+
*/
|
|
183
|
+
|
|
184
|
+
/** @type {readonly string[]} */
|
|
185
|
+
export const AST_KINDS = Object.freeze([
|
|
186
|
+
'source_file',
|
|
187
|
+
'import',
|
|
188
|
+
'sum_type',
|
|
189
|
+
'product_type',
|
|
190
|
+
'word',
|
|
191
|
+
'signature',
|
|
192
|
+
'sig_effect_add',
|
|
193
|
+
'sig_effect_remove',
|
|
194
|
+
'stack_var',
|
|
195
|
+
'quotation_sig',
|
|
196
|
+
'named_quotation_sig',
|
|
197
|
+
'sig_type_expr',
|
|
198
|
+
'type_name',
|
|
199
|
+
'type_var',
|
|
200
|
+
'module_type_ref',
|
|
201
|
+
'paren_type',
|
|
202
|
+
'quotation_type',
|
|
203
|
+
'type_app',
|
|
204
|
+
'literal',
|
|
205
|
+
'word_ref',
|
|
206
|
+
'module_word_ref',
|
|
207
|
+
'builtin',
|
|
208
|
+
'quotation',
|
|
209
|
+
'list_literal',
|
|
210
|
+
'slot_write',
|
|
211
|
+
'slot_read'
|
|
212
|
+
])
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Нормативный перечень builtin_word (RFC-builtins-0.1.md резюме §4).
|
|
3
|
+
*/
|
|
4
|
+
export const BUILTIN_WORDS = new Set([
|
|
5
|
+
'dup', 'drop', 'swap', 'over', 'dup2', 'drop2',
|
|
6
|
+
'rot', 'reverse', 'nip', 'tuck', 'swap2',
|
|
7
|
+
'call', 'dip', 'keep', 'bi', 'tri', 'spread', 'both'
|
|
8
|
+
])
|
|
9
|
+
|
|
10
|
+
export function isBuiltinWord (name) {
|
|
11
|
+
return BUILTIN_WORDS.has(name)
|
|
12
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/** RFC-0.1 §13 templates for parse/lex (E1001–E1007). */
|
|
2
|
+
|
|
3
|
+
export function e1001UnexpectedToken (token) {
|
|
4
|
+
return `Синтаксическая ошибка: неожиданный токен '${token}'.`
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function e1002UnclosedComment () {
|
|
8
|
+
return "Незакрытый комментарий: ожидалась закрывающая пара '--'."
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function e1003BadImportPath (path) {
|
|
12
|
+
return `Некорректный путь импорта '${path}'.`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function e1004UnknownBlock (token) {
|
|
16
|
+
return `Неизвестный блок '${token}'. Ожидался '+', '&' или '@'.`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function e1005ArrowInQuotation () {
|
|
20
|
+
return "Стрелка сигнатуры '->' допустима только в сигнатурах, не внутри тела исполняемого '( ... )'."
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function e1006EffectOutsideSignature (effect) {
|
|
24
|
+
return `Префикс эффекта '${effect}' допустим только внутри сигнатуры в скобках.`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function e1007EffectOnlyAfterArrow (marker) {
|
|
28
|
+
return `Маркер эффекта '${marker}' допустим только справа от '->' в сигнатуре (исходящая часть).`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** RFC-0.1 §13 — E1101–E1113 (декларации, импорты, FFI). */
|
|
32
|
+
|
|
33
|
+
export function e1101DuplicateWord (name) {
|
|
34
|
+
return `Слово '${name}' уже объявлено в текущем модуле.`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function e1102DuplicateType (name) {
|
|
38
|
+
return `Тип '${name}' уже объявлен в текущем модуле.`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function e1103DuplicateSumTag (tag) {
|
|
42
|
+
return `Тег '${tag}' уже использован в sum-типе этого модуля.`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function e1104DuplicateProductField (field, type) {
|
|
46
|
+
return `Поле '${field}' уже объявлено в типе '${type}'.`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function e1105AutogenNameConflict (name) {
|
|
50
|
+
return `Автогенерируемое имя '${name}' конфликтует с существующим объявлением.`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function e1106DuplicateJsSailBlock (name) {
|
|
54
|
+
return `Повторное объявление '@sail' для '${name}' в JS-модуле.`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function e1108DuplicateBracketImportName (name) {
|
|
58
|
+
return `Повторное имя '${name}' в списке скобочного импорта.`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function e1109BracketImportConflicts (name) {
|
|
62
|
+
return `Имя '${name}' уже объявлено в модуле или внесено другим импортом; конфликт со скобочным импортом.`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function e1110SymbolMissingInExport (name) {
|
|
66
|
+
return `Символ '${name}' отсутствует в экспорте модуля (для JS — в извлечённом контракте '@sail').`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function e1111DuplicateModuleImport (module) {
|
|
70
|
+
return `Модуль '${module}' уже импортирован в этом файле.`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function e1112CyclicSailImports (modules) {
|
|
74
|
+
return `Циклическая зависимость между модулями Sail (в цикле участвуют, например: ${modules}).`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function e1113InvalidJsSailJSDoc () {
|
|
78
|
+
return "Блок JSDoc с '@sail': повторный '@sail', либо текст после '@sail' не является валидным фрагментом Sail (§10.1)."
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** RFC-0.1 §13 — E1201–E1206 (резолв имён). */
|
|
82
|
+
|
|
83
|
+
export function e1201UnresolvedName (name) {
|
|
84
|
+
return `Не удалось разрешить имя '${name}'.`
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function e1202AmbiguousName (name) {
|
|
88
|
+
return `Неоднозначная ссылка '${name}' в текущем модуле.`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function e1203ModuleNotFound (module) {
|
|
92
|
+
return `Модуль '${module}' не найден.`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function e1204MissingMember (module, name) {
|
|
96
|
+
return `В модуле '${module}' отсутствует '${name}'.`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function e1205ImportNeedsQualification (name, module) {
|
|
100
|
+
return `Обращение к '${name}' из модуля '${module}' требует '~${module}/${name}' (если символ не внесён скобочным импортом, §4.2).`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function e1206UnknownBuiltin (name) {
|
|
104
|
+
return `Неизвестное встроенное слово '${name}'.`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** RFC-0.1 §13 E1301 */
|
|
108
|
+
export function e1301WordSignature (word) {
|
|
109
|
+
return `Некорректная сигнатура слова '${word}'.`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** RFC-0.1 §13 E1304 */
|
|
113
|
+
export function e1304TypeMismatch (expected, actual) {
|
|
114
|
+
return `Несовместимые типы: expected ${expected}, got ${actual}.`
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** RFC-0.1 §13 E1304 — неразрешённое имя в типовом слоте сигнатуры (этап 3). */
|
|
118
|
+
export function e1304UnknownTypeInSignature (name) {
|
|
119
|
+
return `Неизвестное имя типа '${name}' в сигнатуре.`
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** RFC-0.1 §13 E1303 */
|
|
123
|
+
export function e1303StackEffect (expected, actual) {
|
|
124
|
+
return `Несогласованный стековый эффект: expected ${expected}, got ${actual}.`
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** RFC-0.1 §13 E1305 ({var} в RFC) */
|
|
128
|
+
export function e1305OccursCheck (varName) {
|
|
129
|
+
return `Бесконечный тип недопустим: переменная '${varName}' входит сама в себя.`
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** RFC-0.1 §13 E1306 */
|
|
133
|
+
export function e1306CallNeedsQuote (actual) {
|
|
134
|
+
return `Нельзя применить CALL: ожидается Quote (I -> O), получено ${actual}.`
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** RFC-0.1 §13 E1307 */
|
|
138
|
+
export function e1307EliminatorBranches () {
|
|
139
|
+
return 'Ветки eliminator-а несовместимы: выходные сигнатуры quotations (в т.ч. ~b) не унифицируются.'
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** RFC-0.1 §13 E1308 */
|
|
143
|
+
export function e1308EliminatorQuotes (name) {
|
|
144
|
+
return `Некорректные аргументы eliminator-а '${name}': quotations должны идти в порядке объявления тегов/полей.`
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** RFC-0.1 §13 E1309 (контейнеры List/Dict/Map — выдача из L3 по мере реализации проверки). */
|
|
148
|
+
export function e1309ContainerContract (type, expected, actual) {
|
|
149
|
+
return `Нарушение ограничений контейнера '${type}': expected ${expected}, got ${actual}.`
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** RFC-0.1 §13 E1311 */
|
|
153
|
+
export function e1311ParameterizedTypeNeedsParens (type) {
|
|
154
|
+
return `В сигнатуре параметризованный тип '${type}' должен быть записан в скобках как единый слот (§4.4).`
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** RFC-0.1 §13 E1302 */
|
|
158
|
+
export function e1302QuotationSig (detail) {
|
|
159
|
+
return `Некорректная сигнатура quotation: '${detail}'.`
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** RFC-0.1 §13 E1313 */
|
|
163
|
+
export function e1313DuplicateSlotWrite (name) {
|
|
164
|
+
return `Повторная запись слота ':${name}' в теле слова (§6.1.6).`
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** RFC-0.1 §13 E1314 */
|
|
168
|
+
export function e1314SlotReadBeforeWrite (name) {
|
|
169
|
+
return `Чтение слота ';${name}' до соответствующей записи ':${name}' (§6.1.6).`
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** RFC-0.1 §13 E1310 */
|
|
173
|
+
export function e1310AsyncCall (callee, caller) {
|
|
174
|
+
return `Вызов '${callee}' с эффектом '+Async' недопустим из слова '${caller}' без '+Async' или без снятия '-Async' обёрткой (§5.7).`
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** RFC-0.1 §13 E1312 */
|
|
178
|
+
export function e1312FailCall (callee, caller) {
|
|
179
|
+
return `Вызов '${callee}' с эффектом '+Fail' недопустим из '${caller}' без '+Fail' или без снятия '-Fail' обёрткой (§5.7).`
|
|
180
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse phase (RFC-0.1 §11 step 1): lex (RFC-lex-0.1) + phrase parse (§12.2).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createLexerState, skipWs } from './lexer.js'
|
|
6
|
+
import { parseSourceText } from './parse-source.js'
|
|
7
|
+
import * as ab from './ast-build.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} sourceText
|
|
11
|
+
* @returns {{ ok: boolean, diagnostics: Array<{ code: string, message: string, offset?: number, line?: number, column?: number }>, ast?: unknown }}
|
|
12
|
+
*/
|
|
13
|
+
export function parseSource (sourceText) {
|
|
14
|
+
if (typeof sourceText !== 'string') {
|
|
15
|
+
return {
|
|
16
|
+
ok: false,
|
|
17
|
+
diagnostics: [{
|
|
18
|
+
code: 'E1001',
|
|
19
|
+
message: "Синтаксическая ошибка: неожиданный токен ''.",
|
|
20
|
+
offset: 0,
|
|
21
|
+
line: 1,
|
|
22
|
+
column: 1
|
|
23
|
+
}]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (/^\s*$/.test(sourceText)) {
|
|
27
|
+
const state = createLexerState(sourceText)
|
|
28
|
+
skipWs(state)
|
|
29
|
+
const end = ab.endPosFromState(state)
|
|
30
|
+
const span = {
|
|
31
|
+
start: { offset: 0, line: 1, column: 1 },
|
|
32
|
+
end
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
ok: true,
|
|
36
|
+
diagnostics: [],
|
|
37
|
+
ast: ab.node('source_file', span, { items: [] })
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const { diagnostics, ast } = parseSourceText(sourceText)
|
|
41
|
+
return {
|
|
42
|
+
ok: diagnostics.length === 0,
|
|
43
|
+
diagnostics,
|
|
44
|
+
ast: diagnostics.length === 0 ? ast : undefined
|
|
45
|
+
}
|
|
46
|
+
}
|