parseman 0.50.1 → 0.50.4

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 (57) hide show
  1. package/README.md +14 -10
  2. package/dist/analysis/diagnostics.js +455 -229
  3. package/dist/analysis/diagnostics.js.map +3 -3
  4. package/dist/cli/index.js +445 -194
  5. package/dist/cli/index.js.map +3 -3
  6. package/dist/combinators/choice.d.ts.map +1 -1
  7. package/dist/combinators/first-set.d.ts.map +1 -1
  8. package/dist/combinators/grammar.d.ts.map +1 -1
  9. package/dist/combinators/keywords.d.ts.map +1 -1
  10. package/dist/combinators/literal.d.ts.map +1 -1
  11. package/dist/combinators/map.d.ts.map +1 -1
  12. package/dist/combinators/ref.d.ts.map +1 -1
  13. package/dist/combinators/regex.d.ts.map +1 -1
  14. package/dist/combinators/repeat.d.ts.map +1 -1
  15. package/dist/combinators/scalar.d.ts +6 -0
  16. package/dist/combinators/scalar.d.ts.map +1 -0
  17. package/dist/combinators/sequence.d.ts.map +1 -1
  18. package/dist/combinators/trivia-skip.d.ts +2 -0
  19. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  20. package/dist/compiler/token-capability.js +22 -11
  21. package/dist/compiler/token-capability.js.map +2 -2
  22. package/dist/index.js +446 -195
  23. package/dist/index.js.map +3 -3
  24. package/dist/language-service/index.js +68 -172
  25. package/dist/language-service/index.js.map +3 -3
  26. package/dist/parse-context.d.ts.map +1 -1
  27. package/dist/plugin/index.js +491 -309
  28. package/dist/plugin/index.js.map +3 -3
  29. package/dist/run/index.js +1 -0
  30. package/dist/run/index.js.map +1 -1
  31. package/dist/spec/index.js +421 -285
  32. package/dist/spec/index.js.map +3 -3
  33. package/dist/table/emit-assembly.d.ts.map +1 -1
  34. package/dist/table/encode.d.ts.map +1 -1
  35. package/dist/table/index.js +331 -191
  36. package/dist/table/index.js.map +3 -3
  37. package/dist/types.d.ts +8 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/version.d.ts +1 -1
  40. package/package.json +5 -3
  41. package/src/combinators/choice.ts +34 -1
  42. package/src/combinators/first-set.ts +33 -7
  43. package/src/combinators/grammar.ts +39 -0
  44. package/src/combinators/keywords.ts +14 -3
  45. package/src/combinators/literal.ts +26 -0
  46. package/src/combinators/map.ts +60 -0
  47. package/src/combinators/ref.ts +26 -7
  48. package/src/combinators/regex.ts +23 -0
  49. package/src/combinators/repeat.ts +109 -16
  50. package/src/combinators/scalar.ts +30 -0
  51. package/src/combinators/sequence.ts +76 -161
  52. package/src/combinators/trivia-skip.ts +14 -1
  53. package/src/parse-context.ts +1 -0
  54. package/src/table/emit-assembly.ts +39 -16
  55. package/src/table/encode.ts +14 -2
  56. package/src/types.ts +8 -0
  57. package/src/version.ts +1 -1
package/dist/cli/index.js CHANGED
@@ -43,10 +43,20 @@ function classifyFinalChoice(arms, resolve2) {
43
43
  }
44
44
  return { exclusive, firstSets, nullable: nullable2 };
45
45
  }
