parseman 0.50.1 → 0.50.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +14 -10
  2. package/dist/analysis/diagnostics.js +431 -219
  3. package/dist/analysis/diagnostics.js.map +3 -3
  4. package/dist/cli/index.js +421 -184
  5. package/dist/cli/index.js.map +3 -3
  6. package/dist/combinators/choice.d.ts.map +1 -1
  7. package/dist/combinators/grammar.d.ts.map +1 -1
  8. package/dist/combinators/keywords.d.ts.map +1 -1
  9. package/dist/combinators/literal.d.ts.map +1 -1
  10. package/dist/combinators/map.d.ts.map +1 -1
  11. package/dist/combinators/ref.d.ts.map +1 -1
  12. package/dist/combinators/regex.d.ts.map +1 -1
  13. package/dist/combinators/repeat.d.ts.map +1 -1
  14. package/dist/combinators/scalar.d.ts +6 -0
  15. package/dist/combinators/scalar.d.ts.map +1 -0
  16. package/dist/combinators/sequence.d.ts.map +1 -1
  17. package/dist/combinators/trivia-skip.d.ts +2 -0
  18. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  19. package/dist/compiler/token-capability.js +0 -3
  20. package/dist/compiler/token-capability.js.map +2 -2
  21. package/dist/index.js +422 -185
  22. package/dist/index.js.map +3 -3
  23. package/dist/language-service/index.js +68 -172
  24. package/dist/language-service/index.js.map +3 -3
  25. package/dist/parse-context.d.ts.map +1 -1
  26. package/dist/plugin/index.js +467 -299
  27. package/dist/plugin/index.js.map +3 -3
  28. package/dist/run/index.js +1 -0
  29. package/dist/run/index.js.map +1 -1
  30. package/dist/spec/index.js +399 -277
  31. package/dist/spec/index.js.map +3 -3
  32. package/dist/table/emit-assembly.d.ts.map +1 -1
  33. package/dist/table/index.js +307 -181
  34. package/dist/table/index.js.map +3 -3
  35. package/dist/types.d.ts +8 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/version.d.ts +1 -1
  38. package/package.json +4 -2
  39. package/src/combinators/choice.ts +34 -1
  40. package/src/combinators/grammar.ts +39 -0
  41. package/src/combinators/keywords.ts +14 -3
  42. package/src/combinators/literal.ts +26 -0
  43. package/src/combinators/map.ts +60 -0
  44. package/src/combinators/ref.ts +26 -7
  45. package/src/combinators/regex.ts +23 -0
  46. package/src/combinators/repeat.ts +109 -16
  47. package/src/combinators/scalar.ts +30 -0
  48. package/src/combinators/sequence.ts +76 -161
  49. package/src/combinators/trivia-skip.ts +14 -1
  50. package/src/parse-context.ts +1 -0
  51. package/src/table/emit-assembly.ts +39 -16
  52. package/src/types.ts +8 -0
  53. package/src/version.ts +1 -1
@@ -314,9 +314,43 @@ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
314
314
  }
315
315
  }
316
316
 
317
+ // src/combinators/scalar.ts
318
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
319
+ function scalarOf(combinator) {
320
+ return combinator._parseScalar;
321
+ }
322
+ function scalarTree(parser2, seen) {
323
+ if (seen.has(parser2)) return true;
324
+ if (parser2._parseScalar === void 0) return false;
325
+ seen.add(parser2);
326
+ const def = parser2._def;
327
+ if (!SCALAR_TAG.test(def.tag)) return false;
328
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
329
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
330
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
331
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
332
+ }
333
+ function scalarRootOf(combinator) {
334
+ const scalar = combinator._parseScalar;
335
+ const def = combinator._def;
336
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
337
+ }
338
+
317
339
  // src/combinators/ref.ts
340
+ function withRuleTrivia(trivia2, ctx, run) {
341
+ const savedLabels = ctx.triviaKindLabels;
342
+ ctx.trivia = trivia2;
343
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
344
+ try {
345
+ return run();
346
+ } finally {
347
+ ctx.trivia = void 0;
348
+ ctx.triviaKindLabels = savedLabels;
349
+ }
350
+ }
318
351
  function ref() {
319
352
  let resolved = null;
353
+ let resolvedScalar = null;
320
354
  let ownBoundary = false;
321
355
  const meta = {
322
356
  firstSet: any(),
@@ -333,25 +367,28 @@ function ref() {
333
367
  return resolved;
334
368
  }
335
369
  },
370
+ _parseScalar(input, pos, ctx) {
371
+ const scalar = resolvedScalar;
372
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
373
+ const gt = meta.grammarTrivia;
374
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
375
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
376
+ }
377
+ return scalar(input, pos, ctx);
378
+ },
336
379
  parse(input, pos, ctx) {
337
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
380
+ const parser2 = resolved;
381
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
338
382
  const gt = meta.grammarTrivia;
339
383
  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
- }
384
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
349
385
  }
350
- return resolved.parse(input, pos, ctx);
386
+ return parser2.parse(input, pos, ctx);
351
387
  },
