@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.
Files changed (145) hide show
  1. package/bin/sail.mjs +4 -0
  2. package/cli/run-cli.js +176 -0
  3. package/index.js +11 -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 +33 -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
@@ -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
+ }