parseman 0.45.0 → 0.47.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 (333) hide show
  1. package/README.md +8 -3
  2. package/dist/analysis/choice-cost-gate.d.ts +158 -0
  3. package/dist/analysis/choice-cost-gate.d.ts.map +1 -0
  4. package/dist/analysis/choice-cost-render.d.ts +96 -0
  5. package/dist/analysis/choice-cost-render.d.ts.map +1 -0
  6. package/dist/analysis/choice-cost.d.ts +383 -0
  7. package/dist/analysis/choice-cost.d.ts.map +1 -0
  8. package/dist/analysis/commitment.d.ts +131 -0
  9. package/dist/analysis/commitment.d.ts.map +1 -0
  10. package/dist/analysis/corpus.d.ts +73 -0
  11. package/dist/analysis/corpus.d.ts.map +1 -0
  12. package/dist/analysis/diagnose-render.d.ts +65 -0
  13. package/dist/analysis/diagnose-render.d.ts.map +1 -0
  14. package/dist/analysis/diagnose.d.ts +15 -0
  15. package/dist/analysis/diagnose.d.ts.map +1 -1
  16. package/dist/analysis/diagnostics.cjs +13736 -0
  17. package/dist/analysis/diagnostics.cjs.map +6 -0
  18. package/dist/analysis/diagnostics.d.ts +27 -0
  19. package/dist/analysis/diagnostics.d.ts.map +1 -0
  20. package/dist/analysis/diagnostics.js +13713 -0
  21. package/dist/analysis/diagnostics.js.map +6 -0
  22. package/dist/analysis/duplication.d.ts.map +1 -1
  23. package/dist/analysis/fix-render.d.ts +43 -0
  24. package/dist/analysis/fix-render.d.ts.map +1 -0
  25. package/dist/analysis/fix.d.ts +172 -0
  26. package/dist/analysis/fix.d.ts.map +1 -0
  27. package/dist/analysis/format-number.d.ts +23 -0
  28. package/dist/analysis/format-number.d.ts.map +1 -0
  29. package/dist/analysis/gating.d.ts +47 -2
  30. package/dist/analysis/gating.d.ts.map +1 -1
  31. package/dist/analysis/rebuild.d.ts +61 -0
  32. package/dist/analysis/rebuild.d.ts.map +1 -0
  33. package/dist/analysis/terminal.d.ts +145 -0
  34. package/dist/analysis/terminal.d.ts.map +1 -0
  35. package/dist/cli/index.cjs +14837 -0
  36. package/dist/cli/index.cjs.map +6 -0
  37. package/dist/cli/index.d.ts +3 -0
  38. package/dist/cli/index.d.ts.map +1 -0
  39. package/dist/cli/index.js +14814 -0
  40. package/dist/cli/index.js.map +6 -0
  41. package/dist/combinators/adjacency.d.ts +100 -0
  42. package/dist/combinators/adjacency.d.ts.map +1 -0
  43. package/dist/combinators/choice.d.ts.map +1 -1
  44. package/dist/combinators/completions.d.ts.map +1 -1
  45. package/dist/combinators/dispatch.d.ts +8 -1
  46. package/dist/combinators/dispatch.d.ts.map +1 -1
  47. package/dist/combinators/expect.d.ts.map +1 -1
  48. package/dist/combinators/first-set.d.ts.map +1 -1
  49. package/dist/combinators/gate.d.ts.map +1 -1
  50. package/dist/combinators/grammar.d.ts +22 -0
  51. package/dist/combinators/grammar.d.ts.map +1 -1
  52. package/dist/combinators/literal.d.ts +8 -0
  53. package/dist/combinators/literal.d.ts.map +1 -1
  54. package/dist/combinators/map.d.ts +0 -1
  55. package/dist/combinators/map.d.ts.map +1 -1
  56. package/dist/combinators/node.d.ts +13 -3
  57. package/dist/combinators/node.d.ts.map +1 -1
  58. package/dist/combinators/parser.d.ts +1 -1
  59. package/dist/combinators/parser.d.ts.map +1 -1
  60. package/dist/combinators/ref.d.ts.map +1 -1
  61. package/dist/combinators/regex.d.ts +1 -16
  62. package/dist/combinators/regex.d.ts.map +1 -1
  63. package/dist/combinators/repeat.d.ts +30 -2
  64. package/dist/combinators/repeat.d.ts.map +1 -1
  65. package/dist/combinators/scanTo.d.ts +71 -1
  66. package/dist/combinators/scanTo.d.ts.map +1 -1
  67. package/dist/combinators/sequence.d.ts.map +1 -1
  68. package/dist/combinators/token.d.ts.map +1 -1
  69. package/dist/combinators/trivia-boundary.d.ts +26 -0
  70. package/dist/combinators/trivia-boundary.d.ts.map +1 -0
  71. package/dist/combinators/trivia-skip.d.ts +40 -1
  72. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  73. package/dist/combinators/withCtx.d.ts.map +1 -1
  74. package/dist/compiler/build-arity.d.ts.map +1 -1
  75. package/dist/compiler/compile-linkable-table.d.ts +104 -0
  76. package/dist/compiler/compile-linkable-table.d.ts.map +1 -0
  77. package/dist/compiler/degradation.d.ts +0 -2
  78. package/dist/compiler/degradation.d.ts.map +1 -1
  79. package/dist/compiler/fields.d.ts +13 -0
  80. package/dist/compiler/fields.d.ts.map +1 -1
  81. package/dist/compiler/grammar-coverage-ids.d.ts +5 -5
  82. package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
  83. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  84. package/dist/compiler/linker.d.ts +79 -47
  85. package/dist/compiler/linker.d.ts.map +1 -1
  86. package/dist/compiler/token-alphabet.d.ts +81 -0
  87. package/dist/compiler/token-alphabet.d.ts.map +1 -0
  88. package/dist/compiler/token-dispatch.d.ts +95 -0
  89. package/dist/compiler/token-dispatch.d.ts.map +1 -0
  90. package/dist/compiler/token-scanner.d.ts +53 -0
  91. package/dist/compiler/token-scanner.d.ts.map +1 -0
  92. package/dist/compiler/value-usage.d.ts.map +1 -1
  93. package/dist/coverage.d.ts +1 -1
  94. package/dist/coverage.d.ts.map +1 -1
  95. package/dist/cst/capture-buffer.d.ts +35 -0
  96. package/dist/cst/capture-buffer.d.ts.map +1 -1
  97. package/dist/cst/reflection-attach.d.ts +8 -0
  98. package/dist/cst/reflection-attach.d.ts.map +1 -0
  99. package/dist/cst/reflection-symbols.d.ts +10 -0
  100. package/dist/cst/reflection-symbols.d.ts.map +1 -0
  101. package/dist/cst/reflection.d.ts +2 -4
  102. package/dist/cst/reflection.d.ts.map +1 -1
  103. package/dist/cst/root-trivia-scope.d.ts +26 -0
  104. package/dist/cst/root-trivia-scope.d.ts.map +1 -0
  105. package/dist/cst/trivia-charscan.d.ts +18 -0
  106. package/dist/cst/trivia-charscan.d.ts.map +1 -0
  107. package/dist/cst/trivia-kinds.d.ts +19 -0
  108. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  109. package/dist/functional/doc.d.ts.map +1 -1
  110. package/dist/functional/run-tabled.d.ts +12 -0
  111. package/dist/functional/run-tabled.d.ts.map +1 -0
  112. package/dist/functional/run.d.ts +25 -42
  113. package/dist/functional/run.d.ts.map +1 -1
  114. package/dist/grammar-metadata.d.ts +3 -0
  115. package/dist/grammar-metadata.d.ts.map +1 -0
  116. package/dist/index.cjs +10499 -7478
  117. package/dist/index.cjs.map +3 -4
  118. package/dist/index.d.ts +24 -9
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +10499 -7478
  121. package/dist/index.js.map +3 -4
  122. package/dist/language-service/index.cjs +311 -121
  123. package/dist/language-service/index.cjs.map +3 -4
  124. package/dist/language-service/index.js +311 -121
  125. package/dist/language-service/index.js.map +3 -4
  126. package/dist/oracle/index.cjs.map +0 -1
  127. package/dist/oracle/index.js.map +0 -1
  128. package/dist/parse-context.d.ts +49 -0
  129. package/dist/parse-context.d.ts.map +1 -0
  130. package/dist/plugin/evaluator.d.ts +41 -2
  131. package/dist/plugin/evaluator.d.ts.map +1 -1
  132. package/dist/plugin/free-identifiers.d.ts +23 -0
  133. package/dist/plugin/free-identifiers.d.ts.map +1 -0
  134. package/dist/plugin/index.cjs +11381 -9442
  135. package/dist/plugin/index.cjs.map +3 -4
  136. package/dist/plugin/index.d.ts.map +1 -1
  137. package/dist/plugin/index.js +11381 -9442
  138. package/dist/plugin/index.js.map +3 -4
  139. package/dist/plugin/reducer-resolver.d.ts +17 -1
  140. package/dist/plugin/reducer-resolver.d.ts.map +1 -1
  141. package/dist/regex/classes.d.ts +28 -0
  142. package/dist/regex/classes.d.ts.map +1 -1
  143. package/dist/regex/first-set.d.ts +14 -0
  144. package/dist/regex/first-set.d.ts.map +1 -1
  145. package/dist/run/index.cjs +136 -51
  146. package/dist/run/index.cjs.map +2 -3
  147. package/dist/run/index.js +136 -51
  148. package/dist/run/index.js.map +2 -3
  149. package/dist/spec/index.cjs +2898 -1622
  150. package/dist/spec/index.cjs.map +3 -4
  151. package/dist/spec/index.js +2898 -1622
  152. package/dist/spec/index.js.map +3 -4
  153. package/dist/spec/model.d.ts +8 -0
  154. package/dist/spec/model.d.ts.map +1 -1
  155. package/dist/table/assemble.d.ts +307 -0
  156. package/dist/table/assemble.d.ts.map +1 -0
  157. package/dist/table/cell.d.ts +42 -0
  158. package/dist/table/cell.d.ts.map +1 -0
  159. package/dist/table/child-slots.d.ts +30 -0
  160. package/dist/table/child-slots.d.ts.map +1 -0
  161. package/dist/table/compile-rule-map.d.ts +136 -0
  162. package/dist/table/compile-rule-map.d.ts.map +1 -0
  163. package/dist/table/compile.d.ts +56 -0
  164. package/dist/table/compile.d.ts.map +1 -0
  165. package/dist/table/duplication-hook.d.ts +32 -0
  166. package/dist/table/duplication-hook.d.ts.map +1 -0
  167. package/dist/table/emit-assembly.d.ts +139 -0
  168. package/dist/table/emit-assembly.d.ts.map +1 -0
  169. package/dist/table/emit.d.ts +113 -0
  170. package/dist/table/emit.d.ts.map +1 -0
  171. package/dist/table/encode-baseline.d.ts +16 -0
  172. package/dist/table/encode-baseline.d.ts.map +1 -0
  173. package/dist/table/encode.d.ts +71 -0
  174. package/dist/table/encode.d.ts.map +1 -0
  175. package/dist/table/exec-baseline.d.ts +9 -0
  176. package/dist/table/exec-baseline.d.ts.map +1 -0
  177. package/dist/table/exec.d.ts +72 -0
  178. package/dist/table/exec.d.ts.map +1 -0
  179. package/dist/table/fold.d.ts +25 -0
  180. package/dist/table/fold.d.ts.map +1 -0
  181. package/dist/table/index.cjs +11375 -0
  182. package/dist/table/index.cjs.map +6 -0
  183. package/dist/table/index.d.ts +100 -0
  184. package/dist/table/index.d.ts.map +1 -0
  185. package/dist/table/index.js +11352 -0
  186. package/dist/table/index.js.map +6 -0
  187. package/dist/table/inspect.d.ts +17 -0
  188. package/dist/table/inspect.d.ts.map +1 -0
  189. package/dist/table/ops.d.ts +446 -0
  190. package/dist/table/ops.d.ts.map +1 -0
  191. package/dist/table/program.d.ts +493 -0
  192. package/dist/table/program.d.ts.map +1 -0
  193. package/dist/table/run-support.d.ts +38 -0
  194. package/dist/table/run-support.d.ts.map +1 -0
  195. package/dist/{compiler/scannable-run.d.ts → table/scan-shapes.d.ts} +14 -13
  196. package/dist/table/scan-shapes.d.ts.map +1 -0
  197. package/dist/table/site-labels.d.ts +58 -0
  198. package/dist/table/site-labels.d.ts.map +1 -0
  199. package/dist/table/stamp.d.ts +70 -0
  200. package/dist/table/stamp.d.ts.map +1 -0
  201. package/dist/types.d.ts +80 -24
  202. package/dist/types.d.ts.map +1 -1
  203. package/dist/version.d.ts +1 -1
  204. package/package.json +41 -3
  205. package/src/analysis/choice-cost-gate.ts +359 -0
  206. package/src/analysis/choice-cost-render.ts +293 -0
  207. package/src/analysis/choice-cost.ts +1008 -0
  208. package/src/analysis/commitment.ts +557 -0
  209. package/src/analysis/corpus.ts +130 -0
  210. package/src/analysis/diagnose-render.ts +625 -0
  211. package/src/analysis/diagnose.ts +317 -0
  212. package/src/analysis/diagnostics.ts +33 -0
  213. package/src/analysis/duplication.ts +1955 -0
  214. package/src/analysis/fix-render.ts +217 -0
  215. package/src/analysis/fix.ts +669 -0
  216. package/src/analysis/format-number.ts +31 -0
  217. package/src/analysis/gating.ts +792 -0
  218. package/src/analysis/grammar.ts +72 -0
  219. package/src/analysis/rebuild.ts +287 -0
  220. package/src/analysis/terminal.ts +336 -0
  221. package/src/cli/index.ts +413 -0
  222. package/src/combinators/adjacency.ts +171 -0
  223. package/src/combinators/attempt.ts +41 -0
  224. package/src/combinators/case-fold.ts +90 -0
  225. package/src/combinators/choice.ts +466 -0
  226. package/src/combinators/completions.ts +64 -0
  227. package/src/combinators/dispatch.ts +358 -0
  228. package/src/combinators/expect.ts +159 -0
  229. package/src/combinators/first-set.ts +322 -0
  230. package/src/combinators/gate.ts +50 -0
  231. package/src/combinators/grammar.ts +272 -0
  232. package/src/combinators/keywords.ts +145 -0
  233. package/src/combinators/literal.ts +102 -0
  234. package/src/combinators/map.ts +106 -0
  235. package/src/combinators/node.ts +345 -0
  236. package/src/combinators/not.ts +55 -0
  237. package/src/combinators/parser.ts +266 -0
  238. package/src/combinators/peek.ts +63 -0
  239. package/src/combinators/probe.ts +25 -0
  240. package/src/combinators/ref.ts +109 -0
  241. package/src/combinators/regex.ts +170 -0
  242. package/src/combinators/repeat.ts +561 -0
  243. package/src/combinators/scanTo.ts +393 -0
  244. package/src/combinators/sequence.ts +221 -0
  245. package/src/combinators/token.ts +120 -0
  246. package/src/combinators/trivia-boundary.ts +48 -0
  247. package/src/combinators/trivia-skip.ts +821 -0
  248. package/src/combinators/withCtx.ts +45 -0
  249. package/src/compiler/build-arity.ts +330 -0
  250. package/src/compiler/compile-linkable-table.ts +209 -0
  251. package/src/compiler/degradation.ts +266 -0
  252. package/src/compiler/fields.ts +191 -0
  253. package/src/compiler/grammar-coverage-ids.ts +129 -0
  254. package/src/compiler/ir-serialize.ts +615 -0
  255. package/src/compiler/linker.ts +954 -0
  256. package/src/compiler/token-alphabet.ts +209 -0
  257. package/src/compiler/token-dispatch.ts +353 -0
  258. package/src/compiler/token-scanner.ts +318 -0
  259. package/src/compiler/value-usage.ts +147 -0
  260. package/src/coverage.ts +383 -0
  261. package/src/cst/capture-buffer.ts +297 -0
  262. package/src/cst/host-mode.ts +69 -0
  263. package/src/cst/reflection-attach.ts +11 -0
  264. package/src/cst/reflection-symbols.ts +9 -0
  265. package/src/cst/reflection.ts +149 -0
  266. package/src/cst/relative-spans.ts +207 -0
  267. package/src/cst/root-trivia-scope.ts +30 -0
  268. package/src/cst/trivia-charscan.ts +312 -0
  269. package/src/cst/trivia-entries.ts +285 -0
  270. package/src/cst/trivia-index.ts +131 -0
  271. package/src/cst/trivia-kinds.ts +358 -0
  272. package/src/cst/types.ts +76 -0
  273. package/src/cst/walk.ts +101 -0
  274. package/src/functional/doc.ts +959 -0
  275. package/src/functional/run-tabled.ts +153 -0
  276. package/src/functional/run.ts +558 -0
  277. package/src/grammar-metadata.ts +2 -0
  278. package/src/index.ts +189 -0
  279. package/src/language-service/index.ts +221 -0
  280. package/src/line-index.ts +131 -0
  281. package/src/oracle/digest.ts +620 -0
  282. package/src/oracle/index.ts +55 -0
  283. package/src/parse-context.ts +91 -0
  284. package/src/plugin/direct-builder-static.ts +102 -0
  285. package/src/plugin/evaluator.ts +1505 -0
  286. package/src/plugin/free-identifiers.ts +338 -0
  287. package/src/plugin/index.ts +2281 -0
  288. package/src/plugin/reducer-resolver.ts +606 -0
  289. package/src/recovery/scan.ts +155 -0
  290. package/src/regex/classes.ts +183 -0
  291. package/src/regex/first-set.ts +316 -0
  292. package/src/run/index.ts +31 -0
  293. package/src/spec/ebnf.ts +128 -0
  294. package/src/spec/index.ts +54 -0
  295. package/src/spec/model.ts +636 -0
  296. package/src/spec/railroad-lib.ts +559 -0
  297. package/src/spec/railroad.ts +256 -0
  298. package/src/table/assemble.ts +2994 -0
  299. package/src/table/cell.ts +42 -0
  300. package/src/table/child-slots.ts +113 -0
  301. package/src/table/compile-rule-map.ts +336 -0
  302. package/src/table/compile.ts +244 -0
  303. package/src/table/duplication-hook.ts +89 -0
  304. package/src/table/emit-assembly.ts +1766 -0
  305. package/src/table/emit.ts +418 -0
  306. package/src/table/encode-baseline.ts +340 -0
  307. package/src/table/encode.ts +1569 -0
  308. package/src/table/exec-baseline.ts +537 -0
  309. package/src/table/exec.ts +1672 -0
  310. package/src/table/fold.ts +38 -0
  311. package/src/table/index.ts +108 -0
  312. package/src/table/inspect.ts +52 -0
  313. package/src/table/ops.ts +459 -0
  314. package/src/table/program.ts +855 -0
  315. package/src/table/run-support.ts +66 -0
  316. package/src/table/scan-shapes.ts +1578 -0
  317. package/src/table/site-labels.ts +228 -0
  318. package/src/table/stamp.ts +229 -0
  319. package/src/types.ts +563 -0
  320. package/src/version.ts +16 -0
  321. package/dist/compiler/codegen.d.ts +0 -334
  322. package/dist/compiler/codegen.d.ts.map +0 -1
  323. package/dist/compiler/inline-build.d.ts +0 -11
  324. package/dist/compiler/inline-build.d.ts.map +0 -1
  325. package/dist/compiler/inline-callback.d.ts +0 -21
  326. package/dist/compiler/inline-callback.d.ts.map +0 -1
  327. package/dist/compiler/line-index.d.ts +0 -2
  328. package/dist/compiler/line-index.d.ts.map +0 -1
  329. package/dist/compiler/scannable-run.d.ts.map +0 -1
  330. package/dist/compiler/scannable-terminal.d.ts +0 -23
  331. package/dist/compiler/scannable-terminal.d.ts.map +0 -1
  332. package/dist/compiler/trivia-fast-path.d.ts +0 -38
  333. package/dist/compiler/trivia-fast-path.d.ts.map +0 -1
