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
@@ -35,10 +35,20 @@ function classifyFinalChoice(arms, resolve) {
35
35
  }
36
36
  return { exclusive, firstSets, nullable: nullable2 };
37
37
  }
38
- function resolveNamedRef(p, resolve) {
38
+ function winnerForRef(p, resolve) {
39
39
  if (resolve === void 0) return void 0;
40
40
  const name = p._ruleName;
41
- return name === void 0 ? void 0 : resolve(name);
41
+ const w = name === void 0 ? void 0 : resolve(name);
42
+ if (w === void 0 || w === p) return void 0;
43
+ let cur = w;
44
+ for (const seen = /* @__PURE__ */ new Set(); !seen.has(cur); ) {
45
+ if (cur === p) return void 0;
46
+ seen.add(cur);
47
+ const cd = cur._def;
48
+ if (cd.tag !== "grammar" && cd.tag !== "trivia") return w;
49
+ cur = cd.parser;
50
+ }
51
+ return w;
42
52
  }
43
53
  function union(a, b) {
44
54
  if (a.kind === "any" || b.kind === "any") return { kind: "any" };
@@ -136,13 +146,15 @@ function matchesEmptyBody(p, seen, resolve) {
136
146
  case "grammar":
137
147
  case "recover":
138
148
  return me(d.parser);
139
- case "lazy":
149
+ case "lazy": {
150
+ const w = winnerForRef(p, resolve);
151
+ if (w !== void 0) return me(w);
140
152
  try {
141
153
  return me(d.thunk());
142
154
  } catch {
143
- const t2 = resolveNamedRef(p, resolve);
144
- return t2 ? me(t2) : true;
155
+ return true;
145
156
  }
157
+ }
146
158
  default:
147
159
  return true;
148
160
  }
@@ -206,13 +218,15 @@ function firstSetBody(p, seen, resolve) {
206
218
  // terminals: no refs, cached set is exact
207
219
  case "dispatch":
208
220
  return fs(d.selector);
209
- case "lazy":
221
+ case "lazy": {
222
+ const w = winnerForRef(p, resolve);
223
+ if (w !== void 0) return fs(w);
210
224
  try {
211
225
  return fs(d.thunk());
212
226
  } catch {
213
- const t2 = resolveNamedRef(p, resolve);
214
- return t2 ? fs(t2) : any();
227
+ return any();
215
228
  }
229
+ }
216
230
  case "choice": {
217
231
  let out = empty();
218
232
  for (const arm of d.parsers) out = union(out, fs(arm));
@@ -615,16 +629,26 @@ function keywords(words, opts = {}) {
615
629
  caseInsensitive: opts.caseInsensitive ?? false,
616
630
  boundary: opts.boundary
617
631
  };
632
+ const expected = directTerminalFailureExpected(def);
633
+ const parseScalar = (input, pos, ctx) => {
634
+ re.lastIndex = pos;
635
+ const m = re.exec(input);
636
+ if (m === null) {
637
+ ctx._fx = expected;
638
+ return ~pos;
639
+ }
640
+ ctx._sv = m[0];
641
+ return pos + m[0].length;
642
+ };
618
643
  return {
619
644
  _tag: "keywords",
620
645
  _meta: meta,
621
646
  _def: def,
647
+ _parseScalar: parseScalar,
622
648
  parse(input, pos, ctx) {
623
649
  re.lastIndex = pos;
624
650
  const m = re.exec(input);
625
- if (m === null || m.index !== pos) {
626
- return failAt(ctx, directTerminalFailureExpected(def), pos);
627
- }
651
+ if (m === null) return failAt(ctx, directTerminalFailureExpected(def), pos);
628
652
  const value = m[0];
629
653
  const span = { start: pos, end: pos + value.length };
630
654
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
@@ -768,6 +792,7 @@ function createParseContext() {
768
792
  _fe: void 0,
769
793
  _fx: void 0,
770
794
  _fc: void 0,
795
+ _sv: void 0,
771
796
  _probe: void 0,
772
797
  _cstChildren: void 0,
773
798
  _cstLeaves: void 0,
@@ -1468,6 +1493,9 @@ var fastScanner3;
1468
1493
  function needsDeferredTriviaCommit(ctx) {
1469
1494
  return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1470
1495
  }
1496
+ function needsTriviaRollback(ctx) {
1497
+ 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;
1498
+ }
1471
1499
  function saveTriviaMark(ctx) {
1472
1500
  const m = saveCstMark(ctx);
1473
1501
  return {
@@ -1584,7 +1612,8 @@ function advanceTrivia(input, cur, ctx) {
1584
1612
  const triviaP = ctx.trivia;
1585
1613
  if (!triviaP) return cur;
1586
1614
  if (!ctx.trackLines) {
1587
- const fast2 = fastTriviaScanner(triviaP);
1615
+ const classified = triviaP._meta.triviaScanner;
1616
+ const fast2 = classified === void 0 ? fastTriviaScanner(triviaP) : classified;
1588
1617
  if (fast2) return fast2(input, cur);
1589
1618
  if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
1590
1619
  const tr2 = triviaP.parse(input, cur, createDetachedParseContext(ctx.trackLines, ctx.state));
@@ -2151,6 +2180,28 @@ function refuseUnclassifiedRootScope(strict) {
2151
2180
  if (strict === true) throw new TypeError(ROOT_TRIVIA_SCOPE_REFUSAL);
2152
2181
  }
2153
2182
 
2183
+ // src/combinators/scalar.ts
2184
+ var SCALAR_TAG = /^(?:literal|regex|keywords|sequence|choice|many|oneOrMore|optional|transform|trivia|grammar|sepBy|lazy)$/;
2185
+ function scalarOf(combinator) {
2186
+ return combinator._parseScalar;
2187
+ }
2188
+ function scalarTree(parser2, seen) {
2189
+ if (seen.has(parser2)) return true;
2190
+ if (parser2._parseScalar === void 0) return false;
2191
+ seen.add(parser2);
2192
+ const def = parser2._def;
2193
+ if (!SCALAR_TAG.test(def.tag)) return false;
2194
+ if ("parsers" in def && !def.parsers.every((child) => scalarTree(child, seen))) return false;
2195
+ if ("parser" in def && !scalarTree(def.parser, seen)) return false;
2196
+ if ("separator" in def && !scalarTree(def.separator, seen)) return false;
2197
+ return def.tag !== "lazy" || scalarTree(def.thunk(), seen);
2198
+ }
2199
+ function scalarRootOf(combinator) {
2200
+ const scalar = combinator._parseScalar;
2201
+ const def = combinator._def;
2202
+ return scalar !== void 0 && def.tag === "grammar" && scalarTree(def.parser, /* @__PURE__ */ new Set()) ? scalar : void 0;
2203
+ }
2204
+
2154
2205
  // src/combinators/grammar.ts
2155
2206
  function annotateResultLines(result, index) {
2156
2207
  const annotated = { ...result, span: annotateSpan(result.span, index) };
@@ -2187,6 +2238,24 @@ function parser(opts, root) {
2187
2238
  const captureKinds = clearTrivia ? void 0 : opts.captureTriviaKinds;
2188
2239
  const ownCaptureMask = captureKinds === void 0 ? void 0 : scopeLabels !== void 0 ? triviaKindMask(scopeLabels, captureKinds) : void 0;
2189
2240
  const inheritCaptureMask = captureKinds !== void 0 && scopeLabels === void 0;
2241
+ const rootScalar = scalarOf(root);
2242
+ const scalarEligible = opts.trackLines !== true && opts.recover !== true && !opaqueRootCapture && !forceCaptureTrivia && captureKinds === void 0;
2243
+ const parseScalar = scalarEligible ? (input, pos, ctx) => {
2244
+ const savedTrivia = ctx.trivia;
2245
+ const savedLabels = ctx.triviaKindLabels;
2246
+ if (clearTrivia) {
2247
+ ctx.trivia = void 0;
2248
+ ctx.triviaKindLabels = void 0;
2249
+ } else if (scopeTrivia !== void 0) {
2250
+ ctx.trivia = scopeTrivia;
2251
+ ctx.triviaKindLabels = scopeLabels;
2252
+ }
2253
+ const end = rootScalar(input, pos, ctx);
2254
+ ctx.trivia = savedTrivia;
2255
+ ctx.triviaKindLabels = savedLabels;
2256
+ return end;
2257
+ } : void 0;
2258
+ let publicScalar;
2190
2259
  const grammar = {
2191
2260
  _tag: "grammar",
2192
2261
  _meta: {
@@ -2210,7 +2279,20 @@ function parser(opts, root) {
2210
2279
  constructionTrackLines: trackLinesPolicy,
2211
2280
  ...captureKinds === void 0 ? {} : { constructionCaptureTriviaKinds: captureKinds }
2212
2281
  },
2282
+ _parseScalar: parseScalar,
2213
2283
  parse(input, pos, _ctx) {
2284
+ if (pos === void 0 && _ctx === void 0) {
2285
+ publicScalar ??= scalarRootOf(grammar) ?? null;
2286
+ if (publicScalar) {
2287
+ const ctx2 = createParseContext();
2288
+ const end = publicScalar(input, 0, ctx2);
2289
+ if (end < 0) {
2290
+ const at = ~end;
2291
+ return { ok: false, expected: ctx2._fx ?? [], span: { start: at, end: at } };
2292
+ }
2293
+ return { ok: true, value: ctx2._sv, span: { start: 0, end } };
2294
+ }
2295
+ }
2214
2296
  if (refuseUnclassified) refuseUnclassifiedRootScope(_ctx?._rootTriviaStrictScopes);
2215
2297
  const trackLines = trackLinesOf(_ctx);
2216
2298
  const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
@@ -2245,6 +2327,9 @@ function parse(combinator, input, opts = {}) {
2245
2327
  _analyzed.add(combinator);
2246
2328
  markUnusedValues(combinator);
2247
2329
  }
2330
+ if (!opts.trackLines && !opts.recover && combinator._def.tag === "grammar" && combinator._meta.grammarScanSkip === void 0) {
2331
+ return combinator.parse(input);
2332
+ }
2248
2333
  const trackLines = opts.trackLines ?? combinator._meta.grammarTrackLines ?? false;
2249
2334
  const lineContext = trackLines ? createParseLineContext(input, 0) : void 0;
2250
2335
  const lineIndex = lineContext?.lineIndex;
@@ -3410,7 +3495,8 @@ function choice(...args) {
3410
3495
  disjoint
3411
3496
  };
3412
3497
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
3413
- const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
3498
+ const ordered = strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix";
3499
+ const autoNot = !disjoint && !hasGates && ordered ? computeAutoNot(parsers) : parsers.map(() => null);
3414
3500
  let greedyLitMap = null;
3415
3501
  let sortedParsers = null;
3416
3502
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -3424,6 +3510,37 @@ function choice(...args) {
3424
3510
  } else if (strategy?.tag === "literalsLongestFirst") {
3425
3511
  sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
3426
3512
  }
3513
+ const scalarParsers = parsers.map(scalarOf);
3514
+ const scalarEligible = !hasGates && parsers.every((p) => p._parseScalar !== void 0) && (disjoint || ordered);
3515
+ const scalarExpected = parsers.flatMap(deriveExpected);
3516
+ const parseScalar = (input, pos, ctx) => {
3517
+ if (disjoint) {
3518
+ const code = pos < input.length ? input.codePointAt(pos) : -1;
3519
+ let idx = code >= 0 && code < 128 ? asciiDispatch[code] : -1;
3520
+ if (idx < 0 && code >= 0) {
3521
+ for (let i = 0; i < parsers.length; i++) {
3522
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
3523
+ idx = i;
3524
+ break;
3525
+ }
3526
+ }
3527
+ }
3528
+ if (idx >= 0) {
3529
+ const gate = gates[idx];
3530
+ if (!gate || gate(ctx.state)) return scalarParsers[idx](input, pos, ctx);
3531
+ ctx._fx = deriveExpected(parsers[idx]);
3532
+ return ~pos;
3533
+ }
3534
+ } else {
3535
+ for (let i = 0; i < scalarParsers.length; i++) {
3536
+ if (gates[i] && !gates[i](ctx.state)) continue;
3537
+ const end = scalarParsers[i](input, pos, ctx);
3538
+ if (end >= 0 && (!autoNot[i] || !autoNotFires(input, end, autoNot[i]))) return end;
3539
+ }
3540
+ }
3541
+ ctx._fx = scalarExpected;
3542
+ return ~pos;
3543
+ };
3427
3544
  return {
3428
3545
  _tag: "choice",
3429
3546
  _meta: meta,
@@ -3435,6 +3552,7 @@ function choice(...args) {
3435
3552
  strategy: strategy ?? { tag: "firstMatch" },
3436
3553
  autoNot
3437
3554
  },
3555
+ _parseScalar: scalarEligible ? parseScalar : void 0,
3438
3556
  parse(input, pos, ctx) {
3439
3557
  const expected = [];
3440
3558
  let expectedAt = pos;
@@ -4774,8 +4892,8 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
4774
4892
  }
4775
4893
 
4776
4894
  // src/combinators/repeat.ts
4777
- function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4778
- const mark = saveTriviaMark(ctx);
4895
+ function repItem(combinator, input, cur, ctx, guardable, mandatory, rollbackNeeded) {
4896
+ const mark = rollbackNeeded ? saveTriviaMark(ctx) : void 0;
4779
4897
  let pos = cur;
4780
4898
  if (ctx.trivia) {
4781
4899
  if (needsDeferredTriviaCommit(ctx)) {
@@ -4785,24 +4903,24 @@ function repItem(combinator, input, cur, ctx, guardable, mandatory) {
4785
4903
  }
4786
4904
  }
4787
4905
  if (pos >= input.length && !mandatory) {
4788
- rollbackTrivia(ctx, mark);
4906
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4789
4907
  return "stop";
4790
4908
  }
4791
4909
  if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
4792
- rollbackTrivia(ctx, mark);
4910
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4793
4911
  return "stop";
4794
4912
  }
4795
4913
  const result = combinator.parse(input, pos, ctx);
4796
4914
  if (!result.ok) {
4797
- rollbackTrivia(ctx, mark);
4915
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4798
4916
  if (result.committed) return { fail: result, failPos: pos };
4799
4917
  return { fail: result, failPos: pos };
4800
4918
  }
4801
4919
  if (result.span.end === pos && !mandatory) {
4802
- rollbackTrivia(ctx, mark);
4920
+ if (mark !== void 0) rollbackTrivia(ctx, mark);
4803
4921
  return "stop";
4804
4922
  }
4805
- return { value: result.value, end: result.span.end };
4923
+ return result;
4806
4924
  }
4807
4925
  function resolveBounds(what, opts) {
4808
4926
  const min = opts.min ?? 0;
@@ -4815,6 +4933,21 @@ function resolveBounds(what, opts) {
4815
4933
  if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
4816
4934
  return { min, max };
4817
4935
  }
4936
+ function repeatScalarTail(combinator, child, input, cur, ctx, guardable, values, remaining) {
4937
+ while (cur < input.length && remaining > 0) {
4938
+ let itemPos = cur;
4939
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
4940
+ if (itemPos >= input.length) break;
4941
+ if (guardable && !startsFirstSet(combinator, input, itemPos)) break;
4942
+ const end = child(input, itemPos, ctx);
4943
+ if (end <= itemPos) break;
4944
+ if (values !== void 0) values.push(ctx._sv);
4945
+ cur = end;
4946
+ remaining--;
4947
+ }
4948
+ ctx._sv = values;
4949
+ return cur;
4950
+ }
4818
4951
  function many(combinator, opts = {}) {
4819
4952
  const { min, max } = resolveBounds("many()", opts);
4820
4953
  if (min >= 1) return atLeast(combinator, min, max);
@@ -4826,17 +4959,21 @@ function many(combinator, opts = {}) {
4826
4959
  const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
4827
4960
  let expected;
4828
4961
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
4962
+ const scalarChild = scalarOf(combinator);
4963
+ const parseScalar = (input, pos, ctx) => repeatScalarTail(combinator, scalarChild, input, pos, ctx, guardable, def.valueUnused ? void 0 : [], max);
4829
4964
  return {
4830
4965
  _tag: "many",
4831
4966
  _meta: meta,
4832
4967
  _def: def,
4968
+ _parseScalar: parseScalar,
4833
4969
  parse(input, pos, ctx) {
4834
4970
  const values = def.valueUnused ? void 0 : [];
4971
+ const rollbackNeeded = needsTriviaRollback(ctx);
4835
4972
  let cur = pos;
4836
4973
  let count = 0;
4837
4974
  while (cur < input.length) {
4838
4975
  if (count >= max) break;
4839
- const item = repItem(combinator, input, cur, ctx, guardable, false);
4976
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4840
4977
  if (item === "stop") break;
4841
4978
  if ("fail" in item) {
4842
4979
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4853,7 +4990,7 @@ function many(combinator, opts = {}) {
4853
4990
  }
4854
4991
  if (values !== void 0) values.push(item.value);
4855
4992
  count++;
4856
- cur = item.end;
4993
+ cur = item.span.end;
4857
4994
  }
4858
4995
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4859
4996
  }
@@ -4871,30 +5008,47 @@ function atLeast(combinator, min, max) {
4871
5008
  const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
4872
5009
  let expected;
4873
5010
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
5011
+ const scalarChild = scalarOf(combinator);
5012
+ const parseScalar = (input, pos, ctx) => {
5013
+ let cur = scalarChild(input, pos, ctx);
5014
+ if (cur < 0) return cur;
5015
+ const values = def.valueUnused ? void 0 : [ctx._sv];
5016
+ for (let count = 1; count < min; count++) {
5017
+ let itemPos = cur;
5018
+ if (ctx.trivia) itemPos = advanceTrivia(input, cur, ctx);
5019
+ const end = scalarChild(input, itemPos, ctx);
5020
+ if (end < 0) return ~cur;
5021
+ cur = end;
5022
+ if (values !== void 0) values.push(ctx._sv);
5023
+ }
5024
+ return repeatScalarTail(combinator, scalarChild, input, cur, ctx, guardable, values, max - min);
5025
+ };
4874
5026
  return {
4875
5027
  _tag: "oneOrMore",
4876
5028
  _meta: meta,
4877
5029
  _def: def,
5030
+ _parseScalar: parseScalar,
4878
5031
  parse(input, pos, ctx) {
4879
5032
  const first = combinator.parse(input, pos, ctx);
4880
5033
  if (!first.ok) return first;
4881
5034
  const values = def.valueUnused ? void 0 : [first.value];
5035
+ const rollbackNeeded = needsTriviaRollback(ctx);
4882
5036
  let cur = first.span.end;
4883
5037
  let count = 1;
4884
5038
  while (count < min) {
4885
- const item = repItem(combinator, input, cur, ctx, guardable, true);
5039
+ const item = repItem(combinator, input, cur, ctx, guardable, true, rollbackNeeded);
4886
5040
  if (item === "stop" || "fail" in item) {
4887
5041
  if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
4888
5042
  expected ??= deriveExpected(combinator);
4889
5043
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
4890
5044
  }
4891
5045
  if (values !== void 0) values.push(item.value);
4892
- cur = item.end;
5046
+ cur = item.span.end;
4893
5047
  count++;
4894
5048
  }
4895
5049
  while (cur < input.length) {
4896
5050
  if (count >= max) break;
4897
- const item = repItem(combinator, input, cur, ctx, guardable, false);
5051
+ const item = repItem(combinator, input, cur, ctx, guardable, false, rollbackNeeded);
4898
5052
  if (item === "stop") break;
4899
5053
  if ("fail" in item) {
4900
5054
  if (!item.fail.ok && item.fail.committed) return item.fail;
@@ -4911,7 +5065,7 @@ function atLeast(combinator, min, max) {
4911
5065
  }
4912
5066
  if (values !== void 0) values.push(item.value);
4913
5067
  count++;
4914
- cur = item.end;
5068
+ cur = item.span.end;
4915
5069
  }
4916
5070
  return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
4917
5071
  }
@@ -4924,10 +5078,22 @@ function optional(combinator) {
4924
5078
  isTrivia: false
4925
5079
  };
4926
5080
  const firstSetSkippable = !matchesEmpty(combinator);
5081
+ const scalarChild = scalarOf(combinator);
5082
+ const parseScalar = (input, pos, ctx) => {
5083
+ if (firstSetSkippable && !startsFirstSet(combinator, input, pos)) {
5084
+ ctx._sv = null;
5085
+ return pos;
5086
+ }
5087
+ const end = scalarChild(input, pos, ctx);
5088
+ if (end >= 0) return end;
5089
+ ctx._sv = null;
5090
+ return pos;
5091
+ };
4927
5092
  return {
4928
5093
  _tag: "optional",
4929
5094
  _meta: meta,
4930
5095
  _def: { tag: "optional", parser: combinator },
5096
+ _parseScalar: parseScalar,
4931
5097
  parse(input, pos, ctx) {
4932
5098
  if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
4933
5099
  return { ok: true, value: null, span: { start: pos, end: pos } };
@@ -4958,6 +5124,43 @@ function sepBy(combinator, separatorArg, opts = {}) {
4958
5124
  expected ??= deriveExpected(combinator);
4959
5125
  return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
4960
5126
  };
5127
+ const scalarExpected = deriveExpected(combinator);
5128
+ const scalarChild = scalarOf(combinator);
5129
+ const scalarSeparator = scalarOf(separator);
5130
+ const parseScalar = (input, pos, ctx) => {
5131
+ let cur = scalarChild(input, pos, ctx);
5132
+ if (cur < 0) {
5133
+ if (min >= 1) {
5134
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
5135
+ return ~pos;
5136
+ }
5137
+ ctx._sv = [];
5138
+ return pos;
5139
+ }
5140
+ const values = [ctx._sv];
5141
+ while (values.length < max && (cur < input.length || values.length < min)) {
5142
+ const beforeSeparator = cur;
5143
+ let separatorPos = cur;
5144
+ if (ctx.trivia) separatorPos = advanceTrivia(input, cur, ctx);
5145
+ const separatorEnd = scalarSeparator(input, separatorPos, ctx);
5146
+ if (separatorEnd < 0) break;
5147
+ let itemPos = separatorEnd;
5148
+ if (ctx.trivia) itemPos = advanceTrivia(input, itemPos, ctx);
5149
+ const itemEnd = scalarChild(input, itemPos, ctx);
5150
+ if (itemEnd < 0) {
5151
+ cur = trailing === "allow" ? separatorEnd : beforeSeparator;
5152
+ break;
5153
+ }
5154
+ values.push(ctx._sv);
5155
+ cur = itemEnd;
5156
+ }
5157
+ if (values.length < min) {
5158
+ ctx._fx = scalarExpected.length > 0 ? scalarExpected : [combinator._tag];
5159
+ return ~cur;
5160
+ }
5161
+ ctx._sv = values;
5162
+ return cur;
5163
+ };
4961
5164
  return {
4962
5165
  _tag: "sepBy",
4963
5166
  _meta: meta,
@@ -4973,6 +5176,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
4973
5176
  // this option surface already; parity is held by test/parity, not by hope.
4974
5177
  ...keepSeparators ? { keepSeparators: true } : {}
4975
5178
  },
5179
+ _parseScalar: keepSeparators ? void 0 : parseScalar,
4976
5180
  parse(input, pos, ctx) {
4977
5181
  const first = combinator.parse(input, pos, ctx);
4978
5182
  const values = [];
@@ -5050,11 +5254,54 @@ function sepBy(combinator, separatorArg, opts = {}) {
5050
5254
  }
5051
5255
 
5052
5256
  // src/combinators/map.ts
5257
+ var JSON_STRING_BODY = String.raw`(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*`;
5053
5258
  function transform(combinator, fn) {
5259
+ const observesSpan = fn.length > 1;
5260
+ const sequenceDef = combinator._def.tag === "sequence" ? combinator._def : void 0;
5261
+ const terms = sequenceDef?.parsers;
5262
+ const inner = terms?.[1];
5263
+ 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;
5264
+ const child = scalarOf(combinator);
5265
+ const parseScalar = fused ? (() => {
5266
+ const body = inner._stickyRegex;
5267
+ const tuple = ['"', "", '"'];
5268
+ const expected = [JSON.stringify('"')];
5269
+ return (input, pos, ctx) => {
5270
+ if (ctx.trivia !== void 0) {
5271
+ const end2 = child(input, pos, ctx);
5272
+ if (end2 < 0) return end2;
5273
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end: end2 }) : fn(ctx._sv);
5274
+ return end2;
5275
+ }
5276
+ if (input.charCodeAt(pos) !== 34) {
5277
+ ctx._fx = expected;
5278
+ return ~pos;
5279
+ }
5280
+ body.lastIndex = pos + 1;
5281
+ const match = body.exec(input);
5282
+ const close = pos + 1 + match[0].length;
5283
+ if (input.charCodeAt(close) !== 34) {
5284
+ ctx._fx = expected;
5285
+ return ~close;
5286
+ }
5287
+ tuple[1] = match[0];
5288
+ const end = close + 1;
5289
+ ctx._sv = observesSpan ? fn(tuple, { start: pos, end }) : fn(tuple);
5290
+ return end;
5291
+ };
5292
+ })() : /* @__PURE__ */ (() => {
5293
+ return (input, pos, ctx) => {
5294
+ const end = child(input, pos, ctx);
5295
+ if (end < 0) return end;
5296
+ ctx._sv = observesSpan ? fn(ctx._sv, { start: pos, end }) : fn(ctx._sv);
5297
+ return end;
5298
+ };
5299
+ })();
5054
5300
  return {
5055
5301
  _tag: "transform",
5056
5302
  _meta: combinator._meta,
5057
5303
  _def: { tag: "transform", parser: combinator, fn },
5304
+ _parseScalar: parseScalar,
5058
5305
  parse(input, pos, ctx) {
5059
5306
  const result = combinator.parse(input, pos, ctx);
5060
5307
  if (!result.ok) return result;
@@ -5069,9 +5316,11 @@ function trivia(combinator) {
5069
5316
  _meta: {
5070
5317
  ...combinator._meta,
5071
5318
  isTrivia: true,
5319
+ triviaScanner: fastTriviaScanner(combinator),
5072
5320
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
5073
5321
  },
5074
5322
  _def: { tag: "trivia", parser: combinator },
5323
+ _parseScalar: scalarOf(combinator),
5075
5324
  parse: combinator.parse.bind(combinator)
5076
5325
  };
5077
5326
  }
@@ -5192,10 +5441,32 @@ function regex(pattern, flags = "") {
5192
5441
  const canMatchNewline = raw.canMatchNewline;
5193
5442
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
5194
5443
  const def = { tag: "regex", source, flags: resolvedFlags };
5444
+ const expected = directTerminalFailureExpected(def);
5445
+ const parseScalar = (input, pos, ctx) => {
5446
+ const scanEnd = scan?.(input, pos);
5447
+ if (scanEnd !== void 0) {
5448
+ if (scanEnd === null) {
5449
+ ctx._fx = expected;
5450
+ return ~pos;
5451
+ }
5452
+ ctx._sv = input.slice(pos, scanEnd);
5453
+ return scanEnd;
5454
+ }
5455
+ anchored.lastIndex = pos;
5456
+ const match = anchored.exec(input);
5457
+ if (match === null) {
5458
+ ctx._fx = expected;
5459
+ return ~pos;
5460
+ }
5461
+ ctx._sv = match[0];
5462
+ return pos + match[0].length;
5463
+ };
5195
5464
  return {
5196
5465
  _tag: "regex",
5197
5466
  _meta: meta,
5198
5467
  _def: def,
5468
+ _stickyRegex: anchored,
5469
+ _parseScalar: parseScalar,
5199
5470
  parse(input, pos, ctx) {
5200
5471
  const scanEnd = scan?.(input, pos);
5201
5472
  if (scanEnd !== void 0) {
@@ -6785,7 +7056,7 @@ var Encoder = class {
6785
7056
  d.tags === void 0 ? -1 : this.constant(d.tags)
6786
7057
  );
6787
7058
  if (matchesEmpty(d.parser)) return body;
6788
- const fs = d.parser._meta.firstSet;
7059
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
6789
7060
  if (fs.kind === "any") return body;
6790
7061
  const cls = this.charClass(fs);
6791
7062
  if (cls < 0) return body;
@@ -6805,7 +7076,7 @@ var Encoder = class {
6805
7076
  const dispCovIds = this.plan?.dispatches.get(p);
6806
7077
  let dispCov = 0;
6807
7078
  const arms = [];
6808
- const routed2 = [];
7079
+ const routed = [];
6809
7080
  const key = [], keyArm = [];
6810
7081
  const fold = [], foldArm = [];
6811
7082
  const match = [];
@@ -6813,7 +7084,7 @@ var Encoder = class {
6813
7084
  for (const c of d.cases) {
6814
7085
  const arm = arms.length;
6815
7086
  arms.push(this.covWrap(this.node(c.parser).ip, dispCovIds?.[dispCov++], 1));
6816
- routed2.push(branchUsesRouted(c) ? 1 : 0);
7087
+ routed.push(branchUsesRouted(c) ? 1 : 0);
6817
7088
  for (const kk of c.keys) {
6818
7089
  expected.push(JSON.stringify(kk));
6819
7090
  if (c.caseInsensitive) {
@@ -6829,7 +7100,7 @@ var Encoder = class {
6829
7100
  for (const m of d.matchers ?? []) {
6830
7101
  const arm = arms.length;
6831
7102
  arms.push(this.covWrap(this.node(m.parser).ip, dispCovIds?.[dispCov++], 1));
6832
- routed2.push(branchUsesRouted(m) ? 1 : 0);
7103
+ routed.push(branchUsesRouted(m) ? 1 : 0);
6833
7104
  if (!m.caseInsensitive) {
6834
7105
  match.push([KIND[m.kind], m.value, m.flags ?? "", arm]);
6835
7106
  continue;
@@ -6843,7 +7114,7 @@ var Encoder = class {
6843
7114
  }
6844
7115
  const other = d.otherwise === void 0 ? -1 : this.covWrap(this.node(d.otherwise).ip, dispCovIds?.[dispCov++], 1);
6845
7116
  const dspIdx = this.dsp.length;
6846
- this.dsp.push({ key, keyArm, fold, foldArm, match, routed: routed2, expected });
7117
+ this.dsp.push({ key, keyArm, fold, foldArm, match, routed, expected });
6847
7118
  const head = this.emitHead(OP_DISPATCH, 5 + arms.length);
6848
7119
  this.code[head + 1] = sel;
6849
7120
  this.code[head + 2] = dspIdx;
@@ -6899,7 +7170,7 @@ var Encoder = class {
6899
7170
  case "attempt": {
6900
7171
  const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
6901
7172
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
6902
- const fs = d.parser._meta.firstSet;
7173
+ const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver()) : d.parser._meta.firstSet;
6903
7174
  if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
6904
7175
  const cls = this.charClass(fs);
6905
7176
  if (cls < 0) return inner;
@@ -8715,6 +8986,9 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
8715
8986
  function q(s) {
8716
8987
  return JSON.stringify(s);
8717
8988
  }
8989
+ function isAsciiOnlyClass(cls) {
8990
+ return cls !== null && cls !== void 0 && cls.hi.length === 0;
8991
+ }
8718
8992
  var NO_SINKS = { fd: false, er: false };
8719
8993
  function sinkSlots(t2, s) {
8720
8994
  return `${s.fd ? `,${t2}fd=0` : ""}${s.er ? `,${t2}er=0` : ""}`;
@@ -9261,12 +9535,13 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9261
9535
  return `${head}EC.e=pos;return ''}`;
9262
9536
  case OP_GATE: {
9263
9537
  const child = link(code[ip + 2]);
9264
- const ci = classes.push([t2.cc[code[ip + 1]]]) - 1;
9538
+ const resolved = t2.cc[code[ip + 1]];
9539
+ const ci = classes.push([resolved]) - 1;
9265
9540
  classPlan.push([code[ip + 1]]);
9266
9541
  const cls = hoist("cl", `CLS[${ci}][0]`);
9267
9542
  const xf = fxRef(code[ip + 3]);
9268
9543
  return `${head}
9269
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9544
+ if(${staticBuild && isAsciiOnlyClass(resolved) ? `${cls}.ascii[input.charCodeAt(pos)]!==1` : `!classHas(${cls},lead(input,pos))`}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9270
9545
  return ${child}(input,pos,ctx)
9271
9546
  }`;
9272
9547
  }
@@ -9609,10 +9884,11 @@ return v
9609
9884
  const asc = hoist("as", `DISP[${di}].ascii`);
9610
9885
  const hiArr = table.hi;
9611
9886
  const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
9887
+ const directAscii = staticBuild && table.hi.length === 0;
9612
9888
  return `${head}
9613
- const c=lead(input,pos)
9889
+ const c=${directAscii ? "input.charCodeAt(pos)" : "lead(input,pos)"}
9614
9890
  let arm=-1
9615
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
9891
+ if(${directAscii ? "c<128" : "c>=0&&c<128"}){const a=${asc}[c];if(a!==0)arm=a-1}
9616
9892
  ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
9617
9893
  for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
9618
9894
  if(arm>=0){
@@ -9634,7 +9910,9 @@ return FAIL
9634
9910
  const di = code[ip + 1];
9635
9911
  const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]));
9636
9912
  const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null);
9637
- const gateRefs = Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
9913
+ const maskable = n <= 32;
9914
+ const directAsciiMask = staticBuild && maskable && gates.every(isAsciiOnlyClass);
9915
+ const gateRefs = directAsciiMask ? [] : Array.from({ length: n }, (_, i) => hoist("g", `DISP[${di}].armCls[${i}]`));
9638
9916
  const tokenCandidate = tokenChoiceCandidates.get(ip);
9639
9917
  const pretests = Array.from({ length: n }, (_, i) => {
9640
9918
  if (tokenCandidate?.arm === i) {
@@ -9654,7 +9932,6 @@ return FAIL
9654
9932
  const sequence6 = largeChoiceScalarSequences.get(code[base + i]);
9655
9933
  return sequence6 === void 0 ? void 0 : { sequence: scalarSequenceRef(sequence6) };
9656
9934
  });
9657
- const maskable = n <= 32;
9658
9935
  const maskName = maskable ? hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`) : "";
9659
9936
  if (maskable) maskPlan.push(~di);
9660
9937
  const p = tmp();
@@ -9716,16 +9993,16 @@ ${merge}
9716
9993
  ctx._fe=pos;ctx._fx=acc??${choiceFx}
9717
9994
  return FAIL`;
9718
9995
  return `${head}
9719
- const c=lead(input,pos)
9996
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
9720
9997
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
9721
9998
  ${deepAt.map((at, i) => `let ${at},${deepFx[i]}`).join("\n")}
9722
9999
  ${maskable ? `if(c<128){
9723
- const bits=${maskName}[c<0?128:c]
10000
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
9724
10001
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
9725
10002
  ${lazyArms(true)}
9726
- }else{
10003
+ }${directAsciiMask ? "" : `else{
9727
10004
  ${lazyArms(false)}
9728
- }
10005
+ }`}
9729
10006
  ` : lazyArms(false)}
9730
10007
  ${finish}
9731
10008
  }`;
@@ -9776,7 +10053,7 @@ if(ctx._fc===true){${startFailureExact ? `if(best===pos){acc=${catchName}(${i},0
9776
10053
  ${rollbackFor(i)}
9777
10054
  }${routeMiss}${sequenceMiss}`;
9778
10055
  }).join("\n") : "";
9779
- const generalArms = arms.map((arm, i) => {
10056
+ const generalArms = directAsciiMask ? "" : arms.map((arm, i) => {
9780
10057
  const pretest = pretests[i];
9781
10058
  const decision = pretest?.token === void 0 && pretest?.sequence === void 0 ? "" : tmp();
9782
10059
  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("||")})`;
@@ -9806,12 +10083,12 @@ ${rollbackFor(i)}
9806
10083
  }${miss}`;
9807
10084
  }).join("\n");
9808
10085
  return `${head}
9809
- const c=lead(input,pos)
10086
+ const c=${directAsciiMask ? "input.charCodeAt(pos)" : "lead(input,pos)"}
9810
10087
  ${hasRollback ? emitMark(p, L.buf, L.raw, sinks) : ""}
9811
10088
  let acc
9812
10089
  let best=pos
9813
10090
  ${maskable ? `if(c<128){
9814
- const bits=${maskName}[c<0?128:c]
10091
+ const bits=${maskName}[${directAsciiMask ? "c" : "c<0?128:c"}]
9815
10092
  if(bits===0){ctx._fe=pos;ctx._fx=${choiceFx};return FAIL}
9816
10093
  ${startFailureExact ? "" : "let prev=0"}
9817
10094
  ${maskArms}
@@ -9906,14 +10183,18 @@ return [key,v]
9906
10183
  const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
9907
10184
  const collect = op === OP_REP;
9908
10185
  let itemCls;
10186
+ let itemAscii = false;
9909
10187
  if (!REC) {
9910
10188
  const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
9911
10189
  if (itemClassIndex >= 0) {
9912
- const ci = classes.push([t2.cc[itemClassIndex]]) - 1;
10190
+ const resolved = t2.cc[itemClassIndex];
10191
+ const ci = classes.push([resolved]) - 1;
9913
10192
  classPlan.push([itemClassIndex]);
9914
10193
  itemCls = hoist("ri", `CLS[${ci}][0]`);
10194
+ itemAscii = staticBuild && isAsciiOnlyClass(resolved);
9915
10195
  }
9916
10196
  }
10197
+ const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
9917
10198
  const skipBeforeFirst = sepIp < 0 && min === 0;
9918
10199
  const p = tmp();
9919
10200
  const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
@@ -9973,7 +10254,7 @@ let count=0
9973
10254
  for(;;){
9974
10255
  ${max >= 0 ? `if(count>=${max})break
9975
10256
  ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
9976
- ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&!classHas(${itemCls},lead(input,cur)))break
10257
+ ` : ""}${itemCls !== void 0 && sep === void 0 ? `if(count>=${min}&&${p}gate&&${hasTrivia === "false" ? "true" : hasTrivia === "true" ? "false" : "!hasTrivia"}&&${itemMiss("cur")})break
9977
10258
  ` : ""}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` : ""}
9978
10259
  ${markBody}
9979
10260
  let itemStart=cur
@@ -9998,7 +10279,7 @@ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(inp
9998
10279
  ${rb}
9999
10280
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
10000
10281
  }
10001
- ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
10282
+ ${itemCls === void 0 ? "" : `if(count>=${min}&&${p}gate&&${itemMiss("itemStart")}){
10002
10283
  ${rb}
10003
10284
  ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
10004
10285
  }
@@ -10282,6 +10563,28 @@ function literal(value, opts = {}) {
10282
10563
  isTrivia: false
10283
10564
  };
10284
10565
  const canMatchNewline = meta.canMatchNewline;
10566
+ const parseScalar = !caseInsensitive && value.length === 1 ? (() => {
10567
+ const code = value.charCodeAt(0);
10568
+ return (input, pos, ctx) => {
10569
+ if (input.charCodeAt(pos) === code) {
10570
+ ctx._sv = value;
10571
+ return pos + 1;
10572
+ }
10573
+ ctx._fx = expected;
10574
+ return ~pos;
10575
+ };
10576
+ })() : (input, pos, ctx) => {
10577
+ const end = pos + value.length;
10578
+ if (end <= input.length) {
10579
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
10580
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
10581
+ ctx._sv = matchedValue;
10582
+ return end;
10583
+ }
10584
+ }
10585
+ ctx._fx = expected;
10586
+ return ~pos;
10587
+ };
10285
10588
  if (caseInsensitive) {
10286
10589
  const upper = value.toUpperCase();
10287
10590
  const lower = value.toLowerCase();
@@ -10322,6 +10625,7 @@ function literal(value, opts = {}) {
10322
10625
  _tag: "literal",
10323
10626
  _meta: meta,
10324
10627
  _def: { tag: "literal", value, caseInsensitive },
10628
+ _parseScalar: parseScalar,
10325
10629
  parse: parse2
10326
10630
  };
10327
10631
  }
@@ -10341,6 +10645,7 @@ function sequence(...parsers) {
10341
10645
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
10342
10646
  }
10343
10647
  const hasAdjacency = adjacency !== null;
10648
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
10344
10649
  const meta = {
10345
10650
  // Union through the nullable prefix — a leading optional()/many() lets a later
10346
10651
  // term's first char start the sequence. Just `parsers[0]` under-approximates.
@@ -10349,165 +10654,96 @@ function sequence(...parsers) {
10349
10654
  isTrivia: false
10350
10655
  };
10351
10656
  const def = { tag: "sequence", parsers };
10352
- let followSentinels;
10353
- function parseTolerant(input, pos, ctx) {
10354
- followSentinels ??= parsers.map((_, i) => {
10355
- const fs = parsers.slice(i + 1).reduce(
10356
- (acc, p) => union(acc, firstSetOf(p)),
10357
- { kind: "empty" }
10358
- );
10359
- return firstSetSentinel(fs);
10360
- });
10361
- const values = def.valueUnused ? void 0 : [];
10657
+ const scalarParsers = parsers.map(scalarOf);
10658
+ const parseScalar = (input, pos, ctx) => {
10362
10659
  let cur = pos;
10363
- const inheritedSync = ctx._sync;
10364
- try {
10365
- for (let i = 0; i < parsers.length; i++) {
10366
- ctx._sync = followSentinels[i] ?? inheritedSync;
10367
- const adj = adjacency === null ? null : adjacency[i];
10368
- if (adj) {
10369
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
10370
- if (values !== void 0) values.push(null);
10371
- continue;
10372
- }
10373
- if (ctx.trivia && i > 0) {
10374
- const mTlog = cstTlLen(ctx);
10375
- const mLog = ctx._triviaLog?.length ?? 0;
10376
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
10377
- let scanEnd;
10378
- if (needsDeferredTriviaCommit(ctx)) {
10379
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
10380
- } else {
10381
- scanEnd = advanceTrivia(input, cur, ctx);
10382
- }
10383
- const scanTlog = cstTlLen(ctx);
10384
- const scanLog = ctx._triviaLog?.length ?? 0;
10385
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
10386
- const result2 = parsers[i].parse(input, scanEnd, ctx);
10387
- if (!result2.ok) return result2;
10388
- if (result2.span.end > scanEnd) cur = result2.span.end;
10389
- else rollbackScannedTriviaAt(
10390
- ctx,
10391
- mTlog,
10392
- scanTlog,
10393
- mLog,
10394
- scanLog,
10395
- mRootLog,
10396
- scanRootLog
10397
- );
10398
- if (values !== void 0) values.push(result2.value);
10399
- continue;
10400
- }
10401
- const result = parsers[i].parse(input, cur, ctx);
10402
- if (!result.ok) return result;
10403
- if (values !== void 0) values.push(result.value);
10404
- cur = result.span.end;
10660
+ if (strictArity !== 0) {
10661
+ cur = scalarParsers[0](input, cur, ctx);
10662
+ if (cur < 0) return cur;
10663
+ const first = ctx._sv;
10664
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
10665
+ cur = scalarParsers[1](input, cur, ctx);
10666
+ if (cur < 0) return cur;
10667
+ const second = ctx._sv;
10668
+ if (strictArity === 2) {
10669
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
10670
+ return cur;
10405
10671
  }
10406
- } finally {
10407
- ctx._sync = inheritedSync;
10672
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
10673
+ cur = scalarParsers[2](input, cur, ctx);
10674
+ if (cur < 0) return cur;
10675
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
10676
+ return cur;
10408
10677
  }
10409
- return {
10410
- ok: true,
10411
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
10412
- value: values ?? void 0,
10413
- span: { start: pos, end: cur }
10414
- };
10415
- }
10416
- function parseAdjacent(input, pos, ctx) {
10417
10678
  const values = def.valueUnused ? void 0 : [];
10418
- let cur = pos;
10419
- for (let i = 0; i < parsers.length; i++) {
10420
- const adj = adjacency[i];
10421
- if (adj) {
10422
- if (!holdsAdjacency(input, cur, ctx, adj)) return adjacencyFail(cur, adj);
10423
- if (values !== void 0) values.push(null);
10424
- continue;
10425
- }
10426
- if (ctx.trivia && i > 0) {
10427
- let scanEnd;
10428
- const mTlog = cstTlLen(ctx);
10429
- const mLog = ctx._triviaLog?.length ?? 0;
10430
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
10431
- if (needsDeferredTriviaCommit(ctx)) {
10432
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
10433
- } else {
10434
- scanEnd = advanceTrivia(input, cur, ctx);
10435
- }
10436
- const scanTlog = cstTlLen(ctx);
10437
- const scanLog = ctx._triviaLog?.length ?? 0;
10438
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
10439
- const result2 = parsers[i].parse(input, scanEnd, ctx);
10440
- if (!result2.ok) return result2;
10441
- if (result2.span.end > scanEnd) cur = result2.span.end;
10442
- else rollbackScannedTriviaAt(
10443
- ctx,
10444
- mTlog,
10445
- scanTlog,
10446
- mLog,
10447
- scanLog,
10448
- mRootLog,
10449
- scanRootLog
10450
- );
10451
- if (values !== void 0) values.push(result2.value);
10452
- continue;
10453
- }
10454
- const result = parsers[i].parse(input, cur, ctx);
10455
- if (!result.ok) return result;
10456
- if (values !== void 0) values.push(result.value);
10457
- cur = result.span.end;
10458
- }
10459
- return {
10460
- ok: true,
10461
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
10462
- value: values ?? void 0,
10463
- span: { start: pos, end: cur }
10464
- };
10465
- }
10679
+ for (let i = 0; i < scalarParsers.length; i++) {
10680
+ let termPos = cur;
10681
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
10682
+ const end = scalarParsers[i](input, termPos, ctx);
10683
+ if (end < 0) return end;
10684
+ if (values !== void 0) values.push(ctx._sv);
10685
+ if (end > termPos || termPos === cur) cur = end;
10686
+ }
10687
+ ctx._sv = values;
10688
+ return cur;
10689
+ };
10690
+ let followSentinels;
10466
10691
  return {
10467
10692
  _tag: "sequence",
10468
10693
  _meta: meta,
10469
10694
  _def: def,
10695
+ _parseScalar: hasAdjacency ? void 0 : parseScalar,
10470
10696
  parse(input, pos, ctx) {
10471
- if (ctx._tolerant) return parseTolerant(input, pos, ctx);
10472
- if (hasAdjacency) return parseAdjacent(input, pos, ctx);
10697
+ const tolerant = ctx._tolerant === true;
10698
+ if (tolerant) {
10699
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
10700
+ parsers.slice(i + 1).reduce(
10701
+ (set, parser2) => union(set, firstSetOf(parser2)),
10702
+ { kind: "empty" }
10703
+ )
10704
+ ));
10705
+ }
10706
+ const inheritedSync = ctx._sync;
10707
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
10473
10708
  const values = def.valueUnused ? void 0 : [];
10474
10709
  let cur = pos;
10475
- for (let i = 0; i < parsers.length; i++) {
10476
- if (ctx.trivia && i > 0) {
10477
- let scanEnd;
10478
- const mTlog = cstTlLen(ctx);
10479
- const mLog = ctx._triviaLog?.length ?? 0;
10480
- const mRootLog = ctx._rootTriviaLog?.length ?? 0;
10481
- if (needsDeferredTriviaCommit(ctx)) {
10482
- scanEnd = commitTriviaScan(scanTriviaCompact(input, cur, ctx));
10483
- } else {
10484
- scanEnd = advanceTrivia(input, cur, ctx);
10710
+ try {
10711
+ for (let i = 0; i < parsers.length; i++) {
10712
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
10713
+ const assertion = adjacency?.[i];
10714
+ if (assertion) {
10715
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
10716
+ if (values !== void 0) values.push(null);
10717
+ continue;
10485
10718
  }
10486
- const scanTlog = cstTlLen(ctx);
10487
- const scanLog = ctx._triviaLog?.length ?? 0;
10488
- const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
10489
- const result2 = parsers[i].parse(input, scanEnd, ctx);
10490
- if (!result2.ok) return result2;
10491
- if (result2.span.end > scanEnd) {
10492
- cur = result2.span.end;
10493
- } else {
10719
+ let termPos = cur;
10720
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
10721
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
10722
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
10723
+ if (ctx.trivia && i > 0) {
10724
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
10725
+ }
10726
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
10727
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
10728
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
10729
+ const result = parsers[i].parse(input, termPos, ctx);
10730
+ if (!result.ok) return result;
10731
+ if (values !== void 0) values.push(result.value);
10732
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
10733
+ else if (deferredTrivia) {
10494
10734
  rollbackScannedTriviaAt(
10495
10735
  ctx,
10496
- mTlog,
10736
+ markTlog,
10497
10737
  scanTlog,
10498
- mLog,
10738
+ markLog,
10499
10739
  scanLog,
10500
- mRootLog,
10740
+ markRootLog,
10501
10741
  scanRootLog
10502
10742
  );
10503
10743
  }
10504
- if (values !== void 0) values.push(result2.value);
10505
- continue;
10506
10744
  }
10507
- const result = parsers[i].parse(input, cur, ctx);
10508
- if (!result.ok) return result;
10509
- if (values !== void 0) values.push(result.value);
10510
- cur = result.span.end;
10745
+ } finally {
10746
+ if (tolerant) ctx._sync = inheritedSync;
10511
10747
  }
10512
10748
  return {
10513
10749
  ok: true,
@@ -10520,8 +10756,20 @@ function sequence(...parsers) {
10520
10756
  }
10521
10757
 
10522
10758
  // src/combinators/ref.ts
10759
+ function withRuleTrivia(trivia2, ctx, run) {
10760
+ const savedLabels = ctx.triviaKindLabels;
10761
+ ctx.trivia = trivia2;
10762
+ ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
10763
+ try {
10764
+ return run();
10765
+ } finally {
10766
+ ctx.trivia = void 0;
10767
+ ctx.triviaKindLabels = savedLabels;
10768
+ }
10769
+ }
10523
10770
  function ref() {
10524
10771
  let resolved = null;
10772
+ let resolvedScalar = null;
10525
10773
  let ownBoundary = false;
10526
10774
  const meta = {
10527
10775
  firstSet: any(),
@@ -10538,25 +10786,28 @@ function ref() {
10538
10786
  return resolved;
10539
10787
  }
10540
10788
  },
10789
+ _parseScalar(input, pos, ctx) {
10790
+ const scalar = resolvedScalar;
10791
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
10792
+ const gt = meta.grammarTrivia;
10793
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
10794
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
10795
+ }
10796
+ return scalar(input, pos, ctx);
10797
+ },
10541
10798
  parse(input, pos, ctx) {
10542
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
10799
+ const parser2 = resolved;
10800
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
10543
10801
  const gt = meta.grammarTrivia;
10544
10802
  if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
10545
- const savedLabels = ctx.triviaKindLabels;
10546
- ctx.trivia = gt;
10547
- ctx.triviaKindLabels = gt._meta.triviaKindLabels;
10548
- try {
10549
- return resolved.parse(input, pos, ctx);
10550
- } finally {
10551
- ctx.trivia = void 0;
10552
- ctx.triviaKindLabels = savedLabels;
10553
- }
10803
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
10554
10804
  }
10555
- return resolved.parse(input, pos, ctx);
10805
+ return parser2.parse(input, pos, ctx);
10556
10806
  },
10557
10807
  define(p) {
10558
10808
  if (resolved) throw new Error("ref<T>() already defined");
10559
10809
  resolved = p;
10810
+ resolvedScalar = scalarOf(p);
10560
10811
  ownBoundary = hasOwnTriviaBoundary(p);
10561
10812
  meta.firstSet = p._meta.firstSet;
10562
10813
  meta.canMatchNewline = p._meta.canMatchNewline;
@@ -13461,10 +13712,10 @@ function assemble(t2, prog, cfg) {
13461
13712
  const hasFold = spec.byFold.size > 0;
13462
13713
  const match = spec.match;
13463
13714
  const matchN = match.length;
13464
- const routed2 = spec.routed;
13715
+ const routed = spec.routed;
13465
13716
  const expected = spec.expected;
13466
13717
  const validArm = (arm) => Number.isInteger(arm) && arm >= 0 && arm < n;
13467
- if (routed2.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
13718
+ if (routed.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
13468
13719
  for (const arm of byKey.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch exact arm");
13469
13720
  for (const arm of byFold.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch folded arm");
13470
13721
  for (const m of match) if (!validArm(m[3])) throw new TypeError("table assembler: malformed dispatch matcher arm");
@@ -13489,7 +13740,7 @@ function assemble(t2, prog, cfg) {
13489
13740
  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);
13490
13741
  const neverBranch = () => FAIL;
13491
13742
  const bindArms = (start) => {
13492
- const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed2[i] === 1) : neverBranch;
13743
+ const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed[i] === 1) : neverBranch;
13493
13744
  const next = start + 4 < n ? bindArms(start + 4) : void 0;
13494
13745
  return dispatchArmBlock(
13495
13746
  start,
@@ -14308,7 +14559,7 @@ function buildGrammarPlan(entry, winners) {
14308
14559
  const dispatches = /* @__PURE__ */ new Map();
14309
14560
  const attempts = /* @__PURE__ */ new Map();
14310
14561
  const labels = /* @__PURE__ */ new Map();
14311
- const rules2 = /* @__PURE__ */ new Map();
14562
+ const rules = /* @__PURE__ */ new Map();
14312
14563
  const winnerNames = /* @__PURE__ */ new Map();
14313
14564
  if (winners) {
14314
14565
  for (const [name, winner] of Object.entries(winners)) {
@@ -14329,7 +14580,7 @@ function buildGrammarPlan(entry, winners) {
14329
14580
  if (rule2 && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
14330
14581
  const id = `rule:${rule2}`;
14331
14582
  definitions.set(id, { id, kind: "rule" });
14332
- rules2.set(parser2, id);
14583
+ rules.set(parser2, id);
14333
14584
  }
14334
14585
  if (parser2._def.tag === "choice") {
14335
14586
  const ids = parser2._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
@@ -14353,7 +14604,7 @@ function buildGrammarPlan(entry, winners) {
14353
14604
  for (const root of roots) {
14354
14605
  visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
14355
14606
  }
14356
- return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
14607
+ return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules };
14357
14608
  }
14358
14609
 
14359
14610
  // src/analysis/duplication.ts
@@ -17021,31 +17272,6 @@ function locatedLines(l, opts) {
17021
17272
  return out;
17022
17273
  }
17023
17274
 
17024
- // src/compiler/linker.ts
17025
- function normalizeCstCollapse(collapse) {
17026
- if (collapse === true) return () => true;
17027
- if (Array.isArray(collapse)) {
17028
- const types = new Set(collapse);
17029
- return (type) => types.has(type);
17030
- }
17031
- return typeof collapse === "function" ? collapse : void 0;
17032
- }
17033
- function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state, tags) {
17034
- 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] };
17035
- }
17036
- function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state, _tags) {
17037
- if (typeof typeOrOptions === "string") {
17038
- return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
17039
- }
17040
- const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
17041
- const materializeTags = typeOrOptions?.tags === true;
17042
- const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2, tags) => buildCstNode(type, children3 ?? [], fields, span2, rawChildren2, triviaLog2, state2, materializeTags ? tags : void 0);
17043
- host._parsemanCstOutput = true;
17044
- if (collapse) host._parsemanCstCollapse = collapse;
17045
- return host;
17046
- }
17047
- cstBuildHost._parsemanCstOutput = true;
17048
-
17049
17275
  // src/analysis/diagnose.ts
17050
17276
  function examinedNothing(d) {
17051
17277
  return d.summary.totalChoices === 0 && d.summary.unanalysable > 0;