parser-lr 0.4.1 → 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 (197) hide show
  1. package/README.md +35 -1
  2. package/bin/parser-lr.js +340 -5802
  3. package/bin/parser-lr.js.map +1 -1
  4. package/dist/lib/grammar/grammar-json-path.d.ts +2 -0
  5. package/dist/lib/grammar/grammar-json-path.d.ts.map +1 -0
  6. package/dist/lib/grammar/grammar-json-path.esm.d.ts +5 -0
  7. package/dist/lib/grammar/grammar-json-path.esm.d.ts.map +1 -0
  8. package/dist/lib/grammar/grammar-json-path.esm.js +9 -0
  9. package/dist/lib/grammar/grammar-json-path.esm.js.map +1 -0
  10. package/dist/lib/grammar/grammar-json-path.js +2 -0
  11. package/dist/lib/grammar/grammar-json-path.js.map +1 -0
  12. package/dist/lib/grammar/index.d.ts +2 -0
  13. package/dist/lib/grammar/index.d.ts.map +1 -1
  14. package/dist/lib/grammar/index.js +1 -0
  15. package/dist/lib/grammar/index.js.map +1 -1
  16. package/dist/lib/grammar/meta-grammar-table.d.ts.map +1 -1
  17. package/dist/lib/grammar/meta-grammar-table.js +4 -2
  18. package/dist/lib/grammar/meta-grammar-table.js.map +1 -1
  19. package/dist/lib/grammar/table-validator.d.ts +26 -0
  20. package/dist/lib/grammar/table-validator.d.ts.map +1 -0
  21. package/dist/lib/grammar/table-validator.js +211 -0
  22. package/dist/lib/grammar/table-validator.js.map +1 -0
  23. package/dist/lib/index.d.ts +2 -0
  24. package/dist/lib/index.d.ts.map +1 -1
  25. package/dist/lib/index.js +1 -0
  26. package/dist/lib/index.js.map +1 -1
  27. package/dist/lib/transform/cst-transformer.d.ts +14 -0
  28. package/dist/lib/transform/cst-transformer.d.ts.map +1 -1
  29. package/dist/lib/transform/cst-transformer.js +82 -11
  30. package/dist/lib/transform/cst-transformer.js.map +1 -1
  31. package/dist/lib/transform/grammar-fixture.d.ts +56 -0
  32. package/dist/lib/transform/grammar-fixture.d.ts.map +1 -0
  33. package/dist/lib/transform/grammar-fixture.js +101 -0
  34. package/dist/lib/transform/grammar-fixture.js.map +1 -0
  35. package/dist/lib-cjs/ast/ast-node.js +70 -0
  36. package/dist/lib-cjs/ast/ast-node.js.map +1 -0
  37. package/dist/lib-cjs/errors/index.js +9 -0
  38. package/dist/lib-cjs/errors/index.js.map +1 -0
  39. package/dist/lib-cjs/errors/parser-lr-error.js +52 -0
  40. package/dist/lib-cjs/errors/parser-lr-error.js.map +1 -0
  41. package/dist/lib-cjs/grammar/ast-schema.js +43 -0
  42. package/dist/lib-cjs/grammar/ast-schema.js.map +1 -0
  43. package/dist/lib-cjs/grammar/ast-type.js +3 -0
  44. package/dist/lib-cjs/grammar/ast-type.js.map +1 -0
  45. package/dist/lib-cjs/grammar/expression.js +3 -0
  46. package/dist/lib-cjs/grammar/expression.js.map +1 -0
  47. package/dist/lib-cjs/grammar/grammar-from-cst.js +641 -0
  48. package/dist/lib-cjs/grammar/grammar-from-cst.js.map +1 -0
  49. package/dist/lib-cjs/grammar/grammar-json-path.js +13 -0
  50. package/dist/lib-cjs/grammar/grammar-json-path.js.map +1 -0
  51. package/dist/lib-cjs/grammar/grammar-literals.js +71 -0
  52. package/dist/lib-cjs/grammar/grammar-literals.js.map +1 -0
  53. package/dist/lib-cjs/grammar/grammar.js +64 -0
  54. package/dist/lib-cjs/grammar/grammar.js.map +1 -0
  55. package/dist/lib-cjs/grammar/grammar.json +5760 -0
  56. package/dist/lib-cjs/grammar/index.js +19 -0
  57. package/dist/lib-cjs/grammar/index.js.map +1 -0
  58. package/dist/lib-cjs/grammar/meta-grammar-table.js +39 -0
  59. package/dist/lib-cjs/grammar/meta-grammar-table.js.map +1 -0
  60. package/dist/lib-cjs/grammar/production.js +3 -0
  61. package/dist/lib-cjs/grammar/production.js.map +1 -0
  62. package/dist/lib-cjs/grammar/read-grammar-error.js +22 -0
  63. package/dist/lib-cjs/grammar/read-grammar-error.js.map +1 -0
  64. package/dist/lib-cjs/grammar/read-grammar.js +24 -0
  65. package/dist/lib-cjs/grammar/read-grammar.js.map +1 -0
  66. package/dist/lib-cjs/grammar/table-validator.js +215 -0
  67. package/dist/lib-cjs/grammar/table-validator.js.map +1 -0
  68. package/dist/lib-cjs/grammar/token-rule.js +3 -0
  69. package/dist/lib-cjs/grammar/token-rule.js.map +1 -0
  70. package/dist/lib-cjs/grammar/transform-expression.js +3 -0
  71. package/dist/lib-cjs/grammar/transform-expression.js.map +1 -0
  72. package/dist/lib-cjs/grammar/transform-rule.js +3 -0
  73. package/dist/lib-cjs/grammar/transform-rule.js.map +1 -0
  74. package/dist/lib-cjs/grammar/transform-schema.js +43 -0
  75. package/dist/lib-cjs/grammar/transform-schema.js.map +1 -0
  76. package/dist/lib-cjs/index.js +66 -0
  77. package/dist/lib-cjs/index.js.map +1 -0
  78. package/dist/lib-cjs/lexer/index.js +32 -0
  79. package/dist/lib-cjs/lexer/index.js.map +1 -0
  80. package/dist/lib-cjs/lexer/lexer-compile-error.js +22 -0
  81. package/dist/lib-cjs/lexer/lexer-compile-error.js.map +1 -0
  82. package/dist/lib-cjs/lexer/lexer-compile.js +201 -0
  83. package/dist/lib-cjs/lexer/lexer-compile.js.map +1 -0
  84. package/dist/lib-cjs/lexer/lexer-error.js +22 -0
  85. package/dist/lib-cjs/lexer/lexer-error.js.map +1 -0
  86. package/dist/lib-cjs/lexer/lexer-input-error.js +17 -0
  87. package/dist/lib-cjs/lexer/lexer-input-error.js.map +1 -0
  88. package/dist/lib-cjs/lexer/lexer-state-error.js +19 -0
  89. package/dist/lib-cjs/lexer/lexer-state-error.js.map +1 -0
  90. package/dist/lib-cjs/lexer/lexer.js +278 -0
  91. package/dist/lib-cjs/lexer/lexer.js.map +1 -0
  92. package/dist/lib-cjs/lexer/token.js +44 -0
  93. package/dist/lib-cjs/lexer/token.js.map +1 -0
  94. package/dist/lib-cjs/package.json +3 -0
  95. package/dist/lib-cjs/parse-context-error.js +19 -0
  96. package/dist/lib-cjs/parse-context-error.js.map +1 -0
  97. package/dist/lib-cjs/parse-context.js +137 -0
  98. package/dist/lib-cjs/parse-context.js.map +1 -0
  99. package/dist/lib-cjs/parse-output-error.js +19 -0
  100. package/dist/lib-cjs/parse-output-error.js.map +1 -0
  101. package/dist/lib-cjs/parse-output.js +18 -0
  102. package/dist/lib-cjs/parse-output.js.map +1 -0
  103. package/dist/lib-cjs/parse-table/analysis/first-follow.js +294 -0
  104. package/dist/lib-cjs/parse-table/analysis/first-follow.js.map +1 -0
  105. package/dist/lib-cjs/parse-table/analysis/index.js +9 -0
  106. package/dist/lib-cjs/parse-table/analysis/index.js.map +1 -0
  107. package/dist/lib-cjs/parse-table/bnf/bnf-grammar.js +140 -0
  108. package/dist/lib-cjs/parse-table/bnf/bnf-grammar.js.map +1 -0
  109. package/dist/lib-cjs/parse-table/bnf/bnf-production.js +3 -0
  110. package/dist/lib-cjs/parse-table/bnf/bnf-production.js.map +1 -0
  111. package/dist/lib-cjs/parse-table/bnf/bnf-symbol.js +39 -0
  112. package/dist/lib-cjs/parse-table/bnf/bnf-symbol.js.map +1 -0
  113. package/dist/lib-cjs/parse-table/bnf/desugar-ebnf.js +224 -0
  114. package/dist/lib-cjs/parse-table/bnf/desugar-ebnf.js.map +1 -0
  115. package/dist/lib-cjs/parse-table/bnf/index.js +13 -0
  116. package/dist/lib-cjs/parse-table/bnf/index.js.map +1 -0
  117. package/dist/lib-cjs/parse-table/build-lr-table.js +171 -0
  118. package/dist/lib-cjs/parse-table/build-lr-table.js.map +1 -0
  119. package/dist/lib-cjs/parse-table/index.js +49 -0
  120. package/dist/lib-cjs/parse-table/index.js.map +1 -0
  121. package/dist/lib-cjs/parse-table/lr-algorithm-error.js +19 -0
  122. package/dist/lib-cjs/parse-table/lr-algorithm-error.js.map +1 -0
  123. package/dist/lib-cjs/parse-table/lr-algorithm.js +31 -0
  124. package/dist/lib-cjs/parse-table/lr-algorithm.js.map +1 -0
  125. package/dist/lib-cjs/parse-table/lr0/index.js +14 -0
  126. package/dist/lib-cjs/parse-table/lr0/index.js.map +1 -0
  127. package/dist/lib-cjs/parse-table/lr0/lr0-item-set.js +286 -0
  128. package/dist/lib-cjs/parse-table/lr0/lr0-item-set.js.map +1 -0
  129. package/dist/lib-cjs/parse-table/lr1/index.js +18 -0
  130. package/dist/lib-cjs/parse-table/lr1/index.js.map +1 -0
  131. package/dist/lib-cjs/parse-table/lr1/lr1-item-set.js +432 -0
  132. package/dist/lib-cjs/parse-table/lr1/lr1-item-set.js.map +1 -0
  133. package/dist/lib-cjs/parse-table/parse-table-build-error.js +24 -0
  134. package/dist/lib-cjs/parse-table/parse-table-build-error.js.map +1 -0
  135. package/dist/lib-cjs/parse-table/parse-table-error.js +19 -0
  136. package/dist/lib-cjs/parse-table/parse-table-error.js.map +1 -0
  137. package/dist/lib-cjs/parse-table/parse-table-json.js +12 -0
  138. package/dist/lib-cjs/parse-table/parse-table-json.js.map +1 -0
  139. package/dist/lib-cjs/parse-table/parse-table.js +345 -0
  140. package/dist/lib-cjs/parse-table/parse-table.js.map +1 -0
  141. package/dist/lib-cjs/parse-table/slr/index.js +13 -0
  142. package/dist/lib-cjs/parse-table/slr/index.js.map +1 -0
  143. package/dist/lib-cjs/parse-table/slr/parse-action.js +8 -0
  144. package/dist/lib-cjs/parse-table/slr/parse-action.js.map +1 -0
  145. package/dist/lib-cjs/parse-table/slr/slr-table.js +18 -0
  146. package/dist/lib-cjs/parse-table/slr/slr-table.js.map +1 -0
  147. package/dist/lib-cjs/parse-table/table/index.js +21 -0
  148. package/dist/lib-cjs/parse-table/table/index.js.map +1 -0
  149. package/dist/lib-cjs/parse-table/table/lr-parse-table.js +192 -0
  150. package/dist/lib-cjs/parse-table/table/lr-parse-table.js.map +1 -0
  151. package/dist/lib-cjs/parse-table/table/parse-action.js +54 -0
  152. package/dist/lib-cjs/parse-table/table/parse-action.js.map +1 -0
  153. package/dist/lib-cjs/parse-table/table/table-builder-base.js +153 -0
  154. package/dist/lib-cjs/parse-table/table/table-builder-base.js.map +1 -0
  155. package/dist/lib-cjs/parse-table/token-inventory.js +18 -0
  156. package/dist/lib-cjs/parse-table/token-inventory.js.map +1 -0
  157. package/dist/lib-cjs/parser-lr.js +143 -0
  158. package/dist/lib-cjs/parser-lr.js.map +1 -0
  159. package/dist/lib-cjs/shift-reduce/index.js +11 -0
  160. package/dist/lib-cjs/shift-reduce/index.js.map +1 -0
  161. package/dist/lib-cjs/shift-reduce/shift-reduce-engine.js +224 -0
  162. package/dist/lib-cjs/shift-reduce/shift-reduce-engine.js.map +1 -0
  163. package/dist/lib-cjs/transform/binding-map.js +82 -0
  164. package/dist/lib-cjs/transform/binding-map.js.map +1 -0
  165. package/dist/lib-cjs/transform/cst-transformer.js +480 -0
  166. package/dist/lib-cjs/transform/cst-transformer.js.map +1 -0
  167. package/dist/lib-cjs/transform/grammar-fixture.js +109 -0
  168. package/dist/lib-cjs/transform/grammar-fixture.js.map +1 -0
  169. package/dist/lib-cjs/transform/index.js +12 -0
  170. package/dist/lib-cjs/transform/index.js.map +1 -0
  171. package/docs/grammar.md +80 -0
  172. package/docs/parser-lr-enhancement-proposals.md +548 -0
  173. package/grammars/6502.grammar +233 -0
  174. package/grammars/calc.grammar +30 -0
  175. package/grammars/ferrite.grammar +991 -0
  176. package/grammars/fixtures/build-optional/build-optional.grammar +32 -0
  177. package/grammars/fixtures/build-optional/input.txt +1 -0
  178. package/grammars/fixtures/comparison-op/comparison-op.grammar +28 -0
  179. package/grammars/fixtures/comparison-op/input.txt +1 -0
  180. package/grammars/fixtures/flatten-repeat/flatten-repeat.grammar +28 -0
  181. package/grammars/fixtures/flatten-repeat/input.txt +1 -0
  182. package/grammars/fixtures/help-topic/help-topic.grammar +28 -0
  183. package/grammars/fixtures/help-topic/input.txt +1 -0
  184. package/grammars/fixtures/let-target/input.txt +1 -0
  185. package/grammars/fixtures/let-target/let-target.grammar +33 -0
  186. package/grammars/fixtures/pass-preserves-production/bare-terminal/bare-terminal.grammar +24 -0
  187. package/grammars/fixtures/pass-preserves-production/bare-terminal/input.txt +1 -0
  188. package/grammars/fixtures/pass-preserves-production/labeled-variant/input-end-if.txt +1 -0
  189. package/grammars/fixtures/pass-preserves-production/labeled-variant/input-end.txt +1 -0
  190. package/grammars/fixtures/pass-preserves-production/labeled-variant/labeled-variant.grammar +24 -0
  191. package/grammars/fixtures/pass-preserves-production/optional-absent/input.txt +1 -0
  192. package/grammars/fixtures/pass-preserves-production/optional-absent/optional-absent.grammar +24 -0
  193. package/grammars/fixtures/pass-preserves-production/optional-present/input.txt +1 -0
  194. package/grammars/fixtures/pass-preserves-production/optional-present/optional-present.grammar +24 -0
  195. package/grammars/grammar.grammar +428 -0
  196. package/grammars/lisp.grammar +95 -0
  197. package/package.json +9 -4
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fixtureGrammarPath = fixtureGrammarPath;
4
+ exports.findChildrenBySymbol = findChildrenBySymbol;
5
+ exports.findChildBySymbol = findChildBySymbol;
6
+ exports.parseFixture = parseFixture;
7
+ exports.discoverFixtures = discoverFixtures;
8
+ exports.runFixtureCase = runFixtureCase;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const parse_context_js_1 = require("../parse-context.js");
12
+ /**
13
+ * Returns the `.grammar` file for one fixture directory.
14
+ *
15
+ * Fixture grammars are named after their directory (for example
16
+ * `bare-terminal/bare-terminal.grammar`). The meta-grammar keeps the reserved
17
+ * name `grammar.grammar` at the repo root only.
18
+ *
19
+ * @param fixtureDir - Directory containing a fixture grammar and input files.
20
+ */
21
+ function fixtureGrammarPath(fixtureDir) {
22
+ const grammarPath = (0, node_path_1.join)(fixtureDir, `${(0, node_path_1.basename)(fixtureDir)}.grammar`);
23
+ return (0, node_fs_1.existsSync)(grammarPath) ? grammarPath : null;
24
+ }
25
+ /**
26
+ * Returns child AST nodes matching a symbol name.
27
+ *
28
+ * @param node - Parent AST node.
29
+ * @param symbol - Child symbol to find.
30
+ */
31
+ function findChildrenBySymbol(node, symbol) {
32
+ return node.children.filter((child) => child.symbol === symbol);
33
+ }
34
+ /**
35
+ * Returns the first child AST node matching a symbol name.
36
+ *
37
+ * @param node - Parent AST node.
38
+ * @param symbol - Child symbol to find.
39
+ */
40
+ function findChildBySymbol(node, symbol) {
41
+ return node.children.find((child) => child.symbol === symbol) ?? null;
42
+ }
43
+ /**
44
+ * Parses one fixture grammar and input file into an AST.
45
+ *
46
+ * @param fixtureDir - Directory containing a named fixture grammar and an input file.
47
+ * @param inputFileName - Input file name within the fixture directory.
48
+ */
49
+ function parseFixture(fixtureDir, inputFileName = 'input.txt') {
50
+ const grammarPath = fixtureGrammarPath(fixtureDir);
51
+ if (grammarPath === null) {
52
+ throw new Error(`fixture grammar not found in ${fixtureDir}`);
53
+ }
54
+ const grammarSource = (0, node_fs_1.readFileSync)(grammarPath, 'utf8');
55
+ const input = (0, node_fs_1.readFileSync)((0, node_path_1.join)(fixtureDir, inputFileName), 'utf8').trimEnd();
56
+ const context = parse_context_js_1.ParseContext.fromGrammar(grammarSource, 'lr1');
57
+ return context.parseSource(input);
58
+ }
59
+ /**
60
+ * Discovers fixture directories containing a named `.grammar` file under a root path.
61
+ *
62
+ * @param rootDir - Root directory to scan recursively.
63
+ */
64
+ function discoverFixtures(rootDir) {
65
+ const fixtures = [];
66
+ const visit = (directory) => {
67
+ const grammarPath = fixtureGrammarPath(directory);
68
+ if (grammarPath !== null) {
69
+ const inputFiles = (0, node_fs_1.readdirSync)(directory)
70
+ .filter((name) => name.startsWith('input') && name.endsWith('.txt'))
71
+ .sort();
72
+ for (const inputFile of inputFiles) {
73
+ const baseName = inputFile.replace(/^input/, '').replace(/\.txt$/, '');
74
+ const expectedName = baseName === '' ? 'expected.json' : `expected${baseName}.json`;
75
+ const expectedPath = (0, node_path_1.join)(directory, expectedName);
76
+ fixtures.push({
77
+ name: `${directory.split('/').slice(-2).join('/')}/${inputFile}`,
78
+ grammarPath,
79
+ inputPath: (0, node_path_1.join)(directory, inputFile),
80
+ expectedPath: (0, node_fs_1.existsSync)(expectedPath) ? expectedPath : null,
81
+ });
82
+ }
83
+ }
84
+ for (const entry of (0, node_fs_1.readdirSync)(directory, { withFileTypes: true })) {
85
+ if (entry.isDirectory()) {
86
+ visit((0, node_path_1.join)(directory, entry.name));
87
+ }
88
+ }
89
+ };
90
+ visit(rootDir);
91
+ return fixtures;
92
+ }
93
+ /**
94
+ * Parses a fixture case and compares to expected JSON when present.
95
+ *
96
+ * @param fixture - Fixture metadata.
97
+ */
98
+ function runFixtureCase(fixture, expectFn) {
99
+ const grammarSource = (0, node_fs_1.readFileSync)(fixture.grammarPath, 'utf8');
100
+ const input = (0, node_fs_1.readFileSync)(fixture.inputPath, 'utf8').trimEnd();
101
+ const context = parse_context_js_1.ParseContext.fromGrammar(grammarSource, 'lr1');
102
+ const ast = context.parseSource(input);
103
+ if (fixture.expectedPath !== null) {
104
+ const expected = JSON.parse((0, node_fs_1.readFileSync)(fixture.expectedPath, 'utf8'));
105
+ expectFn(ast).toEqual(expected);
106
+ }
107
+ return ast;
108
+ }
109
+ //# sourceMappingURL=grammar-fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grammar-fixture.js","sourceRoot":"","sources":["../../../src/lib/transform/grammar-fixture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformCst = exports.describeProductionSlots = exports.CstTransformer = exports.referenceSlotIndex = exports.productionSlots = exports.parseRhsSymbolKey = void 0;
4
+ var binding_map_js_1 = require("./binding-map.js");
5
+ Object.defineProperty(exports, "parseRhsSymbolKey", { enumerable: true, get: function () { return binding_map_js_1.parseRhsSymbolKey; } });
6
+ Object.defineProperty(exports, "productionSlots", { enumerable: true, get: function () { return binding_map_js_1.productionSlots; } });
7
+ Object.defineProperty(exports, "referenceSlotIndex", { enumerable: true, get: function () { return binding_map_js_1.referenceSlotIndex; } });
8
+ var cst_transformer_js_1 = require("./cst-transformer.js");
9
+ Object.defineProperty(exports, "CstTransformer", { enumerable: true, get: function () { return cst_transformer_js_1.CstTransformer; } });
10
+ Object.defineProperty(exports, "describeProductionSlots", { enumerable: true, get: function () { return cst_transformer_js_1.describeProductionSlots; } });
11
+ Object.defineProperty(exports, "transformCst", { enumerable: true, get: function () { return cst_transformer_js_1.transformCst; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/transform/index.ts"],"names":[],"mappings":";;;AAAA,mDAA0F;AAAjF,mHAAA,iBAAiB,OAAA;AAAE,iHAAA,eAAe,OAAA;AAAE,oHAAA,kBAAkB,OAAA;AAE/D,2DAA6F;AAApF,oHAAA,cAAc,OAAA;AAAE,6HAAA,uBAAuB,OAAA;AAAE,kHAAA,YAAY,OAAA"}
package/docs/grammar.md CHANGED
@@ -155,6 +155,85 @@ transform
155
155
  ;
156
156
  ```
157
157
 
158
+ ### Choosing `pass`, `build`, and `flatten`
159
+
160
+ | Transform | Use when |
161
+ |-----------|----------|
162
+ | `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
+ | `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. |
165
+
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`.
167
+
168
+ Run `parser-lr table validate -g mylang.grammar` to check `ast` / `transform` consistency. The validator warns when `pass(boundSlot)` targets a production that can match a single terminal and has no transform rule.
169
+
170
+ ## Statement authoring
171
+
172
+ Statements follow the same `grammar` / `ast` / `transform` pattern as expressions. Dispatch on stable `*_stmt` production names instead of keyword tokens.
173
+
174
+ ```ebnf
175
+ grammar
176
+ statement =
177
+ #cls pass(stmt)
178
+ | #print pass(stmt)
179
+ | #end pass(stmt)
180
+ ;
181
+
182
+ cls_stmt =
183
+ #bare kw_cls
184
+ | #with kw_cls kw_with [bg]:expr
185
+ ;
186
+
187
+ print_stmt =
188
+ #bare kw_print
189
+ | #items kw_print [list]:print_list
190
+ ;
191
+
192
+ end_stmt =
193
+ #program kw_end
194
+ | #if kw_end kw_if
195
+ ;
196
+
197
+ ast
198
+ cls_stmt =
199
+ #bare kw_cls
200
+ | #with kw_cls kw_with [bg]:expr
201
+ ;
202
+
203
+ print_stmt =
204
+ #bare kw_print
205
+ | #items kw_print [list]:print_list
206
+ ;
207
+
208
+ end_stmt =
209
+ #program kw_end
210
+ | #if kw_end kw_if
211
+ ;
212
+
213
+ transform
214
+ statement ->
215
+ #cls pass(stmt)
216
+ | #print pass(stmt)
217
+ | #end pass(stmt)
218
+ ;
219
+
220
+ cls_stmt ->
221
+ #bare cls_stmt.#bare(kw_cls)
222
+ | #with cls_stmt.#with(kw_cls, kw_with, bg) ;
223
+
224
+ print_stmt ->
225
+ #bare print_stmt.#bare(kw_print)
226
+ | #items print_stmt.#items(kw_print, list) ;
227
+
228
+ end_stmt ->
229
+ #program end_stmt.#program(kw_end)
230
+ | #if end_stmt.#if(kw_end, kw_if) ;
231
+ ```
232
+
233
+ After `pass(stmt)`, consumers see `cls_stmt`, `print_stmt`, or `end_stmt` at the statement root. Add `ast` + `transform` rules per statement production rather than scanning for keyword terminals in bridge code.
234
+
235
+ See [`docs/parser-lr-enhancement-proposals.md`](parser-lr-enhancement-proposals.md) for the EduBASIC migration that motivated these conventions.
236
+
158
237
  ## Complete example
159
238
 
160
239
  See [`grammars/calc.grammar`](../grammars/calc.grammar) for a small working grammar with `grammar`, `ast`, and `transform` sections. [`grammars/lisp.grammar`](../grammars/lisp.grammar) and [`grammars/6502.grammar`](../grammars/6502.grammar) show larger languages.
@@ -163,6 +242,7 @@ See [`grammars/calc.grammar`](../grammars/calc.grammar) for a small working gram
163
242
 
164
243
  ```bash
165
244
  parser-lr table generate -g mylang.grammar -o mylang.json
245
+ parser-lr table validate -g mylang.grammar
166
246
  parser-lr parse -i source.txt -g mylang.grammar
167
247
  parser-lr parse -i source.txt -t mylang.json
168
248
  ```