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
@@ -1,8 +1,18 @@
1
1
  // src/combinators/first-set.ts
2
- function resolveNamedRef(p, resolve) {
2
+ function winnerForRef(p, resolve) {
3
3
  if (resolve === void 0) return void 0;
4
4
  const name = p._ruleName;
5
- return name === void 0 ? void 0 : resolve(name);
5
+ const w = name === void 0 ? void 0 : resolve(name);
6
+ if (w === void 0 || w === p) return void 0;
7
+ let cur = w;
8
+ for (const seen = /* @__PURE__ */ new Set(); !seen.has(cur); ) {
9
+ if (cur === p) return void 0;
10
+ seen.add(cur);
11
+ const cd = cur._def;
12
+ if (cd.tag !== "grammar" && cd.tag !== "trivia") return w;
13
+ cur = cd.parser;
14
+ }
15
+ return w;
6
16
  }
7
17
  function union(a, b) {
8
18
  if (a.kind === "any" || b.kind === "any") return { kind: "any" };
@@ -100,13 +110,15 @@ function matchesEmptyBody(p, seen, resolve) {
100
110
  case "grammar":
101
111
  case "recover":
102
112
  return me(d.parser);
103
- case "lazy":
113
+ case "lazy": {
114
+ const w = winnerForRef(p, resolve);
115
+ if (w !== void 0) return me(w);
104
116
  try {
105
117
  return me(d.thunk());
106
118
  } catch {
107
- const t = resolveNamedRef(p, resolve);
108
- return t ? me(t) : true;
119
+ return true;
109
120
  }
121
+ }
110
122
  default:
111
123
  return true;
112
124
  }
@@ -170,13 +182,15 @@ function firstSetBody(p, seen, resolve) {
170
182
  // terminals: no refs, cached set is exact
171
183
  case "dispatch":
172
184
  return fs(d.selector);
173
- case "lazy":
185
+ case "lazy": {
186
+ const w = winnerForRef(p, resolve);
187
+ if (w !== void 0) return fs(w);
174
188
  try {
175
189
  return fs(d.thunk());
176
190
  } catch {
177
- const t = resolveNamedRef(p, resolve);
178
- return t ? fs(t) : any();
191
+ return any();
179
192
  }
193
+ }
180
194
  case "choice": {
181
195
  let out = empty();
182
196
  for (const arm of d.parsers) out = union(out, fs(arm));
@@ -270,9 +284,43 @@ function hasOwnTriviaBoundary(p, depth = MAX_DEPTH) {
270
284
  }
271
285
  }
272
286
 
287
+ // src/combinators/scalar.ts
288
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
289
+ function scalarOf(combinator) {
290
+ return combinator._parseScalar;
291
+ }
292
+ function scalarTree(parser2, seen) {
293
+ if (seen.has(parser2)) return true;
294
+ if (parser2._parseScalar === void 0) return false;
295
+ seen.add(parser2);
296
+ const def = parser2._def;
297
+ if (!SCALAR_TAG.test(def.tag)) return false;
298
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
299
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
300
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
301
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
302
+ }
303
+ function scalarRootOf(combinator) {
304
+ const scalar = combinator._parseScalar;
305
+ const def = combinator._def;
306
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
307
+ }
308
+
273
309
  // src/combinators/ref.ts
310
+ function withRuleTrivia(trivia2, ctx, run) {
311
+ const savedLabels = ctx.triviaKindLabels;
312
+ ctx.trivia = trivia2;
313
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
314
+ try {
315
+ return run();
316
+ } finally {
317
+ ctx.trivia = void 0;
318
+ ctx.triviaKindLabels = savedLabels;
319
+ }
320
+ }
274
321
  function ref() {
275
322
  let resolved = null;
323
+ let resolvedScalar = null;
276
324
  let ownBoundary = false;
277
325
  const meta = {
278
326
  firstSet: any(),
@@ -289,25 +337,28 @@ function ref() {
289
337
  return resolved;
290
338
  }
291
339
  },
340
+ _parseScalar(input, pos, ctx) {
341
+ const scalar = resolvedScalar;
342
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
343
+ const gt = meta.grammarTrivia;
344
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
345
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
346
+ }
347
+ return scalar(input, pos, ctx);
348
+ },
292
349
  parse(input, pos, ctx) {
293
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
350
+ const parser2 = resolved;
351
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
294
352
  const gt = meta.grammarTrivia;
295
353
  if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
296
- const savedLabels = ctx.triviaKindLabels;
297
- ctx.trivia = gt;
298
- ctx.triviaKindLabels = gt._meta.triviaKindLabels;
299
- try {
300
- return resolved.parse(input, pos, ctx);
301
- } finally {
302
- ctx.trivia = void 0;
303
- ctx.triviaKindLabels = savedLabels;
304
- }
354
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
305
355
  }
306
- return resolved.parse(input, pos, ctx);
356
+ return parser2.parse(input, pos, ctx);
307
357
  },
308
358
  define(p) {
309
359
  if (resolved) throw new Error("ref<T>() already defined");
310
360
  resolved = p;
361
+ resolvedScalar = scalarOf(p);
311
362
  ownBoundary = hasOwnTriviaBoundary(p);
312
363
  meta.firstSet = p._meta.firstSet;
313
364
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -530,7 +581,7 @@ function pushCstLeaf(ctx, leaf2) {
530
581
  const annotated = leaf2 && typeof leaf2 === "object" && leaf2.span ? { ...leaf2, span: annotateSpanFromLineContext(leaf2.span, ctx) } : leaf2;
531
582
  pushCstChild(ctx, annotated, annotated);
532
583
  }
533
- function pushCstChild(ctx, built, rawEntry2) {
584
+ function pushCstChild(ctx, built, rawEntry) {
534
585
  const b = ctx._cstBuf;
535
586
  if (b) {
536
587
  if (b.rawOnly !== true) {
@@ -541,16 +592,16 @@ function pushCstChild(ctx, built, rawEntry2) {
541
592
  } else b.single = built;
542
593
  }
543
594
  if (b.noRaw === true) b.rawLen = (b.rawLen ?? 0) + 1;
544
- else if (b.raw) b.raw.push(rawEntry2);
595
+ else if (b.raw) b.raw.push(rawEntry);
545
596
  else if (b.rawSingle !== void 0) {
546
- b.raw = [b.rawSingle, rawEntry2];
597
+ b.raw = [b.rawSingle, rawEntry];
547
598
  b.rawSingle = void 0;
548
- } else b.rawSingle = rawEntry2;
599
+ } else b.rawSingle = rawEntry;
549
600
  return;
550
601
  }
551
602
  if (ctx._cstChildren) ctx._cstChildren.push(built);
552
603
  else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
553
- if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry2);
604
+ if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry);
554
605
  }
555
606
  function cstRawLen(ctx) {
556
607
  const b = ctx._cstBuf;
@@ -693,6 +744,7 @@ function createParseContext() {
693
744
  _fe: void 0,
694
745
  _fx: void 0,
695
746
  _fc: void 0,
747
+ _sv: void 0,
696
748
  _probe: void 0,
697
749
  _cstChildren: void 0,
698
750
  _cstLeaves: void 0,
@@ -1530,6 +1582,24 @@ function parser(opts, root) {
1530
1582
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
1531
1583
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
1532
1584
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
1585
+ const rootScalar = scalarOf(root);
1586
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
1587
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
1588
+ const savedTrivia = ctx.trivia;
1589
+ const savedLabels = ctx.triviaKindLabels;
1590
+ if (clearTrivia) {
1591
+ ctx.trivia = void 0;
1592
+ ctx.triviaKindLabels = void 0;
1593
+ } else if (scopeTrivia !== void 0) {
1594
+ ctx.trivia = scopeTrivia;
1595
+ ctx.triviaKindLabels = scopeLabels;
1596
+ }
1597
+ const end = rootScalar(input, pos, ctx);
1598
+ ctx.trivia = savedTrivia;
1599
+ ctx.triviaKindLabels = savedLabels;
1600
+ return end;
1601
+ } : void 0;
1602
+ let publicScalar;
1533
1603
  const grammar = {
1534
1604
  _tag: "grammar",
1535
1605
  _meta: {
@@ -1553,7 +1623,20 @@ function parser(opts, root) {
1553
1623
  constructionTrackLines: trackLinesPolicy,
1554
1624
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
1555
1625
  },
1626
+ _parseScalar: parseScalar,
1556
1627
  parse(input, pos, _ctx) {
1628
+ if (pos === void 0 && _ctx === void 0) {
1629
+ publicScalar ??= scalarRootOf(grammar) ?? null;
1630
+ if (publicScalar) {
1631
+ const ctx2 = createParseContext();
1632
+ const end = publicScalar(input, 0, ctx2);
1633
+ if (end < 0) {
1634
+ const at = ~end;
1635
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
1636
+ }
1637
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
1638
+ }
1639
+ }
1557
1640
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
1558
1641
  const trackLines = trackLinesOf(_ctx);
1559
1642
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -2146,10 +2229,32 @@ function regex(pattern, flags = "") {
2146
2229
  const canMatchNewline = raw.canMatchNewline;
2147
2230
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
2148
2231
  const def = { tag: "regex", source, flags: resolvedFlags };
2232
+ const expected = directTerminalFailureExpected(def);
2233
+ const parseScalar = (input, pos, ctx) => {
2234
+ const scanEnd = scan?.(input, pos);
2235
+ if (scanEnd !== void 0) {
2236
+ if (scanEnd === null) {
2237
+ ctx._fx = expected;
2238
+ return ~pos;
2239
+ }
2240
+ ctx._sv = input.slice(pos, scanEnd);
2241
+ return scanEnd;
2242
+ }
2243
+ anchored.lastIndex = pos;
2244
+ const match = anchored.exec(input);
2245
+ if (match === null) {
2246
+ ctx._fx = expected;
2247
+ return ~pos;
2248
+ }
2249
+ ctx._sv = match[0];
2250
+ return pos + match[0].length;
2251
+ };
2149
2252
  return {
2150
2253
  _tag: "regex",
2151
2254
  _meta: meta,
2152
2255
  _def: def,
2256
+ _stickyRegex: anchored,
2257
+ _parseScalar: parseScalar,
2153
2258
  parse(input, pos, ctx) {
2154
2259
  const scanEnd = scan?.(input, pos);
2155
2260
  if (scanEnd !== void 0) {
@@ -2194,6 +2299,28 @@ function literal(value, opts = {}) {
2194
2299
  isTrivia: false
2195
2300
  };
2196
2301
  const canMatchNewline = meta.canMatchNewline;
2302
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
2303
+ const code = value.charCodeAt(0);
2304
+ return (input, pos, ctx) => {
2305
+ if (input.charCodeAt(pos) === code) {
2306
+ ctx._sv = value;
2307
+ return pos + 1;
2308
+ }
2309
+ ctx._fx = expected;
2310
+ return ~pos;
2311
+ };
2312
+ })() : (input, pos, ctx) => {
2313
+ const end = pos + value.length;
2314
+ if (end <= input.length) {
2315
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
2316
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
2317
+ ctx._sv = matchedValue;
2318
+ return end;
2319
+ }
2320
+ }
2321
+ ctx._fx = expected;
2322
+ return ~pos;
2323
+ };
2197
2324
  if (caseInsensitive) {
2198
2325
  const upper = value.toUpperCase();
2199
2326
  const lower = value.toLowerCase();
@@ -2234,6 +2361,7 @@ function literal(value, opts = {}) {
2234
2361
  _tag: "literal",
2235
2362
  _meta: meta,
2236
2363
  _def: { tag: "literal", value, caseInsensitive },
2364
+ _parseScalar: parseScalar,
2237
2365
  parse
2238
2366
  };
2239
2367
  }
@@ -2301,16 +2429,26 @@ function keywords(words, opts = {}) {
2301
2429
  caseInsensitive: opts.caseInsensitive ?? false,
2302
2430
  boundary: opts.boundary
2303
2431
  };
2432
+ const expected = directTerminalFailureExpected(def);
2433
+ const parseScalar = (input, pos, ctx) => {
2434
+ re.lastIndex = pos;
2435
+ const m = re.exec(input);
2436
+ if (m === null) {
2437
+ ctx._fx = expected;
2438
+ return ~pos;
2439
+ }
2440
+ ctx._sv = m[0];
2441
+ return pos + m[0].length;
2442
+ };
2304
2443
  return {
2305
2444
  _tag: "keywords",
2306
2445
  _meta: meta,
2307
2446
  _def: def,
2447
+ _parseScalar: parseScalar,
2308
2448
  parse(input, pos, ctx) {
2309
2449
  re.lastIndex = pos;
2310
2450
  const m = re.exec(input);
2311
- if (m === null || m.index !== pos) {
2312
- return failAt(ctx, directTerminalFailureExpected(def), pos);
2313
- }
2451
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
2314
2452
  const value = m[0];
2315
2453
  const span = { start: pos, end: pos + value.length };
2316
2454
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -2341,6 +2479,9 @@ var fastScanner3;
2341
2479
  function needsDeferredTriviaCommit(ctx) {
2342
2480
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
2343
2481
  }
2482
+ function needsTriviaRollback(ctx) {
2483
+ 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;
2484
+ }
2344
2485
  function saveTriviaMark(ctx) {
2345
2486
  const m = saveCstMark(ctx);
2346
2487
  return {
@@ -2452,7 +2593,8 @@ function advanceTrivia(input, cur, ctx) {
2452
2593
  const triviaP = ctx.trivia;
2453
2594
  if (!triviaP) return cur;
2454
2595
  if (!ctx.trackLines) {
2455
- const fast2 = fastTriviaScanner(triviaP);
2596
+ const classified = triviaP._meta.triviaScanner;
2597
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
2456
2598
  if (fast2) return fast2(input, cur);
2457
2599
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
2458
2600
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -3043,6 +3185,7 @@ function sequence(...parsers) {
3043
3185
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
3044
3186
  }
3045
3187
  const hasAdjacency = adjacency !== null;
3188
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
3046
3189
  const meta = {
3047
3190
  // Union through the nullable prefix — a leading optional()/many() lets a later
3048
3191
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -3051,165 +3194,96 @@ function sequence(...parsers) {
3051
3194
  isTrivia: false
3052
3195
  };
3053
3196
  const def = { tag: "sequence", parsers };
3054
- let followSentinels;
3055
- function parseTolerant(input, pos, ctx) {
3056
- followSentinels ??= parsers.map((_, i) => {
3057
- const fs = parsers.slice(i + 1).reduce(
3058
- (acc, p) => union(acc, firstSetOf(p)),
3059
- { kind: "empty" }
3060
- );
3061
- return firstSetSentinel(fs);
3062
- });
3063
- const values = def.valueUnused ? void 0 : [];
3197
+ const scalarParsers = parsers.map(scalarOf);
3198
+ const parseScalar = (input, pos, ctx) => {
3064
3199
  let cur = pos;
3065
- const inheritedSync = ctx._sync;
3066
- try {
3067
- for (let i = 0; i < parsers.length; i++) {
3068
- ctx._sync = followSentinels[i] ?? inheritedSync;
3069
- const adj = adjacency === null ? null : adjacency[i];
3070
- if (adj) {
3071
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
3072
- if (values !== void 0) values.push(null);
3073
- continue;
3074
- }
3075
- if (ctx.trivia && i > 0) {
3076
- const mTlog = cstTlLen(ctx);
3077
- const mLog = ctx._triviaLog?.length ?? 0;
3078
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3079
- let scanEnd;
3080
- if (needsDeferredTriviaCommit(ctx)) {
3081
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3082
- } else {
3083
- scanEnd = advanceTrivia(input, cur, ctx);
3084
- }
3085
- const scanTlog = cstTlLen(ctx);
3086
- const scanLog = ctx._triviaLog?.length ?? 0;
3087
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3088
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3089
- if (!result2.ok) return result2;
3090
- if (result2.span.end > scanEnd) cur = result2.span.end;
3091
- else rollbackScannedTriviaAt(
3092
- ctx,
3093
- mTlog,
3094
- scanTlog,
3095
- mLog,
3096
- scanLog,
3097
- mRootLog,
3098
- scanRootLog
3099
- );
3100
- if (values !== void 0) values.push(result2.value);
3101
- continue;
3102
- }
3103
- const result = parsers[i].parse(input, cur, ctx);
3104
- if (!result.ok) return result;
3105
- if (values !== void 0) values.push(result.value);
3106
- cur = result.span.end;
3200
+ if (strictArity !== 0) {
3201
+ cur = scalarParsers[0](input, cur, ctx);
3202
+ if (cur < 0) return cur;
3203
+ const first = ctx._sv;
3204
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3205
+ cur = scalarParsers[1](input, cur, ctx);
3206
+ if (cur < 0) return cur;
3207
+ const second = ctx._sv;
3208
+ if (strictArity === 2) {
3209
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
3210
+ return cur;
3107
3211
  }
3108
- } finally {
3109
- ctx._sync = inheritedSync;
3212
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
3213
+ cur = scalarParsers[2](input, cur, ctx);
3214
+ if (cur < 0) return cur;
3215
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
3216
+ return cur;
3110
3217
  }
3111
- return {
3112
- ok: true,
3113
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3114
- value: values ?? void 0,
3115
- span: { start: pos, end: cur }
3116
- };
3117
- }
3118
- function parseAdjacent(input, pos, ctx) {
3119
3218
  const values = def.valueUnused ? void 0 : [];
3120
- let cur = pos;
3121
- for (let i = 0; i < parsers.length; i++) {
3122
- const adj = adjacency[i];
3123
- if (adj) {
3124
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
3125
- if (values !== void 0) values.push(null);
3126
- continue;
3127
- }
3128
- if (ctx.trivia && i > 0) {
3129
- let scanEnd;
3130
- const mTlog = cstTlLen(ctx);
3131
- const mLog = ctx._triviaLog?.length ?? 0;
3132
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3133
- if (needsDeferredTriviaCommit(ctx)) {
3134
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3135
- } else {
3136
- scanEnd = advanceTrivia(input, cur, ctx);
3137
- }
3138
- const scanTlog = cstTlLen(ctx);
3139
- const scanLog = ctx._triviaLog?.length ?? 0;
3140
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3141
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3142
- if (!result2.ok) return result2;
3143
- if (result2.span.end > scanEnd) cur = result2.span.end;
3144
- else rollbackScannedTriviaAt(
3145
- ctx,
3146
- mTlog,
3147
- scanTlog,
3148
- mLog,
3149
- scanLog,
3150
- mRootLog,
3151
- scanRootLog
3152
- );
3153
- if (values !== void 0) values.push(result2.value);
3154
- continue;
3155
- }
3156
- const result = parsers[i].parse(input, cur, ctx);
3157
- if (!result.ok) return result;
3158
- if (values !== void 0) values.push(result.value);
3159
- cur = result.span.end;
3160
- }
3161
- return {
3162
- ok: true,
3163
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3164
- value: values ?? void 0,
3165
- span: { start: pos, end: cur }
3166
- };
3167
- }
3219
+ for (let i = 0; i < scalarParsers.length; i++) {
3220
+ let termPos = cur;
3221
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
3222
+ const end = scalarParsers[i](input, termPos, ctx);
3223
+ if (end < 0) return end;
3224
+ if (values !== void 0) values.push(ctx._sv);
3225
+ if (end > termPos || termPos === cur) cur = end;
3226
+ }
3227
+ ctx._sv = values;
3228
+ return cur;
3229
+ };
3230
+ let followSentinels;
3168
3231
  return {
3169
3232
  _tag: "sequence",
3170
3233
  _meta: meta,
3171
3234
  _def: def,
3235
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
3172
3236
  parse(input, pos, ctx) {
3173
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
3174
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
3237
+ const tolerant = ctx._tolerant === true;
3238
+ if (tolerant) {
3239
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
3240
+ parsers.slice(i + 1).reduce(
3241
+ (set, parser2) => union(set, firstSetOf(parser2)),
3242
+ { kind: "empty" }
3243
+ )
3244
+ ));
3245
+ }
3246
+ const inheritedSync = ctx._sync;
3247
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
3175
3248
  const values = def.valueUnused ? void 0 : [];
3176
3249
  let cur = pos;
3177
- for (let i = 0; i < parsers.length; i++) {
3178
- if (ctx.trivia && i > 0) {
3179
- let scanEnd;
3180
- const mTlog = cstTlLen(ctx);
3181
- const mLog = ctx._triviaLog?.length ?? 0;
3182
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3183
- if (needsDeferredTriviaCommit(ctx)) {
3184
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
3185
- } else {
3186
- scanEnd = advanceTrivia(input, cur, ctx);
3250
+ try {
3251
+ for (let i = 0; i < parsers.length; i++) {
3252
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
3253
+ const assertion = adjacency?.[i];
3254
+ if (assertion) {
3255
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
3256
+ if (values !== void 0) values.push(null);
3257
+ continue;
3187
3258
  }
3188
- const scanTlog = cstTlLen(ctx);
3189
- const scanLog = ctx._triviaLog?.length ?? 0;
3190
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3191
- const result2 = parsers[i].parse(input, scanEnd, ctx);
3192
- if (!result2.ok) return result2;
3193
- if (result2.span.end > scanEnd) {
3194
- cur = result2.span.end;
3195
- } else {
3259
+ let termPos = cur;
3260
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3261
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3262
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3263
+ if (ctx.trivia && i > 0) {
3264
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
3265
+ }
3266
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
3267
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
3268
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
3269
+ const result = parsers[i].parse(input, termPos, ctx);
3270
+ if (!result.ok) return result;
3271
+ if (values !== void 0) values.push(result.value);
3272
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
3273
+ else if (deferredTrivia) {
3196
3274
  rollbackScannedTriviaAt(
3197
3275
  ctx,
3198
- mTlog,
3276
+ markTlog,
3199
3277
  scanTlog,
3200
- mLog,
3278
+ markLog,
3201
3279
  scanLog,
3202
- mRootLog,
3280
+ markRootLog,
3203
3281
  scanRootLog
3204
3282
  );
3205
3283
  }
3206
- if (values !== void 0) values.push(result2.value);
3207
- continue;
3208
3284
  }
3209
- const result = parsers[i].parse(input, cur, ctx);
3210
- if (!result.ok) return result;
3211
- if (values !== void 0) values.push(result.value);
3212
- cur = result.span.end;
3285
+ } finally {
3286
+ if (tolerant) ctx._sync = inheritedSync;
3213
3287
  }
3214
3288
  return {
3215
3289
  ok: true,
@@ -3341,7 +3415,8 @@ function choice(...args) {
3341
3415
  disjoint
3342
3416
  };
3343
3417
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3344
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3418
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
3419
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
3345
3420
  let greedyLitMap = null;
3346
3421
  let sortedParsers = null;
3347
3422
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -3355,6 +3430,37 @@ function choice(...args) {
3355
3430
  } else if (strategy?.tag === "literalsLongestFirst") {
3356
3431
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
3357
3432
  }
3433
+ const scalarParsers = parsers.map(scalarOf);
3434
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
3435
+ const scalarExpected = parsers.flatMap(deriveExpected);
3436
+ const parseScalar = (input, pos, ctx) => {
3437
+ if (disjoint) {
3438
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3439
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3440
+ if (idx < 0 && code >= 0) {
3441
+ for (let i = 0; i < parsers.length; i++) {
3442
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3443
+ idx = i;
3444
+ break;
3445
+ }
3446
+ }
3447
+ }
3448
+ if (idx >= 0) {
3449
+ const gate = gates[idx];
3450
+ if (!gate || gate(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3451
+ ctx._fx = deriveExpected(parsers[idx]);
3452
+ return ~pos;
3453
+ }
3454
+ } else {
3455
+ for (let i = 0; i < scalarParsers.length; i++) {
3456
+ if (gates[i] && !gates[i](ctx.state)) continue;
3457
+ const end = scalarParsers[i](input, pos, ctx);
3458
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3459
+ }
3460
+ }
3461
+ ctx._fx = scalarExpected;
3462
+ return ~pos;
3463
+ };
3358
3464
  return {
3359
3465
  _tag: "choice",
3360
3466
  _meta: meta,
@@ -3366,6 +3472,7 @@ function choice(...args) {
3366
3472
  strategy: strategy ?? { tag: "firstMatch" },
3367
3473
  autoNot
3368
3474
  },
3475
+ _parseScalar: scalarEligible ? parseScalar : void 0,
3369
3476
  parse(input, pos, ctx) {
3370
3477
  const expected = [];
3371
3478
  let expectedAt = pos;
@@ -3897,8 +4004,8 @@ function attempt(parser2) {
3897
4004
  }
3898
4005
 
3899
4006
  // src/combinators/repeat.ts
3900
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3901
- const mark = saveTriviaMark(ctx);
4007
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
4008
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
3902
4009
  let pos = cur;
3903
4010
  if (ctx.trivia) {
3904
4011
  if (needsDeferredTriviaCommit(ctx)) {
@@ -3908,24 +4015,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
3908
4015
  }
3909
4016
  }
3910
4017
  if (pos >= input.length && !mandatory) {
3911
- rollbackTrivia(ctx, mark);
4018
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3912
4019
  return "stop";
3913
4020
  }
3914
4021
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
3915
- rollbackTrivia(ctx, mark);
4022
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3916
4023
  return "stop";
3917
4024
  }
3918
4025
  const result = combinator.parse(input, pos, ctx);
3919
4026
  if (!result.ok) {
3920
- rollbackTrivia(ctx, mark);
4027
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3921
4028
  if (result.committed) return { fail: result, failPos: pos };
3922
4029
  return { fail: result, failPos: pos };
3923
4030
  }
3924
4031
  if (result.span.end === pos && !mandatory) {
3925
- rollbackTrivia(ctx, mark);
4032
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
3926
4033
  return "stop";
3927
4034
  }
3928
- return { value: result.value, end: result.span.end };
4035
+ return result;
3929
4036
  }
3930
4037
  function resolveBounds(what, opts) {
3931
4038
  const min = opts.min ?? 0;
@@ -3938,6 +4045,21 @@ function resolveBounds(what, opts) {
3938
4045
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
3939
4046
  return { min, max };
3940
4047
  }
4048
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
4049
+ while (cur < input.length && remaining > 0) {
4050
+ let itemPos = cur;
4051
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4052
+ if (itemPos >= input.length) break;
4053
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
4054
+ const end = child(input, itemPos, ctx);
4055
+ if (end <= itemPos) break;
4056
+ if (values !== void 0) values.push(ctx._sv);
4057
+ cur = end;
4058
+ remaining--;
4059
+ }
4060
+ ctx._sv = values;
4061
+ return cur;
4062
+ }
3941
4063
  function many(combinator, opts = {}) {
3942
4064
  const { min, max } = resolveBounds("many()", opts);
3943
4065
  if (min >= 1) return atLeast(combinator, min, max);
@@ -3949,17 +4071,21 @@ function many(combinator, opts = {}) {
3949
4071
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
3950
4072
  let expected;
3951
4073
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4074
+ const scalarChild = scalarOf(combinator);
4075
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
3952
4076
  return {
3953
4077
  _tag: "many",
3954
4078
  _meta: meta,
3955
4079
  _def: def,
4080
+ _parseScalar: parseScalar,
3956
4081
  parse(input, pos, ctx) {
3957
4082
  const values = def.valueUnused ? void 0 : [];
4083
+ const rollbackNeeded = needsTriviaRollback(ctx);
3958
4084
  let cur = pos;
3959
4085
  let count = 0;
3960
4086
  while (cur < input.length) {
3961
4087
  if (count >= max) break;
3962
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4088
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
3963
4089
  if (item === "stop") break;
3964
4090
  if ("fail" in item) {
3965
4091
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -3976,7 +4102,7 @@ function many(combinator, opts = {}) {
3976
4102
  }
3977
4103
  if (values !== void 0) values.push(item.value);
3978
4104
  count++;
3979
- cur = item.end;
4105
+ cur = item.span.end;
3980
4106
  }
3981
4107
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
3982
4108
  }
@@ -3994,30 +4120,47 @@ function atLeast(combinator, min, max) {
3994
4120
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
3995
4121
  let expected;
3996
4122
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4123
+ const scalarChild = scalarOf(combinator);
4124
+ const parseScalar = (input, pos, ctx) => {
4125
+ let cur = scalarChild(input, pos, ctx);
4126
+ if (cur < 0) return cur;
4127
+ const values = def.valueUnused ? void 0 : [ctx._sv];
4128
+ for (let count = 1; count < min; count++) {
4129
+ let itemPos = cur;
4130
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4131
+ const end = scalarChild(input, itemPos, ctx);
4132
+ if (end < 0) return ~cur;
4133
+ cur = end;
4134
+ if (values !== void 0) values.push(ctx._sv);
4135
+ }
4136
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
4137
+ };
3997
4138
  return {
3998
4139
  _tag: "oneOrMore",
3999
4140
  _meta: meta,
4000
4141
  _def: def,
4142
+ _parseScalar: parseScalar,
4001
4143
  parse(input, pos, ctx) {
4002
4144
  const first = combinator.parse(input, pos, ctx);
4003
4145
  if (!first.ok) return first;
4004
4146
  const values = def.valueUnused ? void 0 : [first.value];
4147
+ const rollbackNeeded = needsTriviaRollback(ctx);
4005
4148
  let cur = first.span.end;
4006
4149
  let count = 1;
4007
4150
  while (count < min) {
4008
- const item = repItem(combinator, input, cur, ctx, guardable, true);
4151
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
4009
4152
  if (item === "stop" || "fail" in item) {
4010
4153
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4011
4154
  expected ??= deriveExpected(combinator);
4012
4155
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4013
4156
  }
4014
4157
  if (values !== void 0) values.push(item.value);
4015
- cur = item.end;
4158
+ cur = item.span.end;
4016
4159
  count++;
4017
4160
  }
4018
4161
  while (cur < input.length) {
4019
4162
  if (count >= max) break;
4020
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4163
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4021
4164
  if (item === "stop") break;
4022
4165
  if ("fail" in item) {
4023
4166
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4034,7 +4177,7 @@ function atLeast(combinator, min, max) {
4034
4177
  }
4035
4178
  if (values !== void 0) values.push(item.value);
4036
4179
  count++;
4037
- cur = item.end;
4180
+ cur = item.span.end;
4038
4181
  }
4039
4182
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4040
4183
  }
@@ -4047,10 +4190,22 @@ function optional(combinator) {
4047
4190
  isTrivia: false
4048
4191
  };
4049
4192
  const firstSetSkippable = !matchesEmpty(combinator);
4193
+ const scalarChild = scalarOf(combinator);
4194
+ const parseScalar = (input, pos, ctx) => {
4195
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
4196
+ ctx._sv = null;
4197
+ return pos;
4198
+ }
4199
+ const end = scalarChild(input, pos, ctx);
4200
+ if (end >= 0) return end;
4201
+ ctx._sv = null;
4202
+ return pos;
4203
+ };
4050
4204
  return {
4051
4205
  _tag: "optional",
4052
4206
  _meta: meta,
4053
4207
  _def: { tag: "optional", parser: combinator },
4208
+ _parseScalar: parseScalar,
4054
4209
  parse(input, pos, ctx) {
4055
4210
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4056
4211
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -4084,6 +4239,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
4084
4239
  expected ??= deriveExpected(combinator);
4085
4240
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4086
4241
  };
4242
+ const scalarExpected = deriveExpected(combinator);
4243
+ const scalarChild = scalarOf(combinator);
4244
+ const scalarSeparator = scalarOf(separator);
4245
+ const parseScalar = (input, pos, ctx) => {
4246
+ let cur = scalarChild(input, pos, ctx);
4247
+ if (cur < 0) {
4248
+ if (min >= 1) {
4249
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4250
+ return ~pos;
4251
+ }
4252
+ ctx._sv = [];
4253
+ return pos;
4254
+ }
4255
+ const values = [ctx._sv];
4256
+ while (values.length < max && (cur < input.length || values.length < min)) {
4257
+ const beforeSeparator = cur;
4258
+ let separatorPos = cur;
4259
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
4260
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
4261
+ if (separatorEnd < 0) break;
4262
+ let itemPos = separatorEnd;
4263
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
4264
+ const itemEnd = scalarChild(input, itemPos, ctx);
4265
+ if (itemEnd < 0) {
4266
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
4267
+ break;
4268
+ }
4269
+ values.push(ctx._sv);
4270
+ cur = itemEnd;
4271
+ }
4272
+ if (values.length < min) {
4273
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
4274
+ return ~cur;
4275
+ }
4276
+ ctx._sv = values;
4277
+ return cur;
4278
+ };
4087
4279
  return {
4088
4280
  _tag: "sepBy",
4089
4281
  _meta: meta,
@@ -4099,6 +4291,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
4099
4291
  // this option surface already; parity is held by test/parity, not by hope.
4100
4292
  ...keepSeparators ? { keepSeparators: true } : {}
4101
4293
  },
4294
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
4102
4295
  parse(input, pos, ctx) {
4103
4296
  const first = combinator.parse(input, pos, ctx);
4104
4297
  const values = [];
@@ -4608,9 +4801,9 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
4608
4801
  const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
4609
4802
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
4610
4803
  const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : (cstOutput || !build && project === void 0) && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState, tags) : build(children, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children };
4611
- const rawEntry2 = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
4804
+ const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
4612
4805
  if (saved.buf !== void 0 || saved.ch !== void 0) {
4613
- pushCstChild(ctx, built, rawEntry2);
4806
+ pushCstChild(ctx, built, rawEntry);
4614
4807
  }
4615
4808
  return { ok: true, value: built, span };
4616
4809
  }
@@ -4618,11 +4811,54 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
4618
4811
  }
4619
4812
 
4620
4813
  // src/combinators/map.ts
4814
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
4621
4815
  function transform(combinator, fn) {
4816
+ const observesSpan = fn.length > 1;
4817
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
4818
+ const terms = sequenceDef?.parsers;
4819
+ const inner = terms?.[1];
4820
+ 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;
4821
+ const child = scalarOf(combinator);
4822
+ const parseScalar = fused ? (() => {
4823
+ const body = inner._stickyRegex;
4824
+ const tuple = ['"', "", '"'];
4825
+ const expected = [JSON.stringify('"')];
4826
+ return (input, pos, ctx) => {
4827
+ if (ctx.trivia !== void 0) {
4828
+ const end2 = child(input, pos, ctx);
4829
+ if (end2 < 0) return end2;
4830
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
4831
+ return end2;
4832
+ }
4833
+ if (input.charCodeAt(pos) !== 34) {
4834
+ ctx._fx = expected;
4835
+ return ~pos;
4836
+ }
4837
+ body.lastIndex = pos + 1;
4838
+ const match = body.exec(input);
4839
+ const close = pos + 1 + match[0].length;
4840
+ if (input.charCodeAt(close) !== 34) {
4841
+ ctx._fx = expected;
4842
+ return ~close;
4843
+ }
4844
+ tuple[1] = match[0];
4845
+ const end = close + 1;
4846
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
4847
+ return end;
4848
+ };
4849
+ })() : /* @__PURE__ */ (() => {
4850
+ return (input, pos, ctx) => {
4851
+ const end = child(input, pos, ctx);
4852
+ if (end < 0) return end;
4853
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
4854
+ return end;
4855
+ };
4856
+ })();
4622
4857
  return {
4623
4858
  _tag: "transform",
4624
4859
  _meta: combinator._meta,
4625
4860
  _def: { tag: "transform", parser: combinator, fn },
4861
+ _parseScalar: parseScalar,
4626
4862
  parse(input, pos, ctx) {
4627
4863
  const result = combinator.parse(input, pos, ctx);
4628
4864
  if (!result.ok) return result;
@@ -4637,9 +4873,11 @@ function trivia(combinator) {
4637
4873
  _meta: {
4638
4874
  ...combinator._meta,
4639
4875
  isTrivia: true,
4876
+ triviaScanner: fastTriviaScanner(combinator),
4640
4877
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
4641
4878
  },
4642
4879
  _def: { tag: "trivia", parser: combinator },
4880
+ _parseScalar: scalarOf(combinator),
4643
4881
  parse: combinator.parse.bind(combinator)
4644
4882
  };
4645
4883
  }
@@ -5113,108 +5351,6 @@ function evalRuleMapIR(ir) {
5113
5351
  return Object.entries(map);
5114
5352
  }
5115
5353
 
5116
- // src/table/ops.ts
5117
- var OP_LIT = 1;
5118
- var OP_RX = 2;
5119
- var OP_SEQ = 3;
5120
- var OP_SEQV = 4;
5121
- var OP_CHOICE = 5;
5122
- var OP_REP = 6;
5123
- var OP_REPV = 7;
5124
- var OP_OPT = 8;
5125
- var OP_XFORM = 9;
5126
- var OP_NODE = 10;
5127
- var OP_RULE = 11;
5128
- var OP_GATE = 12;
5129
- var OP_NOT = 13;
5130
- var OP_PEEK = 14;
5131
- var OP_LEAF = 15;
5132
- var OP_EMPTY = 16;
5133
- var OP_LIT_TRACK = 17;
5134
- var OP_RX_TRACK = 18;
5135
- var OP_NODE_TRACK = 19;
5136
- var OP_SCOPE = 20;
5137
- var OP_EXPECT = 21;
5138
- var OP_SEQX = 22;
5139
- var OP_SCAN = 23;
5140
- var OP_FIELD = 24;
5141
- var OP_LIT_CI = 27;
5142
- var OP_LIT_CI_TRACK = 28;
5143
- var OP_TOKEN = 29;
5144
- var OP_SCOPE_CAP = 30;
5145
- var OP_WITHCTX = 31;
5146
- var OP_GUARD = 32;
5147
- var OP_ADJ = 33;
5148
- var OP_GREEDY = 34;
5149
- var OP_REJECT = 35;
5150
- var OP_ARMGATE = 36;
5151
- var OP_LIVE = 37;
5152
- var OP_ATTEMPT = 38;
5153
- var OP_LABEL = 39;
5154
- var OP_COV = 40;
5155
- var OP_SCOPE_PLAIN = 41;
5156
- var OP_LEX_BODY = 42;
5157
- var OP_LEX_PROGRAM = 43;
5158
- var OP_DISPATCH = 25;
5159
- var OP_ROUTED = 26;
5160
- var OP_NAMES = {
5161
- [OP_LIT]: "LIT",
5162
- [OP_RX]: "RX",
5163
- [OP_SEQ]: "SEQ",
5164
- [OP_SEQV]: "SEQV",
5165
- [OP_CHOICE]: "CHOICE",
5166
- [OP_REP]: "REP",
5167
- [OP_REPV]: "REPV",
5168
- [OP_OPT]: "OPT",
5169
- [OP_XFORM]: "XFORM",
5170
- [OP_NODE]: "NODE",
5171
- [OP_RULE]: "RULE",
5172
- [OP_GATE]: "GATE",
5173
- [OP_NOT]: "NOT",
5174
- [OP_PEEK]: "PEEK",
5175
- [OP_LEAF]: "LEAF",
5176
- [OP_EMPTY]: "EMPTY",
5177
- [OP_LIT_TRACK]: "LIT_TRACK",
5178
- [OP_RX_TRACK]: "RX_TRACK",
5179
- [OP_NODE_TRACK]: "NODE_TRACK",
5180
- [OP_SCOPE]: "SCOPE",
5181
- [OP_EXPECT]: "EXPECT",
5182
- [OP_SEQX]: "SEQX",
5183
- [OP_SCAN]: "SCAN",
5184
- [OP_FIELD]: "FIELD",
5185
- [OP_LIT_CI]: "LIT_CI",
5186
- [OP_LIT_CI_TRACK]: "LIT_CI_TRACK",
5187
- [OP_DISPATCH]: "DISPATCH",
5188
- [OP_ROUTED]: "ROUTED",
5189
- [OP_TOKEN]: "TOKEN",
5190
- [OP_SCOPE_CAP]: "SCOPE_CAP",
5191
- [OP_WITHCTX]: "WITHCTX",
5192
- [OP_GUARD]: "GUARD",
5193
- [OP_ADJ]: "ADJ",
5194
- [OP_GREEDY]: "GREEDY",
5195
- [OP_REJECT]: "REJECT",
5196
- [OP_ARMGATE]: "ARMGATE",
5197
- [OP_LIVE]: "LIVE",
5198
- [OP_ATTEMPT]: "ATTEMPT",
5199
- [OP_LABEL]: "LABEL",
5200
- [OP_COV]: "COV",
5201
- [OP_SCOPE_PLAIN]: "SCOPE_PLAIN",
5202
- [OP_LEX_BODY]: "LEX_BODY",
5203
- [OP_LEX_PROGRAM]: "LEX_PROGRAM"
5204
- };
5205
-
5206
- // src/table/scan-shapes.ts
5207
- var META2 = new Set("()[]{}*+?|^$.".split(""));
5208
-
5209
- // src/table/assemble.ts
5210
- var EMIT_ENABLED = globalThis.process?.env?.PM_TABLE_EMIT !== "0";
5211
- var EMPTY_TL2 = Object.freeze([]);
5212
- var EMPTY_SENTS = Object.freeze([]);
5213
-
5214
- // src/analysis/duplication.ts
5215
- var WORD_RE_SRC = "-?[A-Za-z][A-Za-z0-9_-]*";
5216
- var WORDS_RE = new RegExp(`^${WORD_RE_SRC}(?:\\|${WORD_RE_SRC})*$`);
5217
-
5218
5354
  // src/compiler/linker.ts
5219
5355
  function normalizeCstCollapse(collapse) {
5220
5356
  if (collapse === true) return () => true;