parseman 0.50.1 → 0.50.3

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 (53) hide show
  1. package/README.md +14 -10
  2. package/dist/analysis/diagnostics.js +431 -219
  3. package/dist/analysis/diagnostics.js.map +3 -3
  4. package/dist/cli/index.js +421 -184
  5. package/dist/cli/index.js.map +3 -3
  6. package/dist/combinators/choice.d.ts.map +1 -1
  7. package/dist/combinators/grammar.d.ts.map +1 -1
  8. package/dist/combinators/keywords.d.ts.map +1 -1
  9. package/dist/combinators/literal.d.ts.map +1 -1
  10. package/dist/combinators/map.d.ts.map +1 -1
  11. package/dist/combinators/ref.d.ts.map +1 -1
  12. package/dist/combinators/regex.d.ts.map +1 -1
  13. package/dist/combinators/repeat.d.ts.map +1 -1
  14. package/dist/combinators/scalar.d.ts +6 -0
  15. package/dist/combinators/scalar.d.ts.map +1 -0
  16. package/dist/combinators/sequence.d.ts.map +1 -1
  17. package/dist/combinators/trivia-skip.d.ts +2 -0
  18. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  19. package/dist/compiler/token-capability.js +0 -3
  20. package/dist/compiler/token-capability.js.map +2 -2
  21. package/dist/index.js +422 -185
  22. package/dist/index.js.map +3 -3
  23. package/dist/language-service/index.js +68 -172
  24. package/dist/language-service/index.js.map +3 -3
  25. package/dist/parse-context.d.ts.map +1 -1
  26. package/dist/plugin/index.js +467 -299
  27. package/dist/plugin/index.js.map +3 -3
  28. package/dist/run/index.js +1 -0
  29. package/dist/run/index.js.map +1 -1
  30. package/dist/spec/index.js +399 -277
  31. package/dist/spec/index.js.map +3 -3
  32. package/dist/table/emit-assembly.d.ts.map +1 -1
  33. package/dist/table/index.js +307 -181
  34. package/dist/table/index.js.map +3 -3
  35. package/dist/types.d.ts +8 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/version.d.ts +1 -1
  38. package/package.json +4 -2
  39. package/src/combinators/choice.ts +34 -1
  40. package/src/combinators/grammar.ts +39 -0
  41. package/src/combinators/keywords.ts +14 -3
  42. package/src/combinators/literal.ts +26 -0
  43. package/src/combinators/map.ts +60 -0
  44. package/src/combinators/ref.ts +26 -7
  45. package/src/combinators/regex.ts +23 -0
  46. package/src/combinators/repeat.ts +109 -16
  47. package/src/combinators/scalar.ts +30 -0
  48. package/src/combinators/sequence.ts +76 -161
  49. package/src/combinators/trivia-skip.ts +14 -1
  50. package/src/parse-context.ts +1 -0
  51. package/src/table/emit-assembly.ts +39 -16
  52. package/src/types.ts +8 -0
  53. package/src/version.ts +1 -1
package/dist/cli/index.js CHANGED
@@ -689,9 +689,43 @@ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
689
689
  }
690
690
  }
691
691
 
692
+ // src/combinators/scalar.ts
693
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
694
+ function scalarOf(combinator) {
695
+ return combinator._parseScalar;
696
+ }
697
+ function scalarTree(parser2, seen) {
698
+ if (seen.has(parser2)) return true;
699
+ if (parser2._parseScalar === void 0) return false;
700
+ seen.add(parser2);
701
+ const def = parser2._def;
702
+ if (!SCALAR_TAG.test(def.tag)) return false;
703
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
704
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
705
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
706
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
707
+ }
708
+ function scalarRootOf(combinator) {
709
+ const scalar = combinator._parseScalar;
710
+ const def = combinator._def;
711
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
712
+ }
713
+
692
714
  // src/combinators/ref.ts
715
+ function withRuleTrivia(trivia2, ctx, run) {
716
+ const savedLabels = ctx.triviaKindLabels;
717
+ ctx.trivia = trivia2;
718
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
719
+ try {
720
+ return run();
721
+ } finally {
722
+ ctx.trivia = void 0;
723
+ ctx.triviaKindLabels = savedLabels;
724
+ }
725
+ }
693
726
  function ref() {
694
727
  let resolved = null;
728
+ let resolvedScalar = null;
695
729
  let ownBoundary = false;
696
730
  const meta = {
697
731
  firstSet: any(),
@@ -708,25 +742,28 @@ function ref() {
708
742
  return resolved;
709
743
  }
710
744
  },
745
+ _parseScalar(input, pos, ctx) {
746
+ const scalar = resolvedScalar;
747
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
748
+ const gt = meta.grammarTrivia;
749
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
750
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
751
+ }
752
+ return scalar(input, pos, ctx);
753
+ },
711
754
  parse(input, pos, ctx) {
712
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
755
+ const parser2 = resolved;
756
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
713
757
  const gt = meta.grammarTrivia;
714
758
  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
- }
759
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
724
760
  }
