parseman 0.50.0 → 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 (55) hide show
  1. package/README.md +14 -10
  2. package/dist/analysis/diagnostics.js +455 -226
  3. package/dist/analysis/diagnostics.js.map +3 -3
  4. package/dist/cli/index.js +445 -191
  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 +446 -192
  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 +491 -306
  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/encode.d.ts.map +1 -1
  34. package/dist/table/index.js +331 -188
  35. package/dist/table/index.js.map +3 -3
  36. package/dist/types.d.ts +8 -0
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/package.json +4 -2
  40. package/src/combinators/choice.ts +34 -1
  41. package/src/combinators/grammar.ts +39 -0
  42. package/src/combinators/keywords.ts +14 -3
  43. package/src/combinators/literal.ts +26 -0
  44. package/src/combinators/map.ts +60 -0
  45. package/src/combinators/ref.ts +26 -7
  46. package/src/combinators/regex.ts +23 -0
  47. package/src/combinators/repeat.ts +109 -16
  48. package/src/combinators/scalar.ts +30 -0
  49. package/src/combinators/sequence.ts +76 -161
  50. package/src/combinators/trivia-skip.ts +14 -1
  51. package/src/parse-context.ts +1 -0
  52. package/src/table/emit-assembly.ts +39 -16
  53. package/src/table/encode.ts +30 -10
  54. package/src/types.ts +8 -0
  55. package/src/version.ts +1 -1
@@ -615,16 +615,26 @@ function keywords(words, opts = {}) {
615
615
  caseInsensitive: opts.caseInsensitive ?? false,
616
616
  boundary: opts.boundary
617
617
  };