package/src/types.ts ADDED
@@ -0,0 +1,563 @@
1
+ export type Span = {
2
+ start: number
3
+ end: number
4
+ startLine?: number
5
+ startColumn?: number
6
+ endLine?: number
7
+ endColumn?: number
8
+ }
9
+
10
+ export type ParseOk<T> = {
11
+ ok: true
12
+ value: T
13
+ span: Span
14
+ trivia?: Span[]
15
+ /** Populated when parse() is called with { recover: true }. Lists all ParseErrors collected via recover() nodes. */
16
+ errors?: ParseError[]
17
+ /**
18
+ * Populated when parse() is called with { recover: true }. The furthest-position
19
+ * failure seen during the parse (with expected-sets merged across ties) — the
20
+ * standard "this is where it actually got stuck" diagnostic, meaningful even when
21
+ * the parse otherwise succeeds with unconsumed trailing input.
22
+ */
23
+ furthestFail?: ParseFail | null
24
+ }
25
+
26
+ export type ParseFail = {
27
+ ok: false
28
+ expected: string[]
29
+ span: Span
30
+ /**
31
+ * Framework-internal cut/commit signal. A committed failure means an outer
32
+ * backtracking construct must propagate the failure instead of trying a later
33
+ * alternative or swallowing it as an optional/repeat miss.
34
+ */
35
+ committed?: boolean
36
+ }
37
+
38
+ export type ParseResult<T> = ParseOk<T> | ParseFail
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // Combinator definition tree — carried on every Combinator so the compiler can
42
+ // traverse the full combinator structure without re-parsing source.
43
+ // ---------------------------------------------------------------------------
44
+ export type ParserDef =
45
+ | { tag: 'literal'; value: string; caseInsensitive: boolean }
46
+ | { tag: 'regex'; source: string; flags: string }
47
+ // `valueUnused` (set by markUnusedValues): the container's aggregate value is
48
+ // consumed by nothing but capture (it sits directly under a node() that reads
49
+ // children, not this value). When true, the interpreter and codegen skip
50
+ // building the array/tuple — the elements still parse + self-capture.
51
+ | { tag: 'sequence'; parsers: Combinator<unknown>[]; valueUnused?: boolean }
52
+ // `gateSrcs` (set by the macro evaluator): per-arm gate predicate SOURCE TEXT,
53
+ // aligned by arm index (null for an ungated arm). Lets codegen inline the gate
54
+ // into the macro's `_mf` array instead of pushing a `null` source (which would
55
+ // force interpreter fallback). Absent under runtime compile() — the real gate
56
+ // closures live in `gates`.
57
+ | { tag: 'choice'; parsers: Combinator<unknown>[]; gates: (((state: unknown) => boolean) | null)[]; gateSrcs?: (string | null)[]; disjoint: boolean; strategy: ChoiceStrategy; autoNot: (AutoNotCheck[] | null)[] }
58
+ | { tag: 'dispatch'; selector: Combinator<string>; cases: readonly DispatchCase[]; matchers?: readonly DispatchMatcherCase[] | undefined; otherwise?: Combinator<unknown> | undefined; otherwiseUsesRouted?: boolean | undefined }
59
+ | { tag: 'attempt'; parser: Combinator<unknown> }
60
+ // The TAG carries NULLABILITY (what every downstream switch keys on): `many` is
61
+ // the nullable min-0 repeat, `oneOrMore` the non-nullable min>=1 one. `min`/`max`
62
+ // carry the actual ITEM bounds (`many(x, { min: 3, max: 8 })` is a `oneOrMore`
63
+ // def with `min: 3, max: 8`). `max` absent = unbounded.
64
+ | { tag: 'many'; parser: Combinator<unknown>; min: 0; max?: number; valueUnused?: boolean }
65
+ | { tag: 'oneOrMore'; parser: Combinator<unknown>; min: number; max?: number; valueUnused?: boolean }
66
+ | { tag: 'optional'; parser: Combinator<unknown> }
67
+ // `min`/`max` count ITEMS, not separators. `min: 0` (the default) is
68
+ // `(item (sep item)*)?` — NULLABLE, matches the empty string. `min >= 1` is
69
+ // non-nullable with first-set = the item's, so it gates as a choice arm.
70
+ // `trailing` governs a separator with no item after it: 'forbid' (default) leaves
71
+ // it unconsumed, 'allow' consumes it. There is no "one after every item" mode —
72
+ // that is a terminated list, spelled `many(sequence(item, term))`.
73
+ | { tag: 'sepBy'; parser: Combinator<unknown>; separator: Combinator<unknown>; min: number; max?: number; trailing?: 'allow'; /** Author opted in via `keepSeparator()`: separators stay in `children`. Absent = items only. */ keepSeparators?: true }
74
+ | { tag: 'transform'; parser: Combinator<unknown>; fn: (v: unknown, span: { start: number; end: number }) => unknown; fnSrc?: string; recognitionOnly?: boolean }
75
+ | { tag: 'trivia'; parser: Combinator<unknown> }
76
+ | { tag: 'token'; parser: Combinator<unknown> }
77
+ // `fallback` is what `routed()` parses IN PLACE when there is no dispatch-consumed
78
+ // token to reuse (outside a dispatch branch, or at a position other than the one the
79
+ // selector matched). It exists so ONE production can serve both contexts instead of
80
+ // being spelled twice — a `routed()` twin and a concrete-lead original.
81
+ | { tag: 'routed'; fallback?: Combinator<unknown> }
82
+ | { tag: 'leaf'; parser: Combinator<unknown>; fn: (v: unknown, span: { start: number; end: number }) => unknown; fnSrc?: string }
83
+ | { tag: 'label'; label: string; parser: Combinator<unknown> }
84
+ | { tag: 'field'; name: string; parser: Combinator<unknown> }
85
+ | { tag: 'grammar'; parser: Combinator<unknown>; triviaParser: Combinator<unknown> | undefined; clearTrivia?: boolean; captureTrivia?: boolean; rootCapture?: 'opaque'; trackLines: boolean }
86
+ | { tag: 'lazy'; thunk: () => Combinator<unknown> }
87
+ | { tag: 'not'; parser: Combinator<unknown> }
88
+ // Positive lookahead. Zero-width like `not`, but — unlike `not` — it KNOWS what
89
+ // it requires, so it carries `parser`'s first-set and a leading `peek()` gates
90
+ // its choice arm (see `isPositiveLookahead` / `sequenceFirstSet`).
91
+ | { tag: 'peek'; parser: Combinator<unknown> }
92
+ | { tag: 'node'; type?: string; parser: Combinator<unknown>; build?: ((children: ReadonlyArray<unknown>, fields: FieldMap | undefined, span: { start: number; end: number }, rawChildren: ReadonlyArray<unknown>, triviaLog: readonly number[], state: unknown) => unknown) | undefined; buildSrc?: string; /** The IDENTIFIER the type argument was written as at the `node()` call site, when it was a plain identifier rather than a literal — ANALYSIS ONLY, never emitted. Lets the inline-`mk` matcher recognise `node(t, …, (…) => mk(t, …))` from a factory, where the two `t`s are provably one binding. */ typeSrc?: string; /** Resolved source of a NAMED `buildSrc` — ANALYSIS ONLY, never emitted. See `buildAnalysisSrc`. */ buildSigSrc?: string; /** Declared positional arity of `build`: author-declared via `node(..., { buildArity })`, or resolved from the reducer's declaration. Wins over source inspection. */ buildArity?: number; /** Why arity could not be resolved, for the diagnostic. */ buildArityUnresolved?: string; buildStaticError?: readonly string[]; unwrap?: boolean; collapse?: boolean; project?: number; captureTrivia?: boolean; trailingTrivia?: boolean; tags?: readonly string[] }
93
+ // `predSrc`/`extraSrc` (set by the macro evaluator): SOURCE TEXT of the guard
94
+ // predicate / the withCtx `extra` value, so codegen inlines them into `_mf`
95
+ // rather than pushing a `null` source. Absent under runtime compile() (the real
96
+ // closures/values live in `predicate`/`extra`).
97
+ | { tag: 'guard'; predicate: (state: unknown) => boolean; predSrc?: string }
98
+ // ADJACENCY assertion — zero-width, zero-children. `polarity: 'adjacent'` asserts
99
+ // that NOTHING sat between the previous term and this position; `'notAdjacent'`
100
+ // asserts that something did. `kinds` (notAdjacent only) narrows the assertion to
101
+ // trivia CATEGORIES from `classifiedTrivia({...})`. See combinators/adjacency.ts.
102
+ | { tag: 'adjacency'; polarity: 'adjacent' | 'notAdjacent'; kinds?: readonly string[] }
103
+ | { tag: 'withCtx'; extra: unknown; parser: Combinator<unknown>; extraSrc?: string }
104
+ | { tag: 'recover'; parser: Combinator<unknown>; sentinel: Combinator<unknown> }
105
+ | { tag: 'expect'; parser: Combinator<unknown>; label: string | undefined; expected: string[] }
106
+ // `skip` is the per-call opaque-unit list; ambient trivia + grammar-level
107
+ // `scanSkip` are PREPENDED at parse/compile time (explicit skip EXTENDS the
108
+ // ambient default). `raw`: hard opt-out — skip nothing ambiently, restoring the
109
+ // pre-ambient raw byte-walk.
110
+ | { tag: 'scanTo'; sentinel: Combinator<unknown>; skip: Combinator<unknown>[]; raw: boolean; orEOF: boolean }
111
+ | { tag: 'keywords'; words: readonly string[]; caseInsensitive: boolean; boundary: string | undefined }
112
+ | { tag: 'unknown' }
113
+
114
+ export type Combinator<T> = {
115
+ readonly _tag: string
116
+ readonly _meta: ParserMeta
117
+ readonly _def: ParserDef
118
+ parse(input: string, pos: number, ctx: ParseContext): ParseResult<T>
119
+ }
120
+
121
+ export type DispatchCase = {
122
+ keys: readonly string[]
123
+ parser: Combinator<unknown>
124
+ caseInsensitive: boolean
125
+ usesRouted?: boolean | undefined
126
+ }
127
+
128
+ export type DispatchMatcherKind = 'startsWith' | 'endsWith' | 'matches'
129
+
130
+ export type DispatchMatcherCase = {
131
+ kind: DispatchMatcherKind
132
+ value: string
133
+ flags?: string | undefined
134
+ parser: Combinator<unknown>
135
+ caseInsensitive: boolean
136
+ usesRouted?: boolean | undefined
137
+ }
138
+
139
+ import type { CstCaptureBuf } from './cst/capture-buffer.ts'
140
+
141
+ export type CstCollapsePredicate = (
142
+ type: string,
143
+ child: unknown,
144
+ children: ReadonlyArray<unknown>,
145
+ rawChildren: ReadonlyArray<unknown>,
146
+ ) => boolean
147
+
148
+ export type BuildHost = ((
149
+ type: string,
150
+ // Always an array by public contract. When a structural host opts out of the
151
+ // duplicate children collector via `_parsemanReadsChildren === false`, it
152
+ // receives the shared empty array while `rawChildren` retains the full source
153
+ // view. Keeping this non-optional preserves assignability for existing hosts.
154
+ children: ReadonlyArray<unknown>,
155
+ fields: FieldMap | undefined,
156
+ span: { start: number; end: number },
157
+ rawChildren: ReadonlyArray<unknown>,
158
+ triviaLog: readonly number[],
159
+ state: unknown,
160
+ tags?: readonly string[] | undefined,
161
+ ) => unknown) & {
162
+ /** Framework-internal: optional syntax-CST wrapper collapse policy. */
163
+ _parsemanCstCollapse?: CstCollapsePredicate | undefined
164
+ /**
165
+ * Framework-internal: `false` when this host builds its node purely from
166
+ * `rawChildren` (arg 4) and never reads the structural `children` (arg 1).
167
+ * Arity-based elision (`_hostReads`) cannot see this: a host that reads a LATER
168
+ * positional arg (`span`/`rawChildren`/`state`) must still DECLARE `children`
169
+ * positionally, so `Function.length` stays high and every arg-gate reports
170
+ * "read". This explicit opt-out lets a structural node skip allocating its
171
+ * per-node `children` array entirely — a pure duplicate of `rawChildren` for a
172
+ * structural grammar. Default (`undefined`) keeps the array (output-neutral).
173
+ * A host that sets this MUST NOT also read `children`, and must not rely on
174
+ * `_parsemanCstCollapse` (which inspects `children`).
175
+ */
176
+ _parsemanReadsChildren?: boolean | undefined
177
+ /**
178
+ * Framework-internal: node types whose structural host wants triviaLog.
179
+ * This predicate is assembly-specialisation configuration: both its identity
180
+ * and behaviour must remain stable after the host is first used. To change
181
+ * the selection, assign a NEW predicate function; replacing its identity
182
+ * invalidates the host's cached specialisation.
183
+ */
184
+ _parsemanCaptureTrivia?: ((type: string) => boolean) | undefined
185
+ /**
186
+ * Framework-internal: per-node-type trivia-kind filter for the captured
187
+ * `triviaLog`. Returns a bitmask over the trivia's `triviaKindLabels` (bit `k`
188
+ * = keep kind `k`); `undefined` = keep every kind (default). Lets a host ask
189
+ * one node type for comments-only while another still gets whitespace — e.g.
190
+ * `Ruleset`/`Stylesheet` want comment runs, `CompoundSelector` needs the
191
+ * whitespace that marks a descendant combinator. Scoped to the node and
192
+ * restored on exit. Build a mask with `triviaKindMask(labels, keep)`.
193
+ */
194
+ _parsemanTriviaKinds?: ((type: string) => number | undefined) | undefined
195
+ }
196
+
197
+ export type FieldCapture<T = unknown> = {
198
+ value: T
199
+ span: Span
200
+ }
201
+
202
+ export type FieldMap = Record<string, FieldCapture | FieldCapture[]>
203
+
204
+ /**
205
+ * Recovery helpers the runtime driver injects into a COMPILED parse's ctx (`_rec`)
206
+ * when tolerant, so the compiled output reuses the exact interpreter recovery
207
+ * functions (`recoverScan`/`matchesAt`/`orSentinel`) — guaranteeing parity without
208
+ * the emitted `new Function` needing module-scope access.
209
+ */
210
+ export type RecoveryHelpers = {
211
+ scan: (input: string, from: number, ctx: ParseContext, sync: Combinator<unknown>, expected: string[]) => { error: ParseError; end: number }
212
+ at: (sentinel: Combinator<unknown>, input: string, pos: number, ctx: ParseContext) => boolean
213
+ or: (a: Combinator<unknown>, b: Combinator<unknown> | undefined) => Combinator<unknown>
214
+ /** Build a zero-width follow-set sentinel from a first-set. Called from compiled
215
+ * code (via `_ctx`, never `_rp`) so recovery grammars stay macro-inlinable. */
216
+ sentinel: (fs: FirstSet) => Combinator<unknown> | null
217
+ /** Embed a recovered error as a `parseError` CST child at the recovery point
218
+ * (no-op when CST capture is off). Called from both paths so the error lives in
219
+ * the tree — riding reused subtrees across incremental edits — not just the flat
220
+ * `_errors` channel. */
221
+ capture: (ctx: ParseContext, error: ParseError) => void
222
+ }
223
+
224
+ export type ParseContext = {
225
+ // `| undefined` (matching captureTrivia/_cst* below): a nested scope may
226
+ // intentionally CLEAR inherited trivia by setting these to undefined (noTrivia).
227
+ trivia?: Combinator<unknown> | undefined
228
+ /**
229
+ * Grammar-level ambient opaque-unit skippers (strings, balanced brackets, …),
230
+ * declared once via `rules({ scanSkip }, factory)` and threaded here at the
231
+ * parse entry — the scan-skip analogue of `trivia`. A `scanTo`/`balanced` with
232
+ * no explicit per-call `skip` (and not `raw`) consults these so a sentinel
233
+ * hidden inside a string/bracket run is never matched. Separate category from
234
+ * `trivia`: trivia is insignificant everywhere; scanSkip is significant but
235
+ * atomic during a scan. Undefined when the grammar declares none.
236
+ */
237
+ scanSkip?: Combinator<unknown>[] | undefined
238
+ /**
239
+ * Label table for the active trivia parser (`label(name, arm)` strings in
240
+ * choice order). When set, trivia logs include a kind index per entry.
241
+ */
242
+ triviaKindLabels?: readonly string[] | undefined
243
+ /**
244
+ * When true (and a CST node is collecting children), trivia consumed between
245
+ * terms is recorded into _cstRawChildren as separate CSTTrivia tokens — one
246
+ * per maximal sub-match of the trivia parser (e.g. a whitespace run or a
247
+ * comment). When false/unset, trivia is skipped silently. Default: skip.
248
+ */
249
+ captureTrivia?: boolean | undefined
250
+ /**
251
+ * Kind-filter for PER-NODE CST trivia capture (`triviaLog` handed to a node's
252
+ * builder). A bitmask over the active `triviaKindLabels` indices: bit `k` set
253
+ * means "record kind `k`"; `undefined` means record every kind (default). Only
254
+ * the per-node CST log is filtered — the global `_triviaLog` stays complete, so
255
+ * a downstream trivia map is unaffected. Lets a host that only consumes, say,
256
+ * comments enable per-node capture WITHOUT paying to log every whitespace run.
257
+ * Requires labeled trivia (indices align with `triviaKindLabels`); with no
258
+ * labels the mask can't apply and all trivia is captured. Build a mask with
259
+ * `triviaKindMask(labels, keep)`.
260
+ */
261
+ _triviaCaptureMask?: number | undefined
262
+ trackLines: boolean
263
+ /** Grammar-author-provided state, scoped with withCtx() and read in guard(). */
264
+ state?: unknown
265
+ /**
266
+ * Mode host (RULE_ABI_PLAN §7): when set, a linkable/fused grammar's `node()`
267
+ * rules build via `build(type, children, fields, span, rawChildren, triviaLog, state)`
268
+ * instead of their own builder — so ONE grammar serves eval-AST (unset) vs
269
+ * positioned-CST / language-service (set) modes. Ignored by non-linkable output.
270
+ */
271
+ build?: BuildHost | undefined
272
+ /** When set, recovery (tolerant lists / expect()) pushes each ParseError here in addition to embedding it in the tree. */
273
+ _errors?: ParseError[] | undefined
274
+ /**
275
+ * Framework-internal: layered "C+B" list recovery gate. When true, tolerant
276
+ * `many`/`oneOrMore`/`sepBy` recover from a failed element (skip to a sync point,
277
+ * emit a ParseError, keep parsing) instead of stopping the list. Unset (the
278
+ * default / strict path) ⇒ the list combinators behave byte-identically to before;
279
+ * the only residue is a single cold branch on the element-failure edge.
280
+ */
281
+ _tolerant?: boolean | undefined
282
+ /**
283
+ * Framework-internal: the recovery sync sentinel in effect for the current
284
+ * subtree, published DOWN by an enclosing `sequence` in tolerant mode. It is a
285
+ * zero-width combinator that matches when the input could start any of the
286
+ * sequence's remaining terms — i.e. the enclosing delimiter/close a nested list
287
+ * should resync to. A nested `many`/`oneOrMore`/`sepBy` reads it as its recovery
288
+ * terminator on element failure. Inferred automatically from grammar structure
289
+ * (the grammar carries no recovery config); `undefined` when nothing is locally
290
+ * inferable. Dynamic scoping through rule refs gives cross-rule inheritance for
291
+ * free (a list at a rule's tail resyncs to whatever delimiter followed the call).
292
+ */
293
+ _sync?: Combinator<unknown> | undefined
294
+ /**
295
+ * Framework-internal (compiled output only): recovery helpers injected by the
296
+ * runtime driver (`run`) when tolerant, so the compiled parser reuses the EXACT
297
+ * interpreter recovery functions — guaranteeing byte-for-byte parity without the
298
+ * emitted `new Function` needing module-scope access. Unset (strict) ⇒ compiled
299
+ * lists never enter the recovery branch. The interpreter ignores this field.
300
+ */
301
+ _rec?: RecoveryHelpers | undefined
302
+ /**
303
+ * Framework-internal (compiled/macro output only): the deepest failure recorded
304
+ * while a fallible sub-parser was running — position (`_fe`) and expected set
305
+ * (`_fx`). Composite constructs (node, ref, withCtx, …) read these to propagate
306
+ * the inner failure verbatim instead of a coarse structural placeholder, keeping
307
+ * failure diagnostics at parity with the interpreter. Overwritten on each leaf
308
+ * failure; only meaningful immediately after a sub-parse reports failure.
309
+ */
310
+ _fe?: number | undefined
311
+ _fx?: string[] | undefined
312
+ /** Framework-internal compiled-output committed-failure flag. */
313
+ _fc?: boolean | undefined
314
+ /**
315
+ * When set by completionsAt(), tracks the highest-position ParseFail seen
316
+ * during parsing up to _probe.offset. Used to return completions at the cursor
317
+ * even when sepBy/many backtracked past the cursor position.
318
+ */
319
+ _probe?: { offset: number; best: ParseFail | null } | undefined
320
+ /**
321
+ * Framework-internal: current CSTNode rule's child collector.
322
+ * Set by node() during capture; undefined outside an active node parse.
323
+ * CSTNode parsers append themselves here after a successful parse.
324
+ */
325
+ _cstChildren?: unknown[] | undefined
326
+ /**
327
+ * Framework-internal: collector for CSTLeaf terminals.
328
+ * Usually points to the same array as _cstChildren (both live together).
329
+ * literal() and regex() append a CSTLeaf here when set.
330
+ */
331
+ _cstLeaves?: unknown[] | undefined
332
+ /**
333
+ * Framework-internal: collector for ALL children including trivia.
334
+ * Set alongside _cstChildren/_cstLeaves. Receives CSTLeaf + CSTNode entries
335
+ * (same as _cstChildren) PLUS CSTTrivia entries for trivia consumed between terms.
336
+ * Passed to buildNode() as rawChildren so grammars can inspect trivia.
337
+ */
338
+ _cstRawChildren?: unknown[] | undefined
339
+ /**
340
+ * Framework-internal: flat trivia log. When set, scanTrivia records each
341
+ * consumed trivia entry as two numbers [start, end] appended to this
342
+ * array instead of (or in addition to) rawChildren capture. Zero object
343
+ * allocations — just number pushes.
344
+ */
345
+ _triviaLog?: number[] | undefined
346
+ /**
347
+ * Framework-internal: selected root-trivia rows. Each row is
348
+ * `[gapStart, gapEnd, markerStart, markerEnd, kindIndex]`. Unlike
349
+ * `_triviaLog`, this never records an ordinary whitespace chunk: a row exists
350
+ * only for a selected labeled trivia kind, while its first pair preserves the
351
+ * complete committed gap that owns that marker. The fixed-width numeric log
352
+ * keeps compiler rollback as cheap as the legacy root sink.
353
+ */
354
+ _rootTriviaLog?: number[] | undefined
355
+ /** Grammar-label → selected-root-table index. Each trivia scope maps its local
356
+ * label through this once-built table, so composed grammars may use different
357
+ * label orders without a per-chunk linear selected-label search. */
358
+ _rootTriviaKindIndex?: Readonly<Record<string, number>> | undefined
359
+ /** Selected-root capture checks local trivia classification once per scope. */
360
+ _rootTriviaStrictScopes?: boolean | undefined
361
+ /**
362
+ * Scoped selected-root capture switch. `parser({ rootCapture: 'opaque' })`
363
+ * turns this off for its explicit trivia region so that region cannot leak
364
+ * selected markers into the document-root capture.
365
+ */
366
+ _rootTriviaCapture?: boolean | undefined
367
+ /**
368
+ * Framework-internal: flat per-node trivia log for CST capture mode.
369
+ * When set alongside _cstRawChildren, each trivia entry is recorded as three
370
+ * numbers [start, end, insertIdx] appended here (one entry = three numbers) instead of allocating a
371
+ * CSTTrivia object. `insertIdx` is the _cstRawChildren.length at the moment
372
+ * the trivia was consumed, so consumers know where in rawChildren to insert it.
373
+ * Zero object allocations — replaces the CSTTrivia object path entirely.
374
+ */
375
+ _cstTriviaLog?: number[] | undefined
376
+ /** Framework-internal: active node() field captures, enabled only when needed. */
377
+ _fields?: Array<{ name: string; value: unknown; span: Span }> | undefined
378
+ /** Framework-internal: lazy capture buffer for active node() parse. */
379
+ _cstBuf?: CstCaptureBuf | undefined
380
+ /** Framework-internal: value/span already consumed by an enclosing dispatch(). */
381
+ _routed?: { value: unknown; span: Span } | undefined
382
+ /**
383
+ * Framework-internal optional line-start collector. Compiled parsers emitted
384
+ * with line tracking append newline-derived line starts here while matching
385
+ * terminals; the driver normalizes/dedupes once before annotating spans.
386
+ */
387
+ _lineStarts?: number[] | undefined
388
+ /** Framework-internal shared line index for interpreter-side line annotation. */
389
+ _lineIndex?: { lineStarts: number[] } | undefined
390
+ /** Framework-internal high-water mark for optional line tracking range scans. */
391
+ _lineScannedTo?: number | undefined
392
+ /**
393
+ * Framework-internal coverage hook. Previously reached `ctx` only via a
394
+ * conditional spread of `RunOptions.instrumentation`, so an instrumented parse
395
+ * gave `ctx` a DIFFERENT hidden class from an ordinary one. Declared here so
396
+ * every `ctx` has one shape; `undefined` when not instrumented.
397
+ */
398
+ _grammarCoverage?: ((id: string) => void) | undefined
399
+ /** Framework-internal trace sink — same shape rationale as `_grammarCoverage`. */
400
+ _grammarTrace?: {
401
+ write(event: {
402
+ id: string
403
+ phase: 'enter' | 'attempt' | 'selected' | 'success' | 'failure' | 'backtrack' | 'rollback'
404
+ offset: number
405
+ end?: number
406
+ }): void
407
+ } | undefined
408
+ }
409
+
410
+ /**
411
+ * The recovery value produced when a parse fails at a recoverable point (tolerant
412
+ * list recovery, or expect()). The span covers the skipped/missing input; expected
413
+ * lists what the parser wanted there.
414
+ */
415
+ export type ParseError = {
416
+ readonly _tag: 'parseError'
417
+ readonly span: Span
418
+ readonly expected: string[]
419
+ }
420
+
421
+ export type ParserMeta = {
422
+ /** Character codes / ranges that can start this parser (for choice dispatch) */
423
+ firstSet: FirstSet
424
+ /** Whether this parser can consume a newline character */
425
+ canMatchNewline: boolean
426
+ /** Whether this parser is marked as trivia (auto-skip) */
427
+ isTrivia: boolean
428
+ /** User-defined labels for labeled trivia arms (`label(name, parser)`). */
429
+ triviaKindLabels?: readonly string[]
430
+ /** Set only by `classifiedTrivia()`: each root-visible category is a separate
431
+ * grammar arm rather than an arbitrary label on a broad recognizer. */
432
+ rootTriviaClassified?: true
433
+ /** choice(): true when all alternative first sets are pairwise disjoint */
434
+ disjoint?: boolean
435
+ /**
436
+ * Grammar-level ambient trivia declared via `rules({ trivia }, factory)`. When
437
+ * a rule carrying this is parsed as an ENTRY (run()/parse()/compile with no
438
+ * more-local trivia already active), the framework installs it as `ctx.trivia`
439
+ * so it is ambient for the whole parse — "set once, inherited everywhere",
440
+ * including incremental parsing of a single rule. `parser({ trivia })` /
441
+ * `noTrivia` still override it locally. The compiled path bakes it as the
442
+ * seed `activeTrivia` for every rule in the map.
443
+ */
444
+ grammarTrivia?: Combinator<unknown> | undefined
445
+ /**
446
+ * Grammar-level ambient scan-skip declared via `rules({ scanSkip }, factory)`.
447
+ * Mirrors `grammarTrivia`: stamped on every non-trivia rule, installed as
448
+ * `ctx.scanSkip` at the parse entry (and baked as the compiled seed) so a
449
+ * `scanTo`/`balanced` with no explicit `skip` consults it ambiently.
450
+ */
451
+ grammarScanSkip?: Combinator<unknown>[] | undefined
452
+ /**
453
+ * Grammar-level host mode declared via `rules({ hostMode }, factory)`. Stamped on
454
+ * every rule, mirroring the two above. The macro reads it statically to choose what
455
+ * to EMIT; the interpreter routes dynamically and only reads it so `run()` can refuse
456
+ * a mismatched host once per parse. `'ast'` is the default and is never stamped.
457
+ */
458
+ grammarHostMode?: 'ast' | 'cst' | undefined
459
+ /**
460
+ * Grammar-level line tracking declared via `rules({ trackLines: true }, factory)`.
461
+ * Stamped on every non-trivia rule so runtime compile and macro compile can emit
462
+ * a separate line-aware artifact from the same authored grammar source.
463
+ */
464
+ grammarTrackLines?: true | undefined
465
+ }
466
+
467
+ /** A first set is either "any" (unknown/unbounded) or a list of char code ranges */
468
+ export type FirstSet =
469
+ | { kind: 'any' }
470
+ | { kind: 'ranges'; ranges: CharRange[] }
471
+ | { kind: 'empty' }
472
+
473
+ export type CharRange = { lo: number; hi: number }
474
+
475
+ /**
476
+ * Determines how a non-disjoint choice dispatches at runtime/compile-time.
477
+ *
478
+ * greedyClassify: one regex arm subsumes all literal arms — run the regex once,
479
+ * classify the result with string equality. Single parse call, no backtracking.
480
+ * literalsLongestFirst: all arms are literals — try from longest to shortest, no regex,
481
+ * no ambiguity, no backtracking.
482
+ * firstMatch: PEG fallback — try each arm in order; arms with autoNot[] get an inline
483
+ * rejection check so a later arm can "win" without explicit not().
484
+ * sharedPrefix: EVERY arm is a bare `sequence(...)` beginning with the SAME concrete
485
+ * leading literal/regex (a "left factor"). The compiler parses that
486
+ * prefix ONCE, then tries each arm's residual terms in PEG order from
487
+ * the shared end position — no re-parse of the prefix per arm. PEG
488
+ * priority and byte-identical value/CST/diagnostics are preserved; the
489
+ * interpreter treats it exactly as `firstMatch`. Opt-in like
490
+ * greedyClassify (auto-detected only for the narrow shape it can prove).
491
+ */
492
+ export type ChoiceStrategy =
493
+ | { tag: 'greedyClassify'; superIndex: number }
494
+ | { tag: 'literalsLongestFirst'; sortedIndices: number[] }
495
+ | { tag: 'firstMatch' }
496
+ | { tag: 'sharedPrefix'; prefix: Combinator<unknown>; members: number[] }
497
+
498
+ /**
499
+ * Used only by the 'firstMatch' fallback strategy. Describes what char/string at
500
+ * the END of an arm's match should cause that arm to be rejected so the next arm
501
+ * is tried. Auto-derived from sibling alternatives at construction time.
502
+ */
503
+ export type AutoNotCheck =
504
+ | { kind: 'firstSet'; set: FirstSet }
505
+ | { kind: 'startsWith'; value: string }
506
+
507
+ /**
508
+ * A choice arm with an optional gate predicate. When a gate is provided,
509
+ * it is evaluated (cheaply, without parsing) before the arm is attempted.
510
+ * If the gate returns false the arm is skipped entirely.
511
+ *
512
+ * Usage: choice({ gate: s => (s as Ctx).inFn, combinator: returnKw }, ident)
513
+ */
514
+ export type GatedArm<T = unknown> = {
515
+ gate: (state: unknown) => boolean
516
+ combinator: Combinator<T>
517
+ }
518
+
519
+ /**
520
+ * WHAT `compile()` HANDS BACK — the contract, not one engine's return type.
521
+ *
522
+ * This lives with the rest of the library's types rather than inside a lowering
523
+ * because it is the shape BOTH lowerings answer to: `table/compile.ts` returns it
524
+ * today and is what `src/index.ts` exports as `compile`. It started in
525
+ * `compiler/codegen.ts`, which made the table import its own public contract from
526
+ * the engine the table replaced — backwards, and a reason the engine could not be
527
+ * deleted.
528
+ */
529
+ export type CompiledParser<T> = {
530
+ parse(input: string, pos?: number): ParseResult<T>
531
+ /** Like parse(), but with a caller-supplied ParseContext (e.g. `_triviaLog` for CST grammars). */
532
+ parseWithContext(input: string, ctx: ParseContext, pos?: number): ParseResult<T>
533
+ /**
534
+ * Like parse(), but activates the error-collection channel. Recovery points
535
+ * (expect()) collect their ParseErrors into result.errors instead of only
536
+ * embedding them as values. Always returns ParseOk — top-level failures are
537
+ * still ParseFail.
538
+ */
539
+ parseWithErrors(input: string, pos?: number): ParseResult<T> & { errors: ParseError[] }
540
+ /** The generated source (for inspection / future source maps) */
541
+ source: string
542
+ /**
543
+ * A self-contained JS expression (IIFE) that evaluates to a parse function.
544
+ * Safe to inline directly into transformed source — no external references
545
+ * except for runtime-fallback parsers embedded via closures.
546
+ * Returns null if the parser cannot be fully inlined (e.g. contains user
547
+ * closures that can't be serialized).
548
+ */
549
+ inlineExpression: string | null
550
+ /**
551
+ * WHY `inlineExpression` IS NULL — one named reason per cause, present only
552
+ * when the artifact could not be PRINTED. A null with no reason is the failure
553
+ * this field exists to make impossible: the caller's fallback is "leave the
554
+ * grammar interpreted", which is a ~5x silent perf regression, so the reason
555
+ * has to reach a warning rather than being inferred from a null.
556
+ *
557
+ * Empty/absent means printable. Set by the table lowering; the source lowering's
558
+ * own unprintable cases predate this channel and still return a bare null.
559
+ */
560
+ runtimeOnly?: readonly string[]
561
+ /** Present only when compiled with `{ coverage: true }`. */
562
+ coverageDefinitions?: readonly import('./compiler/grammar-coverage-ids.ts').GrammarCoverageDefinition[]
563
+ }
package/src/version.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Parseman's version — stamped into every generated-artifact banner and used as the
3
+ * ARTIFACT VERSION LOCK (see `docs/design/artifact-format.md`).
4
+ *
5
+ * ── ARTIFACTS ARE VERSION-LOCKED ────────────────────────────────────────────────
6
+ * A grammar is compiled AND fused/linked by the SAME parseman version. Parseman does
7
+ * NOT read a compiled artifact produced by a different version. The compiled-artifact
8
+ * format (`firstSetRecipes`, `LinkablePieces`, the fused-body shape, …) may therefore
9
+ * change freely between versions and carries NO back-compat shim: `fusedBody` refuses
10
+ * to link a serialized artifact stamped with a different version, and there is no
11
+ * "legacy format" read path. If you find yourself adding one, STOP — it is dead code.
12
+ *
13
+ * Kept in sync with `package.json` by `test/unit/version-sync.test.ts`, which fails
14
+ * the build if this constant drifts from the published version.
15
+ */
16
+ export const PARSEMAN_VERSION = '0.47.0'