parser-lr 0.7.0 → 0.8.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 (54) hide show
  1. package/bin/parser-lr.js +404 -874
  2. package/bin/parser-lr.js.map +1 -1
  3. package/dist/lib/diagnostics/format-diagnostic.d.ts +31 -0
  4. package/dist/lib/diagnostics/format-diagnostic.d.ts.map +1 -0
  5. package/dist/lib/diagnostics/format-diagnostic.js +36 -0
  6. package/dist/lib/diagnostics/format-diagnostic.js.map +1 -0
  7. package/dist/lib/diagnostics/index.d.ts +5 -0
  8. package/dist/lib/diagnostics/index.d.ts.map +1 -0
  9. package/dist/lib/diagnostics/index.js +3 -0
  10. package/dist/lib/diagnostics/index.js.map +1 -0
  11. package/dist/lib/diagnostics/source-position.d.ts +24 -0
  12. package/dist/lib/diagnostics/source-position.d.ts.map +1 -0
  13. package/dist/lib/diagnostics/source-position.js +39 -0
  14. package/dist/lib/diagnostics/source-position.js.map +1 -0
  15. package/dist/lib/grammar/ast-type.d.ts +2 -0
  16. package/dist/lib/grammar/ast-type.d.ts.map +1 -1
  17. package/dist/lib/grammar/grammar-from-cst.js +8 -4
  18. package/dist/lib/grammar/grammar-from-cst.js.map +1 -1
  19. package/dist/lib/grammar/grammar.json +86 -820
  20. package/dist/lib/grammar/index.d.ts +1 -1
  21. package/dist/lib/grammar/index.d.ts.map +1 -1
  22. package/dist/lib/grammar/production.d.ts +2 -0
  23. package/dist/lib/grammar/production.d.ts.map +1 -1
  24. package/dist/lib/grammar/table-validator.d.ts +12 -2
  25. package/dist/lib/grammar/table-validator.d.ts.map +1 -1
  26. package/dist/lib/grammar/table-validator.js +68 -25
  27. package/dist/lib/grammar/table-validator.js.map +1 -1
  28. package/dist/lib/grammar/transform-rule.d.ts +3 -0
  29. package/dist/lib/grammar/transform-rule.d.ts.map +1 -1
  30. package/dist/lib/grammar-entry.d.ts +1 -1
  31. package/dist/lib/grammar-entry.d.ts.map +1 -1
  32. package/dist/lib/grammar-entry.js.map +1 -1
  33. package/dist/lib/index.d.ts +3 -0
  34. package/dist/lib/index.d.ts.map +1 -1
  35. package/dist/lib/index.js +1 -0
  36. package/dist/lib/index.js.map +1 -1
  37. package/dist/lib/parse-context.d.ts +7 -0
  38. package/dist/lib/parse-context.d.ts.map +1 -1
  39. package/dist/lib/parse-context.js +9 -0
  40. package/dist/lib/parse-context.js.map +1 -1
  41. package/dist/lib/parse-table/table/lr-parse-table.d.ts.map +1 -1
  42. package/dist/lib/parse-table/table/lr-parse-table.js +10 -3
  43. package/dist/lib/parse-table/table/lr-parse-table.js.map +1 -1
  44. package/dist/lib/parser-lr.d.ts +15 -0
  45. package/dist/lib/parser-lr.d.ts.map +1 -1
  46. package/dist/lib/parser-lr.js +38 -9
  47. package/dist/lib/parser-lr.js.map +1 -1
  48. package/docs/The Ferrite Programming Language.md +568 -0
  49. package/docs/grammar.md +55 -3
  50. package/grammars/6502.grammar +2 -2
  51. package/grammars/ferrite.grammar +107 -97
  52. package/grammars/grammar.grammar +19 -140
  53. package/grammars/lisp.grammar +3 -2
  54. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { Lexer, lexChunkStream, lexChunkStreamAsync, lexChunks, lexChunksAsync, } from './lexer/lexer.js';
2
2
  import { ParseTable } from './parse-table/parse-table.js';
3
- import { parseWithTable } from './shift-reduce/shift-reduce-engine.js';
3
+ import { parseWithTable, parseWithTableResult } from './shift-reduce/shift-reduce-engine.js';
4
4
  import { transformCst } from './transform/cst-transformer.js';