618
+ const expected = directTerminalFailureExpected(def);
619
+ const parseScalar = (input, pos, ctx) => {
620
+ re.lastIndex = pos;
621
+ const m = re.exec(input);
622
+ if (m === null) {
623
+ ctx._fx = expected;
624
+ return ~pos;
625
+ }
626
+ ctx._sv = m[0];
627
+ return pos + m[0].length;
628
+ };
618
629
  return {
619
630
  _tag: "keywords",
620
631
  _meta: meta,
621
632
  _def: def,
633
+ _parseScalar: parseScalar,
622
634
  parse(input, pos, ctx) {
623
635
  re.lastIndex = pos;
624
636
  const m = re.exec(input);
625
- if (m === null || m.index !== pos) {
626
- return failAt(ctx, directTerminalFailureExpected(def), pos);
627
- }
637
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
628
638
  const value = m[0];
629
639
  const span = { start: pos, end: pos + value.length };
630
640
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -768,6 +778,7 @@ function createParseContext() {
768
778
  _fe: void 0,
769
779
  _fx: void 0,
770
780
  _fc: void 0,
781
+ _sv: void 0,
771
782
  _probe: void 0,
772
783
  _cstChildren: void 0,
773
784
  _cstLeaves: void 0,
@@ -1468,6 +1479,9 @@ var fastScanner3;
1468
1479
  function needsDeferredTriviaCommit(ctx) {
1469
1480
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1470
1481
  }
1482
+ function needsTriviaRollback(ctx) {
1483
+ 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;
1484
+ }
1471
1485
  function saveTriviaMark(ctx) {
1472
1486
  const m = saveCstMark(ctx);
1473
1487
  return {
@@ -1584,7 +1598,8 @@ function advanceTrivia(input, cur, ctx) {
1584
1598
  const triviaP = ctx.trivia;
1585
1599
  if (!triviaP) return cur;
1586
1600
  if (!ctx.trackLines) {
1587
- const fast2 = fastTriviaScanner(triviaP);
1601
+ const classified = triviaP._meta.triviaScanner;
1602
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
1588
1603
  if (fast2) return fast2(input, cur);
1589
1604
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
1590
1605
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -2151,6 +2166,28 @@ function refuseUnclassifiedRootScope(strict) {
2151
2166
  if (strict === true) throw new TypeError(ROOT_TRIVIA_SCOPE_REFUSAL);
2152
2167
  }
2153
2168
 
2169
+ // src/combinators/scalar.ts
2170
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
2171
+ function scalarOf(combinator) {
2172
+ return combinator._parseScalar;
2173
+ }
2174
+ function scalarTree(parser2, seen) {
2175
+ if (seen.has(parser2)) return true;
2176
+ if (parser2._parseScalar === void 0) return false;
2177
+ seen.add(parser2);
2178
+ const def = parser2._def;
2179
+ if (!SCALAR_TAG.test(def.tag)) return false;
2180
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
2181
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
2182
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
2183
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
2184
+ }
2185
+ function scalarRootOf(combinator) {
2186
+ const scalar = combinator._parseScalar;
2187
+ const def = combinator._def;
2188
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
2189
+ }
2190
+
2154
2191
  // src/combinators/grammar.ts
2155
2192
  function annotateResultLines(result, index) {
2156
2193
  const annotated = { ...result, span: annotateSpan(result.span, index) };
@@ -2187,6 +2224,24 @@ function parser(opts, root) {
2187
2224
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
2188
2225
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
2189
2226
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
2227
+ const rootScalar = scalarOf(root);
2228
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
2229
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
2230
+ const savedTrivia = ctx.trivia;
2231
+ const savedLabels = ctx.triviaKindLabels;
2232
+ if (clearTrivia) {
2233
+ ctx.trivia = void 0;
2234
+ ctx.triviaKindLabels = void 0;
2235
+ } else if (scopeTrivia !== void 0) {
2236
+ ctx.trivia = scopeTrivia;
2237
+ ctx.triviaKindLabels = scopeLabels;
2238
+ }
2239
+ const end = rootScalar(input, pos, ctx);
2240
+ ctx.trivia = savedTrivia;
2241
+ ctx.triviaKindLabels = savedLabels;
2242
+ return end;
2243
+ } : void 0;
2244
+ let publicScalar;
2190
2245
  const grammar = {
2191
2246
  _tag: "grammar",
2192
2247
  _meta: {
@@ -2210,7 +2265,20 @@ function parser(opts, root) {
2210
2265
  constructionTrackLines: trackLinesPolicy,
2211
2266
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
2212
2267
  },
2268
+ _parseScalar: parseScalar,
2213
2269
  parse(input, pos, _ctx) {
2270
+ if (pos === void 0 && _ctx === void 0) {
2271
+ publicScalar ??= scalarRootOf(grammar) ?? null;
2272
+ if (publicScalar) {
2273
+ const ctx2 = createParseContext();
2274
+ const end = publicScalar(input, 0, ctx2);
2275
+ if (end < 0) {
2276
+ const at = ~end;
2277
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
2278
+ }
2279
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
2280
+ }
2281
+ }
2214
2282
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
2215
2283
  const trackLines = trackLinesOf(_ctx);
2216
2284
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -2245,6 +2313,9 @@ function parse(combinator, input, opts = {}) {
2245
2313
  _analyzed.add(combinator);
2246
2314
  markUnusedValues(combinator);
2247
2315
  }
2316
+ if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
2317
+ return combinator.parse(input);
2318
+ }
2248
2319
  const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
2249
2320
  const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
2250
2321
  const lineIndex = lineContext?.lineIndex;
@@ -3410,7 +3481,8 @@ function choice(...args) {
3410
3481
  disjoint
3411
3482
  };
3412
3483
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3413
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3484
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
3485
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
3414
3486
  let greedyLitMap = null;
3415
3487
  let sortedParsers = null;
3416
3488
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -3424,6 +3496,37 @@ function choice(...args) {
3424
3496
  } else if (strategy?.tag === "literalsLongestFirst") {
3425
3497
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
3426
3498
  }
3499
+ const scalarParsers = parsers.map(scalarOf);
3500
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
3501
+ const scalarExpected = parsers.flatMap(deriveExpected);
3502
+ const parseScalar = (input, pos, ctx) => {
3503
+ if (disjoint) {
3504
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3505
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3506
+ if (idx < 0 && code >= 0) {
3507
+ for (let i = 0; i < parsers.length; i++) {
3508
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3509
+ idx = i;
3510
+ break;
3511
+ }
3512
+ }
3513
+ }
3514
+ if (idx >= 0) {
3515
+ const gate = gates[idx];
3516
+ if (!gate || gate(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3517
+ ctx._fx = deriveExpected(parsers[idx]);
3518
+ return ~pos;
3519
+ }
3520
+ } else {
3521
+ for (let i = 0; i < scalarParsers.length; i++) {
3522
+ if (gates[i] && !gates[i](ctx.state)) continue;
3523
+ const end = scalarParsers[i](input, pos, ctx);
3524
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3525
+ }
3526
+ }
3527
+ ctx._fx = scalarExpected;
3528
+ return ~pos;
3529
+ };
3427
3530
  return {
3428
3531
  _tag: "choice",
3429
3532
  _meta: meta,
@@ -3435,6 +3538,7 @@ function choice(...args) {
3435
3538
  strategy: strategy ?? { tag: "firstMatch" },
3436
3539
  autoNot
3437
3540
  },
3541
+ _parseScalar: scalarEligible ? parseScalar : void 0,
3438
3542
  parse(input, pos, ctx) {
3439
3543
  const expected = [];
3440
3544
  let expectedAt = pos;
@@ -4774,8 +4878,8 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
4774
4878
  }
4775
4879
 
4776
4880
  // src/combinators/repeat.ts
4777
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4778
- const mark = saveTriviaMark(ctx);
4881
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
4882
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
4779
4883
  let pos = cur;
4780
4884
  if (ctx.trivia) {
4781
4885
  if (needsDeferredTriviaCommit(ctx)) {
@@ -4785,24 +4889,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4785
4889
  }
4786
4890
  }
4787
4891
  if (pos >= input.length && !mandatory) {
4788
- rollbackTrivia(ctx, mark);
4892
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4789
4893
  return "stop";
4790
4894
  }
4791
4895
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
4792
- rollbackTrivia(ctx, mark);
4896
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4793
4897
  return "stop";
4794
4898
  }
4795
4899
  const result = combinator.parse(input, pos, ctx);
4796
4900
  if (!result.ok) {
4797
- rollbackTrivia(ctx, mark);
4901
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4798
4902
  if (result.committed) return { fail: result, failPos: pos };
4799
4903
  return { fail: result, failPos: pos };
4800
4904
  }
4801
4905
  if (result.span.end === pos && !mandatory) {
4802
- rollbackTrivia(ctx, mark);
4906
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4803
4907
  return "stop";
4804
4908
  }
4805
- return { value: result.value, end: result.span.end };
4909
+ return result;
4806
4910
  }
4807
4911
  function resolveBounds(what, opts) {
4808
4912
  const min = opts.min ?? 0;
@@ -4815,6 +4919,21 @@ function resolveBounds(what, opts) {
4815
4919
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
4816
4920
  return { min, max };
4817
4921
  }
4922
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
4923
+ while (cur < input.length && remaining > 0) {
4924
+ let itemPos = cur;
4925
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4926
+ if (itemPos >= input.length) break;
4927
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
4928
+ const end = child(input, itemPos, ctx);
4929
+ if (end <= itemPos) break;
4930
+ if (values !== void 0) values.push(ctx._sv);
4931
+ cur = end;
4932
+ remaining--;
4933
+ }
4934
+ ctx._sv = values;
4935
+ return cur;
4936
+ }
4818
4937
  function many(combinator, opts = {}) {
4819
4938
  const { min, max } = resolveBounds("many()", opts);
4820
4939
  if (min >= 1) return atLeast(combinator, min, max);
@@ -4826,17 +4945,21 @@ function many(combinator, opts = {}) {
4826
4945
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
4827
4946
  let expected;
4828
4947
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4948
+ const scalarChild = scalarOf(combinator);
4949
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
4829
4950
  return {
4830
4951
  _tag: "many",
4831
4952
  _meta: meta,
4832
4953
  _def: def,
4954
+ _parseScalar: parseScalar,
4833
4955
  parse(input, pos, ctx) {
4834
4956
  const values = def.valueUnused ? void 0 : [];
4957
+ const rollbackNeeded = needsTriviaRollback(ctx);
4835
4958
  let cur = pos;
4836
4959
  let count = 0;
4837
4960
  while (cur < input.length) {
4838
4961
  if (count >= max) break;
4839
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4962
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4840
4963
  if (item === "stop") break;
4841
4964
  if ("fail" in item) {
4842
4965
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4853,7 +4976,7 @@ function many(combinator, opts = {}) {
4853
4976
  }
4854
4977
  if (values !== void 0) values.push(item.value);
4855
4978
  count++;
4856
- cur = item.end;
4979
+ cur = item.span.end;
4857
4980
  }
4858
4981
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4859
4982
  }
@@ -4871,30 +4994,47 @@ function atLeast(combinator, min, max) {
4871
4994
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4872
4995
  let expected;
4873
4996
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4997
+ const scalarChild = scalarOf(combinator);
4998
+ const parseScalar = (input, pos, ctx) => {
4999
+ let cur = scalarChild(input, pos, ctx);
5000
+ if (cur < 0) return cur;
5001
+ const values = def.valueUnused ? void 0 : [ctx._sv];
5002
+ for (let count = 1; count < min; count++) {
5003
+ let itemPos = cur;
5004
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
5005
+ const end = scalarChild(input, itemPos, ctx);
5006
+ if (end < 0) return ~cur;
5007
+ cur = end;
5008
+ if (values !== void 0) values.push(ctx._sv);
5009
+ }
5010
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
5011
+ };
4874
5012
  return {
4875
5013
  _tag: "oneOrMore",
4876
5014
  _meta: meta,
4877
5015
  _def: def,
5016
+ _parseScalar: parseScalar,
4878
5017
  parse(input, pos, ctx) {
4879
5018
  const first = combinator.parse(input, pos, ctx);
4880
5019
  if (!first.ok) return first;
4881
5020
  const values = def.valueUnused ? void 0 : [first.value];
5021
+ const rollbackNeeded = needsTriviaRollback(ctx);
4882
5022
  let cur = first.span.end;
4883
5023
  let count = 1;
4884
5024
  while (count < min) {
4885
- const item = repItem(combinator, input, cur, ctx, guardable, true);
5025
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
4886
5026
  if (item === "stop" || "fail" in item) {
4887
5027
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4888
5028
  expected ??= deriveExpected(combinator);
4889
5029
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4890
5030
  }
4891
5031
  if (values !== void 0) values.push(item.value);
4892
- cur = item.end;
5032
+ cur = item.span.end;
4893
5033
  count++;
4894
5034
  }
4895
5035
  while (cur < input.length) {
4896
5036
  if (count >= max) break;
4897
- const item = repItem(combinator, input, cur, ctx, guardable, false);
5037
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4898
5038
  if (item === "stop") break;
4899
5039
  if ("fail" in item) {
4900
5040
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4911,7 +5051,7 @@ function atLeast(combinator, min, max) {
4911
5051
  }
4912
5052
  if (values !== void 0) values.push(item.value);
4913
5053
  count++;
4914
- cur = item.end;
5054
+ cur = item.span.end;
4915
5055
  }
4916
5056
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4917
5057
  }
@@ -4924,10 +5064,22 @@ function optional(combinator) {
4924
5064
  isTrivia: false
4925
5065
  };
4926
5066
  const firstSetSkippable = !matchesEmpty(combinator);
5067
+ const scalarChild = scalarOf(combinator);
5068
+ const parseScalar = (input, pos, ctx) => {
5069
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
5070
+ ctx._sv = null;
5071
+ return pos;
5072
+ }
5073
+ const end = scalarChild(input, pos, ctx);
5074
+ if (end >= 0) return end;
5075
+ ctx._sv = null;
5076
+ return pos;
5077
+ };
4927
5078
  return {
4928
5079
  _tag: "optional",
4929
5080
  _meta: meta,
4930
5081
  _def: { tag: "optional", parser: combinator },
5082
+ _parseScalar: parseScalar,
4931
5083
  parse(input, pos, ctx) {
4932
5084
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4933
5085
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -4958,6 +5110,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
4958
5110
  expected ??= deriveExpected(combinator);
4959
5111
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4960
5112
  };
5113
+ const scalarExpected = deriveExpected(combinator);
5114
+ const scalarChild = scalarOf(combinator);
5115
+ const scalarSeparator = scalarOf(separator);
5116
+ const parseScalar = (input, pos, ctx) => {
5117
+ let cur = scalarChild(input, pos, ctx);
5118
+ if (cur < 0) {
5119
+ if (min >= 1) {
5120
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
5121
+ return ~pos;
5122
+ }
5123
+ ctx._sv = [];
5124
+ return pos;
5125
+ }
5126
+ const values = [ctx._sv];
5127
+ while (values.length < max && (cur < input.length || values.length < min)) {
5128
+ const beforeSeparator = cur;
5129
+ let separatorPos = cur;
5130
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
5131
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
5132
+ if (separatorEnd < 0) break;
5133
+ let itemPos = separatorEnd;
5134
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
5135
+ const itemEnd = scalarChild(input, itemPos, ctx);
5136
+ if (itemEnd < 0) {
5137
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
5138
+ break;
5139
+ }
5140
+ values.push(ctx._sv);
5141
+ cur = itemEnd;
5142
+ }
5143
+ if (values.length < min) {
5144
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
5145
+ return ~cur;
5146
+ }
5147
+ ctx._sv = values;
5148
+ return cur;
5149
+ };
4961
5150
  return {
4962
5151
  _tag: "sepBy",
4963
5152
  _meta: meta,
@@ -4973,6 +5162,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
4973
5162
  // this option surface already; parity is held by test/parity, not by hope.
4974
5163
  ...keepSeparators ? { keepSeparators: true } : {}
4975
5164
  },
5165
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
4976
5166
  parse(input, pos, ctx) {
4977
5167
  const first = combinator.parse(input, pos, ctx);
4978
5168
  const values = [];
@@ -5050,11 +5240,54 @@ function sepBy(combinator, separatorArg, opts = {}) {
5050
5240
  }
5051
5241
 
5052
5242
  // src/combinators/map.ts
5243
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
5053
5244
  function transform(combinator, fn) {
5245
+ const observesSpan = fn.length > 1;
5246
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
5247
+ const terms = sequenceDef?.parsers;
5248
+ const inner = terms?.[1];
5249
+ 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;
5250
+ const child = scalarOf(combinator);
5251
+ const parseScalar = fused ? (() => {
5252
+ const body = inner._stickyRegex;
5253
+ const tuple = ['"', "", '"'];
5254
+ const expected = [JSON.stringify('"')];
5255
+ return (input, pos, ctx) => {
5256
+ if (ctx.trivia !== void 0) {
5257
+ const end2 = child(input, pos, ctx);
5258
+ if (end2 < 0) return end2;
5259
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
5260
+ return end2;
5261
+ }
5262
+ if (input.charCodeAt(pos) !== 34) {
5263
+ ctx._fx = expected;
5264
+ return ~pos;
5265
+ }
5266
+ body.lastIndex = pos + 1;
5267
+ const match = body.exec(input);
5268
+ const close = pos + 1 + match[0].length;
5269
+ if (input.charCodeAt(close) !== 34) {
5270
+ ctx._fx = expected;
5271
+ return ~close;
5272
+ }
5273
+ tuple[1] = match[0];
5274
+ const end = close + 1;
5275
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
5276
+ return end;
5277
+ };
5278
+ })() : /* @__PURE__ */ (() => {
5279
+ return (input, pos, ctx) => {
5280
+ const end = child(input, pos, ctx);
5281
+ if (end < 0) return end;
5282
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
5283
+ return end;
5284
+ };
5285
+ })();
5054
5286
  return {
5055
5287
  _tag: "transform",
5056
5288
  _meta: combinator._meta,
5057
5289
  _def: { tag: "transform", parser: combinator, fn },
5290
+ _parseScalar: parseScalar,
5058
5291
  parse(input, pos, ctx) {
5059
5292
  const result = combinator.parse(input, pos, ctx);
5060
5293
  if (!result.ok) return result;
@@ -5069,9 +5302,11 @@ function trivia(combinator) {
5069
5302
  _meta: {
5070
5303
  ...combinator._meta,
5071
5304
  isTrivia: true,
5305
+ triviaScanner: fastTriviaScanner(combinator),
5072
5306
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
5073
5307
  },
5074
5308
  _def: { tag: "trivia", parser: combinator },
5309
+ _parseScalar: scalarOf(combinator),
5075
5310
  parse: combinator.parse.bind(combinator)
5076
5311
  };
5077
5312
  }
@@ -5192,10 +5427,32 @@ function regex(pattern, flags = "") {
5192
5427
  const canMatchNewline = raw.canMatchNewline;
5193
5428
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
5194
5429
  const def = { tag: "regex", source, flags: resolvedFlags };
5430
+ const expected = directTerminalFailureExpected(def);
5431
+ const parseScalar = (input, pos, ctx) => {
5432
+ const scanEnd = scan?.(input, pos);
5433
+ if (scanEnd !== void 0) {
5434
+ if (scanEnd === null) {
5435
+ ctx._fx = expected;
5436
+ return ~pos;
5437
+ }
5438
+ ctx._sv = input.slice(pos, scanEnd);
5439
+ return scanEnd;
5440
+ }
5441
+ anchored.lastIndex = pos;
5442
+ const match = anchored.exec(input);
5443
+ if (match === null) {
5444
+ ctx._fx = expected;
5445
+ return ~pos;
5446
+ }
5447
+ ctx._sv = match[0];
5448
+ return pos + match[0].length;
5449
+ };
5195
5450
  return {
5196
5451
  _tag: "regex",
5197
5452
  _meta: meta,
5198
5453
  _def: def,
5454
+ _stickyRegex: anchored,
5455
+ _parseScalar: parseScalar,
5199
5456
  parse(input, pos, ctx) {
5200
5457
  const scanEnd = scan?.(input, pos);
5201
5458
  if (scanEnd !== void 0) {
@@ -5884,6 +6141,22 @@ var Encoder = class {
5884
6141
  choiceRollbackMasks = /* @__PURE__ */ new Map();
5885
6142
  nonCommittingChoiceSites = /* @__PURE__ */ new Set();
5886
6143
  failureRollbackCleanSites = /* @__PURE__ */ new Set();
6144
+ /**
6145
+ * `hasSideWriter` memo for `failureNeedsRollback`, shared across every call
6146
+ * for the lifetime of this `Encoder`. A cached entry is written only when
6147
+ * `complete` is true, which means the answer is a path-independent fact
6148
+ * about that combinator node — it does not depend on which root's traversal
6149
+ * asked, only on the node's own reachable subgraph. Scoping the memo per call
6150
+ * (as a local inside `failureNeedsRollback`) was correct but discarded that
6151
+ * fact after every arm, so a grammar with many ordered-choice arms / optional
6152
+ * / attempt sites re-walked the SAME shared rule graph from scratch for each
6153
+ * site — O(sites × graph size) instead of O(graph size). Measured on the
6154
+ * scss-parser grammar (composed CSS-base superset, the deepest/largest of the
6155
+ * four grammars): 47-50s for one `compileRuleMap` with the per-call memo,
6156
+ * versus the whole macro transform completing in under a second once this
6157
+ * memo is hoisted here.
6158
+ */
6159
+ sideWriterMemo = /* @__PURE__ */ new Map();
5887
6160
  labels = void 0;
5888
6161
  /** Trivia table in scope at the row being encoded — codegen's `ctx.activeTrivia`. */
5889
6162
  activeTrivia = void 0;
@@ -6309,13 +6582,13 @@ var Encoder = class {
6309
6582
  const refName = p._ruleName;
6310
6583
  const winner = refName === void 0 ? void 0 : this.winners?.[refName];
6311
6584
  const root = winner !== void 0 && !winnerWrapsReference2(winner, p) ? winner : p;
6312
- const sideWriterMemo = /* @__PURE__ */ new Map();
6313
- const hasSideWriter = (current, seen = /* @__PURE__ */ new Set()) => {
6585
+ const sideWriterMemo = this.sideWriterMemo;
6586
+ const seen = /* @__PURE__ */ new Set();
6587
+ const hasSideWriter = (current) => {
6314
6588
  const cached = sideWriterMemo.get(current);
6315
6589
  if (cached !== void 0) return { found: cached, complete: true };
6316
6590
  if (seen.has(current)) return { found: false, complete: false };
6317
- const next = new Set(seen);
6318
- next.add(current);
6591
+ seen.add(current);
6319
6592
  const def = current._def;
6320
6593
  let result;
6321
6594
  switch (def.tag) {
@@ -6330,11 +6603,11 @@ var Encoder = class {
6330
6603
  const name = current._ruleName;
6331
6604
  const resolvedWinner = name === void 0 ? void 0 : this.winners?.[name];
6332
6605
  if (resolvedWinner !== void 0 && !winnerWrapsReference2(resolvedWinner, current)) {
6333
- result = hasSideWriter(resolvedWinner, next);
6606
+ result = hasSideWriter(resolvedWinner);
6334
6607
  break;
6335
6608
  }
6336
6609
  try {
6337
- result = hasSideWriter(def.thunk(), next);
6610
+ result = hasSideWriter(def.thunk());
6338
6611
  } catch {
6339
6612
  result = { found: true, complete: true };
6340
6613
  }
@@ -6344,7 +6617,7 @@ var Encoder = class {
6344
6617
  let complete = true;
6345
6618
  result = { found: false, complete: true };
6346
6619
  for (const child of childrenOf(def)) {
6347
- const childResult = hasSideWriter(child, next);
6620
+ const childResult = hasSideWriter(child);
6348
6621
  if (childResult.found) {
6349
6622
  result = { found: true, complete: true };
6350
6623
  break;
@@ -6354,6 +6627,7 @@ var Encoder = class {
6354
6627
  if (!result.found) result = { found: false, complete };
6355
6628
  }
6356
6629
  }
6630
+ seen.delete(current);
6357
6631
  if (result.found || result.complete) sideWriterMemo.set(current, result.found);
6358
6632
  return result;
6359
6633
  };
@@ -6788,7 +7062,7 @@ var Encoder = class {
6788
7062
  const dispCovIds = this.plan?.dispatches.get(p);
6789
7063
  let dispCov = 0;
6790
7064
  const arms = [];
6791
- const routed2 = [];
7065
+ const routed = [];
6792
7066
  const key = [], keyArm = [];
6793
7067
  const fold = [], foldArm = [];
6794
7068
  const match = [];
@@ -6796,7 +7070,7 @@ var Encoder = class {
6796
7070
  for (const c of d.cases) {
6797
7071
  const arm = arms.length;
6798
7072
  arms.push(this.covWrap(this.node(c.parser).ip, dispCovIds?.[dispCov++], 1));
6799
- routed2.push(branchUsesRouted(c) ? 1 : 0);
7073
+ routed.push(branchUsesRouted(c) ? 1 : 0);
6800
7074
  for (const kk of c.keys) {
6801
7075
  expected.push(JSON.stringify(kk));
6802
7076
  if (c.caseInsensitive) {
@@ -6812,7 +7086,7 @@ var Encoder = class {
6812
7086
  for (const m of d.matchers ?? []) {
6813
7087
  const arm = arms.length;
6814
7088
  arms.push(this.covWrap(this.node(m.parser).ip, dispCovIds?.[dispCov++], 1));
6815
- routed2.push(branchUsesRouted(m) ? 1 : 0);
7089
+ routed.push(branchUsesRouted(m) ? 1 : 0);
6816
7090
  if (!m.caseInsensitive) {
6817
7091
  match.push([KIND[m.kind], m.value, m.flags ?? "", arm]);
6818
7092
  continue;
@@ -6826,7 +7100,7 @@ var Encoder = class {
6826
7100
  }
6827
7101
  const other = d.otherwise === void 0 ? -1 : this.covWrap(this.node(d.otherwise).ip, dispCovIds?.[dispCov++], 1);
6828
7102
  const dspIdx = this.dsp.length;
6829
- this.dsp.push({ key, keyArm, fold, foldArm, match, routed: routed2, expected });
7103
+ this.dsp.push({ key, keyArm, fold, foldArm, match, routed, expected });
6830
7104
  const head = this.emitHead(OP_DISPATCH, 5 + arms.length);
6831
7105
  this.code[head + 1] = sel;
6832
7106
  this.code[head + 2] = dspIdx;
@@ -8698,6 +8972,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
8698
8972
  function q(s) {
8699
8973
  return JSON.stringify(s);
8700
8974
  }
8975
+ function isAsciiOnlyClass(cls) {
8976
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
8977
+ }
8701
8978
  var NO_SINKS = { fd: false, er: false };
8702
8979
  function sinkSlots(t2, s) {
8703
8980
  return `${s.fd ? `,${t2}fd=0` : ""}${s.er ? `,${t2}er=0` : ""}`;
@@ -9244,12 +9521,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9244
9521
  return `${head}EC.e=pos;return ''}`;
9245
9522
  case OP_GATE: {
9246
9523
  const child = link(code[ip + 2]);
9247
- const ci = classes.push([t2.cc[code[ip + 1]]]) - 1;
9524
+ const resolved = t2.cc[code[ip + 1]];
9525
+ const ci = classes.push([resolved]) - 1;
9248
9526
  classPlan.push([code[ip + 1]]);
9249
9527
  const cls = hoist("cl", `CLS[${ci}][0]`);
9250
9528
  const xf = fxRef(code[ip + 3]);
9251
9529
  return `${head}
9252
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9530
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9253
9531
  return ${child}(input,pos,ctx)
9254
9532
  }`;
9255
9533
  }
@@ -9592,10 +9870,11 @@ return v
9592
9870
  const asc = hoist("as", `DISP[${di}].ascii`);
9593
9871
  const hiArr = table.hi;
9594
9872
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
9873
+ const directAscii = staticBuild && table.hi.length === 0;
9595
9874
  return `${head}
9596
- const c=lead(input,pos)
9875
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
9597
9876
  let arm=-1
9598
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
9877
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
9599
9878
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
9600
9879
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
9601
9880
  if(arm>=0){
@@ -9617,7 +9896,9 @@ return FAIL
9617
9896
  const di = code[ip + 1];
9618
9897
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
9619
9898
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
9620
- const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
9899
+ const maskable = n <= 32;
9900
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
9901
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
9621
9902
  const tokenCandidate = tokenChoiceCandidates.get(ip);
9622
9903
  const pretests = Array.from({ length: n }, (_, i) => {
9623
9904
  if (tokenCandidate?.arm === i) {
@@ -9637,7 +9918,6 @@ return FAIL
9637
9918
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
9638
9919
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
9639
9920
  });
9640
- const maskable = n <= 32;
9641
9921
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
9642
9922
  if (maskable) maskPlan.push(~di);
9643
9923
  const p = tmp();
@@ -9699,16 +9979,16 @@ ${merge}
9699
9979
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
9700
9980
  return FAIL`;
9701
9981
  return `${head}
9702
- const c=lead(input,pos)
9982
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
9703
9983
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
9704
9984
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
9705
9985
  ${maskable ? `if(c<128){
9706
- const bits=${maskName}[c<0?128:c]
9986
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
9707
9987
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
9708
9988
  ${lazyArms(true)}
9709
- }else{
9989
+ }${directAsciiMask ? "" : `else{
9710
9990
  ${lazyArms(false)}
9711
- }
9991
+ }`}
9712
9992
  ` : lazyArms(false)}
9713
9993
  ${finish}
9714
9994
  }`;
@@ -9759,7 +10039,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
9759
10039
  ${rollbackFor(i)}
9760
10040
  }${routeMiss}${sequenceMiss}`;
9761
10041
  }).join("\n") : "";
9762
- const generalArms = arms.map((arm, i) => {
10042
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
9763
10043
  const pretest = pretests[i];
9764
10044
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
9765
10045
  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("||")})`;
@@ -9789,12 +10069,12 @@ ${rollbackFor(i)}
9789
10069
  }${miss}`;
9790
10070
  }).join("\n");
9791
10071
  return `${head}
9792
- const c=lead(input,pos)
10072
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
9793
10073
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
9794
10074
  let acc
9795
10075
  let best=pos
9796
10076
  ${maskable ? `if(c<128){
9797
- const bits=${maskName}[c<0?128:c]
10077
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
9798
10078
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
9799
10079
  ${startFailureExact ? "" : "let prev=0"}
9800
10080
  ${maskArms}
@@ -9889,14 +10169,18 @@ return [key,v]
9889
10169
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
9890
10170
  const collect = op === OP_REP;
9891
10171
  let itemCls;
10172
+ let itemAscii = false;
9892
10173
  if (!REC) {
9893
10174
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
9894
10175
  if (itemClassIndex >= 0) {
9895
- const ci = classes.push([t2.cc[itemClassIndex]]) - 1;
10176
+ const resolved = t2.cc[itemClassIndex];
10177
+ const ci = classes.push([resolved]) - 1;
9896
10178
  classPlan.push([itemClassIndex]);
9897
10179
  itemCls = hoist("ri", `CLS[${ci}][0]`);
10180
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
9898
10181
  }
9899
10182
  }
10183
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
9900
10184
  const skipBeforeFirst = sepIp < 0 && min === 0;
9901
10185
  const p = tmp();
9902
10186
  const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -9956,7 +10240,7 @@ let count=0
9956
10240
  for(;;){
9957
10241
  ${max >= 0 ? `if(count>=${max})break
9958
10242
  ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
9959
- ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&!classHas(${itemCls},lead(input,cur)))break
10243
+ ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
9960
10244
  ` : ""}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` : ""}
9961
10245
  ${markBody}
9962
10246
  let itemStart=cur
@@ -9981,7 +10265,7 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
9981
10265
  ${rb}
9982
10266
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
9983
10267
  }
9984
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
10268
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
9985
10269
  ${rb}
9986
10270
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
9987
10271
  }
@@ -10265,6 +10549,28 @@ function literal(value, opts = {}) {
10265
10549
  isTrivia: false
10266
10550
  };
10267
10551
  const canMatchNewline = meta.canMatchNewline;
10552
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
10553
+ const code = value.charCodeAt(0);
10554
+ return (input, pos, ctx) => {
10555
+ if (input.charCodeAt(pos) === code) {
10556
+ ctx._sv = value;
10557
+ return pos + 1;
10558
+ }
10559
+ ctx._fx = expected;
10560
+ return ~pos;
10561
+ };
10562
+ })() : (input, pos, ctx) => {
10563
+ const end = pos + value.length;
10564
+ if (end <= input.length) {
10565
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
10566
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
10567
+ ctx._sv = matchedValue;
10568
+ return end;
10569
+ }
10570
+ }
10571
+ ctx._fx = expected;
10572
+ return ~pos;
10573
+ };
10268
10574
  if (caseInsensitive) {
10269
10575
  const upper = value.toUpperCase();
10270
10576
  const lower = value.toLowerCase();
@@ -10305,6 +10611,7 @@ function literal(value, opts = {}) {
10305
10611
  _tag: "literal",
10306
10612
  _meta: meta,
10307
10613
  _def: { tag: "literal", value, caseInsensitive },
10614
+ _parseScalar: parseScalar,
10308
10615
  parse: parse2
10309
10616
  };
10310
10617
  }
@@ -10324,6 +10631,7 @@ function sequence(...parsers) {
10324
10631
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
10325
10632
  }
10326
10633
  const hasAdjacency = adjacency !== null;
10634
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
10327
10635
  const meta = {
10328
10636
  // Union through the nullable prefix — a leading optional()/many() lets a later
10329
10637
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -10332,165 +10640,96 @@ function sequence(...parsers) {
10332
10640
  isTrivia: false
10333
10641
  };
10334
10642
  const def = { tag: "sequence", parsers };
10335
- let followSentinels;
10336
- function parseTolerant(input, pos, ctx) {
10337
- followSentinels ??= parsers.map((_, i) => {
10338
- const fs = parsers.slice(i + 1).reduce(
10339
- (acc, p) => union(acc, firstSetOf(p)),
10340
- { kind: "empty" }
10341
- );
10342
- return firstSetSentinel(fs);
10343
- });
10344
- const values = def.valueUnused ? void 0 : [];
10643
+ const scalarParsers = parsers.map(scalarOf);
10644
+ const parseScalar = (input, pos, ctx) => {
10345
10645
  let cur = pos;
10346
- const inheritedSync = ctx._sync;
10347
- try {
10348
- for (let i = 0; i < parsers.length; i++) {
10349
- ctx._sync = followSentinels[i] ?? inheritedSync;
10350
- const adj = adjacency === null ? null : adjacency[i];
10351
- if (adj) {
10352
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
10353
- if (values !== void 0) values.push(null);
10354
- continue;
10355
- }
10356
- if (ctx.trivia && i > 0) {
10357
- const mTlog = cstTlLen(ctx);
10358
- const mLog = ctx._triviaLog?.length ?? 0;
10359
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
10360
- let scanEnd;
10361
- if (needsDeferredTriviaCommit(ctx)) {
10362
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
10363
- } else {
10364
- scanEnd = advanceTrivia(input, cur, ctx);
10365
- }
10366
- const scanTlog = cstTlLen(ctx);
10367
- const scanLog = ctx._triviaLog?.length ?? 0;
10368
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
10369
- const result2 = parsers[i].parse(input, scanEnd, ctx);
10370
- if (!result2.ok) return result2;
10371
- if (result2.span.end > scanEnd) cur = result2.span.end;
10372
- else rollbackScannedTriviaAt(
10373
- ctx,
10374
- mTlog,
10375
- scanTlog,
10376
- mLog,
10377
- scanLog,
10378
- mRootLog,
10379
- scanRootLog
10380
- );
10381
- if (values !== void 0) values.push(result2.value);
10382
- continue;
10383
- }
10384
- const result = parsers[i].parse(input, cur, ctx);
10385
- if (!result.ok) return result;
10386
- if (values !== void 0) values.push(result.value);
10387
- cur = result.span.end;
10646
+ if (strictArity !== 0) {
10647
+ cur = scalarParsers[0](input, cur, ctx);
10648
+ if (cur < 0) return cur;
10649
+ const first = ctx._sv;
10650
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
10651
+ cur = scalarParsers[1](input, cur, ctx);
10652
+ if (cur < 0) return cur;
10653
+ const second = ctx._sv;
10654
+ if (strictArity === 2) {
10655
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
10656
+ return cur;
10388
10657
  }
10389
- } finally {
10390
- ctx._sync = inheritedSync;
10658
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
10659
+ cur = scalarParsers[2](input, cur, ctx);
10660
+ if (cur < 0) return cur;
10661
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
10662
+ return cur;
10391
10663
  }
10392
- return {
10393
- ok: true,
10394
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
10395
- value: values ?? void 0,
10396
- span: { start: pos, end: cur }
10397
- };
10398
- }
10399
- function parseAdjacent(input, pos, ctx) {
10400
10664
  const values = def.valueUnused ? void 0 : [];
10401
- let cur = pos;
10402
- for (let i = 0; i < parsers.length; i++) {
10403
- const adj = adjacency[i];
10404
- if (adj) {
10405
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
10406
- if (values !== void 0) values.push(null);
10407
- continue;
10408
- }
10409
- if (ctx.trivia && i > 0) {
10410
- let scanEnd;
10411
- const mTlog = cstTlLen(ctx);
10412
- const mLog = ctx._triviaLog?.length ?? 0;
10413
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
10414
- if (needsDeferredTriviaCommit(ctx)) {
10415
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
10416
- } else {
10417
- scanEnd = advanceTrivia(input, cur, ctx);
10418
- }
10419
- const scanTlog = cstTlLen(ctx);
10420
- const scanLog = ctx._triviaLog?.length ?? 0;
10421
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
10422
- const result2 = parsers[i].parse(input, scanEnd, ctx);
10423
- if (!result2.ok) return result2;
10424
- if (result2.span.end > scanEnd) cur = result2.span.end;
10425
- else rollbackScannedTriviaAt(
10426
- ctx,
10427
- mTlog,
10428
- scanTlog,
10429
- mLog,
10430
- scanLog,
10431
- mRootLog,
10432
- scanRootLog
10433
- );
10434
- if (values !== void 0) values.push(result2.value);
10435
- continue;
10436
- }
10437
- const result = parsers[i].parse(input, cur, ctx);
10438
- if (!result.ok) return result;
10439
- if (values !== void 0) values.push(result.value);
10440
- cur = result.span.end;
10441
- }
10442
- return {
10443
- ok: true,
10444
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
10445
- value: values ?? void 0,
10446
- span: { start: pos, end: cur }
10447
- };
10448
- }
10665
+ for (let i = 0; i < scalarParsers.length; i++) {
10666
+ let termPos = cur;
10667
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
10668
+ const end = scalarParsers[i](input, termPos, ctx);
10669
+ if (end < 0) return end;
10670
+ if (values !== void 0) values.push(ctx._sv);
10671
+ if (end > termPos || termPos === cur) cur = end;
10672
+ }
10673
+ ctx._sv = values;
10674
+ return cur;
10675
+ };
10676
+ let followSentinels;
10449
10677
  return {
10450
10678
  _tag: "sequence",
10451
10679
  _meta: meta,
10452
10680
  _def: def,
10681
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
10453
10682
  parse(input, pos, ctx) {
10454
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
10455
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
10683
+ const tolerant = ctx._tolerant === true;
10684
+ if (tolerant) {
10685
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
10686
+ parsers.slice(i + 1).reduce(
10687
+ (set, parser2) => union(set, firstSetOf(parser2)),
10688
+ { kind: "empty" }
10689
+ )
10690
+ ));
10691
+ }
10692
+ const inheritedSync = ctx._sync;
10693
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
10456
10694
  const values = def.valueUnused ? void 0 : [];
10457
10695
  let cur = pos;
10458
- for (let i = 0; i < parsers.length; i++) {
10459
- if (ctx.trivia && i > 0) {
10460
- let scanEnd;
10461
- const mTlog = cstTlLen(ctx);
10462
- const mLog = ctx._triviaLog?.length ?? 0;
10463
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
10464
- if (needsDeferredTriviaCommit(ctx)) {
10465
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
10466
- } else {
10467
- scanEnd = advanceTrivia(input, cur, ctx);
10696
+ try {
10697
+ for (let i = 0; i < parsers.length; i++) {
10698
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
10699
+ const assertion = adjacency?.[i];
10700
+ if (assertion) {
10701
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
10702
+ if (values !== void 0) values.push(null);
10703
+ continue;
10468
10704
  }
10469
- const scanTlog = cstTlLen(ctx);
10470
- const scanLog = ctx._triviaLog?.length ?? 0;
10471
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
10472
- const result2 = parsers[i].parse(input, scanEnd, ctx);
10473
- if (!result2.ok) return result2;
10474
- if (result2.span.end > scanEnd) {
10475
- cur = result2.span.end;
10476
- } else {
10705
+ let termPos = cur;
10706
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
10707
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
10708
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
10709
+ if (ctx.trivia && i > 0) {
10710
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
10711
+ }
10712
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
10713
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
10714
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
10715
+ const result = parsers[i].parse(input, termPos, ctx);
10716
+ if (!result.ok) return result;
10717
+ if (values !== void 0) values.push(result.value);
10718
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
10719
+ else if (deferredTrivia) {
10477
10720
  rollbackScannedTriviaAt(
10478
10721
  ctx,
10479
- mTlog,
10722
+ markTlog,
10480
10723
  scanTlog,
10481
- mLog,
10724
+ markLog,
10482
10725
  scanLog,
10483
- mRootLog,
10726
+ markRootLog,
10484
10727
  scanRootLog
10485
10728
  );
10486
10729
  }
10487
- if (values !== void 0) values.push(result2.value);
10488
- continue;
10489
10730
  }
10490
- const result = parsers[i].parse(input, cur, ctx);
10491
- if (!result.ok) return result;
10492
- if (values !== void 0) values.push(result.value);
10493
- cur = result.span.end;
10731
+ } finally {
10732
+ if (tolerant) ctx._sync = inheritedSync;
10494
10733
  }
10495
10734
  return {
10496
10735
  ok: true,
@@ -10503,8 +10742,20 @@ function sequence(...parsers) {
10503
10742
  }
10504
10743
 
10505
10744
  // src/combinators/ref.ts
10745
+ function withRuleTrivia(trivia2, ctx, run) {
10746
+ const savedLabels = ctx.triviaKindLabels;
10747
+ ctx.trivia = trivia2;
10748
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
10749
+ try {
10750
+ return run();
10751
+ } finally {
10752
+ ctx.trivia = void 0;
10753
+ ctx.triviaKindLabels = savedLabels;
10754
+ }
10755
+ }
10506
10756
  function ref() {
10507
10757
  let resolved = null;
10758
+ let resolvedScalar = null;
10508
10759
  let ownBoundary = false;
10509
10760
  const meta = {
10510
10761
  firstSet: any(),
@@ -10521,25 +10772,28 @@ function ref() {
10521
10772
  return resolved;
10522
10773
  }
10523
10774
  },
10775
+ _parseScalar(input, pos, ctx) {
10776
+ const scalar = resolvedScalar;
10777
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
10778
+ const gt = meta.grammarTrivia;
10779
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
10780
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
10781
+ }
10782
+ return scalar(input, pos, ctx);
10783
+ },
10524
10784
  parse(input, pos, ctx) {
10525
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
10785
+ const parser2 = resolved;
10786
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
10526
10787
  const gt = meta.grammarTrivia;
10527
10788
  if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
10528
- const savedLabels = ctx.triviaKindLabels;
10529
- ctx.trivia = gt;
10530
- ctx.triviaKindLabels = gt._meta.triviaKindLabels;
10531
- try {
10532
- return resolved.parse(input, pos, ctx);
10533
- } finally {
10534
- ctx.trivia = void 0;
10535
- ctx.triviaKindLabels = savedLabels;
10536
- }
10789
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
10537
10790
  }
10538
- return resolved.parse(input, pos, ctx);
10791
+ return parser2.parse(input, pos, ctx);
10539
10792
  },
10540
10793
  define(p) {
10541
10794
  if (resolved) throw new Error("ref<T>() already defined");
10542
10795
  resolved = p;
10796
+ resolvedScalar = scalarOf(p);
10543
10797
  ownBoundary = hasOwnTriviaBoundary(p);
10544
10798
  meta.firstSet = p._meta.firstSet;
10545
10799
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -13444,10 +13698,10 @@ function assemble(t2, prog, cfg) {
13444
13698
  const hasFold = spec.byFold.size > 0;
13445
13699
  const match = spec.match;
13446
13700
  const matchN = match.length;
13447
- const routed2 = spec.routed;
13701
+ const routed = spec.routed;
13448
13702
  const expected = spec.expected;
13449
13703
  const validArm = (arm) => Number.isInteger(arm) && arm >= 0 && arm < n;
13450
- if (routed2.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
13704
+ if (routed.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
13451
13705
  for (const arm of byKey.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch exact arm");
13452
13706
  for (const arm of byFold.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch folded arm");
13453
13707
  for (const m of match) if (!validArm(m[3])) throw new TypeError("table assembler: malformed dispatch matcher arm");
@@ -13472,7 +13726,7 @@ function assemble(t2, prog, cfg) {
13472
13726
  const classify = hasFold ? matchBlock === void 0 ? (key) => byKey.get(key) ?? byFold.get(asciiFoldKey(key)) : (key) => byKey.get(key) ?? byFold.get(asciiFoldKey(key)) ?? matchBlock(key) : matchBlock === void 0 ? (key) => byKey.get(key) : (key) => byKey.get(key) ?? matchBlock(key);
13473
13727
  const neverBranch = () => FAIL;
13474
13728
  const bindArms = (start) => {
13475
- const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed2[i] === 1) : neverBranch;
13729
+ const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed[i] === 1) : neverBranch;
13476
13730
  const next = start + 4 < n ? bindArms(start + 4) : void 0;
13477
13731
  return dispatchArmBlock(
13478
13732
  start,
@@ -14291,7 +14545,7 @@ function buildGrammarPlan(entry, winners) {
14291
14545
  const dispatches = /* @__PURE__ */ new Map();
14292
14546
  const attempts = /* @__PURE__ */ new Map();
14293
14547
  const labels = /* @__PURE__ */ new Map();
14294
- const rules2 = /* @__PURE__ */ new Map();
14548
+ const rules = /* @__PURE__ */ new Map();
14295
14549
  const winnerNames = /* @__PURE__ */ new Map();
14296
14550
  if (winners) {
14297
14551
  for (const [name, winner] of Object.entries(winners)) {
@@ -14312,7 +14566,7 @@ function buildGrammarPlan(entry, winners) {
14312
14566
  if (rule2 && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
14313
14567
  const id = `rule:${rule2}`;
14314
14568
  definitions.set(id, { id, kind: "rule" });
14315
- rules2.set(parser2, id);
14569
+ rules.set(parser2, id);
14316
14570
  }
14317
14571
  if (parser2._def.tag === "choice") {
14318
14572
  const ids = parser2._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
@@ -14336,7 +14590,7 @@ function buildGrammarPlan(entry, winners) {
14336
14590
  for (const root of roots) {
14337
14591
  visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
14338
14592
  }
14339
- return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
14593
+ return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules };
14340
14594
  }
14341
14595
 
14342
14596
  // src/analysis/duplication.ts
@@ -17004,31 +17258,6 @@ function locatedLines(l, opts) {
17004
17258
  return out;
17005
17259
  }
17006
17260
 
17007
- // src/compiler/linker.ts
17008
- function normalizeCstCollapse(collapse) {
17009
- if (collapse === true) return () => true;
17010
- if (Array.isArray(collapse)) {
17011
- const types = new Set(collapse);
17012
- return (type) => types.has(type);
17013
- }
17014
- return typeof collapse === "function" ? collapse : void 0;
17015
- }
17016
- function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state, tags) {
17017
- return tags !== void 0 && tags.length > 0 ? { _tag: "node", type, tags, span: { ...span }, state: state ?? null, children: [...children2] } : { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children2] };
17018
- }
17019
- function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state, _tags) {
17020
- if (typeof typeOrOptions === "string") {
17021
- return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
17022
- }
17023
- const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
17024
- const materializeTags = typeOrOptions?.tags === true;
17025
- const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2, tags) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2, materializeTags ? tags : void 0);
17026
- host._parsemanCstOutput = true;
17027
- if (collapse) host._parsemanCstCollapse = collapse;
17028
- return host;
17029
- }
17030
- cstBuildHost._parsemanCstOutput = true;
17031
-
17032
17261
  // src/analysis/diagnose.ts
17033
17262
  function examinedNothing(d) {
17034
17263
  return d.summary.totalChoices === 0 && d.summary.unanalysable > 0;