parser-lr 0.6.1 → 0.8.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 (185) hide show
  1. package/README.md +14 -30
  2. package/bin/parser-lr.js +12759 -13493
  3. package/bin/parser-lr.js.map +1 -1
  4. package/dist/lib/grammar/grammar-from-cst.js +4 -1
  5. package/dist/lib/grammar/grammar-from-cst.js.map +1 -1
  6. package/dist/lib/grammar/grammar.json +86 -820
  7. package/dist/lib/grammar/index.d.ts +1 -1
  8. package/dist/lib/grammar/index.d.ts.map +1 -1
  9. package/dist/lib/grammar/index.js +1 -1
  10. package/dist/lib/grammar/index.js.map +1 -1
  11. package/dist/lib/grammar/meta-grammar-table.d.ts +0 -12
  12. package/dist/lib/grammar/meta-grammar-table.d.ts.map +1 -1
  13. package/dist/lib/grammar/meta-grammar-table.js +5 -22
  14. package/dist/lib/grammar/meta-grammar-table.js.map +1 -1
  15. package/dist/lib/grammar/table-validator.d.ts.map +1 -1
  16. package/dist/lib/grammar/table-validator.js +19 -1
  17. package/dist/lib/grammar/table-validator.js.map +1 -1
  18. package/dist/lib/grammar-entry.d.ts +42 -0
  19. package/dist/lib/grammar-entry.d.ts.map +1 -0
  20. package/dist/lib/grammar-entry.js +45 -0
  21. package/dist/lib/grammar-entry.js.map +1 -0
  22. package/dist/lib/index.d.ts +7 -5
  23. package/dist/lib/index.d.ts.map +1 -1
  24. package/dist/lib/index.js +0 -3
  25. package/dist/lib/index.js.map +1 -1
  26. package/dist/lib/parse-context.d.ts +4 -15
  27. package/dist/lib/parse-context.d.ts.map +1 -1
  28. package/dist/lib/parse-context.js +4 -23
  29. package/dist/lib/parse-context.js.map +1 -1
  30. package/dist/lib/transform/grammar-fixture.js +3 -3
  31. package/dist/lib/transform/grammar-fixture.js.map +1 -1
  32. package/docs/The Ferrite Programming Language.md +568 -0
  33. package/docs/grammar.md +55 -3
  34. package/docs/parser-lr-browser-lib-split.md +174 -0
  35. package/grammars/6502.grammar +2 -2
  36. package/grammars/ferrite.grammar +107 -97
  37. package/grammars/grammar.grammar +19 -140
  38. package/grammars/lisp.grammar +3 -2
  39. package/package.json +7 -2
  40. package/dist/lib/grammar/grammar-json-path.d.ts +0 -2
  41. package/dist/lib/grammar/grammar-json-path.d.ts.map +0 -1
  42. package/dist/lib/grammar/grammar-json-path.esm.d.ts +0 -5
  43. package/dist/lib/grammar/grammar-json-path.esm.d.ts.map +0 -1
  44. package/dist/lib/grammar/grammar-json-path.esm.js +0 -9
  45. package/dist/lib/grammar/grammar-json-path.esm.js.map +0 -1
  46. package/dist/lib/grammar/grammar-json-path.js +0 -2
  47. package/dist/lib/grammar/grammar-json-path.js.map +0 -1
  48. package/dist/lib-cjs/ast/ast-node.js +0 -70
  49. package/dist/lib-cjs/ast/ast-node.js.map +0 -1
  50. package/dist/lib-cjs/errors/index.js +0 -9
  51. package/dist/lib-cjs/errors/index.js.map +0 -1
  52. package/dist/lib-cjs/errors/parser-lr-error.js +0 -52
  53. package/dist/lib-cjs/errors/parser-lr-error.js.map +0 -1
  54. package/dist/lib-cjs/grammar/ast-schema.js +0 -43
  55. package/dist/lib-cjs/grammar/ast-schema.js.map +0 -1
  56. package/dist/lib-cjs/grammar/ast-type.js +0 -3
  57. package/dist/lib-cjs/grammar/ast-type.js.map +0 -1
  58. package/dist/lib-cjs/grammar/expression.js +0 -3
  59. package/dist/lib-cjs/grammar/expression.js.map +0 -1
  60. package/dist/lib-cjs/grammar/grammar-from-cst.js +0 -641
  61. package/dist/lib-cjs/grammar/grammar-from-cst.js.map +0 -1
  62. package/dist/lib-cjs/grammar/grammar-json-path.js +0 -13
  63. package/dist/lib-cjs/grammar/grammar-json-path.js.map +0 -1
  64. package/dist/lib-cjs/grammar/grammar-literals.js +0 -71
  65. package/dist/lib-cjs/grammar/grammar-literals.js.map +0 -1
  66. package/dist/lib-cjs/grammar/grammar.js +0 -64
  67. package/dist/lib-cjs/grammar/grammar.js.map +0 -1
  68. package/dist/lib-cjs/grammar/grammar.json +0 -5760
  69. package/dist/lib-cjs/grammar/index.js +0 -21
  70. package/dist/lib-cjs/grammar/index.js.map +0 -1
  71. package/dist/lib-cjs/grammar/meta-grammar-table.js +0 -68
  72. package/dist/lib-cjs/grammar/meta-grammar-table.js.map +0 -1
  73. package/dist/lib-cjs/grammar/production.js +0 -3
  74. package/dist/lib-cjs/grammar/production.js.map +0 -1
  75. package/dist/lib-cjs/grammar/read-grammar-error.js +0 -22
  76. package/dist/lib-cjs/grammar/read-grammar-error.js.map +0 -1
  77. package/dist/lib-cjs/grammar/read-grammar.js +0 -24
  78. package/dist/lib-cjs/grammar/read-grammar.js.map +0 -1
  79. package/dist/lib-cjs/grammar/table-validator.js +0 -262
  80. package/dist/lib-cjs/grammar/table-validator.js.map +0 -1
  81. package/dist/lib-cjs/grammar/token-rule.js +0 -3
  82. package/dist/lib-cjs/grammar/token-rule.js.map +0 -1
  83. package/dist/lib-cjs/grammar/transform-expression.js +0 -3
  84. package/dist/lib-cjs/grammar/transform-expression.js.map +0 -1
  85. package/dist/lib-cjs/grammar/transform-rule.js +0 -3
  86. package/dist/lib-cjs/grammar/transform-rule.js.map +0 -1
  87. package/dist/lib-cjs/grammar/transform-schema.js +0 -43
  88. package/dist/lib-cjs/grammar/transform-schema.js.map +0 -1
  89. package/dist/lib-cjs/index.js +0 -66
  90. package/dist/lib-cjs/index.js.map +0 -1
  91. package/dist/lib-cjs/lexer/index.js +0 -32
  92. package/dist/lib-cjs/lexer/index.js.map +0 -1
  93. package/dist/lib-cjs/lexer/lexer-compile-error.js +0 -22
  94. package/dist/lib-cjs/lexer/lexer-compile-error.js.map +0 -1
  95. package/dist/lib-cjs/lexer/lexer-compile.js +0 -201
  96. package/dist/lib-cjs/lexer/lexer-compile.js.map +0 -1
  97. package/dist/lib-cjs/lexer/lexer-error.js +0 -22
  98. package/dist/lib-cjs/lexer/lexer-error.js.map +0 -1
  99. package/dist/lib-cjs/lexer/lexer-input-error.js +0 -17
  100. package/dist/lib-cjs/lexer/lexer-input-error.js.map +0 -1
  101. package/dist/lib-cjs/lexer/lexer-state-error.js +0 -19
  102. package/dist/lib-cjs/lexer/lexer-state-error.js.map +0 -1
  103. package/dist/lib-cjs/lexer/lexer.js +0 -278
  104. package/dist/lib-cjs/lexer/lexer.js.map +0 -1
  105. package/dist/lib-cjs/lexer/token.js +0 -44
  106. package/dist/lib-cjs/lexer/token.js.map +0 -1
  107. package/dist/lib-cjs/package.json +0 -3
  108. package/dist/lib-cjs/parse-context-error.js +0 -19
  109. package/dist/lib-cjs/parse-context-error.js.map +0 -1
  110. package/dist/lib-cjs/parse-context.js +0 -137
  111. package/dist/lib-cjs/parse-context.js.map +0 -1
  112. package/dist/lib-cjs/parse-output-error.js +0 -19
  113. package/dist/lib-cjs/parse-output-error.js.map +0 -1
  114. package/dist/lib-cjs/parse-output.js +0 -18
  115. package/dist/lib-cjs/parse-output.js.map +0 -1
  116. package/dist/lib-cjs/parse-table/analysis/first-follow.js +0 -294
  117. package/dist/lib-cjs/parse-table/analysis/first-follow.js.map +0 -1
  118. package/dist/lib-cjs/parse-table/analysis/index.js +0 -9
  119. package/dist/lib-cjs/parse-table/analysis/index.js.map +0 -1
  120. package/dist/lib-cjs/parse-table/bnf/bnf-grammar.js +0 -140
  121. package/dist/lib-cjs/parse-table/bnf/bnf-grammar.js.map +0 -1
  122. package/dist/lib-cjs/parse-table/bnf/bnf-production.js +0 -3
  123. package/dist/lib-cjs/parse-table/bnf/bnf-production.js.map +0 -1
  124. package/dist/lib-cjs/parse-table/bnf/bnf-symbol.js +0 -39
  125. package/dist/lib-cjs/parse-table/bnf/bnf-symbol.js.map +0 -1
  126. package/dist/lib-cjs/parse-table/bnf/desugar-ebnf.js +0 -224
  127. package/dist/lib-cjs/parse-table/bnf/desugar-ebnf.js.map +0 -1
  128. package/dist/lib-cjs/parse-table/bnf/index.js +0 -13
  129. package/dist/lib-cjs/parse-table/bnf/index.js.map +0 -1
  130. package/dist/lib-cjs/parse-table/build-lr-table.js +0 -171
  131. package/dist/lib-cjs/parse-table/build-lr-table.js.map +0 -1
  132. package/dist/lib-cjs/parse-table/index.js +0 -49
  133. package/dist/lib-cjs/parse-table/index.js.map +0 -1
  134. package/dist/lib-cjs/parse-table/lr-algorithm-error.js +0 -19
  135. package/dist/lib-cjs/parse-table/lr-algorithm-error.js.map +0 -1
  136. package/dist/lib-cjs/parse-table/lr-algorithm.js +0 -31
  137. package/dist/lib-cjs/parse-table/lr-algorithm.js.map +0 -1
  138. package/dist/lib-cjs/parse-table/lr0/index.js +0 -14
  139. package/dist/lib-cjs/parse-table/lr0/index.js.map +0 -1
  140. package/dist/lib-cjs/parse-table/lr0/lr0-item-set.js +0 -286
  141. package/dist/lib-cjs/parse-table/lr0/lr0-item-set.js.map +0 -1
  142. package/dist/lib-cjs/parse-table/lr1/index.js +0 -18
  143. package/dist/lib-cjs/parse-table/lr1/index.js.map +0 -1
  144. package/dist/lib-cjs/parse-table/lr1/lr1-item-set.js +0 -432
  145. package/dist/lib-cjs/parse-table/lr1/lr1-item-set.js.map +0 -1
  146. package/dist/lib-cjs/parse-table/parse-table-build-error.js +0 -24
  147. package/dist/lib-cjs/parse-table/parse-table-build-error.js.map +0 -1
  148. package/dist/lib-cjs/parse-table/parse-table-error.js +0 -19
  149. package/dist/lib-cjs/parse-table/parse-table-error.js.map +0 -1
  150. package/dist/lib-cjs/parse-table/parse-table-json.js +0 -12
  151. package/dist/lib-cjs/parse-table/parse-table-json.js.map +0 -1
  152. package/dist/lib-cjs/parse-table/parse-table.js +0 -345
  153. package/dist/lib-cjs/parse-table/parse-table.js.map +0 -1
  154. package/dist/lib-cjs/parse-table/slr/index.js +0 -13
  155. package/dist/lib-cjs/parse-table/slr/index.js.map +0 -1
  156. package/dist/lib-cjs/parse-table/slr/parse-action.js +0 -8
  157. package/dist/lib-cjs/parse-table/slr/parse-action.js.map +0 -1
  158. package/dist/lib-cjs/parse-table/slr/slr-table.js +0 -18
  159. package/dist/lib-cjs/parse-table/slr/slr-table.js.map +0 -1
  160. package/dist/lib-cjs/parse-table/table/index.js +0 -21
  161. package/dist/lib-cjs/parse-table/table/index.js.map +0 -1
  162. package/dist/lib-cjs/parse-table/table/lr-parse-table.js +0 -192
  163. package/dist/lib-cjs/parse-table/table/lr-parse-table.js.map +0 -1
  164. package/dist/lib-cjs/parse-table/table/parse-action.js +0 -54
  165. package/dist/lib-cjs/parse-table/table/parse-action.js.map +0 -1
  166. package/dist/lib-cjs/parse-table/table/table-builder-base.js +0 -153
  167. package/dist/lib-cjs/parse-table/table/table-builder-base.js.map +0 -1
  168. package/dist/lib-cjs/parse-table/token-inventory.js +0 -18
  169. package/dist/lib-cjs/parse-table/token-inventory.js.map +0 -1
  170. package/dist/lib-cjs/parser-lr.js +0 -143
  171. package/dist/lib-cjs/parser-lr.js.map +0 -1
  172. package/dist/lib-cjs/shift-reduce/index.js +0 -11
  173. package/dist/lib-cjs/shift-reduce/index.js.map +0 -1
  174. package/dist/lib-cjs/shift-reduce/shift-reduce-engine.js +0 -224
  175. package/dist/lib-cjs/shift-reduce/shift-reduce-engine.js.map +0 -1
  176. package/dist/lib-cjs/transform/binding-map.js +0 -82
  177. package/dist/lib-cjs/transform/binding-map.js.map +0 -1
  178. package/dist/lib-cjs/transform/cst-transformer.js +0 -480
  179. package/dist/lib-cjs/transform/cst-transformer.js.map +0 -1
  180. package/dist/lib-cjs/transform/grammar-fixture.js +0 -109
  181. package/dist/lib-cjs/transform/grammar-fixture.js.map +0 -1
  182. package/dist/lib-cjs/transform/index.js +0 -12
  183. package/dist/lib-cjs/transform/index.js.map +0 -1
  184. package/docs/parser-lr-enhancement-proposals.md +0 -337
  185. package/grammars/fixtures/table-only-import/table-only-smoke.cjs +0 -38
