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
@@ -35,10 +35,20 @@ function classifyFinalChoice(arms, resolve) {
35
35
  }
36
36
  return { exclusive, firstSets, nullable: nullable2 };
37
37
  }
38
- function resolveNamedRef(p, resolve) {
38
+ function winnerForRef(p, resolve) {
39
39
  if (resolve === void 0) return void 0;
40
40
  const name = p._ruleName;
41
- return name === void 0 ? void 0 : resolve(name);
41
+ const w = name === void 0 ? void 0 : resolve(name);
42
+ if (w === void 0 || w === p) return void 0;
43
+ let cur = w;
44
+ for (const seen = /* @__PURE__ */ new Set(); !seen.has(cur); ) {
45
+ if (cur === p) return void 0;
46
+ seen.add(cur);
47
+ const cd = cur._def;
48
+ if (cd.tag !== "grammar" && cd.tag !== "trivia") return w;
49
+ cur = cd.parser;
50
+ }
51
+ return w;
42
52
  }
43
53
  function union(a, b) {
44
54
  if (a.kind === "any" || b.kind === "any") return { kind: "any" };
@@ -136,13 +146,15 @@ function matchesEmptyBody(p, seen, resolve) {
136
146
  case "grammar":
137
147
  case "recover":
138
148
  return me(d.parser);
139
- case "lazy":
149
+ case "lazy": {
150
+ const w = winnerForRef(p, resolve);
151
+ if (w !== void 0) return me(w);
140
152
  try {
141
153
  return me(d.thunk());
142
154
  } catch {
143
- const t = resolveNamedRef(p, resolve);
144
- return t ? me(t) : true;
155
+ return true;
145
156
  }
157
+ }
146
158
  default:
147
159
  return true;
148
160
  }
@@ -206,13 +218,15 @@ function firstSetBody(p, seen, resolve) {
206
218
  // terminals: no refs, cached set is exact
207
219
  case "dispatch":
208
220
  return fs(d.selector);
209
- case "lazy":
221
+ case "lazy": {
222
+ const w = winnerForRef(p, resolve);
223
+ if (w !== void 0) return fs(w);
210
224
  try {
211
225
  return fs(d.thunk());
212
226
  } catch {
213
- const t = resolveNamedRef(p, resolve);
214
- return t ? fs(t) : any();
227
+ return any();
215
228
  }
229
+ }
216
230
  case "choice": {
217
231
  let out = empty();
218
232
  for (const arm of d.parsers) out = union(out, fs(arm));
@@ -522,6 +536,28 @@ function literal(value, opts = {}) {
522
536
  isTrivia: false
523
537
  };
524
538
  const canMatchNewline = meta.canMatchNewline;
539
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
540
+ const code = value.charCodeAt(0);
541
+ return (input, pos, ctx) => {
542
+ if (input.charCodeAt(pos) === code) {
543
+ ctx._sv = value;
544
+ return pos + 1;
545
+ }
546
+ ctx._fx = expected;
547
+ return ~pos;
548
+ };
549
+ })() : (input, pos, ctx) => {
550
+ const end = pos + value.length;
551
+ if (end <= input.length) {
552
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
553
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
554
+ ctx._sv = matchedValue;
555
+ return end;
556
+ }
557
+ }
558
+ ctx._fx = expected;
559
+ return ~pos;
560
+ };
525
561
  if (caseInsensitive) {
526
562
  const upper = value.toUpperCase();
527
563
  const lower = value.toLowerCase();
@@ -562,6 +598,7 @@ function literal(value, opts = {}) {
562
598
  _tag: "literal",
563
599
  _meta: meta,
564
600
  _def: { tag: "literal", value, caseInsensitive },
601
+ _parseScalar: parseScalar,
565
602
  parse
566
603
  };
567
604
  }
@@ -1018,10 +1055,32 @@ function regex(pattern, flags = "") {
1018
1055
  const canMatchNewline = raw.canMatchNewline;
1019
1056
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
1020
1057
  const def = { tag: "regex", source, flags: resolvedFlags };
1058
+ const expected = directTerminalFailureExpected(def);
1059
+ const parseScalar = (input, pos, ctx) => {
1060
+ const scanEnd = scan?.(input, pos);
1061
+ if (scanEnd !== void 0) {
1062
+ if (scanEnd === null) {
1063
+ ctx._fx = expected;
1064
+ return ~pos;
1065
+ }
1066
+ ctx._sv = input.slice(pos, scanEnd);
1067
+ return scanEnd;
1068
+ }
1069
+ anchored.lastIndex = pos;
1070
+ const match = anchored.exec(input);
1071
+ if (match === null) {
1072
+ ctx._fx = expected;
1073
+ return ~pos;
1074
+ }
1075
+ ctx._sv = match[0];
1076
+ return pos + match[0].length;
1077
+ };
1021
1078
  return {
1022
1079
  _tag: "regex",
1023
1080
  _meta: meta,
1024
1081
  _def: def,
1082
+ _stickyRegex: anchored,
1083
+ _parseScalar: parseScalar,
1025
1084
  parse(input, pos, ctx) {
1026
1085
  const scanEnd = scan?.(input, pos);
1027
1086
  if (scanEnd !== void 0) {
@@ -1063,6 +1122,7 @@ function createParseContext() {
1063
1122
  _fe: void 0,
1064
1123
  _fx: void 0,
1065
1124
  _fc: void 0,
1125
+ _sv: void 0,
1066
1126
  _probe: void 0,
1067
1127
  _cstChildren: void 0,
1068
1128
  _cstLeaves: void 0,
@@ -1754,6 +1814,9 @@ var fastScanner3;
1754
1814
  function needsDeferredTriviaCommit(ctx) {
1755
1815
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1756
1816
  }
1817
+ function needsTriviaRollback(ctx) {
1818
+ 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;
1819
+ }
1757
1820
  function saveTriviaMark(ctx) {
1758
1821
  const m = saveCstMark(ctx);
1759
1822
  return {
@@ -1863,7 +1926,8 @@ function advanceTrivia(input, cur, ctx) {
1863
1926
  const triviaP = ctx.trivia;
1864
1927
  if (!triviaP) return cur;
1865
1928
  if (!ctx.trackLines) {
1866
- const fast2 = fastTriviaScanner(triviaP);
1929
+ const classified = triviaP._meta.triviaScanner;
1930
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
1867
1931
  if (fast2) return fast2(input, cur);
1868
1932
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
1869
1933
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -2416,6 +2480,11 @@ function adjacencyMisuse(polarity) {
2416
2480
  return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
2417
2481
  }
2418
2482
 
2483
+ // src/combinators/scalar.ts
2484
+ function scalarOf(combinator) {
2485
+ return combinator._parseScalar;
2486
+ }
2487
+
2419
2488
  // src/combinators/sequence.ts
2420
2489
  function sequence(...parsers) {
2421
2490
  let adjacency = null;
@@ -2431,6 +2500,7 @@ function sequence(...parsers) {
2431
2500
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
2432
2501
  }
2433
2502
  const hasAdjacency = adjacency !== null;
2503
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
2434
2504
  const meta = {
2435
2505
  // Union through the nullable prefix — a leading optional()/many() lets a later
2436
2506
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -2439,165 +2509,96 @@ function sequence(...parsers) {
2439
2509
  isTrivia: false
2440
2510
  };
2441
2511
  const def = { tag: "sequence", parsers };
2442
- let followSentinels;
2443
- function parseTolerant(input, pos, ctx) {
2444
- followSentinels ??= parsers.map((_, i) => {
2445
- const fs = parsers.slice(i + 1).reduce(
2446
- (acc, p) => union(acc, firstSetOf(p)),
2447
- { kind: "empty" }
2448
- );
2449
- return firstSetSentinel(fs);
2450
- });
2451
- const values = def.valueUnused ? void 0 : [];
2512
+ const scalarParsers = parsers.map(scalarOf);
2513
+ const parseScalar = (input, pos, ctx) => {
2452
2514
  let cur = pos;
2453
- const inheritedSync = ctx._sync;
2454
- try {
2455
- for (let i = 0; i < parsers.length; i++) {
2456
- ctx._sync = followSentinels[i] ?? inheritedSync;
2457
- const adj = adjacency === null ? null : adjacency[i];
2458
- if (adj) {
2459
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
2460
- if (values !== void 0) values.push(null);
2461
- continue;
2462
- }
2463
- if (ctx.trivia && i > 0) {
2464
- const mTlog = cstTlLen(ctx);
2465
- const mLog = ctx._triviaLog?.length ?? 0;
2466
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2467
- let scanEnd;
2468
- if (needsDeferredTriviaCommit(ctx)) {
2469
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
2470
- } else {
2471
- scanEnd = advanceTrivia(input, cur, ctx);
2472
- }
2473
- const scanTlog = cstTlLen(ctx);
2474
- const scanLog = ctx._triviaLog?.length ?? 0;
2475
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2476
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2477
- if (!result2.ok) return result2;
2478
- if (result2.span.end > scanEnd) cur = result2.span.end;
2479
- else rollbackScannedTriviaAt(
2480
- ctx,
2481
- mTlog,
2482
- scanTlog,
2483
- mLog,
2484
- scanLog,
2485
- mRootLog,
2486
- scanRootLog
2487
- );
2488
- if (values !== void 0) values.push(result2.value);
2489
- continue;
2490
- }
2491
- const result = parsers[i].parse(input, cur, ctx);
2492
- if (!result.ok) return result;
2493
- if (values !== void 0) values.push(result.value);
2494
- cur = result.span.end;
2515
+ if (strictArity !== 0) {
2516
+ cur = scalarParsers[0](input, cur, ctx);
2517
+ if (cur < 0) return cur;
2518
+ const first = ctx._sv;
2519
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
2520
+ cur = scalarParsers[1](input, cur, ctx);
2521
+ if (cur < 0) return cur;
2522
+ const second = ctx._sv;
2523
+ if (strictArity === 2) {
2524
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
2525
+ return cur;
2495
2526
  }
2496
- } finally {
2497
- ctx._sync = inheritedSync;
2527
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
2528
+ cur = scalarParsers[2](input, cur, ctx);
2529
+ if (cur < 0) return cur;
2530
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
2531
+ return cur;
2498
2532
  }
2499
- return {
2500
- ok: true,
2501
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2502
- value: values ?? void 0,
2503
- span: { start: pos, end: cur }
2504
- };
2505
- }
2506
- function parseAdjacent(input, pos, ctx) {
2507
2533
  const values = def.valueUnused ? void 0 : [];
2508
- let cur = pos;
2509
- for (let i = 0; i < parsers.length; i++) {
2510
- const adj = adjacency[i];
2511
- if (adj) {
2512
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
2513
- if (values !== void 0) values.push(null);
2514
- continue;
2515
- }
2516
- if (ctx.trivia && i > 0) {
2517
- let scanEnd;
2518
- const mTlog = cstTlLen(ctx);
2519
- const mLog = ctx._triviaLog?.length ?? 0;
2520
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2521
- if (needsDeferredTriviaCommit(ctx)) {
2522
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
2523
- } else {
2524
- scanEnd = advanceTrivia(input, cur, ctx);
2525
- }
2526
- const scanTlog = cstTlLen(ctx);
2527
- const scanLog = ctx._triviaLog?.length ?? 0;
2528
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2529
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2530
- if (!result2.ok) return result2;
2531
- if (result2.span.end > scanEnd) cur = result2.span.end;
2532
- else rollbackScannedTriviaAt(
2533
- ctx,
2534
- mTlog,
2535
- scanTlog,
2536
- mLog,
2537
- scanLog,
2538
- mRootLog,
2539
- scanRootLog
2540
- );
2541
- if (values !== void 0) values.push(result2.value);
2542
- continue;
2543
- }
2544
- const result = parsers[i].parse(input, cur, ctx);
2545
- if (!result.ok) return result;
2546
- if (values !== void 0) values.push(result.value);
2547
- cur = result.span.end;
2548
- }
2549
- return {
2550
- ok: true,
2551
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2552
- value: values ?? void 0,
2553
- span: { start: pos, end: cur }
2554
- };
2555
- }
2534
+ for (let i = 0; i < scalarParsers.length; i++) {
2535
+ let termPos = cur;
2536
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
2537
+ const end = scalarParsers[i](input, termPos, ctx);
2538
+ if (end < 0) return end;
2539
+ if (values !== void 0) values.push(ctx._sv);
2540
+ if (end > termPos || termPos === cur) cur = end;
2541
+ }
2542
+ ctx._sv = values;
2543
+ return cur;
2544
+ };
2545
+ let followSentinels;
2556
2546
  return {
2557
2547
  _tag: "sequence",
2558
2548
  _meta: meta,
2559
2549
  _def: def,
2550
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
2560
2551
  parse(input, pos, ctx) {
2561
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
2562
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
2552
+ const tolerant = ctx._tolerant === true;
2553
+ if (tolerant) {
2554
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
2555
+ parsers.slice(i + 1).reduce(
2556
+ (set, parser) => union(set, firstSetOf(parser)),
2557
+ { kind: "empty" }
2558
+ )
2559
+ ));
2560
+ }
2561
+ const inheritedSync = ctx._sync;
2562
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
2563
2563
  const values = def.valueUnused ? void 0 : [];
2564
2564
  let cur = pos;
2565
- for (let i = 0; i < parsers.length; i++) {
2566
- if (ctx.trivia && i > 0) {
2567
- let scanEnd;
2568
- const mTlog = cstTlLen(ctx);
2569
- const mLog = ctx._triviaLog?.length ?? 0;
2570
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2571
- if (needsDeferredTriviaCommit(ctx)) {
2572
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
2573
- } else {
2574
- scanEnd = advanceTrivia(input, cur, ctx);
2565
+ try {
2566
+ for (let i = 0; i < parsers.length; i++) {
2567
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
2568
+ const assertion = adjacency?.[i];
2569
+ if (assertion) {
2570
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
2571
+ if (values !== void 0) values.push(null);
2572
+ continue;
2575
2573
  }
2576
- const scanTlog = cstTlLen(ctx);
2577
- const scanLog = ctx._triviaLog?.length ?? 0;
2578
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2579
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2580
- if (!result2.ok) return result2;
2581
- if (result2.span.end > scanEnd) {
2582
- cur = result2.span.end;
2583
- } else {
2574
+ let termPos = cur;
2575
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
2576
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
2577
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
2578
+ if (ctx.trivia && i > 0) {
2579
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
2580
+ }
2581
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
2582
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
2583
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
2584
+ const result = parsers[i].parse(input, termPos, ctx);
2585
+ if (!result.ok) return result;
2586
+ if (values !== void 0) values.push(result.value);
2587
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
2588
+ else if (deferredTrivia) {
2584
2589
  rollbackScannedTriviaAt(
2585
2590
  ctx,
2586
- mTlog,
2591
+ markTlog,
2587
2592
  scanTlog,
2588
- mLog,
2593
+ markLog,
2589
2594
  scanLog,
2590
- mRootLog,
2595
+ markRootLog,
2591
2596
  scanRootLog
2592
2597
  );
2593
2598
  }
2594
- if (values !== void 0) values.push(result2.value);
2595
- continue;
2596
2599
  }
2597
- const result = parsers[i].parse(input, cur, ctx);
2598
- if (!result.ok) return result;
2599
- if (values !== void 0) values.push(result.value);
2600
- cur = result.span.end;
2600
+ } finally {
2601
+ if (tolerant) ctx._sync = inheritedSync;
2601
2602
  }
2602
2603
  return {
2603
2604
  ok: true,
@@ -2729,7 +2730,8 @@ function choice(...args) {
2729
2730
  disjoint
2730
2731
  };
2731
2732
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
2732
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
2733
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
2734
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
2733
2735
  let greedyLitMap = null;
2734
2736
  let sortedParsers = null;
2735
2737
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -2743,6 +2745,37 @@ function choice(...args) {
2743
2745
  } else if (strategy?.tag === "literalsLongestFirst") {
2744
2746
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
2745
2747
  }
2748
+ const scalarParsers = parsers.map(scalarOf);
2749
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
2750
+ const scalarExpected = parsers.flatMap(deriveExpected);
2751
+ const parseScalar = (input, pos, ctx) => {
2752
+ if (disjoint) {
2753
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
2754
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
2755
+ if (idx < 0 && code >= 0) {
2756
+ for (let i = 0; i < parsers.length; i++) {
2757
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
2758
+ idx = i;
2759
+ break;
2760
+ }
2761
+ }
2762
+ }
2763
+ if (idx >= 0) {
2764
+ const gate = gates[idx];
2765
+ if (!gate || gate(ctx.state)) return scalarParsers[idx](input, pos, ctx);
2766
+ ctx._fx = deriveExpected(parsers[idx]);
2767
+ return ~pos;
2768
+ }
2769
+ } else {
2770
+ for (let i = 0; i < scalarParsers.length; i++) {
2771
+ if (gates[i] && !gates[i](ctx.state)) continue;
2772
+ const end = scalarParsers[i](input, pos, ctx);
2773
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
2774
+ }
2775
+ }
2776
+ ctx._fx = scalarExpected;
2777
+ return ~pos;
2778
+ };
2746
2779
  return {
2747
2780
  _tag: "choice",
2748
2781
  _meta: meta,
@@ -2754,6 +2787,7 @@ function choice(...args) {
2754
2787
  strategy: strategy ?? { tag: "firstMatch" },
2755
2788
  autoNot
2756
2789
  },
2790
+ _parseScalar: scalarEligible ? parseScalar : void 0,
2757
2791
  parse(input, pos, ctx) {
2758
2792
  const expected = [];
2759
2793
  let expectedAt = pos;
@@ -3014,8 +3048,8 @@ function buildAsciiDispatch(parsers) {
3014
3048
  }
3015
3049
 
3016
3050
  // src/combinators/repeat.ts
3017
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3018
- const mark = saveTriviaMark(ctx);
3051
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
3052
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
3019
3053
  let pos = cur;
3020
3054
  if (ctx.trivia) {
3021
3055
  if (needsDeferredTriviaCommit(ctx)) {
@@ -3025,24 +3059,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3025
3059
  }
3026
3060
  }
3027
3061
  if (pos >= input.length && !mandatory) {
3028
- rollbackTrivia(ctx, mark);
3062
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3029
3063
  return "stop";
3030
3064
  }
3031
3065
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
3032
- rollbackTrivia(ctx, mark);
3066
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3033
3067
  return "stop";
3034
3068
  }
3035
3069
  const result = combinator.parse(input, pos, ctx);
3036
3070
  if (!result.ok) {
3037
- rollbackTrivia(ctx, mark);
3071
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3038
3072
  if (result.committed) return { fail: result, failPos: pos };
3039
3073
  return { fail: result, failPos: pos };
3040
3074
  }
3041
3075
  if (result.span.end === pos && !mandatory) {
3042
- rollbackTrivia(ctx, mark);
3076
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3043
3077
  return "stop";
3044
3078
  }
3045
- return { value: result.value, end: result.span.end };
3079
+ return result;
3046
3080
  }
3047
3081
  function resolveBounds(what, opts) {
3048
3082
  const min = opts.min ?? 0;
@@ -3055,6 +3089,21 @@ function resolveBounds(what, opts) {
3055
3089
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
3056
3090
  return { min, max };
3057
3091
  }
3092
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
3093
+ while (cur < input.length && remaining > 0) {
3094
+ let itemPos = cur;
3095
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
3096
+ if (itemPos >= input.length) break;
3097
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
3098
+ const end = child(input, itemPos, ctx);
3099
+ if (end <= itemPos) break;
3100
+ if (values !== void 0) values.push(ctx._sv);
3101
+ cur = end;
3102
+ remaining--;
3103
+ }
3104
+ ctx._sv = values;
3105
+ return cur;
3106
+ }
3058
3107
  function many(combinator, opts = {}) {
3059
3108
  const { min, max } = resolveBounds("many()", opts);
3060
3109
  if (min >= 1) return atLeast(combinator, min, max);
@@ -3066,17 +3115,21 @@ function many(combinator, opts = {}) {
3066
3115
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
3067
3116
  let expected;
3068
3117
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
3118
+ const scalarChild = scalarOf(combinator);
3119
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
3069
3120
  return {
3070
3121
  _tag: "many",
3071
3122
  _meta: meta,
3072
3123
  _def: def,
3124
+ _parseScalar: parseScalar,
3073
3125
  parse(input, pos, ctx) {
3074
3126
  const values = def.valueUnused ? void 0 : [];
3127
+ const rollbackNeeded = needsTriviaRollback(ctx);
3075
3128
  let cur = pos;
3076
3129
  let count = 0;
3077
3130
  while (cur < input.length) {
3078
3131
  if (count >= max) break;
3079
- const item = repItem(combinator, input, cur, ctx, guardable, false);
3132
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
3080
3133
  if (item === "stop") break;
3081
3134
  if ("fail" in item) {
3082
3135
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -3093,7 +3146,7 @@ function many(combinator, opts = {}) {
3093
3146
  }
3094
3147
  if (values !== void 0) values.push(item.value);
3095
3148
  count++;
3096
- cur = item.end;
3149
+ cur = item.span.end;
3097
3150
  }
3098
3151
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
3099
3152
  }
@@ -3111,30 +3164,47 @@ function atLeast(combinator, min, max) {
3111
3164
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
3112
3165
  let expected;
3113
3166
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
3167
+ const scalarChild = scalarOf(combinator);
3168
+ const parseScalar = (input, pos, ctx) => {
3169
+ let cur = scalarChild(input, pos, ctx);
3170
+ if (cur < 0) return cur;
3171
+ const values = def.valueUnused ? void 0 : [ctx._sv];
3172
+ for (let count = 1; count < min; count++) {
3173
+ let itemPos = cur;
3174
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
3175
+ const end = scalarChild(input, itemPos, ctx);
3176
+ if (end < 0) return ~cur;
3177
+ cur = end;
3178
+ if (values !== void 0) values.push(ctx._sv);
3179
+ }
3180
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
3181
+ };
3114
3182
  return {
3115
3183
  _tag: "oneOrMore",
3116
3184
  _meta: meta,
3117
3185
  _def: def,
3186
+ _parseScalar: parseScalar,
3118
3187
  parse(input, pos, ctx) {
3119
3188
  const first = combinator.parse(input, pos, ctx);
3120
3189
  if (!first.ok) return first;
3121
3190
  const values = def.valueUnused ? void 0 : [first.value];
3191
+ const rollbackNeeded = needsTriviaRollback(ctx);
3122
3192
  let cur = first.span.end;
3123
3193
  let count = 1;
3124
3194
  while (count < min) {
3125
- const item = repItem(combinator, input, cur, ctx, guardable, true);
3195
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
3126
3196
  if (item === "stop" || "fail" in item) {
3127
3197
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
3128
3198
  expected ??= deriveExpected(combinator);
3129
3199
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
3130
3200
  }
3131
3201
  if (values !== void 0) values.push(item.value);
3132
- cur = item.end;
3202
+ cur = item.span.end;
3133
3203
  count++;
3134
3204
  }
3135
3205
  while (cur < input.length) {
3136
3206
  if (count >= max) break;
3137
- const item = repItem(combinator, input, cur, ctx, guardable, false);
3207
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
3138
3208
  if (item === "stop") break;
3139
3209
  if ("fail" in item) {
3140
3210
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -3151,7 +3221,7 @@ function atLeast(combinator, min, max) {
3151
3221
  }
3152
3222
  if (values !== void 0) values.push(item.value);
3153
3223
  count++;
3154
- cur = item.end;
3224
+ cur = item.span.end;
3155
3225
  }
3156
3226
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
3157
3227
  }
@@ -3159,11 +3229,54 @@ function atLeast(combinator, min, max) {
3159
3229
  }
3160
3230
 
3161
3231
  // src/combinators/map.ts
3232
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
3162
3233
  function transform(combinator, fn) {
3234
+ const observesSpan = fn.length > 1;
3235
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
3236
+ const terms = sequenceDef?.parsers;
3237
+ const inner = terms?.[1];
3238
+ 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;
3239
+ const child = scalarOf(combinator);
3240
+ const parseScalar = fused ? (() => {
3241
+ const body = inner._stickyRegex;
3242
+ const tuple = ['"', "", '"'];
3243
+ const expected = [JSON.stringify('"')];
3244
+ return (input, pos, ctx) => {
3245
+ if (ctx.trivia !== void 0) {
3246
+ const end2 = child(input, pos, ctx);
3247
+ if (end2 < 0) return end2;
3248
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
3249
+ return end2;
3250
+ }
3251
+ if (input.charCodeAt(pos) !== 34) {
3252
+ ctx._fx = expected;
3253
+ return ~pos;
3254
+ }
3255
+ body.lastIndex = pos + 1;
3256
+ const match = body.exec(input);
3257
+ const close = pos + 1 + match[0].length;
3258
+ if (input.charCodeAt(close) !== 34) {
3259
+ ctx._fx = expected;
3260
+ return ~close;
3261
+ }
3262
+ tuple[1] = match[0];
3263
+ const end = close + 1;
3264
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
3265
+ return end;
3266
+ };
3267
+ })() : /* @__PURE__ */ (() => {
3268
+ return (input, pos, ctx) => {
3269
+ const end = child(input, pos, ctx);
3270
+ if (end < 0) return end;
3271
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
3272
+ return end;
3273
+ };
3274
+ })();
3163
3275
  return {
3164
3276
  _tag: "transform",
3165
3277
  _meta: combinator._meta,
3166
3278
  _def: { tag: "transform", parser: combinator, fn },
3279
+ _parseScalar: parseScalar,
3167
3280
  parse(input, pos, ctx) {
3168
3281
  const result = combinator.parse(input, pos, ctx);
3169
3282
  if (!result.ok) return result;
@@ -3178,9 +3291,11 @@ function trivia(combinator) {
3178
3291
  _meta: {
3179
3292
  ...combinator._meta,
3180
3293
  isTrivia: true,
3294
+ triviaScanner: fastTriviaScanner(combinator),
3181
3295
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
3182
3296
  },
3183
3297
  _def: { tag: "trivia", parser: combinator },
3298
+ _parseScalar: scalarOf(combinator),
3184
3299
  parse: combinator.parse.bind(combinator)
3185
3300
  };
3186
3301
  }
@@ -3253,8 +3368,20 @@ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
3253
3368
  }
3254
3369
 
3255
3370
  // src/combinators/ref.ts
3371
+ function withRuleTrivia(trivia2, ctx, run) {
3372
+ const savedLabels = ctx.triviaKindLabels;
3373
+ ctx.trivia = trivia2;
3374
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
3375
+ try {
3376
+ return run();
3377
+ } finally {
3378
+ ctx.trivia = void 0;
3379
+ ctx.triviaKindLabels = savedLabels;
3380
+ }
3381
+ }
3256
3382
  function ref() {
3257
3383
  let resolved = null;
3384
+ let resolvedScalar = null;
3258
3385
  let ownBoundary = false;
3259
3386
  const meta = {
3260
3387
  firstSet: any(),
@@ -3271,25 +3398,28 @@ function ref() {
3271
3398
  return resolved;
3272
3399
  }
3273
3400
  },
3401
+ _parseScalar(input, pos, ctx) {
3402
+ const scalar = resolvedScalar;
3403
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
3404
+ const gt = meta.grammarTrivia;
3405
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
3406
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
3407
+ }
3408
+ return scalar(input, pos, ctx);
3409
+ },
3274
3410
  parse(input, pos, ctx) {
3275
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
3411
+ const parser = resolved;
3412
+ if (!parser) throw new Error("ref<T>() used before .define() was called");
3276
3413
  const gt = meta.grammarTrivia;
3277
3414
  if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
3278
- const savedLabels = ctx.triviaKindLabels;
3279
- ctx.trivia = gt;
3280
- ctx.triviaKindLabels = gt._meta.triviaKindLabels;
3281
- try {
3282
- return resolved.parse(input, pos, ctx);
3283
- } finally {
3284
- ctx.trivia = void 0;
3285
- ctx.triviaKindLabels = savedLabels;
3286
- }
3415
+ return withRuleTrivia(gt, ctx, () => parser.parse(input, pos, ctx));
3287
3416
  }
3288
- return resolved.parse(input, pos, ctx);
3417
+ return parser.parse(input, pos, ctx);
3289
3418
  },
3290
3419
  define(p) {
3291
3420
  if (resolved) throw new Error("ref<T>() already defined");
3292
3421
  resolved = p;
3422
+ resolvedScalar = scalarOf(p);
3293
3423
  ownBoundary = hasOwnTriviaBoundary(p);
3294
3424
  meta.firstSet = p._meta.firstSet;
3295
3425
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -6332,6 +6462,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
6332
6462
  function q(s) {
6333
6463
  return JSON.stringify(s);
6334
6464
  }
6465
+ function isAsciiOnlyClass(cls) {
6466
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
6467
+ }
6335
6468
  var NO_SINKS = { fd: false, er: false };
6336
6469
  function sinkSlots(t, s) {
6337
6470
  return `${s.fd ? `,${t}fd=0` : ""}${s.er ? `,${t}er=0` : ""}`;
@@ -6878,12 +7011,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
6878
7011
  return `${head}EC.e=pos;return ''}`;
6879
7012
  case OP_GATE: {
6880
7013
  const child = link(code[ip + 2]);
6881
- const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
7014
+ const resolved = t.cc[code[ip + 1]];
7015
+ const ci = classes.push([resolved]) - 1;
6882
7016
  classPlan.push([code[ip + 1]]);
6883
7017
  const cls = hoist("cl", `CLS[${ci}][0]`);
6884
7018
  const xf = fxRef(code[ip + 3]);
6885
7019
  return `${head}
6886
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
7020
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
6887
7021
  return ${child}(input,pos,ctx)
6888
7022
  }`;
6889
7023
  }
@@ -7226,10 +7360,11 @@ return v
7226
7360
  const asc = hoist("as", `DISP[${di}].ascii`);
7227
7361
  const hiArr = table.hi;
7228
7362
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
7363
+ const directAscii = staticBuild && table.hi.length === 0;
7229
7364
  return `${head}
7230
- const c=lead(input,pos)
7365
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
7231
7366
  let arm=-1
7232
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
7367
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
7233
7368
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
7234
7369
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
7235
7370
  if(arm>=0){
@@ -7251,7 +7386,9 @@ return FAIL
7251
7386
  const di = code[ip + 1];
7252
7387
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
7253
7388
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
7254
- const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
7389
+ const maskable = n <= 32;
7390
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
7391
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
7255
7392
  const tokenCandidate = tokenChoiceCandidates.get(ip);
7256
7393
  const pretests = Array.from({ length: n }, (_, i) => {
7257
7394
  if (tokenCandidate?.arm === i) {
@@ -7271,7 +7408,6 @@ return FAIL
7271
7408
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
7272
7409
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
7273
7410
  });
7274
- const maskable = n <= 32;
7275
7411
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
7276
7412
  if (maskable) maskPlan.push(~di);
7277
7413
  const p = tmp();
@@ -7333,16 +7469,16 @@ ${merge}
7333
7469
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
7334
7470
  return FAIL`;
7335
7471
  return `${head}
7336
- const c=lead(input,pos)
7472
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
7337
7473
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
7338
7474
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
7339
7475
  ${maskable ? `if(c<128){
7340
- const bits=${maskName}[c<0?128:c]
7476
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
7341
7477
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
7342
7478
  ${lazyArms(true)}
7343
- }else{
7479
+ }${directAsciiMask ? "" : `else{
7344
7480
  ${lazyArms(false)}
7345
- }
7481
+ }`}
7346
7482
  ` : lazyArms(false)}
7347
7483
  ${finish}
7348
7484
  }`;
@@ -7393,7 +7529,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
7393
7529
  ${rollbackFor(i)}
7394
7530
  }${routeMiss}${sequenceMiss}`;
7395
7531
  }).join("\n") : "";
7396
- const generalArms = arms.map((arm, i) => {
7532
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
7397
7533
  const pretest = pretests[i];
7398
7534
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
7399
7535
  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("||")})`;
@@ -7423,12 +7559,12 @@ ${rollbackFor(i)}
7423
7559
  }${miss}`;
7424
7560
  }).join("\n");
7425
7561
  return `${head}
7426
- const c=lead(input,pos)
7562
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
7427
7563
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
7428
7564
  let acc
7429
7565
  let best=pos
7430
7566
  ${maskable ? `if(c<128){
7431
- const bits=${maskName}[c<0?128:c]
7567
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
7432
7568
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
7433
7569
  ${startFailureExact ? "" : "let prev=0"}
7434
7570
  ${maskArms}
@@ -7523,14 +7659,18 @@ return [key,v]
7523
7659
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
7524
7660
  const collect = op === OP_REP;
7525
7661
  let itemCls;
7662
+ let itemAscii = false;
7526
7663
  if (!REC) {
7527
7664
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
7528
7665
  if (itemClassIndex >= 0) {
7529
- const ci = classes.push([t.cc[itemClassIndex]]) - 1;
7666
+ const resolved = t.cc[itemClassIndex];
7667
+ const ci = classes.push([resolved]) - 1;
7530
7668
  classPlan.push([itemClassIndex]);
7531
7669
  itemCls = hoist("ri", `CLS[${ci}][0]`);
7670
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
7532
7671
  }
7533
7672
  }
7673
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
7534
7674
  const skipBeforeFirst = sepIp < 0 && min === 0;
7535
7675
  const p = tmp();
7536
7676
  const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -7590,7 +7730,7 @@ let count=0
7590
7730
  for(;;){
7591
7731
  ${max >= 0 ? `if(count>=${max})break
7592
7732
  ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
7593
- ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&!classHas(${itemCls},lead(input,cur)))break
7733
+ ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
7594
7734
  ` : ""}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` : ""}
7595
7735
  ${markBody}
7596
7736
  let itemStart=cur
@@ -7615,7 +7755,7 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
7615
7755
  ${rb}
7616
7756
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
7617
7757
  }
7618
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
7758
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
7619
7759
  ${rb}
7620
7760
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
7621
7761
  }
@@ -12892,7 +13032,7 @@ var Encoder = class {
12892
13032
  d.tags === void 0 ? -1 : this.constant(d.tags)
12893
13033
  );
12894
13034
  if (matchesEmpty(d.parser)) return body;
12895
- const fs = d.parser._meta.firstSet;
13035
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
12896
13036
  if (fs.kind === "any") return body;
12897
13037
  const cls = this.charClass(fs);
12898
13038
  if (cls < 0) return body;
@@ -13006,7 +13146,7 @@ var Encoder = class {
13006
13146
  case "attempt": {
13007
13147
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
13008
13148
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
13009
- const fs = d.parser._meta.firstSet;
13149
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
13010
13150
  if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
13011
13151
  const cls = this.charClass(fs);
13012
13152
  if (cls < 0) return inner;