5
5
  /**
6
6
  * Shift-reduce parser for EBNF grammars.
@@ -92,6 +92,42 @@ export class ParserLr {
92
92
  }
93
93
  return parseWithTable(this.table, tokens);
94
94
  }
95
+ /**
96
+ * Parses a token stream and retains syntax-error offset details.
97
+ *
98
+ * @param tokens - Token stream ending with `$eof`.
99
+ * @returns Tree and optional syntax-error details.
100
+ */
101
+ parseResult(tokens) {
102
+ if (this.table === null) {
103
+ return {
104
+ tree: null,
105
+ errorOffset: 0,
106
+ errorMessage: 'Parse table has no parser entries',
107
+ };
108
+ }
109
+ const result = parseWithTableResult(this.table, tokens);
110
+ if (result.cst === null) {
111
+ return {
112
+ tree: null,
113
+ errorOffset: result.errorOffset,
114
+ errorMessage: result.errorMessage,
115
+ };
116
+ }
117
+ if (this.grammar.transformSchema === null) {
118
+ return {
119
+ tree: result.cst,
120
+ errorOffset: null,
121
+ errorMessage: null,
122
+ };
123
+ }
124
+ const tree = transformCst(result.cst, this.grammar.transformSchema, this.table);
125
+ return {
126
+ tree,
127
+ errorOffset: tree === null ? result.errorOffset : null,
128
+ errorMessage: tree === null ? 'AST transform failed' : null,
129
+ };
130
+ }
95
131
  /**
96
132
  * Parses a token stream into an AST when transform rules are declared.
97
133
  *
@@ -99,14 +135,7 @@ export class ParserLr {
99
135
  * @returns Transformed AST, CST when no transform section exists, or null on failure.
100
136
  */
101
137
  parseAst(tokens) {
102
- const cst = this.parseCst(tokens);
103
- if (cst === null) {
104
- return null;
105
- }
106
- if (this.grammar.transformSchema === null || this.table === null) {
107
- return cst;
108
- }
109
- return transformCst(cst, this.grammar.transformSchema, this.table);
138
+ return this.parseResult(tokens).tree;
110
139
  }
111
140
  /**
112
141
  * Parses a token stream, applying CST-to-AST transforms when configured.
@@ -1 +1 @@
1
- {"version":3,"file":"parser-lr.js","sourceRoot":"","sources":["../../src/lib/parser-lr.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,EACL,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,cAAc,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAE9D;;GAEG;AACH,MAAM,OAAO,QAAQ;IASG;IACC;IARrB;;;;;OAKG;IACH,YACoB,OAAgB,EACf,QAA2B,IAAI;QADhC,YAAO,GAAP,OAAO,CAAS;QACf,UAAK,GAAL,KAAK,CAA0B;IAGpD,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,cAAc,CAAC,KAAiB;QAE1C,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACI,WAAW;QAEd,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACI,GAAG,CAAC,MAAc;QAErB,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACI,SAAS,CAAC,MAAwB;QAErC,OAAO,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACI,cAAc,CAAC,MAA6B;QAE/C,OAAO,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAED;;;;;OAKG;IACI,cAAc,CAAC,MAAwB;QAE1C,OAAO,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,mBAAmB,CAAC,MAA6B;QAE1D,OAAO,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACI,QAAQ,CAAC,MAAwB;QAEpC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EACvB,CAAC;YACG,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,OAAO,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;OAKG;IACI,QAAQ,CAAC,MAAwB;QAEpC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAElC,IAAI,GAAG,KAAK,IAAI,EAChB,CAAC;YACG,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAChE,CAAC;YACG,OAAO,GAAG,CAAC;QACf,CAAC;QAED,OAAO,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,MAAwB;QAEjC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED;;;;;OAKG;IACI,WAAW,CAAC,MAAc;QAE7B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,CAAC;IAED;;;;;OAKG;IACI,eAAe,CAAC,YAAyB,KAAK;QAEjD,OAAO,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC3D,CAAC;CACJ"}
1
+ {"version":3,"file":"parser-lr.js","sourceRoot":"","sources":["../../src/lib/parser-lr.ts"],"names":[],"mappings":"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"}
@@ -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).