@@ -0,0 +1,568 @@
1
+ # The Ferrite Programming Language
2
+
3
+ Ferrite is a statically typed, C-like language with C#-style structs, file-scoped namespaces, explicit pointer semantics, and no preprocessor. A source file is a single compilation unit: an optional namespace header, `using` directives, and top-level declarations compose the program.
4
+
5
+ This guide describes the language as defined by [`grammars/ferrite.grammar`](../grammars/ferrite.grammar). Ferrite is included with parser-lr as a reference grammar; parsing and AST generation are supported today. Code generation and runtime semantics are outside the scope of this document unless noted.
6
+
7
+ ## Quick start
8
+
9
+ A minimal Ferrite program declares a `main` function and returns an integer:
10
+
11
+ ```ferrite
12
+ public Int32 main()
13
+ {
14
+ return 0;
15
+ }
16
+ ```
17
+
18
+ A more typical program places types in a file-scoped namespace and imports other namespaces with `using`:
19
+
20
+ ```ferrite
21
+ namespace Ferrite.Math;
22
+
23
+ using Ferrite.Core;
24
+
25
+ public struct Vec2
26
+ {
27
+ Float32 x;
28
+ Float32 y;
29
+ Float32 dot(Vec2* other)
30
+ {
31
+ return x * other->x + y * other->y;
32
+ }
33
+ };
34
+
35
+ public Int32 main()
36
+ {
37
+ Vec2 a = { 1.0, 2.0 };
38
+ Vec2* p = &a;
39
+ return (Int32)p->dot(&a);
40
+ }
41
+ ```
42
+
43
+ Comments use C-style syntax:
44
+
45
+ ```ferrite
46
+ // line comment
47
+
48
+ /* block
49
+ comment */
50
+ ```
51
+
52
+ ## Naming conventions
53
+
54
+ These casing rules are **conventions**, not enforced by the parser. Prefer them in Ferrite source so programs stay consistent:
55
+
56
+ | Kind | Convention | Examples |
57
+ |------|------------|----------|
58
+ | Built-in types | PascalCase keywords | `Int32`, `Float64`, `Bool`, `Void` |
59
+ | Struct and other type names | PascalCase | `Vec2`, `Node`, `HttpServer` |
60
+ | Functions and methods | camelCase | `main`, `dot`, `isSet` |
61
+ | Variables, fields, and parameters | camelCase | `count`, `other`, `sum` |
62
+ | Constants | camelCase (same as variables) | `maxRetries` — no `UPPER_CASE` style |
63
+
64
+ Identifiers may contain letters, digits, and underscores; the grammar does not reject names that break these conventions.
65
+
66
+ ## Program structure
67
+
68
+ A Ferrite file has a fixed order. Nothing may appear before the optional namespace, and every `using` directive must appear before any declaration:
69
+
70
+ 1. Optional file-scoped namespace: `namespace Qualified.Name;`
71
+ 2. Zero or more using directives: `using Qualified.Name;`
72
+ 3. Zero or more top-level declarations (structs and functions)
73
+
74
+ | Form | Example |
75
+ |------|---------|
76
+ | File-scoped namespace | `namespace Ferrite.Math;` |
77
+ | Using directive | `using Ferrite.Core;` |
78
+ | Struct | `public struct Point { … };` |
79
+ | Function | `public Int32 add(Int32 a, Int32 b) { … }` or `private Int32 add(Int32 a, Int32 b);` |
80
+
81
+ There is no `#include` or macro layer. Share code across files by using namespaces and `using` directives. Block namespaces (`namespace Name { … }`) and nested namespace bodies are not part of the language.
82
+
83
+ ### File-scoped namespace
84
+
85
+ At most one namespace declaration may appear, and only as the first construct in the file:
86
+
87
+ ```ferrite
88
+ namespace Ferrite.Math;
89
+ ```
90
+
91
+ Qualified names use dot notation: `Ferrite.Math.Vec2`.
92
+
93
+ Omitting the namespace leaves declarations in the global namespace for that file.
94
+
95
+ ### Using directives
96
+
97
+ All `using` directives must follow the namespace (if present) and precede every struct or function declaration:
98
+
99
+ ```ferrite
100
+ namespace Ferrite.App;
101
+
102
+ using Ferrite.Math;
103
+ using Ferrite.Math.Vec;
104
+
105
+ public Int32 main()
106
+ {
107
+ return 0;
108
+ }
109
+ ```
110
+
111
+ A file may begin with usings and no namespace:
112
+
113
+ ```ferrite
114
+ using Ferrite.Math;
115
+
116
+ public Int32 main()
117
+ {
118
+ return 0;
119
+ }
120
+ ```
121
+
122
+ ### Access modifiers
123
+
124
+ Every **top-level** struct, function definition, and function prototype requires `public` or `private`:
125
+
126
+ ```ferrite
127
+ public struct Point
128
+ {
129
+ Int32 x;
130
+ Int32 y;
131
+ };
132
+
133
+ public Int32 twice(Int32 x)
134
+ {
135
+ return x + x;
136
+ }
137
+
138
+ private Void helper();
139
+ ```
140
+
141
+ Access modifiers are **not** required on:
142
+
143
+ - local variables inside functions
144
+ - parameters
145
+ - struct fields
146
+ - struct methods
147
+
148
+ ```ferrite
149
+ public Int32 sum(Int32 a, Int32 b)
150
+ {
151
+ Int32 total = a + b;
152
+ return total;
153
+ }
154
+ ```
155
+
156
+ ## Types
157
+
158
+ ### Primitive types
159
+
160
+ | Type | Description |
161
+ |------|-------------|
162
+ | `Void` | No value; used for functions with no return value |
163
+ | `Bool` | Boolean |
164
+ | `Int8`, `Int16`, `Int32`, `Int64` | Signed integers |
165
+ | `UInt8`, `UInt16`, `UInt32`, `UInt64` | Unsigned integers |
166
+ | `Float32`, `Float64` | Floating point |
167
+ | `Char` | Character |
168
+
169
+ ### Named types
170
+
171
+ Struct names are ordinary type names. After a struct is declared, its identifier can appear wherever a type is expected:
172
+
173
+ ```ferrite
174
+ public struct Point
175
+ {
176
+ Int32 x;
177
+ Int32 y;
178
+ };
179
+
180
+ public Point* origin(Point* cursor)
181
+ {
182
+ return cursor;
183
+ }
184
+ ```
185
+
186
+ ### Pointers
187
+
188
+ Append one or more `*` after a type to form a pointer type:
189
+
190
+ ```ferrite
191
+ Int32 value;
192
+ Int32* p;
193
+ Int32** pp;
194
+ Vec2* origin;
195
+ ```
196
+
197
+ The address-of operator `&` takes a pointer to an lvalue; unary `*` dereferences a pointer:
198
+
199
+ ```ferrite
200
+ Int32 x = 10;
201
+ Int32* p = &x;
202
+ Int32 y = *p;
203
+ ```
204
+
205
+ Member access on pointers uses the arrow operator `->`:
206
+
207
+ ```ferrite
208
+ Vec2* p = &a;
209
+ Float32 x = p->x;
210
+ ```
211
+
212
+ ### Arrays
213
+
214
+ Fixed-size and unsized array types are written with brackets after the element type:
215
+
216
+ ```ferrite
217
+ Int32 buffer[10];
218
+ Int32[] unsized;
219
+ ```
220
+
221
+ Pointer suffixes apply after the array form:
222
+
223
+ ```ferrite
224
+ Int32*[4] row;
225
+ ```
226
+
227
+ ## Declarations
228
+
229
+ ### Functions
230
+
231
+ Functions have an access modifier, return type, name, parameter list, and either a body or a terminating semicolon for a prototype:
232
+
233
+ ```ferrite
234
+ public Int32 abs(Int32 x); // prototype
235
+
236
+ public Int32 twice(Int32 x) // definition
237
+ {
238
+ return x + x;
239
+ }
240
+
241
+ private Void noop() // no parameters
242
+ {
243
+ return;
244
+ }
245
+ ```
246
+
247
+ Parameters are declared as `type name`, comma-separated, without access modifiers:
248
+
249
+ ```ferrite
250
+ public Bool both(Bool a, Bool b)
251
+ {
252
+ return a && b;
253
+ }
254
+ ```
255
+
256
+ ### Structs
257
+
258
+ A struct declares fields and methods inside braces, then ends with a semicolon. The struct itself needs an access modifier; members do not:
259
+
260
+ ```ferrite
261
+ public struct Counter
262
+ {
263
+ Int32 n;
264
+
265
+ Int32 next()
266
+ {
267
+ return n + 1;
268
+ }
269
+
270
+ Int32 add(Int32 delta)
271
+ {
272
+ return n + delta;
273
+ }
274
+ };
275
+ ```
276
+
277
+ Fields are type-name pairs terminated by semicolons. Methods use the same body syntax as free functions but are defined inside the struct body without `public` or `private`.
278
+
279
+ An empty struct is valid:
280
+
281
+ ```ferrite
282
+ public struct Empty
283
+ {
284
+ };
285
+ ```
286
+
287
+ ### Local variables
288
+
289
+ Inside a block, declare variables with a type, name, and optional initializer. Locals do not take access modifiers:
290
+
291
+ ```ferrite
292
+ Int32 sum = 0;
293
+ Vec2 v = { 1, 2 };
294
+ Int32* p;
295
+ ```
296
+
297
+ Brace initialization supplies a comma-separated list of expressions:
298
+
299
+ ```ferrite
300
+ Vec2 a = { 1.0, 2.0 };
301
+ ```
302
+
303
+ ## Statements
304
+
305
+ Statements appear in function bodies, struct methods, and blocks.
306
+
307
+ | Statement | Form |
308
+ |-----------|------|
309
+ | Block | `{ … }` |
310
+ | Variable declaration | `type name [= init];` |
311
+ | Expression | `expr;` |
312
+ | `if` | `if (cond) stmt [else stmt]` |
313
+ | `while` | `while (cond) stmt` |
314
+ | `for` | `for ([init;] [test;] [step]) stmt` |
315
+ | `return` | `return [expr];` |
316
+ | `break` | `break;` |
317
+ | `continue` | `continue;` |
318
+
319
+ ### `if` and `else`
320
+
321
+ ```ferrite
322
+ if (flag)
323
+ {
324
+ x = 1;
325
+ }
326
+ else
327
+ {
328
+ x = 2;
329
+ }
330
+ ```
331
+
332
+ The `else` branch is optional. Each branch is a single statement, often a block.
333
+
334
+ ### `while`
335
+
336
+ ```ferrite
337
+ while (running)
338
+ {
339
+ step = step + 1;
340
+ }
341
+ ```
342
+
343
+ ### `for`
344
+
345
+ Ferrite uses C-style `for` loops. The init, test, and step clauses are each optional:
346
+
347
+ ```ferrite
348
+ for (Int32 i = 0; i < 10; i = i + 1)
349
+ {
350
+ sum = sum + i;
351
+ }
352
+
353
+ for (; i < 10; i = i + 1)
354
+ {
355
+ }
356
+
357
+ for (Int32 i = 0;; i = i + 1)
358
+ {
359
+ if (i >= 10)
360
+ {
361
+ break;
362
+ }
363
+ }
364
+ ```
365
+
366
+ The init clause may be a variable declaration or an expression.
367
+
368
+ ### `return`, `break`, and `continue`
369
+
370
+ ```ferrite
371
+ public Int32 zero()
372
+ {
373
+ return 0;
374
+ }
375
+
376
+ public Void finish()
377
+ {
378
+ return;
379
+ }
380
+
381
+ while (true)
382
+ {
383
+ break;
384
+ }
385
+
386
+ while (true)
387
+ {
388
+ continue;
389
+ }
390
+ ```
391
+
392
+ ## Expressions
393
+
394
+ ### Literals
395
+
396
+ | Kind | Examples |
397
+ |------|----------|
398
+ | Integer | `42`, `0xFF`, `0xDeadBeef`, `0b1010` |
399
+ | Floating | `3.14`, `1.5e10`, `3.14e-2` |
400
+ | Character | `'x'`, `'\n'` |
401
+ | String | `"hello"`, `"line\n"` |
402
+ | Boolean | `true`, `false` |
403
+ | Null pointer | `null` |
404
+
405
+ Integer literals accept hexadecimal (`0x` / `0X`) and binary (`0b` / `0B`) prefixes. Float literals may use a decimal exponent (`e` / `E`).
406
+
407
+ ### Primary expressions
408
+
409
+ Identifiers, literals, parenthesized expressions, and `new`:
410
+
411
+ ```ferrite
412
+ x
413
+ 0xFF
414
+ (obj.field)
415
+ new Node()
416
+ new Node(1, 2)
417
+ ```
418
+
419
+ ### Postfix operations
420
+
421
+ Postfix operators bind to the expression on their left:
422
+
423
+ | Operator | Meaning |
424
+ |----------|---------|
425
+ | `[expr]` | Index |
426
+ | `( )`, `(args…)` | Call |
427
+ | `.name` | Member access |
428
+ | `->name` | Pointer member access |
429
+ | `++`, `--` | Postfix increment / decrement |
430
+
431
+ ```ferrite
432
+ arr[i]
433
+ f(a, b)
434
+ main()
435
+ obj.field
436
+ ptr->field
437
+ i++
438
+ ```
439
+
440
+ ### Unary operators
441
+
442
+ | Operator | Meaning |
443
+ |----------|---------|
444
+ | `(type) expr` | Cast |
445
+ | `++`, `--` | Prefix increment / decrement |
446
+ | `&` | Address of |
447
+ | `*` | Dereference |
448
+ | `!` | Logical not |
449
+ | `~` | Bitwise not |
450
+ | `-`, `+` | Unary minus / plus |
451
+
452
+ ```ferrite
453
+ (Int32)value
454
+ ++i
455
+ &x
456
+ *p
457
+ !flag
458
+ ~mask
459
+ -n
460
+ ```
461
+
462
+ ### Binary operators and precedence
463
+
464
+ From highest to lowest binding strength:
465
+
466
+ 1. Postfix: `[]`, `()`, `.`, `->`, `++`, `--`
467
+ 2. Unary: cast, prefix `++`/`--`, `&`, `*`, `!`, `~`, unary `-`/`+`
468
+ 3. Multiplicative: `*`, `/`, `%`
469
+ 4. Additive: `+`, `-`
470
+ 5. Shift: `<<`, `>>`
471
+ 6. Relational: `<`, `>`, `<=`, `>=`
472
+ 7. Equality: `==`, `!=`
473
+ 8. Bitwise AND: `&`
474
+ 9. Bitwise XOR: `^`
475
+ 10. Bitwise OR: `|`
476
+ 11. Logical AND: `&&`
477
+ 12. Logical OR: `||`
478
+ 13. Assignment: `=`, `+=`, `-=`, `*=`, `/=`, `&=`, `|=`, `^=`
479
+
480
+ Assignment is right-associative. All other binary operators listed here are left-associative.
481
+
482
+ ```ferrite
483
+ a + b * c
484
+ a + b * c < d && e || f
485
+ x = y = 0
486
+ x += 1
487
+ ```
488
+
489
+ ## Memory and construction
490
+
491
+ `new` allocates or constructs a value of the given type:
492
+
493
+ ```ferrite
494
+ Node* n = new Node();
495
+ Node* m = new Node(1, 2);
496
+ ```
497
+
498
+ The result type is typically stored in a pointer. `null` represents a null pointer constant:
499
+
500
+ ```ferrite
501
+ Int32* p = null;
502
+ ```
503
+
504
+ Exact allocation semantics (stack vs heap, constructor dispatch) depend on a future implementation. The syntax above is what the Ferrite grammar accepts.
505
+
506
+ ## Worked example
507
+
508
+ The following program combines a file-scoped namespace, ordered usings, visibility, structs with methods, pointers, and brace initialization:
509
+
510
+ ```ferrite
511
+ namespace Ferrite.Math;
512
+
513
+ using Ferrite.Core;
514
+
515
+ public struct Vec2
516
+ {
517
+ Float32 x;
518
+ Float32 y;
519
+
520
+ Float32 dot(Vec2* other)
521
+ {
522
+ return x * other->x + y * other->y;
523
+ }
524
+ };
525
+
526
+ public Int32 main()
527
+ {
528
+ Vec2 a = { 1.0, 2.0 };
529
+ Vec2* p = &a;
530
+ return (Int32)p->dot(&a);
531
+ }
532
+ ```
533
+
534
+ Reading it top to bottom:
535
+
536
+ 1. The file declares namespace `Ferrite.Math`.
537
+ 2. `using Ferrite.Core;` imports another namespace before any declarations.
538
+ 3. `Vec2` is a public struct with two fields and a method that reads another vector through a pointer.
539
+ 4. `main` creates a vector, takes its address, and calls `dot` through a pointer, casting the result to `Int32`.
540
+
541
+ ## Parsing Ferrite with parser-lr
542
+
543
+ Ferrite ships as a `.grammar` file in this repository. Generate a parse table, validate transforms, or parse source with the CLI:
544
+
545
+ ```bash
546
+ parser-lr table generate -g grammars/ferrite.grammar -o ferrite.json
547
+ parser-lr table validate -g grammars/ferrite.grammar
548
+ parser-lr parse -i program.fe -g grammars/ferrite.grammar
549
+ ```
550
+
551
+ Output is JSON containing an AST when parsing succeeds. See the [project README](../README.md) for install instructions and library usage.
552
+
553
+ Integration tests in [`src/lib/ferrite.test.ts`](../src/lib/ferrite.test.ts) exercise the grammar across types, control flow, operators, and full programs.
554
+
555
+ ## Summary
556
+
557
+ | Topic | Ferrite approach |
558
+ |-------|------------------|
559
+ | Modules | Optional file-scoped `namespace Name;`, then `using` directives; no preprocessor |
560
+ | Visibility | Required `public` / `private` on top-level structs and functions |
561
+ | User-defined types | `struct` with fields and methods |
562
+ | Naming | PascalCase types, camelCase functions and variables (convention) |
563
+ | Pointers | Explicit `*`, `&`, `->`, and `null` |
564
+ | Control flow | `if`, `while`, C-style `for`, `break`, `continue` |
565
+ | Expressions | C-family operators and precedence |
566
+ | Initialization | Assignment and brace lists |
567
+
568
+ For grammar-file mechanics (tokens, AST shapes, transforms), see [`.grammar` file syntax](grammar.md).
package/docs/grammar.md CHANGED
@@ -116,6 +116,19 @@ ast
116
116
  #binary [left]:expr [operator]:operator [right]:expr
