parseman 0.17.0 → 0.18.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.
package/README.md CHANGED
@@ -71,7 +71,7 @@ See **[The three modes](https://matthew-dean.github.io/parseman/guide/modes)** f
71
71
 
72
72
  ## What's in the box
73
73
 
74
- - **[Combinators](https://matthew-dean.github.io/parseman/guide/combinators)** — `literal`, `regex`, `sequence`, `choice`, `many`, `sepBy`, `not`, and more.
74
+ - **[Combinators](https://matthew-dean.github.io/parseman/guide/combinators)** — `literal`, `regex`, `sequence`, `choice`, `many`, `sepBy`, `token`, `not`, and more.
75
75
  - **[Whitespace & trivia](https://matthew-dean.github.io/parseman/guide/trivia)** — grammar-defined filler skipping, with per-chunk kind capture.
76
76
  - **[Recursive rules](https://matthew-dean.github.io/parseman/guide/recursive-rules)** — `rules()` for mutually recursive grammars; fully macro-compilable.
77
77
  - **[CST / AST nodes](https://matthew-dean.github.io/parseman/guide/ast)** — `node()` captures terminals and trivia for you, with a `collapse` option for transparent wrapper rules.
@@ -14,7 +14,7 @@ export type { ParseError };
14
14
  * the interpreter and the compiled output (the compiled path does not rebuild the
15
15
  * runtime `expected` array, so it reads this precomputed set instead).
16
16
  */
17
- export declare function staticExpected(c: Combinator<unknown>): string[];
17
+ export declare function deriveExpected(c: Combinator<unknown>): string[];
18
18
  /**
19
19
  * Required-token combinator. Tries `combinator`; on success returns it verbatim.
20
20
  * On failure it does NOT fail — it records a {@link ParseError} (the statically
@@ -26,7 +26,7 @@ export declare function staticExpected(c: Combinator<unknown>): string[];
26
26
  * block) so a missing one is reported with position + expectation rather than
27
27
  * aborting the whole parse or being silently swallowed by a catch-all.
28
28
  *
29
- * sequence(literal('{'), declList, expect(literal('}'), '}'))
29
+ * sequence(literal('{'), declList, expect(literal('}')))
30
30
  *
31
31
  * Errors are only collected when the parse runs with `{ recover: true }`; without
32
32
  * it, expect() still recovers in place but records nothing (zero overhead beyond
@@ -1 +1 @@
1
- {"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/combinators/expect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAyC,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhG,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE,CA2B/D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,GAAG,UAAU,CAAC,CAmB/F"}
1
+ {"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/combinators/expect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAyC,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhG,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE,CA4B/D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,GAAG,UAAU,CAAC,CAmB/F"}
@@ -1 +1 @@
1
- {"version":3,"file":"first-set.d.ts","sourceRoot":"","sources":["../../src/combinators/first-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAE7E,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAKxD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAS5D;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAE/C;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAE1D;AAED,wBAAgB,GAAG,IAAI,QAAQ,CAE9B;AAED,wBAAgB,KAAK,IAAI,QAAQ,CAEhC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAmCxG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,QAAQ,CAOlF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,QAAQ,CAoCvG"}
1
+ {"version":3,"file":"first-set.d.ts","sourceRoot":"","sources":["../../src/combinators/first-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAE7E,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAKxD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAS5D;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAE/C;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAE1D;AAED,wBAAgB,GAAG,IAAI,QAAQ,CAE9B;AAED,wBAAgB,KAAK,IAAI,QAAQ,CAEhC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAoCxG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,QAAQ,CAOlF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,QAAQ,CAqCvG"}
@@ -0,0 +1,10 @@
1
+ import type { Combinator } from '../types.ts';
2
+ /**
3
+ * Treat a parser as one source token.
4
+ *
5
+ * The wrapped parser runs with trivia cleared, so its parts must be contiguous.
6
+ * On success the token returns the matched source text and captures one CST leaf
7
+ * for the full span, suppressing any internal terminal leaves.
8
+ */
9
+ export declare function token(root: Combinator<unknown>): Combinator<string>;
10
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/combinators/token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAyC,MAAM,aAAa,CAAA;AAGpF;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAqDnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/compiler/codegen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/compiler/codegen.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ir-serialize.d.ts","sourceRoot":"","sources":["../../src/compiler/ir-serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAgBxD,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;AA0C/B,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,GAC9C,MAAM,GAAG,IAAI,CAUf;AAED;;oFAEoF;AACpF,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAgC/D"}
1
+ {"version":3,"file":"ir-serialize.d.ts","sourceRoot":"","sources":["../../src/compiler/ir-serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAiBxD,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;AA2C/B,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,GAC9C,MAAM,GAAG,IAAI,CAUf;AAED;;oFAEoF;AACpF,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAgC/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"value-usage.d.ts","sourceRoot":"","sources":["../../src/compiler/value-usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAuGhE"}
1
+ {"version":3,"file":"value-usage.d.ts","sourceRoot":"","sources":["../../src/compiler/value-usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAwGhE"}
package/dist/index.cjs CHANGED
@@ -85,7 +85,7 @@ __export(index_exports, {
85
85
  sequence: () => sequence,
86
86
  shiftAbsolute: () => shiftAbsolute,
87
87
  skip: () => skip,
88
- staticExpected: () => staticExpected,
88
+ token: () => token,
89
89
  transform: () => transform,
90
90
  trivia: () => trivia,
91
91
  triviaEntries: () => triviaEntries,
@@ -155,6 +155,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
155
155
  case "transform":
156
156
  case "label":
157
157
  case "trivia":
158
+ case "token":
158
159
  case "expect":
159
160
  case "withCtx":
160
161
  case "node":
@@ -217,6 +218,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
217
218
  case "transform":
218
219
  case "label":
219
220
  case "trivia":
221
+ case "token":
220
222
  case "node":
221
223
  case "grammar":
222
224
  case "expect":
@@ -1343,6 +1345,7 @@ function markUnusedValues(root) {
1343
1345
  return;
1344
1346
  case "label":
1345
1347
  case "trivia":
1348
+ case "token":
1346
1349
  case "withCtx":
1347
1350
  case "expect":
1348
1351
  visit(def.parser, consumed);
@@ -1643,8 +1646,60 @@ function parse(combinator, input, opts = {}) {
1643
1646
  return withErrors;
1644
1647
  }
1645
1648
 
1649
+ // src/combinators/token.ts
1650
+ function token(root) {
1651
+ const meta = {
1652
+ firstSet: root._meta.firstSet,
1653
+ canMatchNewline: root._meta.canMatchNewline,
1654
+ isTrivia: false
1655
+ };
1656
+ return {
1657
+ _tag: "token",
1658
+ _meta: meta,
1659
+ _def: { tag: "token", parser: root },
1660
+ parse(input, pos, ctx) {
1661
+ const savedTrivia = ctx.trivia;
1662
+ const savedKinds = ctx.triviaKindLabels;
1663
+ const savedBuf = ctx._cstBuf;
1664
+ const savedChildren = ctx._cstChildren;
1665
+ const savedLeaves = ctx._cstLeaves;
1666
+ const savedRaw = ctx._cstRawChildren;
1667
+ const savedTriviaLog = ctx._cstTriviaLog;
1668
+ const savedOuterTriviaLog = ctx._triviaLog;
1669
+ const wasCapturing = cstCaptureActive(ctx);
1670
+ ctx.trivia = void 0;
1671
+ ctx.triviaKindLabels = void 0;
1672
+ ctx._cstBuf = void 0;
1673
+ ctx._cstChildren = void 0;
1674
+ ctx._cstLeaves = void 0;
1675
+ ctx._cstRawChildren = void 0;
1676
+ ctx._cstTriviaLog = void 0;
1677
+ delete ctx._triviaLog;
1678
+ let result;
1679
+ try {
1680
+ result = root.parse(input, pos, ctx);
1681
+ } finally {
1682
+ ctx.trivia = savedTrivia;
1683
+ ctx.triviaKindLabels = savedKinds;
1684
+ ctx._cstBuf = savedBuf;
1685
+ ctx._cstChildren = savedChildren;
1686
+ ctx._cstLeaves = savedLeaves;
1687
+ ctx._cstRawChildren = savedRaw;
1688
+ ctx._cstTriviaLog = savedTriviaLog;
1689
+ if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
1690
+ else ctx._triviaLog = savedOuterTriviaLog;
1691
+ }
1692
+ if (!result.ok) return result;
1693
+ const span = result.span;
1694
+ const value = input.slice(pos, span.end);
1695
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
1696
+ return { ok: true, value, span };
1697
+ }
1698
+ };
1699
+ }
1700
+
1646
1701
  // src/combinators/expect.ts
1647
- function staticExpected(c) {
1702
+ function deriveExpected(c) {
1648
1703
  const def = c._def;
1649
1704
  switch (def.tag) {
1650
1705
  case "literal":
@@ -1656,22 +1711,23 @@ function staticExpected(c) {
1656
1711
  case "label":
1657
1712
  return [def.label];
1658
1713
  case "choice":
1659
- return def.parsers.flatMap(staticExpected);
1714
+ return def.parsers.flatMap(deriveExpected);
1660
1715
  case "sequence":
1661
- return def.parsers.length > 0 ? staticExpected(def.parsers[0]) : [];
1716
+ return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
1662
1717
  case "node":
1663
1718
  case "grammar":
1664
1719
  case "trivia":
1720
+ case "token":
1665
1721
  case "optional":
1666
1722
  case "many":
1667
1723
  case "oneOrMore":
1668
1724
  case "transform":
1669
1725
  case "not":
1670
- return staticExpected(def.parser);
1726
+ return deriveExpected(def.parser);
1671
1727
  case "lazy": {
1672
1728
  const name = c._ruleName;
1673
1729
  try {
1674
- return staticExpected(def.thunk());
1730
+ return deriveExpected(def.thunk());
1675
1731
  } catch {
1676
1732
  return name ? [name] : [];
1677
1733
  }
@@ -1681,7 +1737,7 @@ function staticExpected(c) {
1681
1737
  }
1682
1738
  }
1683
1739
  function expect(combinator, label2) {
1684
- const expected = label2 !== void 0 ? [label2] : staticExpected(combinator);
1740
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1685
1741
  const meta = {
1686
1742
  firstSet: combinator._meta.firstSet,
1687
1743
  canMatchNewline: combinator._meta.canMatchNewline,
@@ -3333,6 +3389,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
3333
3389
  case "guard":
3334
3390
  case "not":
3335
3391
  case "trivia":
3392
+ case "token":
3336
3393
  case "scanTo":
3337
3394
  case "unknown":
3338
3395
  return false;
@@ -3394,6 +3451,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
3394
3451
  case "regex":
3395
3452
  case "keywords":
3396
3453
  case "node":
3454
+ case "token":
3397
3455
  return true;
3398
3456
  case "not":
3399
3457
  case "guard":
@@ -3672,9 +3730,9 @@ function emitSeq(def, ctx, pos) {
3672
3730
  stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
3673
3731
  return { stmts, valueVar: arrV, endVar };
3674
3732
  }
3675
- function staticExpectedArr(parsers) {
3733
+ function deriveExpectedArr(parsers) {
3676
3734
  return JSON.stringify(parsers.flatMap((p) => {
3677
- const e = staticExpected(p);
3735
+ const e = deriveExpected(p);
3678
3736
  return e.length > 0 ? e : [p._tag];
3679
3737
  }));
3680
3738
  }
@@ -3695,7 +3753,7 @@ function failsAtStart(p) {
3695
3753
  }
3696
3754
  }
3697
3755
  function armStaticExpected(ctx, p) {
3698
- return hoistExpected(ctx, staticExpectedArr([p]));
3756
+ return hoistExpected(ctx, deriveExpectedArr([p]));
3699
3757
  }
3700
3758
  function canMatchEmptyAtStart(p) {
3701
3759
  const d = p._def;
@@ -3733,7 +3791,7 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
3733
3791
  ];
3734
3792
  }
3735
3793
  function emitChoice(def, ctx, pos) {
3736
- const allExpected = staticExpectedArr(def.parsers);
3794
+ const allExpected = deriveExpectedArr(def.parsers);
3737
3795
  if (def.disjoint) {
3738
3796
  const codeV = v(ctx, "_code");
3739
3797
  const valV = v(ctx, "_chv");
@@ -3794,7 +3852,7 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
3794
3852
  const wordV = v(ctx, "_gw");
3795
3853
  const endV = v(ctx, "_ge");
3796
3854
  const valV = v(ctx, "_gcv");
3797
- const regexExpected = JSON.stringify(staticExpected(superParser));
3855
+ const regexExpected = JSON.stringify(deriveExpected(superParser));
3798
3856
  const stmts = [
3799
3857
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
3800
3858
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
@@ -4186,6 +4244,116 @@ function emitNot(def, ctx, pos) {
4186
4244
  endVar: pos
4187
4245
  };
4188
4246
  }
4247
+ function escapeTokenLiteral(value) {
4248
+ return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
4249
+ }
4250
+ function regexMatchesEmpty(source, flags) {
4251
+ try {
4252
+ return new RegExp(`^(?:${source})$`, flags).test("");
4253
+ } catch {
4254
+ return true;
4255
+ }
4256
+ }
4257
+ function tokenTerminalSource(p) {
4258
+ const def = p._def;
4259
+ switch (def.tag) {
4260
+ case "literal":
4261
+ if (def.value.length === 0) return null;
4262
+ return {
4263
+ source: escapeTokenLiteral(def.value),
4264
+ caseInsensitive: def.caseInsensitive,
4265
+ rawCaseSensitive: def.caseInsensitive ? "" : def.value
4266
+ };
4267
+ case "regex": {
4268
+ if (def.flags.replace(/i/g, "") !== "") return null;
4269
+ if (regexMatchesEmpty(def.source, def.flags)) return null;
4270
+ return {
4271
+ source: `(?:${def.source})`,
4272
+ caseInsensitive: def.flags.includes("i"),
4273
+ rawCaseSensitive: def.flags.includes("i") ? "" : def.source
4274
+ };
4275
+ }
4276
+ default:
4277
+ return null;
4278
+ }
4279
+ }
4280
+ function tokenSequenceSource(p) {
4281
+ const def = p._def;
4282
+ const parts = def.tag === "sequence" ? def.parsers.map(tokenTerminalSource) : [tokenTerminalSource(p)];
4283
+ if (parts.some((part) => part === null)) return null;
4284
+ const typed = parts;
4285
+ const flags = typed.some((part) => part.caseInsensitive) ? "i" : "";
4286
+ if (flags.includes("i") && typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))) return null;
4287
+ return {
4288
+ source: typed.map((part) => part.source).join(""),
4289
+ flags,
4290
+ hasCaseSensitiveLetters: typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))
4291
+ };
4292
+ }
4293
+ function combineTokenRegexSources(parts) {
4294
+ const flags = parts.some((part) => part.flags.includes("i")) ? "i" : "";
4295
+ if (flags.includes("i") && parts.some((part) => part.flags === "" && part.hasCaseSensitiveLetters)) return null;
4296
+ return { source: parts.map((part) => part.source).join(""), flags };
4297
+ }
4298
+ function tokenNullableRegex(def) {
4299
+ const inner = def.parser._def;
4300
+ if (inner.tag === "many") {
4301
+ const seq = tokenSequenceSource(inner.parser);
4302
+ if (!seq) return null;
4303
+ return { tag: "regex", source: `(?:${seq.source})*`, flags: seq.flags };
4304
+ }
4305
+ if (inner.tag === "optional") {
4306
+ const seq = tokenSequenceSource(inner.parser);
4307
+ if (!seq) return null;
4308
+ return { tag: "regex", source: `(?:${seq.source})?`, flags: seq.flags };
4309
+ }
4310
+ if (inner.tag === "sepBy") {
4311
+ const item = tokenSequenceSource(inner.parser);
4312
+ const sep = tokenSequenceSource(inner.separator);
4313
+ if (!item || !sep) return null;
4314
+ const combined = combineTokenRegexSources([item, sep]);
4315
+ if (!combined) return null;
4316
+ return { tag: "regex", source: `(?:${item.source}(?:${sep.source}${item.source})*)?`, flags: combined.flags };
4317
+ }
4318
+ return null;
4319
+ }
4320
+ function emitToken(def, ctx, pos) {
4321
+ const lowered = tokenNullableRegex(def);
4322
+ if (lowered) return emitRegex(lowered, ctx, pos);
4323
+ const savedTrivia = ctx.activeTrivia;
4324
+ const savedKindLabels = ctx.triviaKindLabels;
4325
+ ctx.activeTrivia = void 0;
4326
+ ctx.triviaKindLabels = void 0;
4327
+ const inner = emitFallible(def.parser, ctx, pos);
4328
+ ctx.activeTrivia = savedTrivia;
4329
+ ctx.triviaKindLabels = savedKindLabels;
4330
+ const i = ind(ctx);
4331
+ const sc = v(ctx, "_tokCh");
4332
+ const sl = v(ctx, "_tokLv");
4333
+ const sr = v(ctx, "_tokRaw");
4334
+ const sv = v(ctx, "_tokTr");
4335
+ const sk = v(ctx, "_tokKinds");
4336
+ const stl = v(ctx, "_tokTl");
4337
+ const sol = v(ctx, "_tokLog");
4338
+ const sb = v(ctx, "_tokBuf");
4339
+ const valV = v(ctx, "_tok");
4340
+ return {
4341
+ stmts: [
4342
+ `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${sv} = _ctx.trivia, ${sk} = _ctx.triviaKindLabels, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
4343
+ `${i}_ctx.trivia = undefined; _ctx.triviaKindLabels = undefined; _ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
4344
+ `${i}try {`,
4345
+ ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
4346
+ `${i}} finally {`,
4347
+ `${i} _ctx.trivia = ${sv}; _ctx.triviaKindLabels = ${sk}; _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
4348
+ `${i}}`,
4349
+ ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
4350
+ `${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
4351
+ ...emitLeafCapture(ctx, valV, pos, inner.endVar)
4352
+ ],
4353
+ valueVar: valV,
4354
+ endVar: inner.endVar
4355
+ };
4356
+ }
4189
4357
  function emitNode(def, ctx, pos) {
4190
4358
  const structural = def.build === void 0;
4191
4359
  const mkType = structural ? null : analyzeMkInlineBuild(def);
@@ -4305,7 +4473,7 @@ function emitRecover(def, ctx, pos) {
4305
4473
  `${ind0} if (${sentOk}) break`,
4306
4474
  `${ind0} ${scanV}++`,
4307
4475
  `${ind0} }`,
4308
- `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(staticExpected(def.parser))} }`,
4476
+ `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
4309
4477
  `${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
4310
4478
  `${ind0} ${valVar} = ${errV}`,
4311
4479
  `${ind0} ${endVar} = ${scanV}`,
@@ -4435,6 +4603,8 @@ function emitDispatch(p, ctx, pos) {
4435
4603
  return emitLazy(p, def, ctx, pos);
4436
4604
  case "trivia":
4437
4605
  return emit(def.parser, ctx, pos);
4606
+ case "token":
4607
+ return emitToken(def, ctx, pos);
4438
4608
  case "label":
4439
4609
  return emit(def.parser, ctx, pos);
4440
4610
  case "grammar": {
@@ -4536,6 +4706,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
4536
4706
  }
4537
4707
  case "grammar":
4538
4708
  case "trivia":
4709
+ case "token":
4539
4710
  case "label":
4540
4711
  case "optional":
4541
4712
  case "many":
@@ -4571,6 +4742,7 @@ function childrenOf(def) {
4571
4742
  case "optional":
4572
4743
  case "transform":
4573
4744
  case "trivia":
4745
+ case "token":
4574
4746
  case "label":
4575
4747
  case "grammar":
4576
4748
  case "not":
@@ -5081,7 +5253,7 @@ function balanced(open, close, options = {}) {
5081
5253
  const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
5082
5254
  const inner = many(choice(self, ...skips, content));
5083
5255
  const combi = transform(
5084
- sequence(literal(open), inner, expect(literal(close), close)),
5256
+ sequence(literal(open), inner, expect(literal(close))),
5085
5257
  // parts: strings (content/self) or arrays (a sequence-shaped skip) or a
5086
5258
  // ParseError (recovered close). `c` is the close string or a ParseError.
5087
5259
  ([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
@@ -5143,6 +5315,7 @@ function evalRuleMapIR(ir) {
5143
5315
  "node",
5144
5316
  "parser",
5145
5317
  "scanTo",
5318
+ "token",
5146
5319
  "transform",
5147
5320
  "skip",
5148
5321
  "trivia",
@@ -5168,6 +5341,7 @@ function evalRuleMapIR(ir) {
5168
5341
  node,
5169
5342
  parser,
5170
5343
  scanTo,
5344
+ token,
5171
5345
  transform,
5172
5346
  skip,
5173
5347
  trivia,
@@ -5328,7 +5502,7 @@ function recover(combinator, sentinel) {
5328
5502
  canMatchNewline: true,
5329
5503
  isTrivia: false
5330
5504
  };
5331
- const expected = staticExpected(combinator);
5505
+ const expected = deriveExpected(combinator);
5332
5506
  return {
5333
5507
  _tag: "recover",
5334
5508
  _meta: meta,