352
388
  define(p) {
353
389
  if (resolved) throw new Error("ref<T>() already defined");
354
390
  resolved = p;
391
+ resolvedScalar = scalarOf(p);
355
392
  ownBoundary = hasOwnTriviaBoundary(p);
356
393
  meta.firstSet = p._meta.firstSet;
357
394
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -737,6 +774,7 @@ function createParseContext() {
737
774
  _fe: void 0,
738
775
  _fx: void 0,
739
776
  _fc: void 0,
777
+ _sv: void 0,
740
778
  _probe: void 0,
741
779
  _cstChildren: void 0,
742
780
  _cstLeaves: void 0,
@@ -1574,6 +1612,24 @@ function parser(opts, root) {
1574
1612
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
1575
1613
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
1576
1614
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
1615
+ const rootScalar = scalarOf(root);
1616
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
1617
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
1618
+ const savedTrivia = ctx.trivia;
1619
+ const savedLabels = ctx.triviaKindLabels;
1620
+ if (clearTrivia) {
1621
+ ctx.trivia = void 0;
1622
+ ctx.triviaKindLabels = void 0;
1623
+ } else if (scopeTrivia !== void 0) {
1624
+ ctx.trivia = scopeTrivia;
1625
+ ctx.triviaKindLabels = scopeLabels;
1626
+ }
1627
+ const end = rootScalar(input, pos, ctx);
1628
+ ctx.trivia = savedTrivia;
1629
+ ctx.triviaKindLabels = savedLabels;
1630
+ return end;
1631
+ } : void 0;
1632
+ let publicScalar;
1577
1633
  const grammar = {
1578
1634
  _tag: "grammar",
1579
1635
  _meta: {
@@ -1597,7 +1653,20 @@ function parser(opts, root) {
1597
1653
  constructionTrackLines: trackLinesPolicy,
1598
1654
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
1599
1655
  },
1656
+ _parseScalar: parseScalar,
1600
1657
  parse(input, pos, _ctx) {
1658
+ if (pos === void 0 && _ctx === void 0) {
1659
+ publicScalar ??= scalarRootOf(grammar) ?? null;
1660
+ if (publicScalar) {
1661
+ const ctx2 = createParseContext();
1662
+ const end = publicScalar(input, 0, ctx2);
1663
+ if (end < 0) {
1664
+ const at = ~end;
1665
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
1666
+ }
1667
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
1668
+ }
1669
+ }
1601
1670
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
1602
1671
  const trackLines = trackLinesOf(_ctx);
1603
1672
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -1889,6 +1958,28 @@ function literal(value, opts = {}) {
1889
1958
  isTrivia: false
1890
1959
  };
1891
1960
  const canMatchNewline = meta.canMatchNewline;
1961
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
1962
+ const code = value.charCodeAt(0);
1963
+ return (input, pos, ctx) => {
1964
+ if (input.charCodeAt(pos) === code) {
1965
+ ctx._sv = value;
1966
+ return pos + 1;
1967
+ }
1968
+ ctx._fx = expected;
1969
+ return ~pos;
1970
+ };
1971
+ })() : (input, pos, ctx) => {
1972
+ const end = pos + value.length;
1973
+ if (end <= input.length) {
1974
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
1975
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
1976
+ ctx._sv = matchedValue;
1977
+ return end;
1978
+ }
1979
+ }
1980
+ ctx._fx = expected;
1981
+ return ~pos;
1982
+ };
1892
1983
  if (caseInsensitive) {
1893
1984
  const upper = value.toUpperCase();
1894
1985
  const lower = value.toLowerCase();
@@ -1929,6 +2020,7 @@ function literal(value, opts = {}) {
1929
2020
  _tag: "literal",
1930
2021
  _meta: meta,
1931
2022
  _def: { tag: "literal", value, caseInsensitive },
2023
+ _parseScalar: parseScalar,
1932
2024
  parse: parse2
1933
2025
  };
1934
2026
  }
@@ -2268,10 +2360,32 @@ function regex(pattern, flags = "") {
2268
2360
  const canMatchNewline = raw.canMatchNewline;
2269
2361
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
2270
2362
  const def = { tag: "regex", source, flags: resolvedFlags };
2363
+ const expected = directTerminalFailureExpected(def);
2364
+ const parseScalar = (input, pos, ctx) => {
2365
+ const scanEnd = scan?.(input, pos);
2366
+ if (scanEnd !== void 0) {
2367
+ if (scanEnd === null) {
2368
+ ctx._fx = expected;
2369
+ return ~pos;
2370
+ }
2371
+ ctx._sv = input.slice(pos, scanEnd);
2372
+ return scanEnd;
2373
+ }
2374
+ anchored.lastIndex = pos;
2375
+ const match = anchored.exec(input);
2376
+ if (match === null) {
2377
+ ctx._fx = expected;
2378
+ return ~pos;
2379
+ }
2380
+ ctx._sv = match[0];
2381
+ return pos + match[0].length;
2382
+ };
2271
2383
  return {
2272
2384
  _tag: "regex",
2273
2385
  _meta: meta,
2274
2386
  _def: def,
2387
+ _stickyRegex: anchored,
2388
+ _parseScalar: parseScalar,
2275
2389
  parse(input, pos, ctx) {
2276
2390
  const scanEnd = scan?.(input, pos);
2277
2391
  if (scanEnd !== void 0) {
@@ -2363,16 +2477,26 @@ function keywords(words, opts = {}) {
2363
2477
  caseInsensitive: opts.caseInsensitive ?? false,
2364
2478
  boundary: opts.boundary
2365
2479
  };
2480
+ const expected = directTerminalFailureExpected(def);
2481
+ const parseScalar = (input, pos, ctx) => {
2482
+ re.lastIndex = pos;
2483
+ const m = re.exec(input);
2484
+ if (m === null) {
2485
+ ctx._fx = expected;
2486
+ return ~pos;
2487
+ }
2488
+ ctx._sv = m[0];
2489
+ return pos + m[0].length;
2490
+ };
2366
2491
  return {
2367
2492
  _tag: "keywords",
2368
2493
  _meta: meta,
2369
2494
  _def: def,
2495
+ _parseScalar: parseScalar,
2370
2496
  parse(input, pos, ctx) {
2371
2497
  re.lastIndex = pos;
2372
2498
  const m = re.exec(input);
2373
- if (m === null || m.index !== pos) {
2374
- return failAt(ctx, directTerminalFailureExpected(def), pos);
2375
- }
2499
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
2376
2500
  const value = m[0];
2377
2501
  const span = { start: pos, end: pos + value.length };
2378
2502
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -2403,6 +2527,9 @@ var fastScanner3;
2403
2527
  function needsDeferredTriviaCommit(ctx) {
2404
2528
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
2405
2529
  }
2530
+ function needsTriviaRollback(ctx) {
2531
+ 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;
2532
+ }
2406
2533
  function saveTriviaMark(ctx) {
2407
2534
  const m = saveCstMark(ctx);
2408
2535
  return {
@@ -2519,7 +2646,8 @@ function advanceTrivia(input, cur, ctx) {
2519
2646
  const triviaP = ctx.trivia;
2520
2647
  if (!triviaP) return cur;
2521
2648
  if (!ctx.trackLines) {
2522
- const fast2 = fastTriviaScanner(triviaP);
2649
+ const classified = triviaP._meta.triviaScanner;
2650
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
2523
2651
  if (fast2) return fast2(input, cur);
2524
2652
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
2525
2653
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -3124,6 +3252,7 @@ function sequence(...parsers) {
3124
3252
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
3125
3253
  }
3126
3254
  const hasAdjacency = adjacency !== null;
3255
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
3127
3256
  const meta = {
3128
3257
  // Union through the nullable prefix — a leading optional()/many() lets a later
3129
3258
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -3132,165 +3261,96 @@ function sequence(...parsers) {
3132
3261
  isTrivia: false
3133
3262
  };
3134
3263
  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 : [];
3264
+ const scalarParsers = parsers.map(scalarOf);
3265
+ const parseScalar = (input, pos, ctx) => {
3145
3266
  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;
3267
+ if (strictArity !== 0) {
3268
+ cur = scalarParsers[0](input, cur, ctx);
3269
+ if (cur < 0) return cur;
3270
+ const first = ctx._sv;
3271
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3272
+ cur = scalarParsers[1](input, cur, ctx);
3273
+ if (cur < 0) return cur;
3274
+ const second = ctx._sv;
3275
+ if (strictArity === 2) {
3276
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
3277
+ return cur;
3188
3278
  }
3189
- } finally {
3190
- ctx._sync = inheritedSync;
3279
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3280
+ cur = scalarParsers[2](input, cur, ctx);
3281
+ if (cur < 0) return cur;
3282
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
3283
+ return cur;
3191
3284
  }
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
3285
  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
- }
3286
+ for (let i = 0; i < scalarParsers.length; i++) {
3287
+ let termPos = cur;
3288
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
3289
+ const end = scalarParsers[i](input, termPos, ctx);
3290
+ if (end < 0) return end;
3291
+ if (values !== void 0) values.push(ctx._sv);
3292
+ if (end > termPos || termPos === cur) cur = end;
3293
+ }
3294
+ ctx._sv = values;
3295
+ return cur;
3296
+ };
3297
+ let followSentinels;
3249
3298
  return {
3250
3299
  _tag: "sequence",
3251
3300
  _meta: meta,
3252
3301
  _def: def,
3302
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
3253
3303
  parse(input, pos, ctx) {
3254
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
3255
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
3304
+ const tolerant = ctx._tolerant === true;
3305
+ if (tolerant) {
3306
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
3307
+ parsers.slice(i + 1).reduce(
3308
+ (set, parser2) => union(set, firstSetOf(parser2)),
3309
+ { kind: "empty" }
3310
+ )
3311
+ ));
3312
+ }
3313
+ const inheritedSync = ctx._sync;
3314
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
3256
3315
  const values = def.valueUnused ? void 0 : [];
3257
3316
  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);
3317
+ try {
3318
+ for (let i = 0; i < parsers.length; i++) {
3319
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
3320
+ const assertion = adjacency?.[i];
3321
+ if (assertion) {
3322
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
3323
+ if (values !== void 0) values.push(null);
3324
+ continue;
3268
3325
  }
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 {
3326
+ let termPos = cur;
3327
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3328
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3329
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3330
+ if (ctx.trivia && i > 0) {
3331
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
3332
+ }
3333
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3334
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3335
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3336
+ const result = parsers[i].parse(input, termPos, ctx);
3337
+ if (!result.ok) return result;
3338
+ if (values !== void 0) values.push(result.value);
3339
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
3340
+ else if (deferredTrivia) {
3277
3341
  rollbackScannedTriviaAt(
3278
3342
  ctx,
3279
- mTlog,
3343
+ markTlog,
3280
3344
  scanTlog,
3281
- mLog,
3345
+ markLog,
3282
3346
  scanLog,
3283
- mRootLog,
3347
+ markRootLog,
3284
3348
  scanRootLog
3285
3349
  );
3286
3350
  }
3287
- if (values !== void 0) values.push(result2.value);
3288
- continue;
3289
3351
  }
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;
3352
+ } finally {
3353
+ if (tolerant) ctx._sync = inheritedSync;
3294
3354
  }
3295
3355
  return {
3296
3356
  ok: true,
@@ -3422,7 +3482,8 @@ function choice(...args) {
3422
3482
  disjoint
3423
3483
  };
3424
3484
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3425
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3485
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
3486
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
3426
3487
  let greedyLitMap = null;
3427
3488
  let sortedParsers = null;
3428
3489
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -3436,6 +3497,37 @@ function choice(...args) {
3436
3497
  } else if (strategy?.tag === "literalsLongestFirst") {
3437
3498
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
3438
3499
  }
3500
+ const scalarParsers = parsers.map(scalarOf);
3501
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
3502
+ const scalarExpected = parsers.flatMap(deriveExpected);
3503
+ const parseScalar = (input, pos, ctx) => {
3504
+ if (disjoint) {
3505
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3506
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3507
+ if (idx < 0 && code >= 0) {
3508
+ for (let i = 0; i < parsers.length; i++) {
3509
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3510
+ idx = i;
3511
+ break;
3512
+ }
3513
+ }
3514
+ }
3515
+ if (idx >= 0) {
3516
+ const gate2 = gates[idx];
3517
+ if (!gate2 || gate2(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3518
+ ctx._fx = deriveExpected(parsers[idx]);
3519
+ return ~pos;
3520
+ }
3521
+ } else {
3522
+ for (let i = 0; i < scalarParsers.length; i++) {
3523
+ if (gates[i] && !gates[i](ctx.state)) continue;
3524
+ const end = scalarParsers[i](input, pos, ctx);
3525
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3526
+ }
3527
+ }
3528
+ ctx._fx = scalarExpected;
3529
+ return ~pos;
3530
+ };
3439
3531
  return {
3440
3532
  _tag: "choice",
3441
3533
  _meta: meta,
@@ -3447,6 +3539,7 @@ function choice(...args) {
3447
3539
  strategy: strategy ?? { tag: "firstMatch" },
3448
3540
  autoNot
3449
3541
  },
3542
+ _parseScalar: scalarEligible ? parseScalar : void 0,
3450
3543
  parse(input, pos, ctx) {
3451
3544
  const expected = [];
3452
3545
  let expectedAt = pos;
@@ -3978,8 +4071,8 @@ function attempt(parser2) {
3978
4071
  }
3979
4072
 
3980
4073
  // src/combinators/repeat.ts
3981
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3982
- const mark = saveTriviaMark(ctx);
4074
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
4075
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
3983
4076
  let pos = cur;
3984
4077
  if (ctx.trivia) {
3985
4078
  if (needsDeferredTriviaCommit(ctx)) {
@@ -3989,24 +4082,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3989
4082
  }
3990
4083
  }
3991
4084
  if (pos >= input.length && !mandatory) {
3992
- rollbackTrivia(ctx, mark);
4085
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3993
4086
  return "stop";
3994
4087
  }
3995
4088
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
3996
- rollbackTrivia(ctx, mark);
4089
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3997
4090
  return "stop";
3998
4091
  }
3999
4092
  const result = combinator.parse(input, pos, ctx);
4000
4093
  if (!result.ok) {
4001
- rollbackTrivia(ctx, mark);
4094
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4002
4095
  if (result.committed) return { fail: result, failPos: pos };
4003
4096
  return { fail: result, failPos: pos };
4004
4097
  }
4005
4098
  if (result.span.end === pos && !mandatory) {
4006
- rollbackTrivia(ctx, mark);
4099
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4007
4100
  return "stop";
4008
4101
  }
4009
- return { value: result.value, end: result.span.end };
4102
+ return result;
4010
4103
  }
4011
4104
  function resolveBounds(what, opts) {
4012
4105
  const min = opts.min ?? 0;
@@ -4019,6 +4112,21 @@ function resolveBounds(what, opts) {
4019
4112
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
4020
4113
  return { min, max };
4021
4114
  }
4115
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
4116
+ while (cur < input.length && remaining > 0) {
4117
+ let itemPos = cur;
4118
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4119
+ if (itemPos >= input.length) break;
4120
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
4121
+ const end = child(input, itemPos, ctx);
4122
+ if (end <= itemPos) break;
4123
+ if (values !== void 0) values.push(ctx._sv);
4124
+ cur = end;
4125
+ remaining--;
4126
+ }
4127
+ ctx._sv = values;
4128
+ return cur;
4129
+ }
4022
4130
  function many(combinator, opts = {}) {
4023
4131
  const { min, max } = resolveBounds("many()", opts);
4024
4132
  if (min >= 1) return atLeast(combinator, min, max);
@@ -4030,17 +4138,21 @@ function many(combinator, opts = {}) {
4030
4138
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
4031
4139
  let expected;
4032
4140
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4141
+ const scalarChild = scalarOf(combinator);
4142
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
4033
4143
  return {
4034
4144
  _tag: "many",
4035
4145
  _meta: meta,
4036
4146
  _def: def,
4147
+ _parseScalar: parseScalar,
4037
4148
  parse(input, pos, ctx) {
4038
4149
  const values = def.valueUnused ? void 0 : [];
4150
+ const rollbackNeeded = needsTriviaRollback(ctx);
4039
4151
  let cur = pos;
4040
4152
  let count = 0;
4041
4153
  while (cur < input.length) {
4042
4154
  if (count >= max) break;
4043
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4155
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4044
4156
  if (item === "stop") break;
4045
4157
  if ("fail" in item) {
4046
4158
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4057,7 +4169,7 @@ function many(combinator, opts = {}) {
4057
4169
  }
4058
4170
  if (values !== void 0) values.push(item.value);
4059
4171
  count++;
4060
- cur = item.end;
4172
+ cur = item.span.end;
4061
4173
  }
4062
4174
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4063
4175
  }
@@ -4075,30 +4187,47 @@ function atLeast(combinator, min, max) {
4075
4187
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4076
4188
  let expected;
4077
4189
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4190
+ const scalarChild = scalarOf(combinator);
4191
+ const parseScalar = (input, pos, ctx) => {
4192
+ let cur = scalarChild(input, pos, ctx);
4193
+ if (cur < 0) return cur;
4194
+ const values = def.valueUnused ? void 0 : [ctx._sv];
4195
+ for (let count = 1; count < min; count++) {
4196
+ let itemPos = cur;
4197
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4198
+ const end = scalarChild(input, itemPos, ctx);
4199
+ if (end < 0) return ~cur;
4200
+ cur = end;
4201
+ if (values !== void 0) values.push(ctx._sv);
4202
+ }
4203
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
4204
+ };
4078
4205
  return {
4079
4206
  _tag: "oneOrMore",
4080
4207
  _meta: meta,
4081
4208
  _def: def,
4209
+ _parseScalar: parseScalar,
4082
4210
  parse(input, pos, ctx) {
4083
4211
  const first = combinator.parse(input, pos, ctx);
4084
4212
  if (!first.ok) return first;
4085
4213
  const values = def.valueUnused ? void 0 : [first.value];
4214
+ const rollbackNeeded = needsTriviaRollback(ctx);
4086
4215
  let cur = first.span.end;
4087
4216
  let count = 1;
4088
4217
  while (count < min) {
4089
- const item = repItem(combinator, input, cur, ctx, guardable, true);
4218
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
4090
4219
  if (item === "stop" || "fail" in item) {
4091
4220
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4092
4221
  expected ??= deriveExpected(combinator);
4093
4222
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4094
4223
  }
4095
4224
  if (values !== void 0) values.push(item.value);
4096
- cur = item.end;
4225
+ cur = item.span.end;
4097
4226
  count++;
4098
4227
  }
4099
4228
  while (cur < input.length) {
4100
4229
  if (count >= max) break;
4101
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4230
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4102
4231
  if (item === "stop") break;
4103
4232
  if ("fail" in item) {
4104
4233
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4115,7 +4244,7 @@ function atLeast(combinator, min, max) {
4115
4244
  }
4116
4245
  if (values !== void 0) values.push(item.value);
4117
4246
  count++;
4118
- cur = item.end;
4247
+ cur = item.span.end;
4119
4248
  }
4120
4249
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4121
4250
  }
@@ -4128,10 +4257,22 @@ function optional(combinator) {
4128
4257
  isTrivia: false
4129
4258
  };
4130
4259
  const firstSetSkippable = !matchesEmpty(combinator);
4260
+ const scalarChild = scalarOf(combinator);
4261
+ const parseScalar = (input, pos, ctx) => {
4262
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
4263
+ ctx._sv = null;
4264
+ return pos;
4265
+ }
4266
+ const end = scalarChild(input, pos, ctx);
4267
+ if (end >= 0) return end;
4268
+ ctx._sv = null;
4269
+ return pos;
4270
+ };
4131
4271
  return {
4132
4272
  _tag: "optional",
4133
4273
  _meta: meta,
4134
4274
  _def: { tag: "optional", parser: combinator },
4275
+ _parseScalar: parseScalar,
4135
4276
  parse(input, pos, ctx) {
4136
4277
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4137
4278
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -4168,6 +4309,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
4168
4309
  expected ??= deriveExpected(combinator);
4169
4310
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4170
4311
  };
4312
+ const scalarExpected = deriveExpected(combinator);
4313
+ const scalarChild = scalarOf(combinator);
4314
+ const scalarSeparator = scalarOf(separator);
4315
+ const parseScalar = (input, pos, ctx) => {
4316
+ let cur = scalarChild(input, pos, ctx);
4317
+ if (cur < 0) {
4318
+ if (min >= 1) {
4319
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4320
+ return ~pos;
4321
+ }
4322
+ ctx._sv = [];
4323
+ return pos;
4324
+ }
4325
+ const values = [ctx._sv];
4326
+ while (values.length < max && (cur < input.length || values.length < min)) {
4327
+ const beforeSeparator = cur;
4328
+ let separatorPos = cur;
4329
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
4330
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
4331
+ if (separatorEnd < 0) break;
4332
+ let itemPos = separatorEnd;
4333
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
4334
+ const itemEnd = scalarChild(input, itemPos, ctx);
4335
+ if (itemEnd < 0) {
4336
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
4337
+ break;
4338
+ }
4339
+ values.push(ctx._sv);
4340
+ cur = itemEnd;
4341
+ }
4342
+ if (values.length < min) {
4343
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4344
+ return ~cur;
4345
+ }
4346
+ ctx._sv = values;
4347
+ return cur;
4348
+ };
4171
4349
  return {
4172
4350
  _tag: "sepBy",
4173
4351
  _meta: meta,
@@ -4183,6 +4361,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
4183
4361
  // this option surface already; parity is held by test/parity, not by hope.
4184
4362
  ...keepSeparators ? { keepSeparators: true } : {}
4185
4363
  },
4364
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
4186
4365
  parse(input, pos, ctx) {
4187
4366
  const first = combinator.parse(input, pos, ctx);
4188
4367
  const values = [];
@@ -4798,11 +4977,54 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
4798
4977
  }
4799
4978
 
4800
4979
  // src/combinators/map.ts
4980
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
4801
4981
  function transform(combinator, fn) {
4982
+ const observesSpan = fn.length > 1;
4983
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
4984
+ const terms = sequenceDef?.parsers;
4985
+ const inner = terms?.[1];
4986
+ 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;
4987
+ const child = scalarOf(combinator);
4988
+ const parseScalar = fused ? (() => {
4989
+ const body = inner._stickyRegex;
4990
+ const tuple = ['"', "", '"'];
4991
+ const expected = [JSON.stringify('"')];
4992
+ return (input, pos, ctx) => {
4993
+ if (ctx.trivia !== void 0) {
4994
+ const end2 = child(input, pos, ctx);
4995
+ if (end2 < 0) return end2;
4996
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
4997
+ return end2;
4998
+ }
4999
+ if (input.charCodeAt(pos) !== 34) {
5000
+ ctx._fx = expected;
5001
+ return ~pos;
5002
+ }
5003
+ body.lastIndex = pos + 1;
5004
+ const match = body.exec(input);
5005
+ const close = pos + 1 + match[0].length;
5006
+ if (input.charCodeAt(close) !== 34) {
5007
+ ctx._fx = expected;
5008
+ return ~close;
5009
+ }
5010
+ tuple[1] = match[0];
5011
+ const end = close + 1;
5012
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
5013
+ return end;
5014
+ };
5015
+ })() : /* @__PURE__ */ (() => {
5016
+ return (input, pos, ctx) => {
5017
+ const end = child(input, pos, ctx);
5018
+ if (end < 0) return end;
5019
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
5020
+ return end;
5021
+ };
5022
+ })();
4802
5023
  return {
4803
5024
  _tag: "transform",
4804
5025
  _meta: combinator._meta,
4805
5026
  _def: { tag: "transform", parser: combinator, fn },
5027
+ _parseScalar: parseScalar,
4806
5028
  parse(input, pos, ctx) {
4807
5029
  const result = combinator.parse(input, pos, ctx);
4808
5030
  if (!result.ok) return result;
@@ -4817,9 +5039,11 @@ function trivia(combinator) {
4817
5039
  _meta: {
4818
5040
  ...combinator._meta,
4819
5041
  isTrivia: true,
5042
+ triviaScanner: fastTriviaScanner(combinator),
4820
5043
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
4821
5044
  },
4822
5045
  _def: { tag: "trivia", parser: combinator },
5046
+ _parseScalar: scalarOf(combinator),
4823
5047
  parse: combinator.parse.bind(combinator)
4824
5048
  };
4825
5049
  }
@@ -5774,7 +5998,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
5774
5998
  if (!Number.isInteger(spec[2]) || spec[2] < 0) {
5775
5999
  throw new TypeError("table balanced lexical program has an invalid scan reference");
5776
6000
  }
5777
- const run3 = (_input, _pos, ctx, scan) => {
6001
+ const run = (_input, _pos, ctx, scan) => {
5778
6002
  if (scan === void 0) throw new TypeError("table balanced lexical program lost its scan body");
5779
6003
  const result = scan.parse(_input, _pos, ctx);
5780
6004
  if (!result.ok) {
@@ -5784,7 +6008,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
5784
6008
  }
5785
6009
  return result.span.end;
5786
6010
  };
5787
- return Object.assign(run3, { scan: spec[2] });
6011
+ return Object.assign(run, { scan: spec[2] });
5788
6012
  }
5789
6013
  if (spec[0] === 2) return fixedTreeRunner(spec.slice(2), matchers, classes, expected);
5790
6014
  if (spec[0] === 1) {
@@ -7800,15 +8024,15 @@ function parseStringShape(source) {
7800
8024
  if (source.length < 3 || source[source.length - 1] !== q2) return null;
7801
8025
  const inner = source.slice(1, -1);
7802
8026
  const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
7803
- const ESC2 = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
8027
+ const ESC = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
7804
8028
  let body;
7805
8029
  let esc;
7806
- let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC2}\\)\\*$`).exec(inner);
8030
+ let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC}\\)\\*$`).exec(inner);
7807
8031
  if (m) {
7808
8032
  body = m[1];
7809
8033
  esc = m[2];
7810
8034
  } else {
7811
- m = new RegExp(`^\\((?:\\?:)?${ESC2}\\|${CLS}\\)\\*$`).exec(inner);
8035
+ m = new RegExp(`^\\((?:\\?:)?${ESC}\\|${CLS}\\)\\*$`).exec(inner);
7812
8036
  if (m) {
7813
8037
  esc = m[1];
7814
8038
  body = m[2];
@@ -9371,6 +9595,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
9371
9595
  function q(s) {
9372
9596
  return JSON.stringify(s);
9373
9597
  }
9598
+ function isAsciiOnlyClass(cls) {
9599
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
9600
+ }
9374
9601
  var NO_SINKS = { fd: false, er: false };
9375
9602
  function sinkSlots(t, s) {
9376
9603
  return `${s.fd ? `,${t}fd=0` : ""}${s.er ? `,${t}er=0` : ""}`;
@@ -9481,7 +9708,7 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false) {
9481
9708
  const { code, k, fx, disp, dsp, triviaLabelled } = t;
9482
9709
  const swapLegal = !cfg.trackLines;
9483
9710
  const hostCst = cfg.hostCst;
9484
- const REC2 = prog.rec === 1 && cfg.tolerant;
9711
+ const REC = prog.rec === 1 && cfg.tolerant;
9485
9712
  if (cfg.coverage) throw new Unemittable("a coverage assembly");
9486
9713
  const roots = [...Object.values(prog.rules), ...extraIps];
9487
9714
  const reachable = [...reachableSites(code, roots)];
@@ -9560,7 +9787,7 @@ function emitAssemblySource(t, prog, cfg, extraIps = [], staticBuild = false) {
9560
9787
  const op = code[ip];
9561
9788
  sinkBits.set(
9562
9789
  ip,
9563
- op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC2 && (op === OP_REP || op === OP_REPV) ? 2 : 0)
9790
+ op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC && (op === OP_REP || op === OP_REPV) ? 2 : 0)
9564
9791
  );
9565
9792
  }
9566
9793
  const sinkKids = [];
@@ -9917,12 +10144,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9917
10144
  return `${head}EC.e=pos;return ''}`;
9918
10145
  case OP_GATE: {
9919
10146
  const child = link(code[ip + 2]);
9920
- const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
10147
+ const resolved = t.cc[code[ip + 1]];
10148
+ const ci = classes.push([resolved]) - 1;
9921
10149
  classPlan.push([code[ip + 1]]);
9922
10150
  const cls = hoist("cl", `CLS[${ci}][0]`);
9923
10151
  const xf = fxRef(code[ip + 3]);
9924
10152
  return `${head}
9925
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10153
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9926
10154
  return ${child}(input,pos,ctx)
9927
10155
  }`;
9928
10156
  }
@@ -9964,7 +10192,7 @@ if(v!==FAIL)return v
9964
10192
  const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "{start:pos,end:pos}"},expected:${xf}}
9965
10193
  const es=ctx._errors
9966
10194
  if(es!==undefined)es.push(err)
9967
- ${REC2 ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
10195
+ ${REC ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
9968
10196
  EC.e=pos
9969
10197
  return err
9970
10198
  }`;
@@ -10083,7 +10311,7 @@ return v
10083
10311
  }
10084
10312
  case OP_LEX_PROGRAM: {
10085
10313
  const programId = code[ip + 1];
10086
- const run3 = hoist("lexProgram", `LEXPROG[${programId}]`);
10314
+ const run = hoist("lexProgram", `LEXPROG[${programId}]`);
10087
10315
  const scanId = t.lexPrograms[programId].scan;
10088
10316
  if (scanId !== void 0) return `${head}
10089
10317
  const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan
@@ -10101,7 +10329,7 @@ ctx._cstTriviaLog=undefined
10101
10329
  ctx._triviaLog=undefined
10102
10330
  ctx._rootTriviaLog=undefined
10103
10331
  let e
10104
- try{e=${run3}(input,pos,ctx,SCANS[${scanId}])}finally{
10332
+ try{e=${run}(input,pos,ctx,SCANS[${scanId}])}finally{
10105
10333
  _pfScan=sScan
10106
10334
  ctx.trivia=sTri
10107
10335
  ctx.triviaKindLabels=sKinds
@@ -10120,7 +10348,7 @@ EC.e=e
10120
10348
  return v
10121
10349
  }`;
10122
10350
  return `${head}
10123
- const e=${run3}(input,pos,ctx)
10351
+ const e=${run}(input,pos,ctx)
10124
10352
  if(e<0)return FAIL
10125
10353
  const v=input.slice(pos,e)
10126
10354
  if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
@@ -10131,7 +10359,7 @@ return v
10131
10359
  /* ── transaction ─────────────────────────────────────────────────────── */
10132
10360
  case OP_ATTEMPT: {
10133
10361
  const child = link(code[ip + 1]);
10134
- const clean = !REC2 && failureRollbackClean(prog, ip);
10362
+ const clean = !REC && failureRollbackClean(prog, ip);
10135
10363
  const p = tmp();
10136
10364
  return `${head}
10137
10365
  ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
@@ -10184,7 +10412,7 @@ return null
10184
10412
  }
10185
10413
  case OP_OPT: {
10186
10414
  const child = link(code[ip + 1]);
10187
- const clean = !REC2 && failureRollbackClean(prog, ip);
10415
+ const clean = !REC && failureRollbackClean(prog, ip);
10188
10416
  const p = tmp();
10189
10417
  return `${head}
10190
10418
  ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
@@ -10214,15 +10442,15 @@ return v
10214
10442
  const childIp = code[base + i];
10215
10443
  kids.push(code[childIp] === OP_ADJ ? "" : link(childIp));
10216
10444
  }
10217
- const sy = REC2 ? `${tmp()}sy` : "";
10445
+ const sy = REC ? `${tmp()}sy` : "";
10218
10446
  const pub = (i) => {
10219
10447
  const s = sentRef(code[base + n + i]);
10220
10448
  return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
10221
10449
  };
10222
10450
  const parts = [head];
10223
- if (REC2) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
10451
+ if (REC) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
10224
10452
  parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
10225
- const close = () => REC2 ? `${parts.join("\n")}
10453
+ const close = () => REC ? `${parts.join("\n")}
10226
10454
  }finally{ctx._sync=${sy}}
10227
10455
  }` : `${parts.join("\n")}
10228
10456
  }`;
@@ -10235,7 +10463,7 @@ return v
10235
10463
  for (let i = 1; i < n; i++) {
10236
10464
  const vn = `v${i}`;
10237
10465
  parts.push(`let ${vn}`);
10238
- if (REC2) parts.push(pub(i));
10466
+ if (REC) parts.push(pub(i));
10239
10467
  const childIp = code[base + i];
10240
10468
  if (code[childIp] === OP_ADJ) {
10241
10469
  const negated = code[childIp + 1] === 1;
@@ -10265,10 +10493,11 @@ return v
10265
10493
  const asc = hoist("as", `DISP[${di}].ascii`);
10266
10494
  const hiArr = table.hi;
10267
10495
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
10496
+ const directAscii = staticBuild && table.hi.length === 0;
10268
10497
  return `${head}
10269
- const c=lead(input,pos)
10498
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10270
10499
  let arm=-1
10271
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
10500
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
10272
10501
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
10273
10502
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
10274
10503
  if(arm>=0){
@@ -10290,7 +10519,9 @@ return FAIL
10290
10519
  const di = code[ip + 1];
10291
10520
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
10292
10521
  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}]`));
10522
+ const maskable = n <= 32;
10523
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
10524
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
10294
10525
  const tokenCandidate = tokenChoiceCandidates.get(ip);
10295
10526
  const pretests = Array.from({ length: n }, (_, i) => {
10296
10527
  if (tokenCandidate?.arm === i) {
@@ -10310,12 +10541,11 @@ return FAIL
10310
10541
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
10311
10542
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
10312
10543
  });
10313
- const maskable = n <= 32;
10314
10544
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
10315
10545
  if (maskable) maskPlan.push(~di);
10316
10546
  const p = tmp();
10317
10547
  const encodedRollbackMask = choiceRollbackMask(prog, ip) ?? -1;
10318
- const rollbackMask = REC2 ? -1 : encodedRollbackMask;
10548
+ const rollbackMask = REC ? -1 : encodedRollbackMask;
10319
10549
  const hasRollback = rollbackMask !== 0;
10320
10550
  const startFailureExact = arms.every((_arm, i) => {
10321
10551
  const terminal = leadingScalarTerminal(code, code[base + i], 0, false);
@@ -10372,16 +10602,16 @@ ${merge}
10372
10602
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
10373
10603
  return FAIL`;
10374
10604
  return `${head}
10375
- const c=lead(input,pos)
10605
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10376
10606
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10377
10607
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
10378
10608
  ${maskable ? `if(c<128){
10379
- const bits=${maskName}[c<0?128:c]
10609
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10380
10610
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10381
10611
  ${lazyArms(true)}
10382
- }else{
10612
+ }${directAsciiMask ? "" : `else{
10383
10613
  ${lazyArms(false)}
10384
- }
10614
+ }`}
10385
10615
  ` : lazyArms(false)}
10386
10616
  ${finish}
10387
10617
  }`;
@@ -10432,7 +10662,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
10432
10662
  ${rollbackFor(i)}
10433
10663
  }${routeMiss}${sequenceMiss}`;
10434
10664
  }).join("\n") : "";
10435
- const generalArms = arms.map((arm, i) => {
10665
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
10436
10666
  const pretest = pretests[i];
10437
10667
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
10438
10668
  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 +10692,12 @@ ${rollbackFor(i)}
10462
10692
  }${miss}`;
10463
10693
  }).join("\n");
10464
10694
  return `${head}
10465
- const c=lead(input,pos)
10695
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
10466
10696
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
10467
10697
  let acc
10468
10698
  let best=pos
10469
10699
  ${maskable ? `if(c<128){
10470
- const bits=${maskName}[c<0?128:c]
10700
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
10471
10701
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
10472
10702
  ${startFailureExact ? "" : "let prev=0"}
10473
10703
  ${maskArms}
@@ -10562,14 +10792,18 @@ return [key,v]
10562
10792
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
10563
10793
  const collect = op === OP_REP;
10564
10794
  let itemCls;
10565
- if (!REC2) {
10795
+ let itemAscii = false;
10796
+ if (!REC) {
10566
10797
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
10567
10798
  if (itemClassIndex >= 0) {
10568
- const ci = classes.push([t.cc[itemClassIndex]]) - 1;
10799
+ const resolved = t.cc[itemClassIndex];
10800
+ const ci = classes.push([resolved]) - 1;
10569
10801
  classPlan.push([itemClassIndex]);
10570
10802
  itemCls = hoist("ri", `CLS[${ci}][0]`);
10803
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
10571
10804
  }
10572
10805
  }
10806
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
10573
10807
  const skipBeforeFirst = sepIp < 0 && min === 0;
10574
10808
  const p = tmp();
10575
10809
  const via = sep2 !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -10607,11 +10841,11 @@ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
10607
10841
  ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
10608
10842
  }`;
10609
10843
  const my = `${p}my`;
10610
- const recFx = REC2 ? fxRef(code[ip + 6]) : "";
10611
- const sepSent = REC2 ? sentRef(code[ip + 7]) : "undefined";
10844
+ const recFx = REC ? fxRef(code[ip + 6]) : "";
10845
+ const sepSent = REC ? sentRef(code[ip + 7]) : "undefined";
10612
10846
  const recSent = sep2 === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
10613
10847
  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)){
10848
+ const recBranch = !REC ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
10615
10849
  ${sep2 === void 0 ? `${rb}
10616
10850
  ` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
10617
10851
  ${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
@@ -10622,14 +10856,14 @@ continue
10622
10856
  `;
10623
10857
  return `${head}
10624
10858
  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
10859
+ ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC ? `const ${my}=ctx._sync
10626
10860
  ` : ""}${itemCls === void 0 ? "" : `const ${p}gate=ctx._probe===undefined
10627
10861
  `}let cur=pos
10628
10862
  let count=0
10629
10863
  for(;;){
10630
10864
  ${max >= 0 ? `if(count>=${max})break
10631
10865
  ` : ""}${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
10866
+ ` : ""}${itemCls !== void 0 && sep2 === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
10633
10867
  ` : ""}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
10868
  ${markBody}
10635
10869
  let itemStart=cur
@@ -10654,14 +10888,14 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
10654
10888
  ${rb}
10655
10889
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
10656
10890
  }
10657
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
10891
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
10658
10892
  ${rb}
10659
10893
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
10660
10894
  }
10661
10895
  `}ctx._fc=false
10662
10896
  const v=${child}(input,itemStart,ctx)
10663
10897
  if(v===FAIL){
10664
- ${REC2 ? `if(ctx._fc===true){
10898
+ ${REC ? `if(ctx._fc===true){
10665
10899
  ${rb}
10666
10900
  return FAIL
10667
10901
  }
@@ -11232,7 +11466,7 @@ function assemble(t, prog, cfg) {
11232
11466
  const triviaScan = t.triviaScan;
11233
11467
  const swapLegal = !cfg.trackLines;
11234
11468
  const hostCst = cfg.hostCst;
11235
- const REC2 = prog.rec === 1 && cfg.tolerant;
11469
+ const REC = prog.rec === 1 && cfg.tolerant;
11236
11470
  const sentinels = /* @__PURE__ */ new Map();
11237
11471
  function sentinelFor(cls) {
11238
11472
  if (cls < 0) return void 0;
@@ -12233,7 +12467,7 @@ function assemble(t, prog, cfg) {
12233
12467
  const child = link(code[ip + 1]);
12234
12468
  const xf = fx[code[ip + 2]];
12235
12469
  const expectSpan = (ctx, pos) => prog.lines === 1 ? spanLines(ctx, pos, pos) : { start: pos, end: pos };
12236
- if (REC2) {
12470
+ if (REC) {
12237
12471
  return (input, pos, ctx) => {
12238
12472
  const v = child(input, pos, ctx);
12239
12473
  if (v !== FAIL) return v;
@@ -12540,8 +12774,8 @@ function assemble(t, prog, cfg) {
12540
12774
  };
12541
12775
  }
12542
12776
  case OP_LEX_PROGRAM: {
12543
- const run3 = t.lexPrograms[code[ip + 1]];
12544
- const scanId = run3.scan;
12777
+ const run = t.lexPrograms[code[ip + 1]];
12778
+ const scanId = run.scan;
12545
12779
  if (scanId !== void 0) {
12546
12780
  return (input, pos, ctx) => {
12547
12781
  const sTrivia = ctx.trivia, sKinds = ctx.triviaKindLabels;
@@ -12562,7 +12796,7 @@ function assemble(t, prog, cfg) {
12562
12796
  ctx._rootTriviaLog = void 0;
12563
12797
  let end;
12564
12798
  try {
12565
- end = run3(input, pos, ctx, scans[scanId]);
12799
+ end = run(input, pos, ctx, scans[scanId]);
12566
12800
  } finally {
12567
12801
  SCAN = sScan;
12568
12802
  ctx.trivia = sTrivia;
@@ -12583,7 +12817,7 @@ function assemble(t, prog, cfg) {
12583
12817
  };
12584
12818
  }
12585
12819
  return (input, pos, ctx) => {
12586
- const end = run3(input, pos, ctx);
12820
+ const end = run(input, pos, ctx);
12587
12821
  if (end < 0) return FAIL;
12588
12822
  const value = input.slice(pos, end);
12589
12823
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: { start: pos, end } });
@@ -12680,7 +12914,7 @@ function assemble(t, prog, cfg) {
12680
12914
  return next === void 0 ? cur : next(input, cur, ctx, values, inherited);
12681
12915
  };
12682
12916
  };
12683
- if (REC2) {
12917
+ if (REC) {
12684
12918
  const first2 = link(code[base]);
12685
12919
  const firstSync = sentinelFor(code[base + n]);
12686
12920
  const runnerAt = (i) => {
@@ -13137,7 +13371,7 @@ function assemble(t, prog, cfg) {
13137
13371
  if (n === 2 || n === 3) {
13138
13372
  const a0 = link(code[base]), a1 = link(code[base + 1]);
13139
13373
  const a2 = n === 3 ? link(code[base + 2]) : void 0;
13140
- const predecide = !hostCst && !REC2 && !cfg.probe && !cfg.coverage && !cfg.trackLines;
13374
+ const predecide = !hostCst && !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
13141
13375
  const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
13142
13376
  const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
13143
13377
  const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
@@ -13528,10 +13762,10 @@ function assemble(t, prog, cfg) {
13528
13762
  const itemFx = reportItem ? fx[code[ip + 6]] : EMPTY_FX2;
13529
13763
  const collect = op === OP_REP;
13530
13764
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
13531
- const itemClass = !REC2 && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
13765
+ const itemClass = !REC && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
13532
13766
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
13533
13767
  const skipBeforeFirst = sepIp < 0 && min === 0;
13534
- if (REC2) {
13768
+ if (REC) {
13535
13769
  const itemFx2 = fx[code[ip + 6]];
13536
13770
  const sepSent = sentinelFor(code[ip + 7]);
13537
13771
  return (input, pos, ctx) => {
@@ -14038,7 +14272,7 @@ function assemble(t, prog, cfg) {
14038
14272
  lead,
14039
14273
  asciiFoldKey,
14040
14274
  ROUTED_FX,
14041
- REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14275
+ REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14042
14276
  matchesAt,
14043
14277
  recoverScan,
14044
14278
  orSentinel,
@@ -14120,7 +14354,7 @@ function assemble(t, prog, cfg) {
14120
14354
  // — a strict one emits no reader — and through the SAME `sentinelFor` memo
14121
14355
  // the closure pieces use, so both engines resync to the same combinator
14122
14356
  // object rather than to two separately constructed ones.
14123
- REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14357
+ REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
14124
14358
  matchesAt,
14125
14359
  recoverScan,
14126
14360
  orSentinel,
@@ -15153,36 +15387,36 @@ function findRegexFragments(visited) {
15153
15387
  if (branches.length >= 2) runs.add(branches.join("|"));
15154
15388
  for (let i = 0; i < branches.length; i++) {
15155
15389
  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);
15390
+ const run = branches.slice(i, i + n).join("|");
15391
+ if (run.length < 4) continue;
15392
+ runs.add(run);
15159
15393
  }
15160
15394
  }
15161
15395
  }
15162
- for (const run3 of runs) {
15163
- let e = byRun.get(run3);
15396
+ for (const run of runs) {
15397
+ let e = byRun.get(run);
15164
15398
  if (e === void 0) {
15165
- e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches: run3.split("|").length };
15166
- byRun.set(run3, e);
15399
+ e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches: run.split("|").length };
15400
+ byRun.set(run, e);
15167
15401
  }
15168
15402
  if (e.nodes.has(v.p)) continue;
15169
15403
  e.nodes.add(v.p);
15170
15404
  e.occ.push({ site: v.site, source: d.source });
15171
15405
  }
15172
15406
  }
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);
15407
+ 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
15408
  const kept = [];
15175
15409
  for (const c of candidates) {
15176
15410
  if (kept.some((k) => k.e.occ.length >= c.e.occ.length && `|${k.run}|`.includes(`|${c.run}|`))) continue;
15177
15411
  kept.push(c);
15178
15412
  }
15179
- return kept.map(({ run: run3, e }) => ({
15413
+ return kept.map(({ run, e }) => ({
15180
15414
  kind: "regex-fragment",
15181
- id: `regex-fragment:${run3}`,
15182
- fragment: run3,
15415
+ id: `regex-fragment:${run}`,
15416
+ fragment: run,
15183
15417
  branches: e.branches,
15184
15418
  count: e.occ.length,
15185
- savings: (e.occ.length - 1) * run3.length,
15419
+ savings: (e.occ.length - 1) * run.length,
15186
15420
  sources: e.occ.map((o) => `/${o.source}/`),
15187
15421
  sites: e.occ.map((o) => o.site),
15188
15422
  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 +16926,7 @@ function compileRuleMap(ruleMap, opts = {}) {
16692
16926
  }
16693
16927
 
16694
16928
  // src/version.ts
16695
- var PARSEMAN_VERSION = "0.50.1";
16929
+ var PARSEMAN_VERSION = "0.50.3";
16696
16930
 
16697
16931
  // src/compiler/compile-linkable-table.ts
16698
16932
  function isLocal(rule) {
@@ -16785,72 +17019,6 @@ function cstBuildHost(typeOrOptions, children3, _fields, span, rawChildren, triv
16785
17019
  cstBuildHost._parsemanCstOutput = true;
16786
17020
  var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
16787
17021
 
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
17022
  // src/combinators/gate.ts
16855
17023
  function gate(predicate) {
16856
17024
  const meta = {