117
117
  | #literal number
118
118
  ;
119
+
120
+ list =
121
+ #list { item }
122
+ ;
123
+ ```
124
+
125
+ Every `type.#variant` referenced from `transform` must appear as a `#variant` label on that AST type, including types with only one alternative:
126
+
127
+ ```ebnf
128
+ ast
129
+ program =
130
+ #program { form }
131
+ ;
119
132
  ```
120
133
 
121
134
  When present, transform rules map parse trees to these types.
@@ -161,9 +174,48 @@ transform
161
174
  |-----------|----------|
162
175
  | `pass(slot)` | Lift one bound child unchanged. `pass(boundSlot)` preserves the bound production symbol and its `#` variant. `pass(terminalName)` at the same rule may collapse to that terminal. |
163
176
  | `build(type.#variant, …)` | Construct an AST node with a fixed shape. Omit absent optional bindings from the argument list. |
164
- | `flatten(type.#variant, head, tail)` | Turn a `{ repeat }` list into one AST node with ordered children. Use the repeat non-terminal (for example `list$repeat_0`) as `tail` on the head production. |
177
+ | `flatten(type.#variant, head, tail)` | Turn a `head { }` list into one AST node with ordered children. Prefer putting `flatten` on the **parent** production that owns the required head and the synthetic repeat tail. |
178
+
179
+ Preferred parent-flatten pattern for a required head plus optional rest:
180
+
181
+ ```ebnf
182
+ grammar
183
+ list =
184
+ #list [first]:item { comma [rest]:item }
185
+ ;
186
+
187
+ ast
188
+ list =
189
+ #list { item }
190
+ ;
191
+
192
+ transform
193
+ list ->
194
+ #list flatten(list.#list, first, list$repeat_0) ;
195
+ ```
196
+
197
+ Use a `$repeat_*` helper transform when the list is zero-or-more and nested among other fields, or when the parent must `build(...)` a wrapper around the flattened list. The transform language cannot nest `flatten(...)` inside `type.#variant(...)` arguments:
198
+
199
+ ```ebnf
200
+ transform
201
+ program ->
202
+ #main pass(program$repeat_0)
203
+ ;
204
+
205
+ program$repeat_0 ->
206
+ #main flatten(program.#program, item, program$repeat_0)
207
+ ;
208
+
209
+ wrapped_list ->
210
+ #main wrapped_list.#wrapped(open, wrapped_list$repeat_0, close)
211
+ ;
212
+
213
+ wrapped_list$repeat_0 ->
214
+ #main flatten(wrapped_list.#items, member, wrapped_list$repeat_0)
215
+ ;
216
+ ```
165
217
 