725
- return resolved.parse(input, pos, ctx);
761
+ return parser2.parse(input, pos, ctx);
726
762
  },
727
763
  define(p) {
728
764
  if (resolved) throw new Error("ref<T>() already defined");
729
765
  resolved = p;
766
+ resolvedScalar = scalarOf(p);
730
767
  ownBoundary = hasOwnTriviaBoundary(p);
731
768
  meta.firstSet = p._meta.firstSet;
732
769
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -1112,6 +1149,7 @@ function createParseContext() {
1112
1149
  _fe: void 0,
1113
1150
  _fx: void 0,
1114
1151
  _fc: void 0,
1152
+ _sv: void 0,
1115
1153
  _probe: void 0,
1116
1154
  _cstChildren: void 0,
1117
1155
  _cstLeaves: void 0,
@@ -1949,6 +1987,24 @@ function parser(opts, root) {
1949
1987
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
1950
1988
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
1951
1989
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
1990
+ const rootScalar = scalarOf(root);
1991
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
1992
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
1993
+ const savedTrivia = ctx.trivia;
1994
+ const savedLabels = ctx.triviaKindLabels;
1995
+ if (clearTrivia) {
1996
+ ctx.trivia = void 0;
1997
+ ctx.triviaKindLabels = void 0;
1998
+ } else if (scopeTrivia !== void 0) {
1999
+ ctx.trivia = scopeTrivia;
2000
+ ctx.triviaKindLabels = scopeLabels;
2001
+ }
2002
+ const end = rootScalar(input, pos, ctx);
2003
+ ctx.trivia = savedTrivia;
2004
+ ctx.triviaKindLabels = savedLabels;
2005
+ return end;
2006
+ } : void 0;
2007
+ let publicScalar;
1952
2008
  const grammar = {
1953
2009
  _tag: "grammar",
1954
2010
  _meta: {
@@ -1972,7 +2028,20 @@ function parser(opts, root) {
1972
2028
  constructionTrackLines: trackLinesPolicy,
1973
2029
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
1974
2030
  },
2031
+ _parseScalar: parseScalar,
1975
2032
  parse(input, pos, _ctx) {
2033
+ if (pos === void 0 && _ctx === void 0) {
2034
+ publicScalar ??= scalarRootOf(grammar) ?? null;
2035
+ if (publicScalar) {
2036
+ const ctx2 = createParseContext();
2037
+ const end = publicScalar(input, 0, ctx2);
2038
+ if (end < 0) {
2039
+ const at = ~end;
2040
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
2041
+ }
2042
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
2043
+ }
2044
+ }
1976
2045
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
1977
2046
  const trackLines = trackLinesOf(_ctx);
1978
2047
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -2007,6 +2076,9 @@ function parse(combinator, input, opts = {}) {
2007
2076
  _analyzed.add(combinator);
2008
2077
  markUnusedValues(combinator);
2009
2078
  }
2079
+ if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
2080
+ return combinator.parse(input);
2081
+ }
2010
2082
  const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
2011
2083
  const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
2012
2084
  const lineIndex = lineContext?.lineIndex;
@@ -2601,10 +2673,32 @@ function regex(pattern, flags = "") {
2601
2673
  const canMatchNewline = raw.canMatchNewline;
2602
2674
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
2603
2675
  const def = { tag: "regex", source, flags: resolvedFlags };
2676
+ const expected = directTerminalFailureExpected(def);
2677
+ const parseScalar = (input, pos, ctx) => {
2678
+ const scanEnd = scan?.(input, pos);
2679
+ if (scanEnd !== void 0) {
2680
+ if (scanEnd === null) {
2681
+ ctx._fx = expected;
2682
+ return ~pos;
2683
+ }
2684
+ ctx._sv = input.slice(pos, scanEnd);
2685
+ return scanEnd;
2686
+ }
2687
+ anchored.lastIndex = pos;
2688
+ const match = anchored.exec(input);
2689
+ if (match === null) {
2690
+ ctx._fx = expected;
2691
+ return ~pos;
2692
+ }
2693
+ ctx._sv = match[0];
2694
+ return pos + match[0].length;
2695
+ };
2604
2696
  return {
2605
2697
  _tag: "regex",
2606
2698
  _meta: meta,
2607
2699
  _def: def,
2700
+ _stickyRegex: anchored,
2701
+ _parseScalar: parseScalar,
2608
2702
  parse(input, pos, ctx) {
2609
2703
  const scanEnd = scan?.(input, pos);
2610
2704
  if (scanEnd !== void 0) {
@@ -2649,6 +2743,28 @@ function literal(value, opts = {}) {
2649
2743
  isTrivia: false
2650
2744
  };
2651
2745
  const canMatchNewline = meta.canMatchNewline;
2746
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
2747
+ const code = value.charCodeAt(0);
2748
+ return (input, pos, ctx) => {
2749
+ if (input.charCodeAt(pos) === code) {
2750
+ ctx._sv = value;
2751
+ return pos + 1;
2752
+ }
2753
+ ctx._fx = expected;
2754
+ return ~pos;
2755
+ };
2756
+ })() : (input, pos, ctx) => {
2757
+ const end = pos + value.length;
2758
+ if (end <= input.length) {
2759
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
2760
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
2761
+ ctx._sv = matchedValue;
2762
+ return end;
2763
+ }
2764
+ }
2765
+ ctx._fx = expected;
2766
+ return ~pos;
2767
+ };
2652
2768
  if (caseInsensitive) {
2653
2769
  const upper = value.toUpperCase();
2654
2770
  const lower = value.toLowerCase();
@@ -2689,6 +2805,7 @@ function literal(value, opts = {}) {
2689
2805
  _tag: "literal",
2690
2806
  _meta: meta,
2691
2807
  _def: { tag: "literal", value, caseInsensitive },
2808
+ _parseScalar: parseScalar,
2692
2809
  parse: parse2
2693
2810
  };
2694
2811
  }
@@ -2756,16 +2873,26 @@ function keywords(words, opts = {}) {
2756
2873
  caseInsensitive: opts.caseInsensitive ?? false,
2757
2874
  boundary: opts.boundary
2758
2875
  };
2876
+ const expected = directTerminalFailureExpected(def);
2877
+ const parseScalar = (input, pos, ctx) => {
2878
+ re.lastIndex = pos;
2879
+ const m = re.exec(input);
2880
+ if (m === null) {
2881
+ ctx._fx = expected;
2882
+ return ~pos;
2883
+ }
2884
+ ctx._sv = m[0];
2885
+ return pos + m[0].length;
2886
+ };
2759
2887
  return {
2760
2888
  _tag: "keywords",
2761
2889
  _meta: meta,
2762
2890
  _def: def,
2891
+ _parseScalar: parseScalar,
2763
2892
  parse(input, pos, ctx) {
2764
2893
  re.lastIndex = pos;
2765
2894
  const m = re.exec(input);
2766
- if (m === null || m.index !== pos) {
2767
- return failAt(ctx, directTerminalFailureExpected(def), pos);
2768
- }
2895
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
2769
2896
  const value = m[0];
2770
2897
  const span = { start: pos, end: pos + value.length };
2771
2898
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -2796,6 +2923,9 @@ var fastScanner3;
2796
2923
  function needsDeferredTriviaCommit(ctx) {
2797
2924
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
2798
2925
  }
2926
+ function needsTriviaRollback(ctx) {
2927
+ 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;
2928
+ }
2799
2929
  function saveTriviaMark(ctx) {
2800
2930
  const m = saveCstMark(ctx);
2801
2931
  return {
@@ -2912,7 +3042,8 @@ function advanceTrivia(input, cur, ctx) {
2912
3042
  const triviaP = ctx.trivia;
2913
3043
  if (!triviaP) return cur;
2914
3044
  if (!ctx.trackLines) {
2915
- const fast2 = fastTriviaScanner(triviaP);
3045
+ const classified = triviaP._meta.triviaScanner;
3046
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
2916
3047
  if (fast2) return fast2(input, cur);
2917
3048
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
2918
3049
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -3517,6 +3648,7 @@ function sequence(...parsers) {
3517
3648
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
3518
3649
  }
3519
3650
  const hasAdjacency = adjacency !== null;
3651
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
3520
3652
  const meta = {
3521
3653
  // Union through the nullable prefix — a leading optional()/many() lets a later
3522
3654
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -3525,165 +3657,96 @@ function sequence(...parsers) {
3525
3657
  isTrivia: false
3526
3658
  };
3527
3659
  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 : [];
3660
+ const scalarParsers = parsers.map(scalarOf);
3661
+ const parseScalar = (input, pos, ctx) => {
3538
3662
  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;
3663
+ if (strictArity !== 0) {
3664
+ cur = scalarParsers[0](input, cur, ctx);
3665
+ if (cur < 0) return cur;
3666
+ const first = ctx._sv;
3667
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3668
+ cur = scalarParsers[1](input, cur, ctx);
3669
+ if (cur < 0) return cur;
3670
+ const second = ctx._sv;
3671
+ if (strictArity === 2) {
3672
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
3673
+ return cur;
3581
3674
  }
3582
- } finally {
3583
- ctx._sync = inheritedSync;
3675
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3676
+ cur = scalarParsers[2](input, cur, ctx);
3677
+ if (cur < 0) return cur;
3678
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
3679
+ return cur;
3584
3680
  }
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
3681
  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
- }
3682
+ for (let i = 0; i < scalarParsers.length; i++) {
3683
+ let termPos = cur;
3684
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
3685
+ const end = scalarParsers[i](input, termPos, ctx);
3686
+ if (end < 0) return end;
3687
+ if (values !== void 0) values.push(ctx._sv);
3688
+ if (end > termPos || termPos === cur) cur = end;
3689
+ }
3690
+ ctx._sv = values;
3691
+ return cur;
3692
+ };
3693
+ let followSentinels;
3642
3694
  return {
3643
3695
  _tag: "sequence",
3644
3696
  _meta: meta,
3645
3697
  _def: def,
3698
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
3646
3699
  parse(input, pos, ctx) {
3647
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
3648
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
3700
+ const tolerant = ctx._tolerant === true;
3701
+ if (tolerant) {
3702
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
3703
+ parsers.slice(i + 1).reduce(
3704
+ (set, parser2) => union(set, firstSetOf(parser2)),
3705
+ { kind: "empty" }
3706
+ )
3707
+ ));
3708
+ }
3709
+ const inheritedSync = ctx._sync;
3710
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
3649
3711
  const values = def.valueUnused ? void 0 : [];
3650
3712
  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);
3713
+ try {
3714
+ for (let i = 0; i < parsers.length; i++) {
3715
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
3716
+ const assertion = adjacency?.[i];
3717
+ if (assertion) {
3718
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
3719
+ if (values !== void 0) values.push(null);
3720
+ continue;
3661
3721
  }
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 {
3722
+ let termPos = cur;
3723
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3724
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3725
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3726
+ if (ctx.trivia && i > 0) {
3727
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
3728
+ }
3729
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3730
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3731
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3732
+ const result = parsers[i].parse(input, termPos, ctx);
3733
+ if (!result.ok) return result;
3734
+ if (values !== void 0) values.push(result.value);
3735
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
3736
+ else if (deferredTrivia) {
3670
3737
  rollbackScannedTriviaAt(
3671
3738
  ctx,
3672
- mTlog,
3739
+ markTlog,
3673
3740
  scanTlog,
3674
- mLog,
3741
+ markLog,
3675
3742
  scanLog,
3676
- mRootLog,
3743
+ markRootLog,
3677
3744
  scanRootLog
3678
3745
  );
3679
3746
  }
3680
- if (values !== void 0) values.push(result2.value);
3681
- continue;
3682
3747
  }
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;
3748
+ } finally {
3749
+ if (tolerant) ctx._sync = inheritedSync;
3687
3750
  }
3688
3751
  return {
3689
3752
  ok: true,
@@ -3815,7 +3878,8 @@ function choice(...args) {
3815
3878
  disjoint
3816
3879
  };
3817
3880
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3818
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3881
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
3882
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
3819
3883
  let greedyLitMap = null;
3820
3884
  let sortedParsers = null;
3821
3885
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -3829,6 +3893,37 @@ function choice(...args) {
3829
3893
  } else if (strategy?.tag === "literalsLongestFirst") {
3830
3894
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
3831
3895
  }
3896
+ const scalarParsers = parsers.map(scalarOf);
3897
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
3898
+ const scalarExpected = parsers.flatMap(deriveExpected);
3899
+ const parseScalar = (input, pos, ctx) => {
3900
+ if (disjoint) {
3901
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3902
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3903
+ if (idx < 0 && code >= 0) {
3904
+ for (let i = 0; i < parsers.length; i++) {
3905
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3906
+ idx = i;
3907
+ break;
3908
+ }
3909
+ }
3910
+ }
3911
+ if (idx >= 0) {
3912
+ const gate = gates[idx];
3913
+ if (!gate || gate(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3914
+ ctx._fx = deriveExpected(parsers[idx]);
3915
+ return ~pos;
3916
+ }
3917
+ } else {
3918
+ for (let i = 0; i < scalarParsers.length; i++) {
3919
+ if (gates[i] && !gates[i](ctx.state)) continue;
3920
+ const end = scalarParsers[i](input, pos, ctx);
3921
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3922
+ }
3923
+ }
3924
+ ctx._fx = scalarExpected;
3925
+ return ~pos;
3926
+ };
3832
3927
  return {
3833
3928
  _tag: "choice",
3834
3929
  _meta: meta,
@@ -3840,6 +3935,7 @@ function choice(...args) {
3840
3935
  strategy: strategy ?? { tag: "firstMatch" },
3841
3936
  autoNot
3842
3937
  },
3938
+ _parseScalar: scalarEligible ? parseScalar : void 0,
3843
3939
  parse(input, pos, ctx) {
3844
3940
  const expected = [];
3845
3941
  let expectedAt = pos;
@@ -4371,8 +4467,8 @@ function attempt(parser2) {
4371
4467
  }
4372
4468
 
4373
4469
  // src/combinators/repeat.ts
4374
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4375
- const mark = saveTriviaMark(ctx);
4470
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
4471
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
4376
4472
  let pos = cur;
4377
4473
  if (ctx.trivia) {
4378
4474
  if (needsDeferredTriviaCommit(ctx)) {
@@ -4382,24 +4478,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4382
4478
  }
4383
4479
  }
4384
4480
  if (pos >= input.length && !mandatory) {
4385
- rollbackTrivia(ctx, mark);
4481
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4386
4482
  return "stop";
4387
4483
  }
4388
4484
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
4389
- rollbackTrivia(ctx, mark);
4485
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4390
4486
  return "stop";
4391
4487
  }
4392
4488
  const result = combinator.parse(input, pos, ctx);
4393
4489
  if (!result.ok) {
4394
- rollbackTrivia(ctx, mark);
4490
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4395
4491
  if (result.committed) return { fail: result, failPos: pos };
4396
4492
  return { fail: result, failPos: pos };
4397
4493
  }
4398
4494
  if (result.span.end === pos && !mandatory) {
4399
- rollbackTrivia(ctx, mark);
4495
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4400
4496
  return "stop";
4401
4497
  }
4402
- return { value: result.value, end: result.span.end };
4498
+ return result;
4403
4499
  }
4404
4500
  function resolveBounds(what, opts) {
4405
4501
  const min = opts.min ?? 0;
@@ -4412,6 +4508,21 @@ function resolveBounds(what, opts) {
4412
4508
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
4413
4509
  return { min, max };
4414
4510
  }
4511
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
4512
+ while (cur < input.length && remaining > 0) {
4513
+ let itemPos = cur;
4514
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4515
+ if (itemPos >= input.length) break;
4516
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
4517
+ const end = child(input, itemPos, ctx);
4518
+ if (end <= itemPos) break;
4519
+ if (values !== void 0) values.push(ctx._sv);
4520
+ cur = end;
4521
+ remaining--;
4522
+ }
4523
+ ctx._sv = values;
4524
+ return cur;
4525
+ }
4415
4526
  function many(combinator, opts = {}) {
4416
4527
  const { min, max } = resolveBounds("many()", opts);
4417
4528
  if (min >= 1) return atLeast(combinator, min, max);
@@ -4423,17 +4534,21 @@ function many(combinator, opts = {}) {
4423
4534
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
4424
4535
  let expected;
4425
4536
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4537
+ const scalarChild = scalarOf(combinator);
4538
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
4426
4539
  return {
4427
4540
  _tag: "many",
4428
4541
  _meta: meta,
4429
4542
  _def: def,
4543
+ _parseScalar: parseScalar,
4430
4544
  parse(input, pos, ctx) {
4431
4545
  const values = def.valueUnused ? void 0 : [];
4546
+ const rollbackNeeded = needsTriviaRollback(ctx);
4432
4547
  let cur = pos;
4433
4548
  let count = 0;
4434
4549
  while (cur < input.length) {
4435
4550
  if (count >= max) break;
4436
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4551
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4437
4552
  if (item === "stop") break;
4438
4553
  if ("fail" in item) {
4439
4554
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4450,7 +4565,7 @@ function many(combinator, opts = {}) {
4450
4565
  }
4451
4566
  if (values !== void 0) values.push(item.value);
4452
4567
  count++;
4453
- cur = item.end;
4568
+ cur = item.span.end;
4454
4569
  }
4455
4570
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4456
4571
  }
@@ -4468,30 +4583,47 @@ function atLeast(combinator, min, max) {
4468
4583
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4469
4584
  let expected;
4470
4585
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4586
+ const scalarChild = scalarOf(combinator);
4587
+ const parseScalar = (input, pos, ctx) => {
4588
+ let cur = scalarChild(input, pos, ctx);
4589
+ if (cur < 0) return cur;
4590
+ const values = def.valueUnused ? void 0 : [ctx._sv];
4591
+ for (let count = 1; count < min; count++) {
4592
+ let itemPos = cur;
4593
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4594
+ const end = scalarChild(input, itemPos, ctx);
4595
+ if (end < 0) return ~cur;
4596
+ cur = end;
4597
+ if (values !== void 0) values.push(ctx._sv);
4598
+ }
4599
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
4600
+ };
4471
4601
  return {
4472
4602
  _tag: "oneOrMore",
4473
4603
  _meta: meta,
4474
4604
  _def: def,
4605
+ _parseScalar: parseScalar,
4475
4606
  parse(input, pos, ctx) {
4476
4607
  const first = combinator.parse(input, pos, ctx);
4477
4608
  if (!first.ok) return first;
4478
4609
  const values = def.valueUnused ? void 0 : [first.value];
4610
+ const rollbackNeeded = needsTriviaRollback(ctx);
4479
4611
  let cur = first.span.end;
4480
4612
  let count = 1;
4481
4613
  while (count < min) {
4482
- const item = repItem(combinator, input, cur, ctx, guardable, true);
4614
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
4483
4615
  if (item === "stop" || "fail" in item) {
4484
4616
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4485
4617
  expected ??= deriveExpected(combinator);
4486
4618
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4487
4619
  }
4488
4620
  if (values !== void 0) values.push(item.value);
4489
- cur = item.end;
4621
+ cur = item.span.end;
4490
4622
  count++;
4491
4623
  }
4492
4624
  while (cur < input.length) {
4493
4625
  if (count >= max) break;
4494
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4626
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4495
4627
  if (item === "stop") break;
4496
4628
  if ("fail" in item) {
4497
4629
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4508,7 +4640,7 @@ function atLeast(combinator, min, max) {
4508
4640
  }
4509
4641
  if (values !== void 0) values.push(item.value);
4510
4642
  count++;
4511
- cur = item.end;
4643
+ cur = item.span.end;
4512
4644
  }
4513
4645
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4514
4646
  }
@@ -4521,10 +4653,22 @@ function optional(combinator) {
4521
4653
  isTrivia: false
4522
4654
  };
4523
4655
  const firstSetSkippable = !matchesEmpty(combinator);
4656
+ const scalarChild = scalarOf(combinator);
4657
+ const parseScalar = (input, pos, ctx) => {
4658
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
4659
+ ctx._sv = null;
4660
+ return pos;
4661
+ }
4662
+ const end = scalarChild(input, pos, ctx);
4663
+ if (end >= 0) return end;
4664
+ ctx._sv = null;
4665
+ return pos;
4666
+ };
4524
4667
  return {
4525
4668
  _tag: "optional",
4526
4669
  _meta: meta,
4527
4670
  _def: { tag: "optional", parser: combinator },
4671
+ _parseScalar: parseScalar,
4528
4672
  parse(input, pos, ctx) {
4529
4673
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4530
4674
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -4558,6 +4702,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
4558
4702
  expected ??= deriveExpected(combinator);
4559
4703
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4560
4704
  };
4705
+ const scalarExpected = deriveExpected(combinator);
4706
+ const scalarChild = scalarOf(combinator);
4707
+ const scalarSeparator = scalarOf(separator);
4708
+ const parseScalar = (input, pos, ctx) => {
4709
+ let cur = scalarChild(input, pos, ctx);
4710
+ if (cur < 0) {
4711
+ if (min >= 1) {
4712
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4713
+ return ~pos;
4714
+ }
4715
+ ctx._sv = [];
4716
+ return pos;
4717
+ }
4718
+ const values = [ctx._sv];
4719
+ while (values.length < max && (cur < input.length || values.length < min)) {
4720
+ const beforeSeparator = cur;
4721
+ let separatorPos = cur;
4722
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
4723
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
4724
+ if (separatorEnd < 0) break;
4725
+ let itemPos = separatorEnd;
4726
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
4727
+ const itemEnd = scalarChild(input, itemPos, ctx);
4728
+ if (itemEnd < 0) {
4729
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
4730
+ break;
4731
+ }
4732
+ values.push(ctx._sv);
4733
+ cur = itemEnd;
4734
+ }
4735
+ if (values.length < min) {
4736
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4737
+ return ~cur;
4738
+ }
4739
+ ctx._sv = values;
4740
+ return cur;
4741
+ };
4561
4742
  return {
4562
4743
  _tag: "sepBy",
4563
4744
  _meta: meta,
@@ -4573,6 +4754,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
4573
4754
  // this option surface already; parity is held by test/parity, not by hope.
4574
4755
  ...keepSeparators ? { keepSeparators: true } : {}
4575
4756
  },
4757
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
4576
4758
  parse(input, pos, ctx) {
4577
4759
  const first = combinator.parse(input, pos, ctx);
4578
4760
  const values = [];
@@ -5155,11 +5337,54 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
5155
5337
  }
5156
5338
 
5157
5339
  // src/combinators/map.ts
5340
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
5158
5341
  function transform(combinator, fn) {
5342
+ const observesSpan = fn.length > 1;
5343
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
5344
+ const terms = sequenceDef?.parsers;
5345
+ const inner = terms?.[1];
5346
+ 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;
5347
+ const child = scalarOf(combinator);
5348
+ const parseScalar = fused ? (() => {
5349
+ const body = inner._stickyRegex;
5350
+ const tuple = ['"', "", '"'];
5351
+ const expected = [JSON.stringify('"')];
5352
+ return (input, pos, ctx) => {
5353
+ if (ctx.trivia !== void 0) {
5354
+ const end2 = child(input, pos, ctx);
5355
+ if (end2 < 0) return end2;
5356
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
5357
+ return end2;
5358
+ }
5359
+ if (input.charCodeAt(pos) !== 34) {
5360
+ ctx._fx = expected;
5361
+ return ~pos;
5362
+ }
5363
+ body.lastIndex = pos + 1;
5364
+ const match = body.exec(input);
5365
+ const close = pos + 1 + match[0].length;
5366
+ if (input.charCodeAt(close) !== 34) {
5367
+ ctx._fx = expected;
5368
+ return ~close;
5369
+ }
5370
+ tuple[1] = match[0];
5371
+ const end = close + 1;
5372
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
5373
+ return end;
5374
+ };
5375
+ })() : /* @__PURE__ */ (() => {
5376
+ return (input, pos, ctx) => {
5377
+ const end = child(input, pos, ctx);
5378
+ if (end < 0) return end;
5379
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
5380
+ return end;
5381
+ };
5382
+ })();
5159
5383
  return {
5160
5384
  _tag: "transform",
5161
5385
  _meta: combinator._meta,
5162
5386
  _def: { tag: "transform", parser: combinator, fn },
5387
+ _parseScalar: parseScalar,
5163
5388
  parse(input, pos, ctx) {
5164
5389
  const result = combinator.parse(input, pos, ctx);
5165
5390
  if (!result.ok) return result;
@@ -5174,9 +5399,11 @@ function trivia(combinator) {
5174
5399
  _meta: {
5175
5400
  ...combinator._meta,
5176
5401
  isTrivia: true,
5402
+ triviaScanner: fastTriviaScanner(combinator),
5177
5403
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
5178
5404
  },
5179
5405
  _def: { tag: "trivia", parser: combinator },
5406
+ _parseScalar: scalarOf(combinator),
5180
5407
  parse: combinator.parse.bind(combinator)
5181
5408
  };
5182
5409
  }
@@ -9909,6 +10136,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
9909
10136
  function q(s) {
9910
10137
  return JSON.stringify(s);
9911
10138
  }
10139
+ function isAsciiOnlyClass(cls) {
10140
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
10141
+ }
9912
10142
  var NO_SINKS = { fd: false, er: false };
9913
10143
  function sinkSlots(t2, s) {
9914
10144
  return `${s.fd ? `,${t2}fd=0` : ""}${s.er ? `,${t2}er=0` : ""}`;
@@ -10455,12 +10685,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
10455
10685
  return `${head}EC.e=pos;return ''}`;
10456
10686
  case OP_GATE: {
10457
10687
  const child = link(code[ip + 2]);
10458
- const ci = classes.push([t2.cc[code[ip + 1]]]) - 1;
10688
+ const resolved = t2.cc[code[ip + 1]];
10689
+ const ci = classes.push([resolved]) - 1;
10459
10690
  classPlan.push([code[ip + 1]]);
10460
10691
  const cls = hoist("cl", `CLS[${ci}][0]`);
10461
10692
  const xf = fxRef(code[ip + 3]);
10462
10693
  return `${head}
10463
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10694
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10464
10695
  return ${child}(input,pos,ctx)
10465
10696
  }`;
10466
10697
  }
@@ -10803,10 +11034,11 @@ return v
10803
11034
  const asc = hoist("as", `DISP[${di}].ascii`);
10804
11035
  const hiArr = table.hi;
10805
11036
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
11037
+ const directAscii = staticBuild && table.hi.length === 0;
10806
11038
  return `${head}
10807
- const c=lead(input,pos)
11039
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10808
11040
  let arm=-1
10809
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
11041
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
10810
11042
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
10811
11043
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
10812
11044
  if(arm>=0){
@@ -10828,7 +11060,9 @@ return FAIL
10828
11060
  const di = code[ip + 1];
10829
11061
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10830
11062
  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}]`));
11063
+ const maskable = n <= 32;
11064
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
11065
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10832
11066
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10833
11067
  const pretests = Array.from({ length: n }, (_, i) => {
10834
11068
  if (tokenCandidate?.arm === i) {
@@ -10848,7 +11082,6 @@ return FAIL
10848
11082
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
10849
11083
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
10850
11084
  });
10851
- const maskable = n <= 32;
10852
11085
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
10853
11086
  if (maskable) maskPlan.push(~di);
10854
11087
  const p = tmp();
@@ -10910,16 +11143,16 @@ ${merge}
10910
11143
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
10911
11144
  return FAIL`;
10912
11145
  return `${head}
10913
- const c=lead(input,pos)
11146
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10914
11147
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10915
11148
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
10916
11149
  ${maskable ? `if(c<128){
10917
- const bits=${maskName}[c<0?128:c]
11150
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10918
11151
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10919
11152
  ${lazyArms(true)}
10920
- }else{
11153
+ }${directAsciiMask ? "" : `else{
10921
11154
  ${lazyArms(false)}
10922
- }
11155
+ }`}
10923
11156
  ` : lazyArms(false)}
10924
11157
  ${finish}
10925
11158
  }`;
@@ -10970,7 +11203,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
10970
11203
  ${rollbackFor(i)}
10971
11204
  }${routeMiss}${sequenceMiss}`;
10972
11205
  }).join("\n") : "";
10973
- const generalArms = arms.map((arm, i) => {
11206
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
10974
11207
  const pretest = pretests[i];
10975
11208
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10976
11209
  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 +11233,12 @@ ${rollbackFor(i)}
11000
11233
  }${miss}`;
11001
11234
  }).join("\n");
11002
11235
  return `${head}
11003
- const c=lead(input,pos)
11236
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
11004
11237
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
11005
11238
  let acc
11006
11239
  let best=pos
11007
11240
  ${maskable ? `if(c<128){
11008
- const bits=${maskName}[c<0?128:c]
11241
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
11009
11242
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
11010
11243
  ${startFailureExact ? "" : "let prev=0"}
11011
11244
  ${maskArms}
@@ -11100,14 +11333,18 @@ return [key,v]
11100
11333
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
11101
11334
  const collect = op === OP_REP;
11102
11335
  let itemCls;
11336
+ let itemAscii = false;
11103
11337
  if (!REC) {
11104
11338
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
11105
11339
  if (itemClassIndex >= 0) {
11106
- const ci = classes.push([t2.cc[itemClassIndex]]) - 1;
11340
+ const resolved = t2.cc[itemClassIndex];
11341
+ const ci = classes.push([resolved]) - 1;
11107
11342
  classPlan.push([itemClassIndex]);
11108
11343
  itemCls = hoist("ri", `CLS[${ci}][0]`);
11344
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
11109
11345
  }
11110
11346
  }
11347
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
11111
11348
  const skipBeforeFirst = sepIp < 0 && min === 0;
11112
11349
  const p = tmp();
11113
11350
  const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -11167,7 +11404,7 @@ let count=0
11167
11404
  for(;;){
11168
11405
  ${max >= 0 ? `if(count>=${max})break
11169
11406
  ` : ""}${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
11407
+ ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
11171
11408
  ` : ""}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
11409
  ${markBody}
11173
11410
  let itemStart=cur
@@ -11192,7 +11429,7 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
11192
11429
  ${rb}
11193
11430
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
11194
11431
  }
11195
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
11432
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
11196
11433
  ${rb}
11197
11434
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
11198
11435
  }