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/index.js CHANGED
@@ -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));
@@ -595,6 +609,28 @@ function literal(value, opts = {}) {
595
609
  isTrivia: false
596
610
  };
597
611
  const canMatchNewline = meta.canMatchNewline;
612
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
613
+ const code = value.charCodeAt(0);
614
+ return (input, pos, ctx) => {
615
+ if (input.charCodeAt(pos) === code) {
616
+ ctx._sv = value;
617
+ return pos + 1;
618
+ }
619
+ ctx._fx = expected;
620
+ return ~pos;
621
+ };
622
+ })() : (input, pos, ctx) => {
623
+ const end = pos + value.length;
624
+ if (end <= input.length) {
625
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
626
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
627
+ ctx._sv = matchedValue;
628
+ return end;
629
+ }
630
+ }
631
+ ctx._fx = expected;
632
+ return ~pos;
633
+ };
598
634
  if (caseInsensitive) {
599
635
  const upper = value.toUpperCase();
600
636
  const lower = value.toLowerCase();
@@ -635,6 +671,7 @@ function literal(value, opts = {}) {
635
671
  _tag: "literal",
636
672
  _meta: meta,
637
673
  _def: { tag: "literal", value, caseInsensitive },
674
+ _parseScalar: parseScalar,
638
675
  parse: parse2
639
676
  };
640
677
  }