166
- **Production symbols are preserved.** When a CST node has parse-table metadata, transforms keep its production name even if it has only one terminal child. Bare `CLS` through `pass(stmt)` where `[stmt]:cls_stmt` yields an `cls_stmt` node, not `kw_cls`.
218
+ **Production symbols are preserved.** When a CST node has parse-table metadata, transforms keep its production name even if it has only one terminal child. Bare `CLS` through `pass(stmt)` where `[stmt]:cls_stmt` yields a `cls_stmt` node, not `kw_cls`.
167
219
 
168
220
  ### Transform contract
169
221
 
@@ -195,7 +247,7 @@ Before / after for `CASE IS < 0` with `case_selector = #relational kw_is compari
195
247
  Run `parser-lr table validate -g mylang.grammar` to check `ast` / `transform` consistency. The validator:
196
248
 
197
249
  - warns when `pass(boundSlot)` targets a production that can match a single terminal and has no transform rule;
198
- - errors when a `build` / `fold` / `flatten` references a `type.#variant` not declared in `ast`;
250
+ - errors when a `build` / `fold` / `flatten` references a `type.#variant` not declared in `ast`, including single-alternative labeled types;
199
251
  - warns when a production, `ast` type, or `transform` rule is declared more than once (the later definition silently overrides the earlier one).
200
252
 
201
253
  Add `--strict` to fail on warnings in CI.