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
@@ -43,10 +43,20 @@ function classifyFinalChoice(arms, resolve3) {
43
43
  }
44
44
  return { exclusive, firstSets, nullable: nullable2 };
45
45
  }
46
- function resolveNamedRef(p, resolve3) {
46
+ function winnerForRef(p, resolve3) {
47
47
  if (resolve3 === void 0) return void 0;
48
48
  const name = p._ruleName;
49
- return name === void 0 ? void 0 : resolve3(name);
49
+ const w = name === void 0 ? void 0 : resolve3(name);
50
+ if (w === void 0 || w === p) return void 0;
51
+ let cur = w;
52
+ for (const seen = /* @__PURE__ */ new Set(); !seen.has(cur); ) {
53
+ if (cur === p) return void 0;
54
+ seen.add(cur);
55
+ const cd = cur._def;
56
+ if (cd.tag !== "grammar" && cd.tag !== "trivia") return w;
57
+ cur = cd.parser;
58
+ }
59
+ return w;
50
60
  }
51
61
  function union(a, b) {
52
62
  if (a.kind === "any" || b.kind === "any") return { kind: "any" };
@@ -144,13 +154,15 @@ function matchesEmptyBody(p, seen, resolve3) {
144
154
  case "grammar":
145
155
  case "recover":
146
156
  return me(d.parser);
147
- case "lazy":
157
+ case "lazy": {
158
+ const w = winnerForRef(p, resolve3);
159
+ if (w !== void 0) return me(w);
148
160
  try {
149
161
  return me(d.thunk());
150
162
  } catch {
151
- const t = resolveNamedRef(p, resolve3);
152
- return t ? me(t) : true;
163
+ return true;
153
164
  }
165
+ }
154
166
  default:
155
167
  return true;
156
168
  }
@@ -214,13 +226,15 @@ function firstSetBody(p, seen, resolve3) {
214
226
  // terminals: no refs, cached set is exact
215
227
  case "dispatch":
216
228
  return fs3(d.selector);
217
- case "lazy":
229
+ case "lazy": {
230
+ const w = winnerForRef(p, resolve3);
231
+ if (w !== void 0) return fs3(w);
218
232
  try {
219
233
  return fs3(d.thunk());
220
234
  } catch {
221
- const t = resolveNamedRef(p, resolve3);
222
- return t ? fs3(t) : any();
235
+ return any();
223
236
  }
237
+ }
224
238
  case "choice": {
225
239
  let out = empty();
226
240
  for (const arm of d.parsers) out = union(out, fs3(arm));
@@ -314,9 +328,43 @@ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
314
328
  }
315
329
  }
316
330
 
331
+ // src/combinators/scalar.ts
332
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
333
+ function scalarOf(combinator) {
334
+ return combinator._parseScalar;
335
+ }
336
+ function scalarTree(parser2, seen) {
337
+ if (seen.has(parser2)) return true;
338
+ if (parser2._parseScalar === void 0) return false;
339
+ seen.add(parser2);
340
+ const def = parser2._def;
341
+ if (!SCALAR_TAG.test(def.tag)) return false;
342
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
343
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
344
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
345
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
346
+ }
347
+ function scalarRootOf(combinator) {
348
+ const scalar = combinator._parseScalar;
349
+ const def = combinator._def;
350
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
351
+ }
352
+
317
353
  // src/combinators/ref.ts
354
+ function withRuleTrivia(trivia2, ctx, run) {
355
+ const savedLabels = ctx.triviaKindLabels;
356
+ ctx.trivia = trivia2;
357
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
358
+ try {
359
+ return run();
360
+ } finally {
361
+ ctx.trivia = void 0;
362
+ ctx.triviaKindLabels = savedLabels;
363
+ }
364
+ }
318
365
  function ref() {
319
366
  let resolved = null;
367
+ let resolvedScalar = null;
320
368
  let ownBoundary = false;
321
369
  const meta = {
322
370
  firstSet: any(),
@@ -333,25 +381,28 @@ function ref() {
333
381
  return resolved;
334
382
  }
335
383
  },
384
+ _parseScalar(input, pos, ctx) {
385
+ const scalar = resolvedScalar;
386
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
387
+ const gt = meta.grammarTrivia;
388
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
389
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
390
+ }
391
+ return scalar(input, pos, ctx);
392
+ },
336
393
  parse(input, pos, ctx) {
337
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
394
+ const parser2 = resolved;
395
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
338
396
  const gt = meta.grammarTrivia;
339
397
  if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
340
- const savedLabels = ctx.triviaKindLabels;
341
- ctx.trivia = gt;
342
- ctx.triviaKindLabels = gt._meta.triviaKindLabels;
343
- try {
344
- return resolved.parse(input, pos, ctx);
345
- } finally {
346
- ctx.trivia = void 0;
347
- ctx.triviaKindLabels = savedLabels;
348
- }
398
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
349
399
  }
350
- return resolved.parse(input, pos, ctx);
400
+ return parser2.parse(input, pos, ctx);
351
401
  },
352
402
  define(p) {
353
403
  if (resolved) throw new Error("ref<T>() already defined");
354
404
  resolved = p;
405
+ resolvedScalar = scalarOf(p);
355
406
  ownBoundary = hasOwnTriviaBoundary(p);
356
407
  meta.firstSet = p._meta.firstSet;
357
408
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -737,6 +788,7 @@ function createParseContext() {
737
788
  _fe: void 0,
738
789
  _fx: void 0,
739
790
  _fc: void 0,
791
+ _sv: void 0,
740
792
  _probe: void 0,
741
793
  _cstChildren: void 0,
742
794
  _cstLeaves: void 0,
@@ -1574,6 +1626,24 @@ function parser(opts, root) {
1574
1626
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
1575
1627
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
1576
1628
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
1629
+ const rootScalar = scalarOf(root);
1630
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
1631
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
1632
+ const savedTrivia = ctx.trivia;
1633
+ const savedLabels = ctx.triviaKindLabels;
1634
+ if (clearTrivia) {
1635
+ ctx.trivia = void 0;
1636
+ ctx.triviaKindLabels = void 0;
1637
+ } else if (scopeTrivia !== void 0) {
1638
+ ctx.trivia = scopeTrivia;
1639
+ ctx.triviaKindLabels = scopeLabels;
1640
+ }
1641
+ const end = rootScalar(input, pos, ctx);
1642
+ ctx.trivia = savedTrivia;
1643
+ ctx.triviaKindLabels = savedLabels;
1644
+ return end;
1645
+ } : void 0;
1646
+ let publicScalar;
1577
1647
  const grammar = {
1578
1648
  _tag: "grammar",
1579
1649
  _meta: {
@@ -1597,7 +1667,20 @@ function parser(opts, root) {
1597
1667
  constructionTrackLines: trackLinesPolicy,
1598
1668
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
1599
1669
  },
1670
+ _parseScalar: parseScalar,
1600
1671
  parse(input, pos, _ctx) {
1672
+ if (pos === void 0 && _ctx === void 0) {
1673
+ publicScalar ??= scalarRootOf(grammar) ?? null;
1674
+ if (publicScalar) {
1675
+ const ctx2 = createParseContext();
1676
+ const end = publicScalar(input, 0, ctx2);
1677
+ if (end < 0) {
1678
+ const at = ~end;
1679
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
1680
+ }
1681
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
1682
+ }
1683
+ }
1601
1684
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
1602
1685
  const trackLines = trackLinesOf(_ctx);
1603
1686
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -1889,6 +1972,28 @@ function literal(value, opts = {}) {
1889
1972
  isTrivia: false
1890
1973
  };
1891
1974
  const canMatchNewline = meta.canMatchNewline;
1975
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
1976
+ const code = value.charCodeAt(0);
1977
+ return (input, pos, ctx) => {
1978
+ if (input.charCodeAt(pos) === code) {
1979
+ ctx._sv = value;
1980
+ return pos + 1;
1981
+ }
1982
+ ctx._fx = expected;
1983
+ return ~pos;
1984
+ };
1985
+ })() : (input, pos, ctx) => {
1986
+ const end = pos + value.length;
1987
+ if (end <= input.length) {
1988
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
1989
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
1990
+ ctx._sv = matchedValue;
1991
+ return end;
1992
+ }
1993
+ }
1994
+ ctx._fx = expected;
1995
+ return ~pos;
1996
+ };
1892
1997
  if (caseInsensitive) {
1893
1998
  const upper = value.toUpperCase();
1894
1999
  const lower = value.toLowerCase();
@@ -1929,6 +2034,7 @@ function literal(value, opts = {}) {
1929
2034
  _tag: "literal",
1930
2035
  _meta: meta,
1931
2036
  _def: { tag: "literal", value, caseInsensitive },
2037
+ _parseScalar: parseScalar,
1932
2038
  parse: parse2
1933
2039
  };
1934
2040
  }
@@ -2268,10 +2374,32 @@ function regex(pattern, flags = "") {
2268
2374
  const canMatchNewline = raw.canMatchNewline;
2269
2375
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
2270
2376
  const def = { tag: "regex", source, flags: resolvedFlags };
2377
+ const expected = directTerminalFailureExpected(def);
2378
+ const parseScalar = (input, pos, ctx) => {
2379
+ const scanEnd = scan?.(input, pos);
2380
+ if (scanEnd !== void 0) {
2381
+ if (scanEnd === null) {
2382
+ ctx._fx = expected;
2383
+ return ~pos;
2384
+ }
2385
+ ctx._sv = input.slice(pos, scanEnd);
2386
+ return scanEnd;
2387
+ }
2388
+ anchored.lastIndex = pos;
2389
+ const match = anchored.exec(input);
2390
+ if (match === null) {
2391
+ ctx._fx = expected;
2392
+ return ~pos;
2393
+ }
2394
+ ctx._sv = match[0];
2395
+ return pos + match[0].length;
2396
+ };
2271
2397
  return {
2272
2398
  _tag: "regex",
2273
2399
  _meta: meta,
2274
2400
  _def: def,
2401
+ _stickyRegex: anchored,
2402
+ _parseScalar: parseScalar,
2275
2403
  parse(input, pos, ctx) {
2276
2404
  const scanEnd = scan?.(input, pos);
2277
2405
  if (scanEnd !== void 0) {
@@ -2363,16 +2491,26 @@ function keywords(words, opts = {}) {
2363
2491
  caseInsensitive: opts.caseInsensitive ?? false,
2364
2492
  boundary: opts.boundary
2365
2493
  };
2494
+ const expected = directTerminalFailureExpected(def);
2495
+ const parseScalar = (input, pos, ctx) => {
2496
+ re.lastIndex = pos;
2497
+ const m = re.exec(input);
2498
+ if (m === null) {
2499
+ ctx._fx = expected;
2500
+ return ~pos;
2501
+ }
2502
+ ctx._sv = m[0];
2503
+ return pos + m[0].length;
2504
+ };
2366
2505
  return {
2367
2506
  _tag: "keywords",
2368
2507
  _meta: meta,
2369
2508
  _def: def,
2509
+ _parseScalar: parseScalar,
2370
2510
  parse(input, pos, ctx) {
2371
2511
  re.lastIndex = pos;
2372
2512
  const m = re.exec(input);
2373
- if (m === null || m.index !== pos) {
2374
- return failAt(ctx, directTerminalFailureExpected(def), pos);
2375
- }
2513
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
2376
2514
  const value = m[0];
2377
2515
  const span = { start: pos, end: pos + value.length };
2378
2516
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -2403,6 +2541,9 @@ var fastScanner3;
2403
2541
  function needsDeferredTriviaCommit(ctx) {
2404
2542
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
2405
2543
  }
2544
+ function needsTriviaRollback(ctx) {
2545
+ 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;
2546
+ }
2406
2547
  function saveTriviaMark(ctx) {
2407
2548
  const m = saveCstMark(ctx);
2408
2549
  return {
@@ -2519,7 +2660,8 @@ function advanceTrivia(input, cur, ctx) {
2519
2660
  const triviaP = ctx.trivia;
2520
2661
  if (!triviaP) return cur;
2521
2662
  if (!ctx.trackLines) {
2522
- const fast2 = fastTriviaScanner(triviaP);
2663
+ const classified = triviaP._meta.triviaScanner;
2664
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
2523
2665
  if (fast2) return fast2(input, cur);
2524
2666
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
2525
2667
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -3124,6 +3266,7 @@ function sequence(...parsers) {
3124
3266
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
3125
3267
  }
3126
3268
  const hasAdjacency = adjacency !== null;
3269
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
3127
3270
  const meta = {
3128
3271
  // Union through the nullable prefix — a leading optional()/many() lets a later
3129
3272
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -3132,165 +3275,96 @@ function sequence(...parsers) {
3132
3275
  isTrivia: false
3133
3276
  };
3134
3277
  const def = { tag: "sequence", parsers };
3135
- let followSentinels;
3136
- function parseTolerant(input, pos, ctx) {
3137
- followSentinels ??= parsers.map((_, i) => {
3138
- const fs3 = parsers.slice(i + 1).reduce(
3139
- (acc, p) => union(acc, firstSetOf(p)),
3140
- { kind: "empty" }
3141
- );
3142
- return firstSetSentinel(fs3);
3143
- });
3144
- const values = def.valueUnused ? void 0 : [];
3278
+ const scalarParsers = parsers.map(scalarOf);
3279
+ const parseScalar = (input, pos, ctx) => {
3145
3280
  let cur = pos;
3146
- const inheritedSync = ctx._sync;
3147
- try {
3148
- for (let i = 0; i < parsers.length; i++) {
3149
- ctx._sync = followSentinels[i] ?? inheritedSync;
3150
- const adj = adjacency === null ? null : adjacency[i];
3151
- if (adj) {
3152
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
3153
- if (values !== void 0) values.push(null);
3154
- continue;
3155
- }
3156
- if (ctx.trivia && i > 0) {
3157
- const mTlog = cstTlLen(ctx);
3158
- const mLog = ctx._triviaLog?.length ?? 0;
3159
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3160
- let scanEnd;
3161
- if (needsDeferredTriviaCommit(ctx)) {
3162
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3163
- } else {
3164
- scanEnd = advanceTrivia(input, cur, ctx);
3165
- }
3166
- const scanTlog = cstTlLen(ctx);
3167
- const scanLog = ctx._triviaLog?.length ?? 0;
3168
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3169
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3170
- if (!result2.ok) return result2;
3171
- if (result2.span.end > scanEnd) cur = result2.span.end;
3172
- else rollbackScannedTriviaAt(
3173
- ctx,
3174
- mTlog,
3175
- scanTlog,
3176
- mLog,
3177
- scanLog,
3178
- mRootLog,
3179
- scanRootLog
3180
- );
3181
- if (values !== void 0) values.push(result2.value);
3182
- continue;
3183
- }
3184
- const result = parsers[i].parse(input, cur, ctx);
3185
- if (!result.ok) return result;
3186
- if (values !== void 0) values.push(result.value);
3187
- cur = result.span.end;
3281
+ if (strictArity !== 0) {
3282
+ cur = scalarParsers[0](input, cur, ctx);
3283
+ if (cur < 0) return cur;
3284
+ const first = ctx._sv;
3285
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3286
+ cur = scalarParsers[1](input, cur, ctx);
3287
+ if (cur < 0) return cur;
3288
+ const second = ctx._sv;
3289
+ if (strictArity === 2) {
3290
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
3291
+ return cur;
3188
3292
  }
3189
- } finally {
3190
- ctx._sync = inheritedSync;
3293
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3294
+ cur = scalarParsers[2](input, cur, ctx);
3295
+ if (cur < 0) return cur;
3296
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
3297
+ return cur;
3191
3298
  }
3192
- return {
3193
- ok: true,
3194
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3195
- value: values ?? void 0,
3196
- span: { start: pos, end: cur }
3197
- };
3198
- }
3199
- function parseAdjacent(input, pos, ctx) {
3200
3299
  const values = def.valueUnused ? void 0 : [];
3201
- let cur = pos;
3202
- for (let i = 0; i < parsers.length; i++) {
3203
- const adj = adjacency[i];
3204
- if (adj) {
3205
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
3206
- if (values !== void 0) values.push(null);
3207
- continue;
3208
- }
3209
- if (ctx.trivia && i > 0) {
3210
- let scanEnd;
3211
- const mTlog = cstTlLen(ctx);
3212
- const mLog = ctx._triviaLog?.length ?? 0;
3213
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3214
- if (needsDeferredTriviaCommit(ctx)) {
3215
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3216
- } else {
3217
- scanEnd = advanceTrivia(input, cur, ctx);
3218
- }
3219
- const scanTlog = cstTlLen(ctx);
3220
- const scanLog = ctx._triviaLog?.length ?? 0;
3221
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3222
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3223
- if (!result2.ok) return result2;
3224
- if (result2.span.end > scanEnd) cur = result2.span.end;
3225
- else rollbackScannedTriviaAt(
3226
- ctx,
3227
- mTlog,
3228
- scanTlog,
3229
- mLog,
3230
- scanLog,
3231
- mRootLog,
3232
- scanRootLog
3233
- );
3234
- if (values !== void 0) values.push(result2.value);
3235
- continue;
3236
- }
3237
- const result = parsers[i].parse(input, cur, ctx);
3238
- if (!result.ok) return result;
3239
- if (values !== void 0) values.push(result.value);
3240
- cur = result.span.end;
3241
- }
3242
- return {
3243
- ok: true,
3244
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3245
- value: values ?? void 0,
3246
- span: { start: pos, end: cur }
3247
- };
3248
- }
3300
+ for (let i = 0; i < scalarParsers.length; i++) {
3301
+ let termPos = cur;
3302
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
3303
+ const end = scalarParsers[i](input, termPos, ctx);
3304
+ if (end < 0) return end;
3305
+ if (values !== void 0) values.push(ctx._sv);
3306
+ if (end > termPos || termPos === cur) cur = end;
3307
+ }
3308
+ ctx._sv = values;
3309
+ return cur;
3310
+ };
3311
+ let followSentinels;
3249
3312
  return {
3250
3313
  _tag: "sequence",
3251
3314
  _meta: meta,
3252
3315
  _def: def,
3316
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
3253
3317
  parse(input, pos, ctx) {
3254
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
3255
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
3318
+ const tolerant = ctx._tolerant === true;
3319
+ if (tolerant) {
3320
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
3321
+ parsers.slice(i + 1).reduce(
3322
+ (set, parser2) => union(set, firstSetOf(parser2)),
3323
+ { kind: "empty" }
3324
+ )
3325
+ ));
3326
+ }
3327
+ const inheritedSync = ctx._sync;
3328
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
3256
3329
  const values = def.valueUnused ? void 0 : [];
3257
3330
  let cur = pos;
3258
- for (let i = 0; i < parsers.length; i++) {
3259
- if (ctx.trivia && i > 0) {
3260
- let scanEnd;
3261
- const mTlog = cstTlLen(ctx);
3262
- const mLog = ctx._triviaLog?.length ?? 0;
3263
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3264
- if (needsDeferredTriviaCommit(ctx)) {
3265
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3266
- } else {
3267
- scanEnd = advanceTrivia(input, cur, ctx);
3331
+ try {
3332
+ for (let i = 0; i < parsers.length; i++) {
3333
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
3334
+ const assertion = adjacency?.[i];
3335
+ if (assertion) {
3336
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
3337
+ if (values !== void 0) values.push(null);
3338
+ continue;
3268
3339
  }
3269
- const scanTlog = cstTlLen(ctx);
3270
- const scanLog = ctx._triviaLog?.length ?? 0;
3271
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3272
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3273
- if (!result2.ok) return result2;
3274
- if (result2.span.end > scanEnd) {
3275
- cur = result2.span.end;
3276
- } else {
3340
+ let termPos = cur;
3341
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3342
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3343
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3344
+ if (ctx.trivia && i > 0) {
3345
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
3346
+ }
3347
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3348
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3349
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3350
+ const result = parsers[i].parse(input, termPos, ctx);
3351
+ if (!result.ok) return result;
3352
+ if (values !== void 0) values.push(result.value);
3353
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
3354
+ else if (deferredTrivia) {
3277
3355
  rollbackScannedTriviaAt(
3278
3356
  ctx,
3279
- mTlog,
3357
+ markTlog,
3280
3358
  scanTlog,
3281
- mLog,
3359
+ markLog,
3282
3360
  scanLog,
3283
- mRootLog,
3361
+ markRootLog,
3284
3362
  scanRootLog
3285
3363
  );
3286
3364
  }
3287
- if (values !== void 0) values.push(result2.value);
3288
- continue;
3289
3365
  }
3290
- const result = parsers[i].parse(input, cur, ctx);
3291
- if (!result.ok) return result;
3292
- if (values !== void 0) values.push(result.value);
3293
- cur = result.span.end;
3366
+ } finally {
3367
+ if (tolerant) ctx._sync = inheritedSync;
3294
3368
  }
3295
3369
  return {
3296
3370
  ok: true,
@@ -3422,7 +3496,8 @@ function choice(...args) {
3422
3496
  disjoint
3423
3497
  };
3424
3498
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3425
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3499
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
3500
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
3426
3501
  let greedyLitMap = null;
3427
3502
  let sortedParsers = null;
3428
3503
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -3436,6 +3511,37 @@ function choice(...args) {
3436
3511
  } else if (strategy?.tag === "literalsLongestFirst") {
3437
3512
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
3438
3513
  }
3514
+ const scalarParsers = parsers.map(scalarOf);
3515
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
3516
+ const scalarExpected = parsers.flatMap(deriveExpected);
3517
+ const parseScalar = (input, pos, ctx) => {
3518
+ if (disjoint) {
3519
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3520
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3521
+ if (idx < 0 && code >= 0) {
3522
+ for (let i = 0; i < parsers.length; i++) {
3523
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3524
+ idx = i;
3525
+ break;
3526
+ }
3527
+ }
3528
+ }
3529
+ if (idx >= 0) {
3530
+ const gate2 = gates[idx];
3531
+ if (!gate2 || gate2(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3532
+ ctx._fx = deriveExpected(parsers[idx]);
3533
+ return ~pos;
3534
+ }
3535
+ } else {
3536
+ for (let i = 0; i < scalarParsers.length; i++) {
3537
+ if (gates[i] && !gates[i](ctx.state)) continue;
3538
+ const end = scalarParsers[i](input, pos, ctx);
3539
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3540
+ }
3541
+ }
3542
+ ctx._fx = scalarExpected;
3543
+ return ~pos;
3544
+ };
3439
3545
  return {
3440
3546
  _tag: "choice",
3441
3547
  _meta: meta,
@@ -3447,6 +3553,7 @@ function choice(...args) {
3447
3553
  strategy: strategy ?? { tag: "firstMatch" },
3448
3554
  autoNot
3449
3555
  },
3556
+ _parseScalar: scalarEligible ? parseScalar : void 0,
3450
3557
  parse(input, pos, ctx) {
3451
3558
  const expected = [];
3452
3559
  let expectedAt = pos;
@@ -3978,8 +4085,8 @@ function attempt(parser2) {
3978
4085
  }
3979
4086
 
3980
4087
  // src/combinators/repeat.ts
3981
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3982
- const mark = saveTriviaMark(ctx);
4088
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
4089
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
3983
4090
  let pos = cur;
3984
4091
  if (ctx.trivia) {
3985
4092
  if (needsDeferredTriviaCommit(ctx)) {
@@ -3989,24 +4096,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3989
4096
  }
3990
4097
  }
3991
4098
  if (pos >= input.length && !mandatory) {
3992
- rollbackTrivia(ctx, mark);
4099
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3993
4100
  return "stop";
3994
4101
  }
3995
4102
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
3996
- rollbackTrivia(ctx, mark);
4103
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3997
4104
  return "stop";
3998
4105
  }
3999
4106
  const result = combinator.parse(input, pos, ctx);
4000
4107
  if (!result.ok) {
4001
- rollbackTrivia(ctx, mark);
4108
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4002
4109
  if (result.committed) return { fail: result, failPos: pos };
4003
4110
  return { fail: result, failPos: pos };
4004
4111
  }
4005
4112
  if (result.span.end === pos && !mandatory) {
4006
- rollbackTrivia(ctx, mark);
4113
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4007
4114
  return "stop";
4008
4115
  }
4009
- return { value: result.value, end: result.span.end };
4116
+ return result;
4010
4117
  }
4011
4118
  function resolveBounds(what, opts) {
4012
4119
  const min = opts.min ?? 0;
@@ -4019,6 +4126,21 @@ function resolveBounds(what, opts) {
4019
4126
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
4020
4127
  return { min, max };
4021
4128
  }
4129
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
4130
+ while (cur < input.length && remaining > 0) {
4131
+ let itemPos = cur;
4132
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4133
+ if (itemPos >= input.length) break;
4134
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
4135
+ const end = child(input, itemPos, ctx);
4136
+ if (end <= itemPos) break;
4137
+ if (values !== void 0) values.push(ctx._sv);
4138
+ cur = end;
4139
+ remaining--;
4140
+ }
4141
+ ctx._sv = values;
4142
+ return cur;
4143
+ }
4022
4144
  function many(combinator, opts = {}) {
4023
4145
  const { min, max } = resolveBounds("many()", opts);
4024
4146
  if (min >= 1) return atLeast(combinator, min, max);
@@ -4030,17 +4152,21 @@ function many(combinator, opts = {}) {
4030
4152
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
4031
4153
  let expected;
4032
4154
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4155
+ const scalarChild = scalarOf(combinator);
4156
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
4033
4157
  return {
4034
4158
  _tag: "many",
4035
4159
  _meta: meta,
4036
4160
  _def: def,
4161
+ _parseScalar: parseScalar,
4037
4162
  parse(input, pos, ctx) {
4038
4163
  const values = def.valueUnused ? void 0 : [];
4164
+ const rollbackNeeded = needsTriviaRollback(ctx);
4039
4165
  let cur = pos;
4040
4166
  let count = 0;
4041
4167
  while (cur < input.length) {
4042
4168
  if (count >= max) break;
4043
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4169
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4044
4170
  if (item === "stop") break;
4045
4171
  if ("fail" in item) {
4046
4172
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4057,7 +4183,7 @@ function many(combinator, opts = {}) {
4057
4183
  }
4058
4184
  if (values !== void 0) values.push(item.value);
4059
4185
  count++;
4060
- cur = item.end;
4186
+ cur = item.span.end;
4061
4187
  }
4062
4188
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4063
4189
  }
@@ -4075,30 +4201,47 @@ function atLeast(combinator, min, max) {
4075
4201
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4076
4202
  let expected;
4077
4203
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4204
+ const scalarChild = scalarOf(combinator);
4205
+ const parseScalar = (input, pos, ctx) => {
4206
+ let cur = scalarChild(input, pos, ctx);
4207
+ if (cur < 0) return cur;
4208
+ const values = def.valueUnused ? void 0 : [ctx._sv];
4209
+ for (let count = 1; count < min; count++) {
4210
+ let itemPos = cur;
4211
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4212
+ const end = scalarChild(input, itemPos, ctx);
4213
+ if (end < 0) return ~cur;
4214
+ cur = end;
4215
+ if (values !== void 0) values.push(ctx._sv);
4216
+ }
4217
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
4218
+ };
4078
4219
  return {
4079
4220
  _tag: "oneOrMore",
4080
4221
  _meta: meta,
4081
4222
  _def: def,
4223
+ _parseScalar: parseScalar,
4082
4224
  parse(input, pos, ctx) {
4083
4225
  const first = combinator.parse(input, pos, ctx);
4084
4226
  if (!first.ok) return first;
4085
4227
  const values = def.valueUnused ? void 0 : [first.value];
4228
+ const rollbackNeeded = needsTriviaRollback(ctx);
4086
4229
  let cur = first.span.end;
4087
4230
  let count = 1;
4088
4231
  while (count < min) {
4089
- const item = repItem(combinator, input, cur, ctx, guardable, true);
4232
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
4090
4233
  if (item === "stop" || "fail" in item) {
4091
4234
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4092
4235
  expected ??= deriveExpected(combinator);
4093
4236
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4094
4237
  }
4095
4238
  if (values !== void 0) values.push(item.value);
4096
- cur = item.end;
4239
+ cur = item.span.end;
4097
4240
  count++;
4098
4241
  }
4099
4242
  while (cur < input.length) {
4100
4243
  if (count >= max) break;
4101
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4244
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4102
4245
  if (item === "stop") break;
4103
4246
  if ("fail" in item) {
4104
4247
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4115,7 +4258,7 @@ function atLeast(combinator, min, max) {
4115
4258
  }
4116
4259
  if (values !== void 0) values.push(item.value);
4117
4260
  count++;
4118
- cur = item.end;
4261
+ cur = item.span.end;
4119
4262
  }
4120
4263
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4121
4264
  }
@@ -4128,10 +4271,22 @@ function optional(combinator) {
4128
4271
  isTrivia: false
4129
4272
  };
4130
4273
  const firstSetSkippable = !matchesEmpty(combinator);
4274
+ const scalarChild = scalarOf(combinator);
4275
+ const parseScalar = (input, pos, ctx) => {
4276
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
4277
+ ctx._sv = null;
4278
+ return pos;
4279
+ }
4280
+ const end = scalarChild(input, pos, ctx);
4281
+ if (end >= 0) return end;
4282
+ ctx._sv = null;
4283
+ return pos;
4284
+ };
4131
4285
  return {
4132
4286
  _tag: "optional",
4133
4287
  _meta: meta,
4134
4288
  _def: { tag: "optional", parser: combinator },
4289
+ _parseScalar: parseScalar,
4135
4290
  parse(input, pos, ctx) {
4136
4291
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4137
4292
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -4168,6 +4323,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
4168
4323
  expected ??= deriveExpected(combinator);
4169
4324
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4170
4325
  };
4326
+ const scalarExpected = deriveExpected(combinator);
4327
+ const scalarChild = scalarOf(combinator);
4328
+ const scalarSeparator = scalarOf(separator);
4329
+ const parseScalar = (input, pos, ctx) => {
4330
+ let cur = scalarChild(input, pos, ctx);
4331
+ if (cur < 0) {
4332
+ if (min >= 1) {
4333
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4334
+ return ~pos;
4335
+ }
4336
+ ctx._sv = [];
4337
+ return pos;
4338
+ }
4339
+ const values = [ctx._sv];
4340
+ while (values.length < max && (cur < input.length || values.length < min)) {
4341
+ const beforeSeparator = cur;
4342
+ let separatorPos = cur;
4343
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
4344
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
4345
+ if (separatorEnd < 0) break;
4346
+ let itemPos = separatorEnd;
4347
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
4348
+ const itemEnd = scalarChild(input, itemPos, ctx);
4349
+ if (itemEnd < 0) {
4350
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
4351
+ break;
4352
+ }
4353
+ values.push(ctx._sv);
4354
+ cur = itemEnd;
4355
+ }
4356
+ if (values.length < min) {
4357
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4358
+ return ~cur;
4359
+ }
4360
+ ctx._sv = values;
4361
+ return cur;
4362
+ };
4171
4363
  return {
4172
4364
  _tag: "sepBy",
4173
4365
  _meta: meta,
@@ -4183,6 +4375,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
4183
4375
  // this option surface already; parity is held by test/parity, not by hope.
4184
4376
  ...keepSeparators ? { keepSeparators: true } : {}
4185
4377
  },
4378
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
4186
4379
  parse(input, pos, ctx) {
4187
4380
  const first = combinator.parse(input, pos, ctx);
4188
4381
  const values = [];
@@ -4798,11 +4991,54 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
4798
4991
  }
4799
4992
 
4800
4993
  // src/combinators/map.ts
4994
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
4801
4995
  function transform(combinator, fn) {
4996
+ const observesSpan = fn.length > 1;
4997
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
4998
+ const terms = sequenceDef?.parsers;
4999
+ const inner = terms?.[1];
5000
+ 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;
5001
+ const child = scalarOf(combinator);
5002
+ const parseScalar = fused ? (() => {
5003
+ const body = inner._stickyRegex;
5004
+ const tuple = ['"', "", '"'];
5005
+ const expected = [JSON.stringify('"')];
5006
+ return (input, pos, ctx) => {
5007
+ if (ctx.trivia !== void 0) {
5008
+ const end2 = child(input, pos, ctx);
5009
+ if (end2 < 0) return end2;
5010
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
5011
+ return end2;
5012
+ }
5013
+ if (input.charCodeAt(pos) !== 34) {
5014
+ ctx._fx = expected;
5015
+ return ~pos;
5016
+ }
5017
+ body.lastIndex = pos + 1;
5018
+ const match = body.exec(input);
5019
+ const close = pos + 1 + match[0].length;
5020
+ if (input.charCodeAt(close) !== 34) {
5021
+ ctx._fx = expected;
5022
+ return ~close;
5023
+ }
5024
+ tuple[1] = match[0];
5025
+ const end = close + 1;
5026
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
5027
+ return end;
5028
+ };
5029
+ })() : /* @__PURE__ */ (() => {
5030
+ return (input, pos, ctx) => {
5031
+ const end = child(input, pos, ctx);
5032
+ if (end < 0) return end;
5033
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
5034
+ return end;
5035
+ };
5036
+ })();
4802
5037
  return {
4803
5038
  _tag: "transform",
4804
5039
  _meta: combinator._meta,
4805
5040
  _def: { tag: "transform", parser: combinator, fn },
5041
+ _parseScalar: parseScalar,
4806
5042
  parse(input, pos, ctx) {
4807
5043
  const result = combinator.parse(input, pos, ctx);
4808
5044
  if (!result.ok) return result;
@@ -4817,9 +5053,11 @@ function trivia(combinator) {
4817
5053
  _meta: {
4818
5054
  ...combinator._meta,
4819
5055
  isTrivia: true,
5056
+ triviaScanner: fastTriviaScanner(combinator),
4820
5057
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
4821
5058
  },
4822
5059
  _def: { tag: "trivia", parser: combinator },
5060
+ _parseScalar: scalarOf(combinator),
4823
5061
  parse: combinator.parse.bind(combinator)
4824
5062
  };
4825
5063
  }
@@ -5774,7 +6012,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
5774
6012
  if (!Number.isInteger(spec[2]) || spec[2] < 0) {
5775
6013
  throw new TypeError("table balanced lexical program has an invalid scan reference");
5776
6014
  }
5777
- const run3 = (_input, _pos, ctx, scan) => {
6015
+ const run = (_input, _pos, ctx, scan) => {
5778
6016
  if (scan === void 0) throw new TypeError("table balanced lexical program lost its scan body");
5779
6017
  const result = scan.parse(_input, _pos, ctx);
5780
6018
  if (!result.ok) {
@@ -5784,7 +6022,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
5784
6022
  }
5785
6023
  return result.span.end;
5786
6024
  };
5787
- return Object.assign(run3, { scan: spec[2] });
6025
+ return Object.assign(run, { scan: spec[2] });
5788
6026
  }
5789
6027
  if (spec[0] === 2) return fixedTreeRunner(spec.slice(2), matchers, classes, expected);
5790
6028
  if (spec[0] === 1) {
@@ -7441,7 +7679,7 @@ var Encoder = class {
7441
7679
  d.tags === void 0 ? -1 : this.constant(d.tags)
7442
7680
  );
7443
7681
  if (matchesEmpty(d.parser)) return body;
7444
- const fs3 = d.parser._meta.firstSet;
7682
+ const fs3 = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
7445
7683
  if (fs3.kind === "any") return body;
7446
7684
  const cls = this.charClass(fs3);
7447
7685
  if (cls < 0) return body;
@@ -7555,7 +7793,7 @@ var Encoder = class {
7555
7793
  case "attempt": {
7556
7794
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
7557
7795
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
7558
- const fs3 = d.parser._meta.firstSet;
7796
+ const fs3 = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
7559
7797
  if (fs3.kind === "any" || matchesEmpty(d.parser)) return inner;
7560
7798
  const cls = this.charClass(fs3);
7561
7799
  if (cls < 0) return inner;
@@ -7800,15 +8038,15 @@ function parseStringShape(source) {
7800
8038
  if (source.length < 3 || source[source.length - 1] !== q2) return null;
7801
8039
  const inner = source.slice(1, -1);
7802
8040
  const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
7803
- const ESC2 = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
8041
+ const ESC = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
7804
8042
  let body;
7805
8043
  let esc;
7806
- let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC2}\\)\\*$`).exec(inner);
8044
+ let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC}\\)\\*$`).exec(inner);
7807
8045
  if (m) {
7808
8046
  body = m[1];
7809
8047
  esc = m[2];
7810
8048
  } else {
7811
- m = new RegExp(`^\\((?:\\?:)?${ESC2}\\|${CLS}\\)\\*$`).exec(inner);
8049
+ m = new RegExp(`^\\((?:\\?:)?${ESC}\\|${CLS}\\)\\*$`).exec(inner);
7812
8050
  if (m) {
7813
8051
  esc = m[1];
7814
8052
  body = m[2];
@@ -9371,6 +9609,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
9371
9609
  function q(s) {
9372
9610
  return JSON.stringify(s);
9373
9611
  }
9612
+ function isAsciiOnlyClass(cls) {
9613
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
9614
+ }
9374
9615
  var NO_SINKS = { fd: false, er: false };
9375
9616
  function sinkSlots(t, s) {
9376
9617
  return `${s.fd ? `,${t}fd=0` : ""}${s.er ? `,${t}er=0` : ""}`;
@@ -9481,7 +9722,7 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false) {
9481
9722
  const { code, k, fx, disp, dsp, triviaLabelled } = t;
9482
9723
  const swapLegal = !cfg.trackLines;
9483
9724
  const hostCst = cfg.hostCst;
9484
- const REC2 = prog.rec === 1 && cfg.tolerant;
9725
+ const REC = prog.rec === 1 && cfg.tolerant;
9485
9726
  if (cfg.coverage) throw new Unemittable("a coverage assembly");
9486
9727
  const roots = [...Object.values(prog.rules), ...extraIps];
9487
9728
  const reachable = [...reachableSites(code, roots)];
@@ -9560,7 +9801,7 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false) {
9560
9801
  const op = code[ip];
9561
9802
  sinkBits.set(
9562
9803
  ip,
9563
- op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC2 && (op === OP_REP || op === OP_REPV) ? 2 : 0)
9804
+ op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC && (op === OP_REP || op === OP_REPV) ? 2 : 0)
9564
9805
  );
9565
9806
  }
9566
9807
  const sinkKids = [];
@@ -9917,12 +10158,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9917
10158
  return `${head}EC.e=pos;return ''}`;
9918
10159
  case OP_GATE: {
9919
10160
  const child = link(code[ip + 2]);
9920
- const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
10161
+ const resolved = t.cc[code[ip + 1]];
10162
+ const ci = classes.push([resolved]) - 1;
9921
10163
  classPlan.push([code[ip + 1]]);
9922
10164
  const cls = hoist("cl", `CLS[${ci}][0]`);
9923
10165
  const xf = fxRef(code[ip + 3]);
9924
10166
  return `${head}
9925
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10167
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9926
10168
  return ${child}(input,pos,ctx)
9927
10169
  }`;
9928
10170
  }
@@ -9964,7 +10206,7 @@ if(v!==FAIL)return v
9964
10206
  const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "{start:pos,end:pos}"},expected:${xf}}
9965
10207
  const es=ctx._errors
9966
10208
  if(es!==undefined)es.push(err)
9967
- ${REC2 ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
10209
+ ${REC ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
9968
10210
  EC.e=pos
9969
10211
  return err
9970
10212
  }`;
@@ -10083,7 +10325,7 @@ return v
10083
10325
  }
10084
10326
  case OP_LEX_PROGRAM: {
10085
10327
  const programId = code[ip + 1];
10086
- const run3 = hoist("lexProgram", `LEXPROG[${programId}]`);
10328
+ const run = hoist("lexProgram", `LEXPROG[${programId}]`);
10087
10329
  const scanId = t.lexPrograms[programId].scan;
10088
10330
  if (scanId !== void 0) return `${head}
10089
10331
  const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan
@@ -10101,7 +10343,7 @@ ctx._cstTriviaLog=undefined
10101
10343
  ctx._triviaLog=undefined
10102
10344
  ctx._rootTriviaLog=undefined
10103
10345
  let e
10104
- try{e=${run3}(input,pos,ctx,SCANS[${scanId}])}finally{
10346
+ try{e=${run}(input,pos,ctx,SCANS[${scanId}])}finally{
10105
10347
  _pfScan=sScan
10106
10348
  ctx.trivia=sTri
10107
10349
  ctx.triviaKindLabels=sKinds
@@ -10120,7 +10362,7 @@ EC.e=e
10120
10362
  return v
10121
10363
  }`;
10122
10364
  return `${head}
10123
- const e=${run3}(input,pos,ctx)
10365
+ const e=${run}(input,pos,ctx)
10124
10366
  if(e<0)return FAIL
10125
10367
  const v=input.slice(pos,e)
10126
10368
  if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
@@ -10131,7 +10373,7 @@ return v
10131
10373
  /* ── transaction ─────────────────────────────────────────────────────── */
10132
10374
  case OP_ATTEMPT: {
10133
10375
  const child = link(code[ip + 1]);
10134
- const clean = !REC2 && failureRollbackClean(prog, ip);
10376
+ const clean = !REC && failureRollbackClean(prog, ip);
10135
10377
  const p = tmp();
10136
10378
  return `${head}
10137
10379
  ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
@@ -10184,7 +10426,7 @@ return null
10184
10426
  }
10185
10427
  case OP_OPT: {
10186
10428
  const child = link(code[ip + 1]);
10187
- const clean = !REC2 && failureRollbackClean(prog, ip);
10429
+ const clean = !REC && failureRollbackClean(prog, ip);
10188
10430
  const p = tmp();
10189
10431
  return `${head}
10190
10432
  ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
@@ -10214,15 +10456,15 @@ return v
10214
10456
  const childIp = code[base + i];
10215
10457
  kids.push(code[childIp] === OP_ADJ ? "" : link(childIp));
10216
10458
  }
10217
- const sy = REC2 ? `${tmp()}sy` : "";
10459
+ const sy = REC ? `${tmp()}sy` : "";
10218
10460
  const pub = (i) => {
10219
10461
  const s = sentRef(code[base + n + i]);
10220
10462
  return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
10221
10463
  };
10222
10464
  const parts = [head];
10223
- if (REC2) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
10465
+ if (REC) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
10224
10466
  parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
10225
- const close = () => REC2 ? `${parts.join("\n")}
10467
+ const close = () => REC ? `${parts.join("\n")}
10226
10468
  }finally{ctx._sync=${sy}}
10227
10469
  }` : `${parts.join("\n")}
10228
10470
  }`;
@@ -10235,7 +10477,7 @@ return v
10235
10477
  for (let i = 1; i < n; i++) {
10236
10478
  const vn = `v${i}`;
10237
10479
  parts.push(`let ${vn}`);
10238
- if (REC2) parts.push(pub(i));
10480
+ if (REC) parts.push(pub(i));
10239
10481
  const childIp = code[base + i];
10240
10482
  if (code[childIp] === OP_ADJ) {
10241
10483
  const negated = code[childIp + 1] === 1;
@@ -10265,10 +10507,11 @@ return v
10265
10507
  const asc = hoist("as", `DISP[${di}].ascii`);
10266
10508
  const hiArr = table.hi;
10267
10509
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
10510
+ const directAscii = staticBuild && table.hi.length === 0;
10268
10511
  return `${head}
10269
- const c=lead(input,pos)
10512
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10270
10513
  let arm=-1
10271
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
10514
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
10272
10515
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
10273
10516
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
10274
10517
  if(arm>=0){
@@ -10290,7 +10533,9 @@ return FAIL
10290
10533
  const di = code[ip + 1];
10291
10534
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10292
10535
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
10293
- const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10536
+ const maskable = n <= 32;
10537
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
10538
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10294
10539
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10295
10540
  const pretests = Array.from({ length: n }, (_, i) => {
10296
10541
  if (tokenCandidate?.arm === i) {
@@ -10310,12 +10555,11 @@ return FAIL
10310
10555
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
10311
10556
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
10312
10557
  });
10313
- const maskable = n <= 32;
10314
10558
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
10315
10559
  if (maskable) maskPlan.push(~di);
10316
10560
  const p = tmp();
10317
10561
  const encodedRollbackMask = choiceRollbackMask(prog, ip) ?? -1;
10318
- const rollbackMask = REC2 ? -1 : encodedRollbackMask;
10562
+ const rollbackMask = REC ? -1 : encodedRollbackMask;
10319
10563
  const hasRollback = rollbackMask !== 0;
10320
10564
  const startFailureExact = arms.every((_arm, i) => {
10321
10565
  const terminal = leadingScalarTerminal(code, code[base + i], 0, false);
@@ -10372,16 +10616,16 @@ ${merge}
10372
10616
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
10373
10617
  return FAIL`;
10374
10618
  return `${head}
10375
- const c=lead(input,pos)
10619
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10376
10620
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10377
10621
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
10378
10622
  ${maskable ? `if(c<128){
10379
- const bits=${maskName}[c<0?128:c]
10623
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10380
10624
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10381
10625
  ${lazyArms(true)}
10382
- }else{
10626
+ }${directAsciiMask ? "" : `else{
10383
10627
  ${lazyArms(false)}
10384
- }
10628
+ }`}
10385
10629
  ` : lazyArms(false)}
10386
10630
  ${finish}
10387
10631
  }`;
@@ -10432,7 +10676,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
10432
10676
  ${rollbackFor(i)}
10433
10677
  }${routeMiss}${sequenceMiss}`;
10434
10678
  }).join("\n") : "";
10435
- const generalArms = arms.map((arm, i) => {
10679
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
10436
10680
  const pretest = pretests[i];
10437
10681
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10438
10682
  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("||")})`;
@@ -10462,12 +10706,12 @@ ${rollbackFor(i)}
10462
10706
  }${miss}`;
10463
10707
  }).join("\n");
10464
10708
  return `${head}
10465
- const c=lead(input,pos)
10709
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10466
10710
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10467
10711
  let acc
10468
10712
  let best=pos
10469
10713
  ${maskable ? `if(c<128){
10470
- const bits=${maskName}[c<0?128:c]
10714
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10471
10715
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10472
10716
  ${startFailureExact ? "" : "let prev=0"}
10473
10717
  ${maskArms}
@@ -10562,14 +10806,18 @@ return [key,v]
10562
10806
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
10563
10807
  const collect = op === OP_REP;
10564
10808
  let itemCls;
10565
- if (!REC2) {
10809
+ let itemAscii = false;
10810
+ if (!REC) {
10566
10811
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
10567
10812
  if (itemClassIndex >= 0) {
10568
- const ci = classes.push([t.cc[itemClassIndex]]) - 1;
10813
+ const resolved = t.cc[itemClassIndex];
10814
+ const ci = classes.push([resolved]) - 1;
10569
10815
  classPlan.push([itemClassIndex]);
10570
10816
  itemCls = hoist("ri", `CLS[${ci}][0]`);
10817
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
10571
10818
  }
10572
10819
  }
10820
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
10573
10821
  const skipBeforeFirst = sepIp < 0 && min === 0;
10574
10822
  const p = tmp();
10575
10823
  const via = sep2 !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -10607,11 +10855,11 @@ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
10607
10855
  ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
10608
10856
  }`;
10609
10857
  const my = `${p}my`;
10610
- const recFx = REC2 ? fxRef(code[ip + 6]) : "";
10611
- const sepSent = REC2 ? sentRef(code[ip + 7]) : "undefined";
10858
+ const recFx = REC ? fxRef(code[ip + 6]) : "";
10859
+ const sepSent = REC ? sentRef(code[ip + 7]) : "undefined";
10612
10860
  const recSent = sep2 === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
10613
10861
  const recGate = sep2 !== void 0 || min === 0 ? "" : `count>=${min}&&`;
10614
- const recBranch = !REC2 ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
10862
+ const recBranch = !REC ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
10615
10863
  ${sep2 === void 0 ? `${rb}
10616
10864
  ` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
10617
10865
  ${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
@@ -10622,14 +10870,14 @@ continue
10622
10870
  `;
10623
10871
  return `${head}
10624
10872
  const out=${collect ? "[]" : "undefined"}
10625
- ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC2 ? `const ${my}=ctx._sync
10873
+ ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC ? `const ${my}=ctx._sync
10626
10874
  ` : ""}${itemCls === void 0 ? "" : `const ${p}gate=ctx._probe===undefined
10627
10875
  `}let cur=pos
10628
10876
  let count=0
10629
10877
  for(;;){
10630
10878
  ${max >= 0 ? `if(count>=${max})break
10631
10879
  ` : ""}${sep2 !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
10632
- ` : ""}${itemCls !== void 0 && sep2 === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&!classHas(${itemCls},lead(input,cur)))break
10880
+ ` : ""}${itemCls !== void 0 && sep2 === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
10633
10881
  ` : ""}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` : ""}
10634
10882
  ${markBody}
10635
10883
  let itemStart=cur
@@ -10654,14 +10902,14 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
10654
10902
  ${rb}
10655
10903
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
10656
10904
  }
10657
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
10905
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
10658
10906
  ${rb}
10659
10907
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
10660
10908
  }
10661
10909
  `}ctx._fc=false
10662
10910
  const v=${child}(input,itemStart,ctx)
10663
10911
  if(v===FAIL){
10664
- ${REC2 ? `if(ctx._fc===true){
10912
+ ${REC ? `if(ctx._fc===true){
10665
10913
  ${rb}
10666
10914
  return FAIL
10667
10915
  }
@@ -11232,7 +11480,7 @@ function assemble(t, prog, cfg) {
11232
11480
  const triviaScan = t.triviaScan;
11233
11481
  const swapLegal = !cfg.trackLines;
11234
11482
  const hostCst = cfg.hostCst;
11235
- const REC2 = prog.rec === 1 && cfg.tolerant;
11483
+ const REC = prog.rec === 1 && cfg.tolerant;
11236
11484
  const sentinels = /* @__PURE__ */ new Map();
11237
11485
  function sentinelFor(cls) {
11238
11486
  if (cls < 0) return void 0;
@@ -12233,7 +12481,7 @@ function assemble(t, prog, cfg) {
12233
12481
  const child = link(code[ip + 1]);
12234
12482
  const xf = fx[code[ip + 2]];
12235
12483
  const expectSpan = (ctx, pos) => prog.lines === 1 ? spanLines(ctx, pos, pos) : { start: pos, end: pos };
12236
- if (REC2) {
12484
+ if (REC) {
12237
12485
  return (input, pos, ctx) => {
12238
12486
  const v = child(input, pos, ctx);
12239
12487
  if (v !== FAIL) return v;
@@ -12540,8 +12788,8 @@ function assemble(t, prog, cfg) {
12540
12788
  };
12541
12789
  }
12542
12790
  case OP_LEX_PROGRAM: {
12543
- const run3 = t.lexPrograms[code[ip + 1]];
12544
- const scanId = run3.scan;
12791
+ const run = t.lexPrograms[code[ip + 1]];
12792
+ const scanId = run.scan;
12545
12793
  if (scanId !== void 0) {
12546
12794
  return (input, pos, ctx) => {
12547
12795
  const sTrivia = ctx.trivia, sKinds = ctx.triviaKindLabels;
@@ -12562,7 +12810,7 @@ function assemble(t, prog, cfg) {
12562
12810
  ctx._rootTriviaLog = void 0;
12563
12811
  let end;
12564
12812
  try {
12565
- end = run3(input, pos, ctx, scans[scanId]);
12813
+ end = run(input, pos, ctx, scans[scanId]);
12566
12814
  } finally {
12567
12815
  SCAN = sScan;
12568
12816
  ctx.trivia = sTrivia;
@@ -12583,7 +12831,7 @@ function assemble(t, prog, cfg) {
12583
12831
  };
12584
12832
  }
12585
12833
  return (input, pos, ctx) => {
12586
- const end = run3(input, pos, ctx);
12834
+ const end = run(input, pos, ctx);
12587
12835
  if (end < 0) return FAIL;
12588
12836
  const value = input.slice(pos, end);
12589
12837
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: { start: pos, end } });
@@ -12680,7 +12928,7 @@ function assemble(t, prog, cfg) {
12680
12928
  return next === void 0 ? cur : next(input, cur, ctx, values, inherited);
12681
12929
  };
12682
12930
  };
12683
- if (REC2) {
12931
+ if (REC) {
12684
12932
  const first2 = link(code[base]);
12685
12933
  const firstSync = sentinelFor(code[base + n]);
12686
12934
  const runnerAt = (i) => {
@@ -13137,7 +13385,7 @@ function assemble(t, prog, cfg) {
13137
13385
  if (n === 2 || n === 3) {
13138
13386
  const a0 = link(code[base]), a1 = link(code[base + 1]);
13139
13387
  const a2 = n === 3 ? link(code[base + 2]) : void 0;
13140
- const predecide = !hostCst && !REC2 && !cfg.probe && !cfg.coverage && !cfg.trackLines;
13388
+ const predecide = !hostCst && !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
13141
13389
  const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
13142
13390
  const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
13143
13391
  const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
@@ -13528,10 +13776,10 @@ function assemble(t, prog, cfg) {
13528
13776
  const itemFx = reportItem ? fx[code[ip + 6]] : EMPTY_FX2;
13529
13777
  const collect = op === OP_REP;
13530
13778
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
13531
- const itemClass = !REC2 && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
13779
+ const itemClass = !REC && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
13532
13780
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
13533
13781
  const skipBeforeFirst = sepIp < 0 && min === 0;
13534
- if (REC2) {
13782
+ if (REC) {
13535
13783
  const itemFx2 = fx[code[ip + 6]];
13536
13784
  const sepSent = sentinelFor(code[ip + 7]);
13537
13785
  return (input, pos, ctx) => {
@@ -14038,7 +14286,7 @@ function assemble(t, prog, cfg) {
14038
14286
  lead,
14039
14287
  asciiFoldKey,
14040
14288
  ROUTED_FX,
14041
- REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14289
+ REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14042
14290
  matchesAt,
14043
14291
  recoverScan,
14044
14292
  orSentinel,
@@ -14120,7 +14368,7 @@ function assemble(t, prog, cfg) {
14120
14368
  // — a strict one emits no reader — and through the SAME `sentinelFor` memo
14121
14369
  // the closure pieces use, so both engines resync to the same combinator
14122
14370
  // object rather than to two separately constructed ones.
14123
- REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14371
+ REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14124
14372
  matchesAt,
14125
14373
  recoverScan,
14126
14374
  orSentinel,
@@ -15153,36 +15401,36 @@ function findRegexFragments(visited) {
15153
15401
  if (branches.length >= 2) runs.add(branches.join("|"));
15154
15402
  for (let i = 0; i < branches.length; i++) {
15155
15403
  for (let n = 2; n <= Math.min(MAX_RUN, branches.length - i); n++) {
15156
- const run3 = branches.slice(i, i + n).join("|");
15157
- if (run3.length < 4) continue;
15158
- runs.add(run3);
15404
+ const run = branches.slice(i, i + n).join("|");
15405
+ if (run.length < 4) continue;
15406
+ runs.add(run);
15159
15407
  }
15160
15408
  }
15161
15409
  }
15162
- for (const run3 of runs) {
15163
- let e = byRun.get(run3);
15410
+ for (const run of runs) {
15411
+ let e = byRun.get(run);
15164
15412
  if (e === void 0) {
15165
- e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches: run3.split("|").length };
15166
- byRun.set(run3, e);
15413
+ e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches: run.split("|").length };
15414
+ byRun.set(run, e);
15167
15415
  }
15168
15416
  if (e.nodes.has(v.p)) continue;
15169
15417
  e.nodes.add(v.p);
15170
15418
  e.occ.push({ site: v.site, source: d.source });
15171
15419
  }
15172
15420
  }
15173
- const candidates = [...byRun.entries()].filter(([, e]) => e.occ.length >= 2).map(([run3, e]) => ({ run: run3, e, savings: (e.occ.length - 1) * run3.length })).sort((a, b) => b.e.occ.length - a.e.occ.length || b.savings - a.savings || b.run.length - a.run.length);
15421
+ const candidates = [...byRun.entries()].filter(([, e]) => e.occ.length >= 2).map(([run, e]) => ({ run, e, savings: (e.occ.length - 1) * run.length })).sort((a, b) => b.e.occ.length - a.e.occ.length || b.savings - a.savings || b.run.length - a.run.length);
15174
15422
  const kept = [];
15175
15423
  for (const c of candidates) {
15176
15424
  if (kept.some((k) => k.e.occ.length >= c.e.occ.length && `|${k.run}|`.includes(`|${c.run}|`))) continue;
15177
15425
  kept.push(c);
15178
15426
  }
15179
- return kept.map(({ run: run3, e }) => ({
15427
+ return kept.map(({ run, e }) => ({
15180
15428
  kind: "regex-fragment",
15181
- id: `regex-fragment:${run3}`,
15182
- fragment: run3,
15429
+ id: `regex-fragment:${run}`,
15430
+ fragment: run,
15183
15431
  branches: e.branches,
15184
15432
  count: e.occ.length,
15185
- savings: (e.occ.length - 1) * run3.length,
15433
+ savings: (e.occ.length - 1) * run.length,
15186
15434
  sources: e.occ.map((o) => `/${o.source}/`),
15187
15435
  sites: e.occ.map((o) => o.site),
15188
15436
  suggestion: `this ${e.branches}-branch alternation is re-spelled in ${e.occ.length} DISTINCT regex() terminals. Hoist it to one shared source string and interpolate it (\`new RegExp(\\\`\u2026\\\${OP}\u2026\\\`)\`) or lift the shared part into its own terminal \u2014 an edit to the operator set currently has to land in ${e.occ.length} places, and the analysis cannot tell you when one of them drifts.`
@@ -16692,7 +16940,7 @@ function compileRuleMap(ruleMap, opts = {}) {
16692
16940
  }
16693
16941
 
16694
16942
  // src/version.ts
16695
- var PARSEMAN_VERSION = "0.50.1";
16943
+ var PARSEMAN_VERSION = "0.50.4";
16696
16944
 
16697
16945
  // src/compiler/compile-linkable-table.ts
16698
16946
  function isLocal(rule) {
@@ -16785,72 +17033,6 @@ function cstBuildHost(typeOrOptions, children3, _fields, span, rawChildren, triv
16785
17033
  cstBuildHost._parsemanCstOutput = true;
16786
17034
  var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
16787
17035
 
16788
- // src/cst/trivia-entries.ts
16789
- var EMPTY_INDICES = Object.freeze([]);
16790
- var EMPTY_GAPS = Object.freeze([]);
16791
-
16792
- // src/functional/run.ts
16793
- var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
16794
- var REMOVED_RUN_RESULT_FIELDS = [
16795
- [
16796
- "triviaMap",
16797
- `It was a dense root-trivia index built on every parse; root trivia is now an OPT-IN sparse capture, because most grammars paid for an index they never read. Migration: name the trivia labels your grammar defines \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia\`, whose \`.index\` carries the labels and gap lookups \`triviaMap\` exposed.`
16798
- ],
16799
- [
16800
- "triviaLog",
16801
- `It was the flat \`start, end[, kindIndex]\` log every other trivia view was derived from, and it is no longer allocated at all \u2014 not empty, absent. Migration: request the labels you need \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia.rows\`. Do NOT reuse a stride-2/3 reader: rows are a different width and a different unit (one row per SELECTED marker, not one per trivia chunk), so an old loop reads confidently wrong offsets rather than failing.`
16802
- ],
16803
- [
16804
- "triviaKindLabels",
16805
- `It was already optional, so nothing ever flagged its disappearance \u2014 and \`triviaKindMask(undefined, \u2026)\` means "capture everything", so reading it now silently WIDENS capture instead of erroring. Migration: request labels \u2014 ${SELECT_EXAMPLE} \u2014 then the set you asked for is \`RunResult.rootTrivia.select\` and the resolved table is \`RunResult.rootTrivia.index.labels\`.`
16806
- ]
16807
- ];
16808
- var RunResultRecord = class {
16809
- constructor(ok, value, span, expected, errors, unconsumedFrom) {
16810
- this.ok = ok;
16811
- this.value = value;
16812
- this.span = span;
16813
- this.expected = expected;
16814
- this.errors = errors;
16815
- this.unconsumedFrom = unconsumedFrom;
16816
- }
16817
- };
16818
- var RunResultWithRootTrivia = class {
16819
- constructor(ok, value, span, expected, errors, rootTrivia, unconsumedFrom) {
16820
- this.ok = ok;
16821
- this.value = value;
16822
- this.span = span;
16823
- this.expected = expected;
16824
- this.errors = errors;
16825
- this.rootTrivia = rootTrivia;
16826
- this.unconsumedFrom = unconsumedFrom;
16827
- }
16828
- };
16829
- for (const proto of [RunResultRecord.prototype, RunResultWithRootTrivia.prototype]) {
16830
- for (const [name, detail] of REMOVED_RUN_RESULT_FIELDS) {
16831
- Object.defineProperty(proto, name, {
16832
- configurable: true,
16833
- enumerable: false,
16834
- get() {
16835
- throw new TypeError(
16836
- `RunResult.${name} was REMOVED in parseman 0.44.0 and has no default replacement. ${detail}`
16837
- );
16838
- }
16839
- });
16840
- }
16841
- }
16842
-
16843
- // src/analysis/choice-cost-render.ts
16844
- var ESC = "\x1B";
16845
- var ANSI = {
16846
- dim: `${ESC}[2m`,
16847
- bold: `${ESC}[1m`,
16848
- red: `${ESC}[31m`,
16849
- yellow: `${ESC}[33m`,
16850
- cyan: `${ESC}[36m`,
16851
- reset: `${ESC}[0m`
16852
- };
16853
-
16854
17036
  // src/combinators/gate.ts
16855
17037
  function gate(predicate) {
16856
17038
  const meta = {