46
- function resolveNamedRef(p, resolve2) {
46
+ function winnerForRef(p, resolve2) {
47
47
  if (resolve2 === void 0) return void 0;
48
48
  const name = p._ruleName;
49
- return name === void 0 ? void 0 : resolve2(name);
49
+ const w = name === void 0 ? void 0 : resolve2(name);
50
+ if (w === void 0 || w === p) return void 0;
51
+ let cur = w;
52
+ for (const seen = /* @__PURE__ */ new Set(); !seen.has(cur); ) {
53
+ if (cur === p) return void 0;
54
+ seen.add(cur);
55
+ const cd = cur._def;
56
+ if (cd.tag !== "grammar" && cd.tag !== "trivia") return w;
57
+ cur = cd.parser;
58
+ }
59
+ return w;
50
60
  }
51
61
  function union(a, b) {
52
62
  if (a.kind === "any" || b.kind === "any") return { kind: "any" };
@@ -144,13 +154,15 @@ function matchesEmptyBody(p, seen, resolve2) {
144
154
  case "grammar":
145
155
  case "recover":
146
156
  return me(d.parser);
147
- case "lazy":
157
+ case "lazy": {
158
+ const w = winnerForRef(p, resolve2);
159
+ if (w !== void 0) return me(w);
148
160
  try {
149
161
  return me(d.thunk());
150
162
  } catch {
151
- const t2 = resolveNamedRef(p, resolve2);
152
- return t2 ? me(t2) : true;
163
+ return true;
153
164
  }
165
+ }
154
166
  default:
155
167
  return true;
156
168
  }
@@ -214,13 +226,15 @@ function firstSetBody(p, seen, resolve2) {
214
226
  // terminals: no refs, cached set is exact
215
227
  case "dispatch":
216
228
  return fs(d.selector);
217
- case "lazy":
229
+ case "lazy": {
230
+ const w = winnerForRef(p, resolve2);
231
+ if (w !== void 0) return fs(w);
218
232
  try {
219
233
  return fs(d.thunk());
220
234
  } catch {
221
- const t2 = resolveNamedRef(p, resolve2);
222
- return t2 ? fs(t2) : any();
235
+ return any();
223
236
  }
237
+ }
224
238
  case "choice": {
225
239
  let out = empty();
226
240
  for (const arm of d.parsers) out = union(out, fs(arm));
@@ -689,9 +703,43 @@ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
689
703
  }
690
704
  }
691
705
 
706
+ // src/combinators/scalar.ts
707
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
708
+ function scalarOf(combinator) {
709
+ return combinator._parseScalar;
710
+ }
711
+ function scalarTree(parser2, seen) {
712
+ if (seen.has(parser2)) return true;
713
+ if (parser2._parseScalar === void 0) return false;
714
+ seen.add(parser2);
715
+ const def = parser2._def;
716
+ if (!SCALAR_TAG.test(def.tag)) return false;
717
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
718
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
719
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
720
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
721
+ }
722
+ function scalarRootOf(combinator) {
723
+ const scalar = combinator._parseScalar;
724
+ const def = combinator._def;
725
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
726
+ }
727
+
692
728
  // src/combinators/ref.ts
729
+ function withRuleTrivia(trivia2, ctx, run) {
730
+ const savedLabels = ctx.triviaKindLabels;
731
+ ctx.trivia = trivia2;
732
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
733
+ try {
734
+ return run();
735
+ } finally {
736
+ ctx.trivia = void 0;
737
+ ctx.triviaKindLabels = savedLabels;
738
+ }
739
+ }
693
740
  function ref() {
694
741
  let resolved = null;
742
+ let resolvedScalar = null;
695
743
  let ownBoundary = false;
696
744
  const meta = {
697
745
  firstSet: any(),
@@ -708,25 +756,28 @@ function ref() {
708
756
  return resolved;
709
757
  }
710
758
  },
759
+ _parseScalar(input, pos, ctx) {
760
+ const scalar = resolvedScalar;
761
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
762
+ const gt = meta.grammarTrivia;
763
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
764
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
765
+ }
766
+ return scalar(input, pos, ctx);
767
+ },
711
768
  parse(input, pos, ctx) {
712
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
769
+ const parser2 = resolved;
770
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
713
771
  const gt = meta.grammarTrivia;
714
772
  if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
715
- const savedLabels = ctx.triviaKindLabels;
716
- ctx.trivia = gt;
717
- ctx.triviaKindLabels = gt._meta.triviaKindLabels;
718
- try {
719
- return resolved.parse(input, pos, ctx);
720
- } finally {
721
- ctx.trivia = void 0;
722
- ctx.triviaKindLabels = savedLabels;
723
- }
773
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
724
774
  }
725
- return resolved.parse(input, pos, ctx);
775
+ return parser2.parse(input, pos, ctx);
726
776
  },
727
777
  define(p) {
728
778
  if (resolved) throw new Error("ref<T>() already defined");
729
779
  resolved = p;
780
+ resolvedScalar = scalarOf(p);
730
781
  ownBoundary = hasOwnTriviaBoundary(p);
731
782
  meta.firstSet = p._meta.firstSet;
732
783
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -1112,6 +1163,7 @@ function createParseContext() {
1112
1163
  _fe: void 0,
1113
1164
  _fx: void 0,
1114
1165
  _fc: void 0,
1166
+ _sv: void 0,
1115
1167
  _probe: void 0,
1116
1168
  _cstChildren: void 0,
1117
1169
  _cstLeaves: void 0,
@@ -1949,6 +2001,24 @@ function parser(opts, root) {
1949
2001
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
1950
2002
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
1951
2003
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
2004
+ const rootScalar = scalarOf(root);
2005
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
2006
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
2007
+ const savedTrivia = ctx.trivia;
2008
+ const savedLabels = ctx.triviaKindLabels;
2009
+ if (clearTrivia) {
2010
+ ctx.trivia = void 0;
2011
+ ctx.triviaKindLabels = void 0;
2012
+ } else if (scopeTrivia !== void 0) {
2013
+ ctx.trivia = scopeTrivia;
2014
+ ctx.triviaKindLabels = scopeLabels;
2015
+ }
2016
+ const end = rootScalar(input, pos, ctx);
2017
+ ctx.trivia = savedTrivia;
2018
+ ctx.triviaKindLabels = savedLabels;
2019
+ return end;
2020
+ } : void 0;
2021
+ let publicScalar;
1952
2022
  const grammar = {
1953
2023
  _tag: "grammar",
1954
2024
  _meta: {
@@ -1972,7 +2042,20 @@ function parser(opts, root) {
1972
2042
  constructionTrackLines: trackLinesPolicy,
1973
2043
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
1974
2044
  },
2045
+ _parseScalar: parseScalar,
1975
2046
  parse(input, pos, _ctx) {
2047
+ if (pos === void 0 && _ctx === void 0) {
2048
+ publicScalar ??= scalarRootOf(grammar) ?? null;
2049
+ if (publicScalar) {
2050
+ const ctx2 = createParseContext();
2051
+ const end = publicScalar(input, 0, ctx2);
2052
+ if (end < 0) {
2053
+ const at = ~end;
2054
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
2055
+ }
2056
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
2057
+ }
2058
+ }
1976
2059
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
1977
2060
  const trackLines = trackLinesOf(_ctx);
1978
2061
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -2007,6 +2090,9 @@ function parse(combinator, input, opts = {}) {
2007
2090
  _analyzed.add(combinator);
2008
2091
  markUnusedValues(combinator);
2009
2092
  }
2093
+ if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
2094
+ return combinator.parse(input);
2095
+ }
2010
2096
  const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
2011
2097
  const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
2012
2098
  const lineIndex = lineContext?.lineIndex;
@@ -2601,10 +2687,32 @@ function regex(pattern, flags = "") {
2601
2687
  const canMatchNewline = raw.canMatchNewline;
2602
2688
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
2603
2689
  const def = { tag: "regex", source, flags: resolvedFlags };
2690
+ const expected = directTerminalFailureExpected(def);
2691
+ const parseScalar = (input, pos, ctx) => {
2692
+ const scanEnd = scan?.(input, pos);
2693
+ if (scanEnd !== void 0) {
2694
+ if (scanEnd === null) {
2695
+ ctx._fx = expected;
2696
+ return ~pos;
2697
+ }
2698
+ ctx._sv = input.slice(pos, scanEnd);
2699
+ return scanEnd;
2700
+ }
2701
+ anchored.lastIndex = pos;
2702
+ const match = anchored.exec(input);
2703
+ if (match === null) {
2704
+ ctx._fx = expected;
2705
+ return ~pos;
2706
+ }
2707
+ ctx._sv = match[0];
2708
+ return pos + match[0].length;
2709
+ };
2604
2710
  return {
2605
2711
  _tag: "regex",
2606
2712
  _meta: meta,
2607
2713
  _def: def,
2714
+ _stickyRegex: anchored,
2715
+ _parseScalar: parseScalar,
2608
2716
  parse(input, pos, ctx) {
2609
2717
  const scanEnd = scan?.(input, pos);
2610
2718
  if (scanEnd !== void 0) {
@@ -2649,6 +2757,28 @@ function literal(value, opts = {}) {
2649
2757
  isTrivia: false
2650
2758
  };
2651
2759
  const canMatchNewline = meta.canMatchNewline;
2760
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
2761
+ const code = value.charCodeAt(0);
2762
+ return (input, pos, ctx) => {
2763
+ if (input.charCodeAt(pos) === code) {
2764
+ ctx._sv = value;
2765
+ return pos + 1;
2766
+ }
2767
+ ctx._fx = expected;
2768
+ return ~pos;
2769
+ };
2770
+ })() : (input, pos, ctx) => {
2771
+ const end = pos + value.length;
2772
+ if (end <= input.length) {
2773
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
2774
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
2775
+ ctx._sv = matchedValue;
2776
+ return end;
2777
+ }
2778
+ }
2779
+ ctx._fx = expected;
2780
+ return ~pos;
2781
+ };
2652
2782
  if (caseInsensitive) {
2653
2783
  const upper = value.toUpperCase();
2654
2784
  const lower = value.toLowerCase();
@@ -2689,6 +2819,7 @@ function literal(value, opts = {}) {
2689
2819
  _tag: "literal",
2690
2820
  _meta: meta,
2691
2821
  _def: { tag: "literal", value, caseInsensitive },
2822
+ _parseScalar: parseScalar,
2692
2823
  parse: parse2
2693
2824
  };
2694
2825
  }
@@ -2756,16 +2887,26 @@ function keywords(words, opts = {}) {
2756
2887
  caseInsensitive: opts.caseInsensitive ?? false,
2757
2888
  boundary: opts.boundary
2758
2889
  };
2890
+ const expected = directTerminalFailureExpected(def);
2891
+ const parseScalar = (input, pos, ctx) => {
2892
+ re.lastIndex = pos;
2893
+ const m = re.exec(input);
2894
+ if (m === null) {
2895
+ ctx._fx = expected;
2896
+ return ~pos;
2897
+ }
2898
+ ctx._sv = m[0];
2899
+ return pos + m[0].length;
2900
+ };
2759
2901
  return {
2760
2902
  _tag: "keywords",
2761
2903
  _meta: meta,
2762
2904
  _def: def,
2905
+ _parseScalar: parseScalar,
2763
2906
  parse(input, pos, ctx) {
2764
2907
  re.lastIndex = pos;
2765
2908
  const m = re.exec(input);
2766
- if (m === null || m.index !== pos) {
2767
- return failAt(ctx, directTerminalFailureExpected(def), pos);
2768
- }
2909
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
2769
2910
  const value = m[0];
2770
2911
  const span = { start: pos, end: pos + value.length };
2771
2912
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -2796,6 +2937,9 @@ var fastScanner3;
2796
2937
  function needsDeferredTriviaCommit(ctx) {
2797
2938
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
2798
2939
  }
2940
+ function needsTriviaRollback(ctx) {
2941
+ return ctx._cstBuf !== void 0 || ctx._cstLeaves !== void 0 || ctx._cstRawChildren !== void 0 || ctx._cstTriviaLog !== void 0 || ctx._fields !== void 0 || ctx._errors !== void 0 || ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0;
2942
+ }
2799
2943
  function saveTriviaMark(ctx) {
2800
2944
  const m = saveCstMark(ctx);
2801
2945
  return {
@@ -2912,7 +3056,8 @@ function advanceTrivia(input, cur, ctx) {
2912
3056
  const triviaP = ctx.trivia;
2913
3057
  if (!triviaP) return cur;
2914
3058
  if (!ctx.trackLines) {
2915
- const fast2 = fastTriviaScanner(triviaP);
3059
+ const classified = triviaP._meta.triviaScanner;
3060
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
2916
3061
  if (fast2) return fast2(input, cur);
2917
3062
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
2918
3063
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -3517,6 +3662,7 @@ function sequence(...parsers) {
3517
3662
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
3518
3663
  }
3519
3664
  const hasAdjacency = adjacency !== null;
3665
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
3520
3666
  const meta = {
3521
3667
  // Union through the nullable prefix — a leading optional()/many() lets a later
3522
3668
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -3525,165 +3671,96 @@ function sequence(...parsers) {
3525
3671
  isTrivia: false
3526
3672
  };
3527
3673
  const def = { tag: "sequence", parsers };
3528
- let followSentinels;
3529
- function parseTolerant(input, pos, ctx) {
3530
- followSentinels ??= parsers.map((_, i) => {
3531
- const fs = parsers.slice(i + 1).reduce(
3532
- (acc, p) => union(acc, firstSetOf(p)),
3533
- { kind: "empty" }
3534
- );
3535
- return firstSetSentinel(fs);
3536
- });
3537
- const values = def.valueUnused ? void 0 : [];
3674
+ const scalarParsers = parsers.map(scalarOf);
3675
+ const parseScalar = (input, pos, ctx) => {
3538
3676
  let cur = pos;
3539
- const inheritedSync = ctx._sync;
3540
- try {
3541
- for (let i = 0; i < parsers.length; i++) {
3542
- ctx._sync = followSentinels[i] ?? inheritedSync;
3543
- const adj = adjacency === null ? null : adjacency[i];
3544
- if (adj) {
3545
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
3546
- if (values !== void 0) values.push(null);
3547
- continue;
3548
- }
3549
- if (ctx.trivia && i > 0) {
3550
- const mTlog = cstTlLen(ctx);
3551
- const mLog = ctx._triviaLog?.length ?? 0;
3552
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3553
- let scanEnd;
3554
- if (needsDeferredTriviaCommit(ctx)) {
3555
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3556
- } else {
3557
- scanEnd = advanceTrivia(input, cur, ctx);
3558
- }
3559
- const scanTlog = cstTlLen(ctx);
3560
- const scanLog = ctx._triviaLog?.length ?? 0;
3561
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3562
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3563
- if (!result2.ok) return result2;
3564
- if (result2.span.end > scanEnd) cur = result2.span.end;
3565
- else rollbackScannedTriviaAt(
3566
- ctx,
3567
- mTlog,
3568
- scanTlog,
3569
- mLog,
3570
- scanLog,
3571
- mRootLog,
3572
- scanRootLog
3573
- );
3574
- if (values !== void 0) values.push(result2.value);
3575
- continue;
3576
- }
3577
- const result = parsers[i].parse(input, cur, ctx);
3578
- if (!result.ok) return result;
3579
- if (values !== void 0) values.push(result.value);
3580
- cur = result.span.end;
3677
+ if (strictArity !== 0) {
3678
+ cur = scalarParsers[0](input, cur, ctx);
3679
+ if (cur < 0) return cur;
3680
+ const first = ctx._sv;
3681
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3682
+ cur = scalarParsers[1](input, cur, ctx);
3683
+ if (cur < 0) return cur;
3684
+ const second = ctx._sv;
3685
+ if (strictArity === 2) {
3686
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
3687
+ return cur;
3581
3688
  }
3582
- } finally {
3583
- ctx._sync = inheritedSync;
3689
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3690
+ cur = scalarParsers[2](input, cur, ctx);
3691
+ if (cur < 0) return cur;
3692
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
3693
+ return cur;
3584
3694
  }
3585
- return {
3586
- ok: true,
3587
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3588
- value: values ?? void 0,
3589
- span: { start: pos, end: cur }
3590
- };
3591
- }
3592
- function parseAdjacent(input, pos, ctx) {
3593
3695
  const values = def.valueUnused ? void 0 : [];
3594
- let cur = pos;
3595
- for (let i = 0; i < parsers.length; i++) {
3596
- const adj = adjacency[i];
3597
- if (adj) {
3598
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
3599
- if (values !== void 0) values.push(null);
3600
- continue;
3601
- }
3602
- if (ctx.trivia && i > 0) {
3603
- let scanEnd;
3604
- const mTlog = cstTlLen(ctx);
3605
- const mLog = ctx._triviaLog?.length ?? 0;
3606
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3607
- if (needsDeferredTriviaCommit(ctx)) {
3608
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3609
- } else {
3610
- scanEnd = advanceTrivia(input, cur, ctx);
3611
- }
3612
- const scanTlog = cstTlLen(ctx);
3613
- const scanLog = ctx._triviaLog?.length ?? 0;
3614
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3615
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3616
- if (!result2.ok) return result2;
3617
- if (result2.span.end > scanEnd) cur = result2.span.end;
3618
- else rollbackScannedTriviaAt(
3619
- ctx,
3620
- mTlog,
3621
- scanTlog,
3622
- mLog,
3623
- scanLog,
3624
- mRootLog,
3625
- scanRootLog
3626
- );
3627
- if (values !== void 0) values.push(result2.value);
3628
- continue;
3629
- }
3630
- const result = parsers[i].parse(input, cur, ctx);
3631
- if (!result.ok) return result;
3632
- if (values !== void 0) values.push(result.value);
3633
- cur = result.span.end;
3634
- }
3635
- return {
3636
- ok: true,
3637
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3638
- value: values ?? void 0,
3639
- span: { start: pos, end: cur }
3640
- };
3641
- }
3696
+ for (let i = 0; i < scalarParsers.length; i++) {
3697
+ let termPos = cur;
3698
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
3699
+ const end = scalarParsers[i](input, termPos, ctx);
3700
+ if (end < 0) return end;
3701
+ if (values !== void 0) values.push(ctx._sv);
3702
+ if (end > termPos || termPos === cur) cur = end;
3703
+ }
3704
+ ctx._sv = values;
3705
+ return cur;
3706
+ };
3707
+ let followSentinels;
3642
3708
  return {
3643
3709
  _tag: "sequence",
3644
3710
  _meta: meta,
3645
3711
  _def: def,
3712
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
3646
3713
  parse(input, pos, ctx) {
3647
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
3648
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
3714
+ const tolerant = ctx._tolerant === true;
3715
+ if (tolerant) {
3716
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
3717
+ parsers.slice(i + 1).reduce(
3718
+ (set, parser2) => union(set, firstSetOf(parser2)),
3719
+ { kind: "empty" }
3720
+ )
3721
+ ));
3722
+ }
3723
+ const inheritedSync = ctx._sync;
3724
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
3649
3725
  const values = def.valueUnused ? void 0 : [];
3650
3726
  let cur = pos;
3651
- for (let i = 0; i < parsers.length; i++) {
3652
- if (ctx.trivia && i > 0) {
3653
- let scanEnd;
3654
- const mTlog = cstTlLen(ctx);
3655
- const mLog = ctx._triviaLog?.length ?? 0;
3656
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3657
- if (needsDeferredTriviaCommit(ctx)) {
3658
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3659
- } else {
3660
- scanEnd = advanceTrivia(input, cur, ctx);
3727
+ try {
3728
+ for (let i = 0; i < parsers.length; i++) {
3729
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
3730
+ const assertion = adjacency?.[i];
3731
+ if (assertion) {
3732
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
3733
+ if (values !== void 0) values.push(null);
3734
+ continue;
3661
3735
  }
3662
- const scanTlog = cstTlLen(ctx);
3663
- const scanLog = ctx._triviaLog?.length ?? 0;
3664
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3665
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3666
- if (!result2.ok) return result2;
3667
- if (result2.span.end > scanEnd) {
3668
- cur = result2.span.end;
3669
- } else {
3736
+ let termPos = cur;
3737
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3738
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3739
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3740
+ if (ctx.trivia && i > 0) {
3741
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
3742
+ }
3743
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3744
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3745
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3746
+ const result = parsers[i].parse(input, termPos, ctx);
3747
+ if (!result.ok) return result;
3748
+ if (values !== void 0) values.push(result.value);
3749
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
3750
+ else if (deferredTrivia) {
3670
3751
  rollbackScannedTriviaAt(
3671
3752
  ctx,
3672
- mTlog,
3753
+ markTlog,
3673
3754
  scanTlog,
3674
- mLog,
3755
+ markLog,
3675
3756
  scanLog,
3676
- mRootLog,
3757
+ markRootLog,
3677
3758
  scanRootLog
3678
3759
  );
3679
3760
  }
3680
- if (values !== void 0) values.push(result2.value);
3681
- continue;
3682
3761
  }
3683
- const result = parsers[i].parse(input, cur, ctx);
3684
- if (!result.ok) return result;
3685
- if (values !== void 0) values.push(result.value);
3686
- cur = result.span.end;
3762
+ } finally {
3763
+ if (tolerant) ctx._sync = inheritedSync;
3687
3764
  }
3688
3765
  return {
3689
3766
  ok: true,
@@ -3815,7 +3892,8 @@ function choice(...args) {
3815
3892
  disjoint
3816
3893
  };
3817
3894
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3818
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3895
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
3896
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
3819
3897
  let greedyLitMap = null;
3820
3898
  let sortedParsers = null;
3821
3899
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -3829,6 +3907,37 @@ function choice(...args) {
3829
3907
  } else if (strategy?.tag === "literalsLongestFirst") {
3830
3908
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
3831
3909
  }
3910
+ const scalarParsers = parsers.map(scalarOf);
3911
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
3912
+ const scalarExpected = parsers.flatMap(deriveExpected);
3913
+ const parseScalar = (input, pos, ctx) => {
3914
+ if (disjoint) {
3915
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3916
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3917
+ if (idx < 0 && code >= 0) {
3918
+ for (let i = 0; i < parsers.length; i++) {
3919
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3920
+ idx = i;
3921
+ break;
3922
+ }
3923
+ }
3924
+ }
3925
+ if (idx >= 0) {
3926
+ const gate = gates[idx];
3927
+ if (!gate || gate(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3928
+ ctx._fx = deriveExpected(parsers[idx]);
3929
+ return ~pos;
3930
+ }
3931
+ } else {
3932
+ for (let i = 0; i < scalarParsers.length; i++) {
3933
+ if (gates[i] && !gates[i](ctx.state)) continue;
3934
+ const end = scalarParsers[i](input, pos, ctx);
3935
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3936
+ }
3937
+ }
3938
+ ctx._fx = scalarExpected;
3939
+ return ~pos;
3940
+ };
3832
3941
  return {
3833
3942
  _tag: "choice",
3834
3943
  _meta: meta,
@@ -3840,6 +3949,7 @@ function choice(...args) {
3840
3949
  strategy: strategy ?? { tag: "firstMatch" },
3841
3950
  autoNot
3842
3951
  },
3952
+ _parseScalar: scalarEligible ? parseScalar : void 0,
3843
3953
  parse(input, pos, ctx) {
3844
3954
  const expected = [];
3845
3955
  let expectedAt = pos;
@@ -4371,8 +4481,8 @@ function attempt(parser2) {
4371
4481
  }
4372
4482
 
4373
4483
  // src/combinators/repeat.ts
4374
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4375
- const mark = saveTriviaMark(ctx);
4484
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
4485
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
4376
4486
  let pos = cur;
4377
4487
  if (ctx.trivia) {
4378
4488
  if (needsDeferredTriviaCommit(ctx)) {
@@ -4382,24 +4492,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4382
4492
  }
4383
4493
  }
4384
4494
  if (pos >= input.length && !mandatory) {
4385
- rollbackTrivia(ctx, mark);
4495
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4386
4496
  return "stop";
4387
4497
  }
4388
4498
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
4389
- rollbackTrivia(ctx, mark);
4499
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4390
4500
  return "stop";
4391
4501
  }
4392
4502
  const result = combinator.parse(input, pos, ctx);
4393
4503
  if (!result.ok) {
4394
- rollbackTrivia(ctx, mark);
4504
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4395
4505
  if (result.committed) return { fail: result, failPos: pos };
4396
4506
  return { fail: result, failPos: pos };
4397
4507
  }
4398
4508
  if (result.span.end === pos && !mandatory) {
4399
- rollbackTrivia(ctx, mark);
4509
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4400
4510
  return "stop";
4401
4511
  }
4402
- return { value: result.value, end: result.span.end };
4512
+ return result;
4403
4513
  }
4404
4514
  function resolveBounds(what, opts) {
4405
4515
  const min = opts.min ?? 0;
@@ -4412,6 +4522,21 @@ function resolveBounds(what, opts) {
4412
4522
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
4413
4523
  return { min, max };
4414
4524
  }
4525
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
4526
+ while (cur < input.length && remaining > 0) {
4527
+ let itemPos = cur;
4528
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4529
+ if (itemPos >= input.length) break;
4530
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
4531
+ const end = child(input, itemPos, ctx);
4532
+ if (end <= itemPos) break;
4533
+ if (values !== void 0) values.push(ctx._sv);
4534
+ cur = end;
4535
+ remaining--;
4536
+ }
4537
+ ctx._sv = values;
4538
+ return cur;
4539
+ }
4415
4540
  function many(combinator, opts = {}) {
4416
4541
  const { min, max } = resolveBounds("many()", opts);
4417
4542
  if (min >= 1) return atLeast(combinator, min, max);
@@ -4423,17 +4548,21 @@ function many(combinator, opts = {}) {
4423
4548
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
4424
4549
  let expected;
4425
4550
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4551
+ const scalarChild = scalarOf(combinator);
4552
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
4426
4553
  return {
4427
4554
  _tag: "many",
4428
4555
  _meta: meta,
4429
4556
  _def: def,
4557
+ _parseScalar: parseScalar,
4430
4558
  parse(input, pos, ctx) {
4431
4559
  const values = def.valueUnused ? void 0 : [];
4560
+ const rollbackNeeded = needsTriviaRollback(ctx);
4432
4561
  let cur = pos;
4433
4562
  let count = 0;
4434
4563
  while (cur < input.length) {
4435
4564
  if (count >= max) break;
4436
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4565
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4437
4566
  if (item === "stop") break;
4438
4567
  if ("fail" in item) {
4439
4568
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4450,7 +4579,7 @@ function many(combinator, opts = {}) {
4450
4579
  }
4451
4580
  if (values !== void 0) values.push(item.value);
4452
4581
  count++;
4453
- cur = item.end;
4582
+ cur = item.span.end;
4454
4583
  }
4455
4584
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4456
4585
  }
@@ -4468,30 +4597,47 @@ function atLeast(combinator, min, max) {
4468
4597
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4469
4598
  let expected;
4470
4599
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4600
+ const scalarChild = scalarOf(combinator);
4601
+ const parseScalar = (input, pos, ctx) => {
4602
+ let cur = scalarChild(input, pos, ctx);
4603
+ if (cur < 0) return cur;
4604
+ const values = def.valueUnused ? void 0 : [ctx._sv];
4605
+ for (let count = 1; count < min; count++) {
4606
+ let itemPos = cur;
4607
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4608
+ const end = scalarChild(input, itemPos, ctx);
4609
+ if (end < 0) return ~cur;
4610
+ cur = end;
4611
+ if (values !== void 0) values.push(ctx._sv);
4612
+ }
4613
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
4614
+ };
4471
4615
  return {
4472
4616
  _tag: "oneOrMore",
4473
4617
  _meta: meta,
4474
4618
  _def: def,
4619
+ _parseScalar: parseScalar,
4475
4620
  parse(input, pos, ctx) {
4476
4621
  const first = combinator.parse(input, pos, ctx);
4477
4622
  if (!first.ok) return first;
4478
4623
  const values = def.valueUnused ? void 0 : [first.value];
4624
+ const rollbackNeeded = needsTriviaRollback(ctx);
4479
4625
  let cur = first.span.end;
4480
4626
  let count = 1;
4481
4627
  while (count < min) {
4482
- const item = repItem(combinator, input, cur, ctx, guardable, true);
4628
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
4483
4629
  if (item === "stop" || "fail" in item) {
4484
4630
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4485
4631
  expected ??= deriveExpected(combinator);
4486
4632
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4487
4633
  }
4488
4634
  if (values !== void 0) values.push(item.value);
4489
- cur = item.end;
4635
+ cur = item.span.end;
4490
4636
  count++;
4491
4637
  }
4492
4638
  while (cur < input.length) {
4493
4639
  if (count >= max) break;
4494
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4640
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4495
4641
  if (item === "stop") break;
4496
4642
  if ("fail" in item) {
4497
4643
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4508,7 +4654,7 @@ function atLeast(combinator, min, max) {
4508
4654
  }
4509
4655
  if (values !== void 0) values.push(item.value);
4510
4656
  count++;
4511
- cur = item.end;
4657
+ cur = item.span.end;
4512
4658
  }
4513
4659
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4514
4660
  }
@@ -4521,10 +4667,22 @@ function optional(combinator) {
4521
4667
  isTrivia: false
4522
4668
  };
4523
4669
  const firstSetSkippable = !matchesEmpty(combinator);
4670
+ const scalarChild = scalarOf(combinator);
4671
+ const parseScalar = (input, pos, ctx) => {
4672
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
4673
+ ctx._sv = null;
4674
+ return pos;
4675
+ }
4676
+ const end = scalarChild(input, pos, ctx);
4677
+ if (end >= 0) return end;
4678
+ ctx._sv = null;
4679
+ return pos;
4680
+ };
4524
4681
  return {
4525
4682
  _tag: "optional",
4526
4683
  _meta: meta,
4527
4684
  _def: { tag: "optional", parser: combinator },
4685
+ _parseScalar: parseScalar,
4528
4686
  parse(input, pos, ctx) {
4529
4687
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4530
4688
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -4558,6 +4716,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
4558
4716
  expected ??= deriveExpected(combinator);
4559
4717
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4560
4718
  };
4719
+ const scalarExpected = deriveExpected(combinator);
4720
+ const scalarChild = scalarOf(combinator);
4721
+ const scalarSeparator = scalarOf(separator);
4722
+ const parseScalar = (input, pos, ctx) => {
4723
+ let cur = scalarChild(input, pos, ctx);
4724
+ if (cur < 0) {
4725
+ if (min >= 1) {
4726
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4727
+ return ~pos;
4728
+ }
4729
+ ctx._sv = [];
4730
+ return pos;
4731
+ }
4732
+ const values = [ctx._sv];
4733
+ while (values.length < max && (cur < input.length || values.length < min)) {
4734
+ const beforeSeparator = cur;
4735
+ let separatorPos = cur;
4736
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
4737
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
4738
+ if (separatorEnd < 0) break;
4739
+ let itemPos = separatorEnd;
4740
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
4741
+ const itemEnd = scalarChild(input, itemPos, ctx);
4742
+ if (itemEnd < 0) {
4743
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
4744
+ break;
4745
+ }
4746
+ values.push(ctx._sv);
4747
+ cur = itemEnd;
4748
+ }
4749
+ if (values.length < min) {
4750
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4751
+ return ~cur;
4752
+ }
4753
+ ctx._sv = values;
4754
+ return cur;
4755
+ };
4561
4756
  return {
4562
4757
  _tag: "sepBy",
4563
4758
  _meta: meta,
@@ -4573,6 +4768,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
4573
4768
  // this option surface already; parity is held by test/parity, not by hope.
4574
4769
  ...keepSeparators ? { keepSeparators: true } : {}
4575
4770
  },
4771
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
4576
4772
  parse(input, pos, ctx) {
4577
4773
  const first = combinator.parse(input, pos, ctx);
4578
4774
  const values = [];
@@ -5155,11 +5351,54 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
5155
5351
  }
5156
5352
 
5157
5353
  // src/combinators/map.ts
5354
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
5158
5355
  function transform(combinator, fn) {
5356
+ const observesSpan = fn.length > 1;
5357
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
5358
+ const terms = sequenceDef?.parsers;
5359
+ const inner = terms?.[1];
5360
+ const fused = terms?.length === 3 && terms[0]._def.tag === "literal" && terms[0]._def.value === '"' && !terms[0]._def.caseInsensitive && inner._def.tag === "regex" && inner._def.source === JSON_STRING_BODY && inner._def.flags === "" && terms[2]._def.tag === "literal" && terms[2]._def.value === '"' && !terms[2]._def.caseInsensitive && inner._stickyRegex !== void 0;
5361
+ const child = scalarOf(combinator);
5362
+ const parseScalar = fused ? (() => {
5363
+ const body = inner._stickyRegex;
5364
+ const tuple = ['"', "", '"'];
5365
+ const expected = [JSON.stringify('"')];
5366
+ return (input, pos, ctx) => {
5367
+ if (ctx.trivia !== void 0) {
5368
+ const end2 = child(input, pos, ctx);
5369
+ if (end2 < 0) return end2;
5370
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
5371
+ return end2;
5372
+ }
5373
+ if (input.charCodeAt(pos) !== 34) {
5374
+ ctx._fx = expected;
5375
+ return ~pos;
5376
+ }
5377
+ body.lastIndex = pos + 1;
5378
+ const match = body.exec(input);
5379
+ const close = pos + 1 + match[0].length;
5380
+ if (input.charCodeAt(close) !== 34) {
5381
+ ctx._fx = expected;
5382
+ return ~close;
5383
+ }
5384
+ tuple[1] = match[0];
5385
+ const end = close + 1;
5386
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
5387
+ return end;
5388
+ };
5389
+ })() : /* @__PURE__ */ (() => {
5390
+ return (input, pos, ctx) => {
5391
+ const end = child(input, pos, ctx);
5392
+ if (end < 0) return end;
5393
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
5394
+ return end;
5395
+ };
5396
+ })();
5159
5397
  return {
5160
5398
  _tag: "transform",
5161
5399
  _meta: combinator._meta,
5162
5400
  _def: { tag: "transform", parser: combinator, fn },
5401
+ _parseScalar: parseScalar,
5163
5402
  parse(input, pos, ctx) {
5164
5403
  const result = combinator.parse(input, pos, ctx);
5165
5404
  if (!result.ok) return result;
@@ -5174,9 +5413,11 @@ function trivia(combinator) {
5174
5413
  _meta: {
5175
5414
  ...combinator._meta,
5176
5415
  isTrivia: true,
5416
+ triviaScanner: fastTriviaScanner(combinator),
5177
5417
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
5178
5418
  },
5179
5419
  _def: { tag: "trivia", parser: combinator },
5420
+ _parseScalar: scalarOf(combinator),
5180
5421
  parse: combinator.parse.bind(combinator)
5181
5422
  };
5182
5423
  }
@@ -7979,7 +8220,7 @@ var Encoder = class {
7979
8220
  d.tags === void 0 ? -1 : this.constant(d.tags)
7980
8221
  );
7981
8222
  if (matchesEmpty(d.parser)) return body;
7982
- const fs = d.parser._meta.firstSet;
8223
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
7983
8224
  if (fs.kind === "any") return body;
7984
8225
  const cls = this.charClass(fs);
7985
8226
  if (cls < 0) return body;
@@ -8093,7 +8334,7 @@ var Encoder = class {
8093
8334
  case "attempt": {
8094
8335
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
8095
8336
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
8096
- const fs = d.parser._meta.firstSet;
8337
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
8097
8338
  if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
8098
8339
  const cls = this.charClass(fs);
8099
8340
  if (cls < 0) return inner;
@@ -9909,6 +10150,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
9909
10150
  function q(s) {
9910
10151
  return JSON.stringify(s);
9911
10152
  }
10153
+ function isAsciiOnlyClass(cls) {
10154
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
10155
+ }
9912
10156
  var NO_SINKS = { fd: false, er: false };
9913
10157
  function sinkSlots(t2, s) {
9914
10158
  return `${s.fd ? `,${t2}fd=0` : ""}${s.er ? `,${t2}er=0` : ""}`;
@@ -10455,12 +10699,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
10455
10699
  return `${head}EC.e=pos;return ''}`;
10456
10700
  case OP_GATE: {
10457
10701
  const child = link(code[ip + 2]);
10458
- const ci = classes.push([t2.cc[code[ip + 1]]]) - 1;
10702
+ const resolved = t2.cc[code[ip + 1]];
10703
+ const ci = classes.push([resolved]) - 1;
10459
10704
  classPlan.push([code[ip + 1]]);
10460
10705
  const cls = hoist("cl", `CLS[${ci}][0]`);
10461
10706
  const xf = fxRef(code[ip + 3]);
10462
10707
  return `${head}
10463
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10708
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10464
10709
  return ${child}(input,pos,ctx)
10465
10710
  }`;
10466
10711
  }
@@ -10803,10 +11048,11 @@ return v
10803
11048
  const asc = hoist("as", `DISP[${di}].ascii`);
10804
11049
  const hiArr = table.hi;
10805
11050
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
11051
+ const directAscii = staticBuild && table.hi.length === 0;
10806
11052
  return `${head}
10807
- const c=lead(input,pos)
11053
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10808
11054
  let arm=-1
10809
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
11055
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
10810
11056
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
10811
11057
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
10812
11058
  if(arm>=0){
@@ -10828,7 +11074,9 @@ return FAIL
10828
11074
  const di = code[ip + 1];
10829
11075
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10830
11076
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
10831
- const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
11077
+ const maskable = n <= 32;
11078
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
11079
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10832
11080
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10833
11081
  const pretests = Array.from({ length: n }, (_, i) => {
10834
11082
  if (tokenCandidate?.arm === i) {
@@ -10848,7 +11096,6 @@ return FAIL
10848
11096
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
10849
11097
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
10850
11098
  });
10851
- const maskable = n <= 32;
10852
11099
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
10853
11100
  if (maskable) maskPlan.push(~di);
10854
11101
  const p = tmp();
@@ -10910,16 +11157,16 @@ ${merge}
10910
11157
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
10911
11158
  return FAIL`;
10912
11159
  return `${head}
10913
- const c=lead(input,pos)
11160
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10914
11161
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10915
11162
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
10916
11163
  ${maskable ? `if(c<128){
10917
- const bits=${maskName}[c<0?128:c]
11164
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10918
11165
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10919
11166
  ${lazyArms(true)}
10920
- }else{
11167
+ }${directAsciiMask ? "" : `else{
10921
11168
  ${lazyArms(false)}
10922
- }
11169
+ }`}
10923
11170
  ` : lazyArms(false)}
10924
11171
  ${finish}
10925
11172
  }`;
@@ -10970,7 +11217,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
10970
11217
  ${rollbackFor(i)}
10971
11218
  }${routeMiss}${sequenceMiss}`;
10972
11219
  }).join("\n") : "";
10973
- const generalArms = arms.map((arm, i) => {
11220
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
10974
11221
  const pretest = pretests[i];
10975
11222
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10976
11223
  const scalarCondition = pretest?.scalar === void 0 ? "" : pretest.scalar.length === 1 ? `&&${pretest.scalar[0]}(input,pos)>=0` : `&&(${pretest.scalar.map((recognize) => `${recognize}(input,pos)>=0`).join("||")})`;
@@ -11000,12 +11247,12 @@ ${rollbackFor(i)}
11000
11247
  }${miss}`;
11001
11248
  }).join("\n");
11002
11249
  return `${head}
11003
- const c=lead(input,pos)
11250
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
11004
11251
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
11005
11252
  let acc
11006
11253
  let best=pos
11007
11254
  ${maskable ? `if(c<128){
11008
- const bits=${maskName}[c<0?128:c]
11255
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
11009
11256
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
11010
11257
  ${startFailureExact ? "" : "let prev=0"}
11011
11258
  ${maskArms}
@@ -11100,14 +11347,18 @@ return [key,v]
11100
11347
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
11101
11348
  const collect = op === OP_REP;
11102
11349
  let itemCls;
11350
+ let itemAscii = false;
11103
11351
  if (!REC) {
11104
11352
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
11105
11353
  if (itemClassIndex >= 0) {
11106
- const ci = classes.push([t2.cc[itemClassIndex]]) - 1;
11354
+ const resolved = t2.cc[itemClassIndex];
11355
+ const ci = classes.push([resolved]) - 1;
11107
11356
  classPlan.push([itemClassIndex]);
11108
11357
  itemCls = hoist("ri", `CLS[${ci}][0]`);
11358
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
11109
11359
  }
11110
11360
  }
11361
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
11111
11362
  const skipBeforeFirst = sepIp < 0 && min === 0;
11112
11363
  const p = tmp();
11113
11364
  const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -11167,7 +11418,7 @@ let count=0
11167
11418
  for(;;){
11168
11419
  ${max >= 0 ? `if(count>=${max})break
11169
11420
  ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
11170
- ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&!classHas(${itemCls},lead(input,cur)))break
11421
+ ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
11171
11422
  ` : ""}let ${p}raw=0,${p}tl=0,${p}lv=0,${p}lg=0,${p}rt=0${sinks.fd ? `,${p}fd=0` : ""}${sinks.er ? `,${p}er=0` : ""}
11172
11423
  ${markBody}
11173
11424
  let itemStart=cur
@@ -11192,7 +11443,7 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
11192
11443
  ${rb}
11193
11444
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
11194
11445
  }
11195
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
11446
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
11196
11447
  ${rb}
11197
11448
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
11198
11449
  }