@@ -1091,10 +1128,32 @@ function regex(pattern, flags = "") {
1091
1128
  const canMatchNewline = raw.canMatchNewline;
1092
1129
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
1093
1130
  const def = { tag: "regex", source, flags: resolvedFlags };
1131
+ const expected = directTerminalFailureExpected(def);
1132
+ const parseScalar = (input, pos, ctx) => {
1133
+ const scanEnd = scan?.(input, pos);
1134
+ if (scanEnd !== void 0) {
1135
+ if (scanEnd === null) {
1136
+ ctx._fx = expected;
1137
+ return ~pos;
1138
+ }
1139
+ ctx._sv = input.slice(pos, scanEnd);
1140
+ return scanEnd;
1141
+ }
1142
+ anchored.lastIndex = pos;
1143
+ const match = anchored.exec(input);
1144
+ if (match === null) {
1145
+ ctx._fx = expected;
1146
+ return ~pos;
1147
+ }
1148
+ ctx._sv = match[0];
1149
+ return pos + match[0].length;
1150
+ };
1094
1151
  return {
1095
1152
  _tag: "regex",
1096
1153
  _meta: meta,
1097
1154
  _def: def,
1155
+ _stickyRegex: anchored,
1156
+ _parseScalar: parseScalar,
1098
1157
  parse(input, pos, ctx) {
1099
1158
  const scanEnd = scan?.(input, pos);
1100
1159
  if (scanEnd !== void 0) {
@@ -1191,16 +1250,26 @@ function keywords(words, opts = {}) {
1191
1250
  caseInsensitive: opts.caseInsensitive ?? false,
1192
1251
  boundary: opts.boundary
1193
1252
  };
1253
+ const expected = directTerminalFailureExpected(def);
1254
+ const parseScalar = (input, pos, ctx) => {
1255
+ re.lastIndex = pos;
1256
+ const m = re.exec(input);
1257
+ if (m === null) {
1258
+ ctx._fx = expected;
1259
+ return ~pos;
1260
+ }
1261
+ ctx._sv = m[0];
1262
+ return pos + m[0].length;
1263
+ };
1194
1264
  return {
1195
1265
  _tag: "keywords",
1196
1266
  _meta: meta,
1197
1267
  _def: def,
1268
+ _parseScalar: parseScalar,
1198
1269
  parse(input, pos, ctx) {
1199
1270
  re.lastIndex = pos;
1200
1271
  const m = re.exec(input);
1201
- if (m === null || m.index !== pos) {
1202
- return failAt(ctx, directTerminalFailureExpected(def), pos);
1203
- }
1272
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
1204
1273
  const value = m[0];
1205
1274
  const span = { start: pos, end: pos + value.length };
1206
1275
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -1227,6 +1296,7 @@ function createParseContext() {
1227
1296
  _fe: void 0,
1228
1297
  _fx: void 0,
1229
1298
  _fc: void 0,
1299
+ _sv: void 0,
1230
1300
  _probe: void 0,
1231
1301
  _cstChildren: void 0,
1232
1302
  _cstLeaves: void 0,
@@ -1927,6 +1997,9 @@ var fastScanner3;
1927
1997
  function needsDeferredTriviaCommit(ctx) {
1928
1998
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1929
1999
  }
2000
+ function needsTriviaRollback(ctx) {
2001
+ 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;
2002
+ }
1930
2003
  function saveTriviaMark(ctx) {
1931
2004
  const m = saveCstMark(ctx);
1932
2005
  return {
@@ -2043,7 +2116,8 @@ function advanceTrivia(input, cur, ctx) {
2043
2116
  const triviaP = ctx.trivia;
2044
2117
  if (!triviaP) return cur;
2045
2118
  if (!ctx.trackLines) {
2046
- const fast2 = fastTriviaScanner(triviaP);
2119
+ const classified = triviaP._meta.triviaScanner;
2120
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
2047
2121
  if (fast2) return fast2(input, cur);
2048
2122
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
2049
2123
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -2634,6 +2708,28 @@ function notAdjacent(options) {
2634
2708
  );
2635
2709
  }
2636
2710
 
2711
+ // src/combinators/scalar.ts
2712
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
2713
+ function scalarOf(combinator) {
2714
+ return combinator._parseScalar;
2715
+ }
2716
+ function scalarTree(parser2, seen) {
2717
+ if (seen.has(parser2)) return true;
2718
+ if (parser2._parseScalar === void 0) return false;
2719
+ seen.add(parser2);
2720
+ const def = parser2._def;
2721
+ if (!SCALAR_TAG.test(def.tag)) return false;
2722
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
2723
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
2724
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
2725
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
2726
+ }
2727
+ function scalarRootOf(combinator) {
2728
+ const scalar = combinator._parseScalar;
2729
+ const def = combinator._def;
2730
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
2731
+ }
2732
+
2637
2733
  // src/combinators/sequence.ts
2638
2734
  function sequence(...parsers) {
2639
2735
  let adjacency = null;
@@ -2649,6 +2745,7 @@ function sequence(...parsers) {
2649
2745
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
2650
2746
  }
2651
2747
  const hasAdjacency = adjacency !== null;
2748
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
2652
2749
  const meta = {
2653
2750
  // Union through the nullable prefix — a leading optional()/many() lets a later
2654
2751
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -2657,165 +2754,96 @@ function sequence(...parsers) {
2657
2754
  isTrivia: false
2658
2755
  };
2659
2756
  const def = { tag: "sequence", parsers };
2660
- let followSentinels;
2661
- function parseTolerant(input, pos, ctx) {
2662
- followSentinels ??= parsers.map((_, i) => {
2663
- const fs = parsers.slice(i + 1).reduce(
2664
- (acc, p) => union(acc, firstSetOf(p)),
2665
- { kind: "empty" }
2666
- );
2667
- return firstSetSentinel(fs);
2668
- });
2669
- const values = def.valueUnused ? void 0 : [];
2757
+ const scalarParsers = parsers.map(scalarOf);
2758
+ const parseScalar = (input, pos, ctx) => {
2670
2759
  let cur = pos;
2671
- const inheritedSync = ctx._sync;
2672
- try {
2673
- for (let i = 0; i < parsers.length; i++) {
2674
- ctx._sync = followSentinels[i] ?? inheritedSync;
2675
- const adj = adjacency === null ? null : adjacency[i];
2676
- if (adj) {
2677
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
2678
- if (values !== void 0) values.push(null);
2679
- continue;
2680
- }
2681
- if (ctx.trivia && i > 0) {
2682
- const mTlog = cstTlLen(ctx);
2683
- const mLog = ctx._triviaLog?.length ?? 0;
2684
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2685
- let scanEnd;
2686
- if (needsDeferredTriviaCommit(ctx)) {
2687
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
2688
- } else {
2689
- scanEnd = advanceTrivia(input, cur, ctx);
2690
- }
2691
- const scanTlog = cstTlLen(ctx);
2692
- const scanLog = ctx._triviaLog?.length ?? 0;
2693
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2694
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2695
- if (!result2.ok) return result2;
2696
- if (result2.span.end > scanEnd) cur = result2.span.end;
2697
- else rollbackScannedTriviaAt(
2698
- ctx,
2699
- mTlog,
2700
- scanTlog,
2701
- mLog,
2702
- scanLog,
2703
- mRootLog,
2704
- scanRootLog
2705
- );
2706
- if (values !== void 0) values.push(result2.value);
2707
- continue;
2708
- }
2709
- const result = parsers[i].parse(input, cur, ctx);
2710
- if (!result.ok) return result;
2711
- if (values !== void 0) values.push(result.value);
2712
- cur = result.span.end;
2760
+ if (strictArity !== 0) {
2761
+ cur = scalarParsers[0](input, cur, ctx);
2762
+ if (cur < 0) return cur;
2763
+ const first = ctx._sv;
2764
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
2765
+ cur = scalarParsers[1](input, cur, ctx);
2766
+ if (cur < 0) return cur;
2767
+ const second = ctx._sv;
2768
+ if (strictArity === 2) {
2769
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
2770
+ return cur;
2713
2771
  }
2714
- } finally {
2715
- ctx._sync = inheritedSync;
2772
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
2773
+ cur = scalarParsers[2](input, cur, ctx);
2774
+ if (cur < 0) return cur;
2775
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
2776
+ return cur;
2716
2777
  }
2717
- return {
2718
- ok: true,
2719
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2720
- value: values ?? void 0,
2721
- span: { start: pos, end: cur }
2722
- };
2723
- }
2724
- function parseAdjacent(input, pos, ctx) {
2725
2778
  const values = def.valueUnused ? void 0 : [];
2726
- let cur = pos;
2727
- for (let i = 0; i < parsers.length; i++) {
2728
- const adj = adjacency[i];
2729
- if (adj) {
2730
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
2731
- if (values !== void 0) values.push(null);
2732
- continue;
2733
- }
2734
- if (ctx.trivia && i > 0) {
2735
- let scanEnd;
2736
- const mTlog = cstTlLen(ctx);
2737
- const mLog = ctx._triviaLog?.length ?? 0;
2738
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2739
- if (needsDeferredTriviaCommit(ctx)) {
2740
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
2741
- } else {
2742
- scanEnd = advanceTrivia(input, cur, ctx);
2743
- }
2744
- const scanTlog = cstTlLen(ctx);
2745
- const scanLog = ctx._triviaLog?.length ?? 0;
2746
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2747
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2748
- if (!result2.ok) return result2;
2749
- if (result2.span.end > scanEnd) cur = result2.span.end;
2750
- else rollbackScannedTriviaAt(
2751
- ctx,
2752
- mTlog,
2753
- scanTlog,
2754
- mLog,
2755
- scanLog,
2756
- mRootLog,
2757
- scanRootLog
2758
- );
2759
- if (values !== void 0) values.push(result2.value);
2760
- continue;
2761
- }
2762
- const result = parsers[i].parse(input, cur, ctx);
2763
- if (!result.ok) return result;
2764
- if (values !== void 0) values.push(result.value);
2765
- cur = result.span.end;
2766
- }
2767
- return {
2768
- ok: true,
2769
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2770
- value: values ?? void 0,
2771
- span: { start: pos, end: cur }
2772
- };
2773
- }
2779
+ for (let i = 0; i < scalarParsers.length; i++) {
2780
+ let termPos = cur;
2781
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
2782
+ const end = scalarParsers[i](input, termPos, ctx);
2783
+ if (end < 0) return end;
2784
+ if (values !== void 0) values.push(ctx._sv);
2785
+ if (end > termPos || termPos === cur) cur = end;
2786
+ }
2787
+ ctx._sv = values;
2788
+ return cur;
2789
+ };
2790
+ let followSentinels;
2774
2791
  return {
2775
2792
  _tag: "sequence",
2776
2793
  _meta: meta,
2777
2794
  _def: def,
2795
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
2778
2796
  parse(input, pos, ctx) {
2779
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
2780
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
2797
+ const tolerant = ctx._tolerant === true;
2798
+ if (tolerant) {
2799
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
2800
+ parsers.slice(i + 1).reduce(
2801
+ (set, parser2) => union(set, firstSetOf(parser2)),
2802
+ { kind: "empty" }
2803
+ )
2804
+ ));
2805
+ }
2806
+ const inheritedSync = ctx._sync;
2807
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
2781
2808
  const values = def.valueUnused ? void 0 : [];
2782
2809
  let cur = pos;
2783
- for (let i = 0; i < parsers.length; i++) {
2784
- if (ctx.trivia && i > 0) {
2785
- let scanEnd;
2786
- const mTlog = cstTlLen(ctx);
2787
- const mLog = ctx._triviaLog?.length ?? 0;
2788
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2789
- if (needsDeferredTriviaCommit(ctx)) {
2790
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
2791
- } else {
2792
- scanEnd = advanceTrivia(input, cur, ctx);
2810
+ try {
2811
+ for (let i = 0; i < parsers.length; i++) {
2812
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
2813
+ const assertion = adjacency?.[i];
2814
+ if (assertion) {
2815
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
2816
+ if (values !== void 0) values.push(null);
2817
+ continue;
2793
2818
  }
2794
- const scanTlog = cstTlLen(ctx);
2795
- const scanLog = ctx._triviaLog?.length ?? 0;
2796
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2797
- const result2 = parsers[i].parse(input, scanEnd, ctx);
2798
- if (!result2.ok) return result2;
2799
- if (result2.span.end > scanEnd) {
2800
- cur = result2.span.end;
2801
- } else {
2819
+ let termPos = cur;
2820
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
2821
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
2822
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
2823
+ if (ctx.trivia && i > 0) {
2824
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
2825
+ }
2826
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
2827
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
2828
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
2829
+ const result = parsers[i].parse(input, termPos, ctx);
2830
+ if (!result.ok) return result;
2831
+ if (values !== void 0) values.push(result.value);
2832
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
2833
+ else if (deferredTrivia) {
2802
2834
  rollbackScannedTriviaAt(
2803
2835
  ctx,
2804
- mTlog,
2836
+ markTlog,
2805
2837
  scanTlog,
2806
- mLog,
2838
+ markLog,
2807
2839
  scanLog,
2808
- mRootLog,
2840
+ markRootLog,
2809
2841
  scanRootLog
2810
2842
  );
2811
2843
  }
2812
- if (values !== void 0) values.push(result2.value);
2813
- continue;
2814
2844
  }
2815
- const result = parsers[i].parse(input, cur, ctx);
2816
- if (!result.ok) return result;
2817
- if (values !== void 0) values.push(result.value);
2818
- cur = result.span.end;
2845
+ } finally {
2846
+ if (tolerant) ctx._sync = inheritedSync;
2819
2847
  }
2820
2848
  return {
2821
2849
  ok: true,
@@ -2950,7 +2978,8 @@ function choice(...args) {
2950
2978
  disjoint
2951
2979
  };
2952
2980
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
2953
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
2981
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
2982
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
2954
2983
  let greedyLitMap = null;
2955
2984
  let sortedParsers = null;
2956
2985
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -2964,6 +2993,37 @@ function choice(...args) {
2964
2993
  } else if (strategy?.tag === "literalsLongestFirst") {
2965
2994
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
2966
2995
  }
2996
+ const scalarParsers = parsers.map(scalarOf);
2997
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
2998
+ const scalarExpected = parsers.flatMap(deriveExpected);
2999
+ const parseScalar = (input, pos, ctx) => {
3000
+ if (disjoint) {
3001
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3002
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3003
+ if (idx < 0 && code >= 0) {
3004
+ for (let i = 0; i < parsers.length; i++) {
3005
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3006
+ idx = i;
3007
+ break;
3008
+ }
3009
+ }
3010
+ }
3011
+ if (idx >= 0) {
3012
+ const gate2 = gates[idx];
3013
+ if (!gate2 || gate2(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3014
+ ctx._fx = deriveExpected(parsers[idx]);
3015
+ return ~pos;
3016
+ }
3017
+ } else {
3018
+ for (let i = 0; i < scalarParsers.length; i++) {
3019
+ if (gates[i] && !gates[i](ctx.state)) continue;
3020
+ const end = scalarParsers[i](input, pos, ctx);
3021
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3022
+ }
3023
+ }
3024
+ ctx._fx = scalarExpected;
3025
+ return ~pos;
3026
+ };
2967
3027
  return {
2968
3028
  _tag: "choice",
2969
3029
  _meta: meta,
@@ -2975,6 +3035,7 @@ function choice(...args) {
2975
3035
  strategy: strategy ?? { tag: "firstMatch" },
2976
3036
  autoNot
2977
3037
  },
3038
+ _parseScalar: scalarEligible ? parseScalar : void 0,
2978
3039
  parse(input, pos, ctx) {
2979
3040
  const expected = [];
2980
3041
  let expectedAt = pos;
@@ -3509,8 +3570,8 @@ function attempt(parser2) {
3509
3570
  }
3510
3571
 
3511
3572
  // src/combinators/repeat.ts
3512
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3513
- const mark = saveTriviaMark(ctx);
3573
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
3574
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
3514
3575
  let pos = cur;
3515
3576
  if (ctx.trivia) {
3516
3577
  if (needsDeferredTriviaCommit(ctx)) {
@@ -3520,24 +3581,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3520
3581
  }
3521
3582
  }
3522
3583
  if (pos >= input.length && !mandatory) {
3523
- rollbackTrivia(ctx, mark);
3584
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3524
3585
  return "stop";
3525
3586
  }
3526
3587
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
3527
- rollbackTrivia(ctx, mark);
3588
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3528
3589
  return "stop";
3529
3590
  }
3530
3591
  const result = combinator.parse(input, pos, ctx);
3531
3592
  if (!result.ok) {
3532
- rollbackTrivia(ctx, mark);
3593
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3533
3594
  if (result.committed) return { fail: result, failPos: pos };
3534
3595
  return { fail: result, failPos: pos };
3535
3596
  }
3536
3597
  if (result.span.end === pos && !mandatory) {
3537
- rollbackTrivia(ctx, mark);
3598
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3538
3599
  return "stop";
3539
3600
  }
3540
- return { value: result.value, end: result.span.end };
3601
+ return result;
3541
3602
  }
3542
3603
  function resolveBounds(what, opts) {
3543
3604
  const min = opts.min ?? 0;
@@ -3550,6 +3611,21 @@ function resolveBounds(what, opts) {
3550
3611
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
3551
3612
  return { min, max };
3552
3613
  }
3614
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
3615
+ while (cur < input.length && remaining > 0) {
3616
+ let itemPos = cur;
3617
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
3618
+ if (itemPos >= input.length) break;
3619
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
3620
+ const end = child(input, itemPos, ctx);
3621
+ if (end <= itemPos) break;
3622
+ if (values !== void 0) values.push(ctx._sv);
3623
+ cur = end;
3624
+ remaining--;
3625
+ }
3626
+ ctx._sv = values;
3627
+ return cur;
3628
+ }
3553
3629
  function many(combinator, opts = {}) {
3554
3630
  const { min, max } = resolveBounds("many()", opts);
3555
3631
  if (min >= 1) return atLeast(combinator, min, max);
@@ -3561,17 +3637,21 @@ function many(combinator, opts = {}) {
3561
3637
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
3562
3638
  let expected;
3563
3639
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
3640
+ const scalarChild = scalarOf(combinator);
3641
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
3564
3642
  return {
3565
3643
  _tag: "many",
3566
3644
  _meta: meta,
3567
3645
  _def: def,
3646
+ _parseScalar: parseScalar,
3568
3647
  parse(input, pos, ctx) {
3569
3648
  const values = def.valueUnused ? void 0 : [];
3649
+ const rollbackNeeded = needsTriviaRollback(ctx);
3570
3650
  let cur = pos;
3571
3651
  let count = 0;
3572
3652
  while (cur < input.length) {
3573
3653
  if (count >= max) break;
3574
- const item = repItem(combinator, input, cur, ctx, guardable, false);
3654
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
3575
3655
  if (item === "stop") break;
3576
3656
  if ("fail" in item) {
3577
3657
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -3588,7 +3668,7 @@ function many(combinator, opts = {}) {
3588
3668
  }
3589
3669
  if (values !== void 0) values.push(item.value);
3590
3670
  count++;
3591
- cur = item.end;
3671
+ cur = item.span.end;
3592
3672
  }
3593
3673
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
3594
3674
  }
@@ -3606,30 +3686,47 @@ function atLeast(combinator, min, max) {
3606
3686
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
3607
3687
  let expected;
3608
3688
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
3689
+ const scalarChild = scalarOf(combinator);
3690
+ const parseScalar = (input, pos, ctx) => {
3691
+ let cur = scalarChild(input, pos, ctx);
3692
+ if (cur < 0) return cur;
3693
+ const values = def.valueUnused ? void 0 : [ctx._sv];
3694
+ for (let count = 1; count < min; count++) {
3695
+ let itemPos = cur;
3696
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
3697
+ const end = scalarChild(input, itemPos, ctx);
3698
+ if (end < 0) return ~cur;
3699
+ cur = end;
3700
+ if (values !== void 0) values.push(ctx._sv);
3701
+ }
3702
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
3703
+ };
3609
3704
  return {
3610
3705
  _tag: "oneOrMore",
3611
3706
  _meta: meta,
3612
3707
  _def: def,
3708
+ _parseScalar: parseScalar,
3613
3709
  parse(input, pos, ctx) {
3614
3710
  const first = combinator.parse(input, pos, ctx);
3615
3711
  if (!first.ok) return first;
3616
3712
  const values = def.valueUnused ? void 0 : [first.value];
3713
+ const rollbackNeeded = needsTriviaRollback(ctx);
3617
3714
  let cur = first.span.end;
3618
3715
  let count = 1;
3619
3716
  while (count < min) {
3620
- const item = repItem(combinator, input, cur, ctx, guardable, true);
3717
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
3621
3718
  if (item === "stop" || "fail" in item) {
3622
3719
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
3623
3720
  expected ??= deriveExpected(combinator);
3624
3721
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
3625
3722
  }
3626
3723
  if (values !== void 0) values.push(item.value);
3627
- cur = item.end;
3724
+ cur = item.span.end;
3628
3725
  count++;
3629
3726
  }
3630
3727
  while (cur < input.length) {
3631
3728
  if (count >= max) break;
3632
- const item = repItem(combinator, input, cur, ctx, guardable, false);
3729
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
3633
3730
  if (item === "stop") break;
3634
3731
  if ("fail" in item) {
3635
3732
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -3646,7 +3743,7 @@ function atLeast(combinator, min, max) {
3646
3743
  }
3647
3744
  if (values !== void 0) values.push(item.value);
3648
3745
  count++;
3649
- cur = item.end;
3746
+ cur = item.span.end;
3650
3747
  }
3651
3748
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
3652
3749
  }
@@ -3659,10 +3756,22 @@ function optional(combinator) {
3659
3756
  isTrivia: false
3660
3757
  };
3661
3758
  const firstSetSkippable = !matchesEmpty(combinator);
3759
+ const scalarChild = scalarOf(combinator);
3760
+ const parseScalar = (input, pos, ctx) => {
3761
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
3762
+ ctx._sv = null;
3763
+ return pos;
3764
+ }
3765
+ const end = scalarChild(input, pos, ctx);
3766
+ if (end >= 0) return end;
3767
+ ctx._sv = null;
3768
+ return pos;
3769
+ };
3662
3770
  return {
3663
3771
  _tag: "optional",
3664
3772
  _meta: meta,
3665
3773
  _def: { tag: "optional", parser: combinator },
3774
+ _parseScalar: parseScalar,
3666
3775
  parse(input, pos, ctx) {
3667
3776
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
3668
3777
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -3699,6 +3808,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
3699
3808
  expected ??= deriveExpected(combinator);
3700
3809
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
3701
3810
  };
3811
+ const scalarExpected = deriveExpected(combinator);
3812
+ const scalarChild = scalarOf(combinator);
3813
+ const scalarSeparator = scalarOf(separator);
3814
+ const parseScalar = (input, pos, ctx) => {
3815
+ let cur = scalarChild(input, pos, ctx);
3816
+ if (cur < 0) {
3817
+ if (min >= 1) {
3818
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
3819
+ return ~pos;
3820
+ }
3821
+ ctx._sv = [];
3822
+ return pos;
3823
+ }
3824
+ const values = [ctx._sv];
3825
+ while (values.length < max && (cur < input.length || values.length < min)) {
3826
+ const beforeSeparator = cur;
3827
+ let separatorPos = cur;
3828
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
3829
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
3830
+ if (separatorEnd < 0) break;
3831
+ let itemPos = separatorEnd;
3832
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
3833
+ const itemEnd = scalarChild(input, itemPos, ctx);
3834
+ if (itemEnd < 0) {
3835
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
3836
+ break;
3837
+ }
3838
+ values.push(ctx._sv);
3839
+ cur = itemEnd;
3840
+ }
3841
+ if (values.length < min) {
3842
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
3843
+ return ~cur;
3844
+ }
3845
+ ctx._sv = values;
3846
+ return cur;
3847
+ };
3702
3848
  return {
3703
3849
  _tag: "sepBy",
3704
3850
  _meta: meta,
@@ -3714,6 +3860,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
3714
3860
  // this option surface already; parity is held by test/parity, not by hope.
3715
3861
  ...keepSeparators ? { keepSeparators: true } : {}
3716
3862
  },
3863
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
3717
3864
  parse(input, pos, ctx) {
3718
3865
  const first = combinator.parse(input, pos, ctx);
3719
3866
  const values = [];
@@ -3827,8 +3974,20 @@ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
3827
3974
  }
3828
3975
 
3829
3976
  // src/combinators/ref.ts
3977
+ function withRuleTrivia(trivia2, ctx, run3) {
3978
+ const savedLabels = ctx.triviaKindLabels;
3979
+ ctx.trivia = trivia2;
3980
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
3981
+ try {
3982
+ return run3();
3983
+ } finally {
3984
+ ctx.trivia = void 0;
3985
+ ctx.triviaKindLabels = savedLabels;
3986
+ }
3987
+ }
3830
3988
  function ref() {
3831
3989
  let resolved = null;
3990
+ let resolvedScalar = null;
3832
3991
  let ownBoundary = false;
3833
3992
  const meta = {
3834
3993
  firstSet: any(),
@@ -3845,25 +4004,28 @@ function ref() {
3845
4004
  return resolved;
3846
4005
  }
3847
4006
  },
4007
+ _parseScalar(input, pos, ctx) {
4008
+ const scalar = resolvedScalar;
4009
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
4010
+ const gt = meta.grammarTrivia;
4011
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
4012
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
4013
+ }
4014
+ return scalar(input, pos, ctx);
4015
+ },
3848
4016
  parse(input, pos, ctx) {
3849
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
4017
+ const parser2 = resolved;
4018
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
3850
4019
  const gt = meta.grammarTrivia;
3851
4020
  if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
3852
- const savedLabels = ctx.triviaKindLabels;
3853
- ctx.trivia = gt;
3854
- ctx.triviaKindLabels = gt._meta.triviaKindLabels;
3855
- try {
3856
- return resolved.parse(input, pos, ctx);
3857
- } finally {
3858
- ctx.trivia = void 0;
3859
- ctx.triviaKindLabels = savedLabels;
3860
- }
4021
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
3861
4022
  }
3862
- return resolved.parse(input, pos, ctx);
4023
+ return parser2.parse(input, pos, ctx);
3863
4024
  },
3864
4025
  define(p) {
3865
4026
  if (resolved) throw new Error("ref<T>() already defined");
3866
4027
  resolved = p;
4028
+ resolvedScalar = scalarOf(p);
3867
4029
  ownBoundary = hasOwnTriviaBoundary(p);
3868
4030
  meta.firstSet = p._meta.firstSet;
3869
4031
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -4021,6 +4183,24 @@ function parser(opts, root) {
4021
4183
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
4022
4184
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
4023
4185
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
4186
+ const rootScalar = scalarOf(root);
4187
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
4188
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
4189
+ const savedTrivia = ctx.trivia;
4190
+ const savedLabels = ctx.triviaKindLabels;
4191
+ if (clearTrivia) {
4192
+ ctx.trivia = void 0;
4193
+ ctx.triviaKindLabels = void 0;
4194
+ } else if (scopeTrivia !== void 0) {
4195
+ ctx.trivia = scopeTrivia;
4196
+ ctx.triviaKindLabels = scopeLabels;
4197
+ }
4198
+ const end = rootScalar(input, pos, ctx);
4199
+ ctx.trivia = savedTrivia;
4200
+ ctx.triviaKindLabels = savedLabels;
4201
+ return end;
4202
+ } : void 0;
4203
+ let publicScalar;
4024
4204
  const grammar = {
4025
4205
  _tag: "grammar",
4026
4206
  _meta: {
@@ -4044,7 +4224,20 @@ function parser(opts, root) {
4044
4224
  constructionTrackLines: trackLinesPolicy,
4045
4225
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
4046
4226
  },
4227
+ _parseScalar: parseScalar,
4047
4228
  parse(input, pos, _ctx) {
4229
+ if (pos === void 0 && _ctx === void 0) {
4230
+ publicScalar ??= scalarRootOf(grammar) ?? null;
4231
+ if (publicScalar) {
4232
+ const ctx2 = createParseContext();
4233
+ const end = publicScalar(input, 0, ctx2);
4234
+ if (end < 0) {
4235
+ const at = ~end;
4236
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
4237
+ }
4238
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
4239
+ }
4240
+ }
4048
4241
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
4049
4242
  const trackLines = trackLinesOf(_ctx);
4050
4243
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -4082,6 +4275,9 @@ function parse(combinator, input, opts = {}) {
4082
4275
  _analyzed.add(combinator);
4083
4276
  markUnusedValues(combinator);
4084
4277
  }
4278
+ if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
4279
+ return combinator.parse(input);
4280
+ }
4085
4281
  const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
4086
4282
  const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
4087
4283
  const lineIndex = lineContext?.lineIndex;
@@ -4820,11 +5016,54 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
4820
5016
  }
4821
5017
 
4822
5018
  // src/combinators/map.ts
5019
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
4823
5020
  function transform(combinator, fn) {
5021
+ const observesSpan = fn.length > 1;
5022
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
5023
+ const terms = sequenceDef?.parsers;
5024
+ const inner = terms?.[1];
5025
+ 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;
5026
+ const child = scalarOf(combinator);
5027
+ const parseScalar = fused ? (() => {
5028
+ const body = inner._stickyRegex;
5029
+ const tuple = ['"', "", '"'];
5030
+ const expected = [JSON.stringify('"')];
5031
+ return (input, pos, ctx) => {
5032
+ if (ctx.trivia !== void 0) {
5033
+ const end2 = child(input, pos, ctx);
5034
+ if (end2 < 0) return end2;
5035
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
5036
+ return end2;
5037
+ }
5038
+ if (input.charCodeAt(pos) !== 34) {
5039
+ ctx._fx = expected;
5040
+ return ~pos;
5041
+ }
5042
+ body.lastIndex = pos + 1;
5043
+ const match = body.exec(input);
5044
+ const close = pos + 1 + match[0].length;
5045
+ if (input.charCodeAt(close) !== 34) {
5046
+ ctx._fx = expected;
5047
+ return ~close;
5048
+ }
5049
+ tuple[1] = match[0];
5050
+ const end = close + 1;
5051
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
5052
+ return end;
5053
+ };
5054
+ })() : /* @__PURE__ */ (() => {
5055
+ return (input, pos, ctx) => {
5056
+ const end = child(input, pos, ctx);
5057
+ if (end < 0) return end;
5058
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
5059
+ return end;
5060
+ };
5061
+ })();
4824
5062
  return {
4825
5063
  _tag: "transform",
4826
5064
  _meta: combinator._meta,
4827
5065
  _def: { tag: "transform", parser: combinator, fn },
5066
+ _parseScalar: parseScalar,
4828
5067
  parse(input, pos, ctx) {
4829
5068
  const result = combinator.parse(input, pos, ctx);
4830
5069
  if (!result.ok) return result;
@@ -4839,9 +5078,11 @@ function trivia(combinator) {
4839
5078
  _meta: {
4840
5079
  ...combinator._meta,
4841
5080
  isTrivia: true,
5081
+ triviaScanner: fastTriviaScanner(combinator),
4842
5082
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
4843
5083
  },
4844
5084
  _def: { tag: "trivia", parser: combinator },
5085
+ _parseScalar: scalarOf(combinator),
4845
5086
  parse: combinator.parse.bind(combinator)
4846
5087
  };
4847
5088
  }
@@ -7839,7 +8080,7 @@ var Encoder = class {
7839
8080
  d.tags === void 0 ? -1 : this.constant(d.tags)
7840
8081
  );
7841
8082
  if (matchesEmpty(d.parser)) return body;
7842
- const fs = d.parser._meta.firstSet;
8083
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
7843
8084
  if (fs.kind === "any") return body;
7844
8085
  const cls = this.charClass(fs);
7845
8086
  if (cls < 0) return body;
@@ -7953,7 +8194,7 @@ var Encoder = class {
7953
8194
  case "attempt": {
7954
8195
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
7955
8196
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
7956
- const fs = d.parser._meta.firstSet;
8197
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
7957
8198
  if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
7958
8199
  const cls = this.charClass(fs);
7959
8200
  if (cls < 0) return inner;
@@ -9772,6 +10013,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
9772
10013
  function q(s) {
9773
10014
  return JSON.stringify(s);
9774
10015
  }
10016
+ function isAsciiOnlyClass(cls) {
10017
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
10018
+ }
9775
10019
  var NO_SINKS = { fd: false, er: false };
9776
10020
  function sinkSlots(t, s) {
9777
10021
  return `${s.fd ? `,${t}fd=0` : ""}${s.er ? `,${t}er=0` : ""}`;
@@ -10318,12 +10562,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
10318
10562
  return `${head}EC.e=pos;return ''}`;
10319
10563
  case OP_GATE: {
10320
10564
  const child = link(code[ip + 2]);
10321
- const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
10565
+ const resolved = t.cc[code[ip + 1]];
10566
+ const ci = classes.push([resolved]) - 1;
10322
10567
  classPlan.push([code[ip + 1]]);
10323
10568
  const cls = hoist("cl", `CLS[${ci}][0]`);
10324
10569
  const xf = fxRef(code[ip + 3]);
10325
10570
  return `${head}
10326
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10571
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10327
10572
  return ${child}(input,pos,ctx)
10328
10573
  }`;
10329
10574
  }
@@ -10666,10 +10911,11 @@ return v
10666
10911
  const asc = hoist("as", `DISP[${di}].ascii`);
10667
10912
  const hiArr = table.hi;
10668
10913
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
10914
+ const directAscii = staticBuild && table.hi.length === 0;
10669
10915
  return `${head}
10670
- const c=lead(input,pos)
10916
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10671
10917
  let arm=-1
10672
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
10918
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
10673
10919
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
10674
10920
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
10675
10921
  if(arm>=0){
@@ -10691,7 +10937,9 @@ return FAIL
10691
10937
  const di = code[ip + 1];
10692
10938
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10693
10939
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
10694
- const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10940
+ const maskable = n <= 32;
10941
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
10942
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10695
10943
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10696
10944
  const pretests = Array.from({ length: n }, (_, i) => {
10697
10945
  if (tokenCandidate?.arm === i) {
@@ -10711,7 +10959,6 @@ return FAIL
10711
10959
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
10712
10960
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
10713
10961
  });
10714
- const maskable = n <= 32;
10715
10962
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
10716
10963
  if (maskable) maskPlan.push(~di);
10717
10964
  const p = tmp();
@@ -10773,16 +11020,16 @@ ${merge2}
10773
11020
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
10774
11021
  return FAIL`;
10775
11022
  return `${head}
10776
- const c=lead(input,pos)
11023
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10777
11024
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10778
11025
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
10779
11026
  ${maskable ? `if(c<128){
10780
- const bits=${maskName}[c<0?128:c]
11027
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10781
11028
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10782
11029
  ${lazyArms(true)}
10783
- }else{
11030
+ }${directAsciiMask ? "" : `else{
10784
11031
  ${lazyArms(false)}
10785
- }
11032
+ }`}
10786
11033
  ` : lazyArms(false)}
10787
11034
  ${finish}
10788
11035
  }`;
@@ -10833,7 +11080,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
10833
11080
  ${rollbackFor(i)}
10834
11081
  }${routeMiss}${sequenceMiss}`;
10835
11082
  }).join("\n") : "";
10836
- const generalArms = arms.map((arm, i) => {
11083
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
10837
11084
  const pretest = pretests[i];
10838
11085
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10839
11086
  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("||")})`;
@@ -10863,12 +11110,12 @@ ${rollbackFor(i)}
10863
11110
  }${miss}`;
10864
11111
  }).join("\n");
10865
11112
  return `${head}
10866
- const c=lead(input,pos)
11113
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10867
11114
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10868
11115
  let acc
10869
11116
  let best=pos
10870
11117
  ${maskable ? `if(c<128){
10871
- const bits=${maskName}[c<0?128:c]
11118
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10872
11119
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10873
11120
  ${startFailureExact ? "" : "let prev=0"}
10874
11121
  ${maskArms}
@@ -10963,14 +11210,18 @@ return [key,v]
10963
11210
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
10964
11211
  const collect = op === OP_REP;
10965
11212
  let itemCls;
11213
+ let itemAscii = false;
10966
11214
  if (!REC2) {
10967
11215
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
10968
11216
  if (itemClassIndex >= 0) {
10969
- const ci = classes.push([t.cc[itemClassIndex]]) - 1;
11217
+ const resolved = t.cc[itemClassIndex];
11218
+ const ci = classes.push([resolved]) - 1;
10970
11219
  classPlan.push([itemClassIndex]);
10971
11220
  itemCls = hoist("ri", `CLS[${ci}][0]`);
11221
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
10972
11222
  }
10973
11223
  }
11224
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
10974
11225
  const skipBeforeFirst = sepIp < 0 && min === 0;
10975
11226
  const p = tmp();
10976
11227
  const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -11030,7 +11281,7 @@ let count=0
11030
11281
  for(;;){
11031
11282
  ${max >= 0 ? `if(count>=${max})break
11032
11283
  ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
11033
- ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&!classHas(${itemCls},lead(input,cur)))break
11284
+ ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
11034
11285
  ` : ""}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` : ""}
11035
11286
  ${markBody}
11036
11287
  let itemStart=cur
@@ -11055,7 +11306,7 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
11055
11306
  ${rb}
11056
11307
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
11057
11308
  }
11058
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
11309
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
11059
11310
  ${rb}
11060
11311
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
11061
11312
  }
@@ -17106,7 +17357,7 @@ function compileRuleMap(ruleMap, opts = {}) {
17106
17357
  }
17107
17358
 
17108
17359
  // src/version.ts
17109
- var PARSEMAN_VERSION = "0.50.1";
17360
+ var PARSEMAN_VERSION = "0.50.4";
17110
17361
 
17111
17362
  // src/compiler/compile-linkable-table.ts
17112
17363
  function isLocal(rule) {