parseman 0.57.0 → 0.58.1

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 (69) hide show
  1. package/dist/analysis/diagnostics.js +1800 -962
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +1929 -1091
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/dispatch.d.ts.map +1 -1
  6. package/dist/compiler/token-alphabet.d.ts +11 -1
  7. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  8. package/dist/compiler/token-capability.js +69 -16
  9. package/dist/compiler/token-capability.js.map +2 -2
  10. package/dist/cst/capture-buffer.d.ts +6 -0
  11. package/dist/cst/capture-buffer.d.ts.map +1 -1
  12. package/dist/index.js +1017 -177
  13. package/dist/index.js.map +3 -3
  14. package/dist/plugin/index.d.ts +25 -1
  15. package/dist/plugin/index.d.ts.map +1 -1
  16. package/dist/plugin/index.js +1210 -236
  17. package/dist/plugin/index.js.map +3 -3
  18. package/dist/run/index.d.ts +2 -0
  19. package/dist/run/index.d.ts.map +1 -1
  20. package/dist/run/index.js +9 -0
  21. package/dist/run/index.js.map +1 -1
  22. package/dist/table/assemble.d.ts.map +1 -1
  23. package/dist/table/compile-rule-map.d.ts.map +1 -1
  24. package/dist/table/emit-assembly.d.ts +1 -1
  25. package/dist/table/emit-assembly.d.ts.map +1 -1
  26. package/dist/table/emit.d.ts.map +1 -1
  27. package/dist/table/encode.d.ts.map +1 -1
  28. package/dist/table/exec.d.ts.map +1 -1
  29. package/dist/table/factor-choice.d.ts +42 -0
  30. package/dist/table/factor-choice.d.ts.map +1 -0
  31. package/dist/table/fail-clean.d.ts +3 -0
  32. package/dist/table/fail-clean.d.ts.map +1 -0
  33. package/dist/table/hold-gap.d.ts +8 -0
  34. package/dist/table/hold-gap.d.ts.map +1 -0
  35. package/dist/table/index.js +1370 -259
  36. package/dist/table/index.js.map +3 -3
  37. package/dist/table/lex-program.d.ts +7 -3
  38. package/dist/table/lex-program.d.ts.map +1 -1
  39. package/dist/table/ops.d.ts +8 -0
  40. package/dist/table/ops.d.ts.map +1 -1
  41. package/dist/table/run-support.d.ts +19 -0
  42. package/dist/table/run-support.d.ts.map +1 -1
  43. package/dist/table/scalar-terminal.d.ts +2 -0
  44. package/dist/table/scalar-terminal.d.ts.map +1 -1
  45. package/dist/table/site-labels.d.ts +66 -0
  46. package/dist/table/site-labels.d.ts.map +1 -1
  47. package/dist/version.d.ts +1 -1
  48. package/package.json +1 -1
  49. package/src/combinators/dispatch.ts +12 -3
  50. package/src/compiler/token-alphabet.ts +57 -17
  51. package/src/cst/capture-buffer.ts +25 -0
  52. package/src/plugin/index.ts +230 -35
  53. package/src/run/index.ts +5 -0
  54. package/src/table/assemble.ts +252 -62
  55. package/src/table/child-slots.ts +2 -2
  56. package/src/table/compile-rule-map.ts +14 -5
  57. package/src/table/emit-assembly.ts +112 -23
  58. package/src/table/emit.ts +3 -1
  59. package/src/table/encode.ts +83 -14
  60. package/src/table/exec.ts +27 -8
  61. package/src/table/factor-choice.ts +173 -0
  62. package/src/table/fail-clean.ts +130 -0
  63. package/src/table/hold-gap.ts +68 -0
  64. package/src/table/lex-program.ts +197 -43
  65. package/src/table/ops.ts +9 -1
  66. package/src/table/run-support.ts +35 -0
  67. package/src/table/scalar-terminal.ts +8 -0
  68. package/src/table/site-labels.ts +135 -4
  69. package/src/version.ts +1 -1
@@ -478,6 +478,31 @@ function pushCstChild(ctx, built, rawEntry2) {
478
478
  else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
479
479
  if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry2);
480
480
  }
481
+ function popCstChild(ctx) {
482
+ const b = ctx._cstBuf;
483
+ if (b) {
484
+ const ch2 = b.ch;
485
+ if (b.rawOnly !== true && ch2) {
486
+ ch2.pop();
487
+ if (ch2.length === 1) {
488
+ b.single = ch2[0];
489
+ b.ch = void 0;
490
+ }
491
+ }
492
+ if (b.noRaw === true) b.rawLen = (b.rawLen ?? 1) - 1;
493
+ else if (b.raw) {
494
+ b.raw.pop();
495
+ if (b.raw.length === 1) {
496
+ b.rawSingle = b.raw[0];
497
+ b.raw = void 0;
498
+ }
499
+ } else b.rawSingle = void 0;
500
+ return;
501
+ }
502
+ if (ctx._cstChildren) ctx._cstChildren.pop();
503
+ else if (ctx._cstLeaves) ctx._cstLeaves.pop();
504
+ if (ctx._cstRawChildren) ctx._cstRawChildren.pop();
505
+ }
481
506
  function cstRawLen(ctx) {
482
507
  const b = ctx._cstBuf;
483
508
  if (b) {
@@ -2346,6 +2371,9 @@ function parser(opts, root) {
2346
2371
  };
2347
2372
  return grammar;
2348
2373
  }
2374
+ function noTrivia(root) {
2375
+ return parser({ trivia: null }, root);
2376
+ }
2349
2377
  var _analyzed = /* @__PURE__ */ new WeakSet();
2350
2378
  function parse(combinator, input, opts = {}) {
2351
2379
  if (!_analyzed.has(combinator)) {
@@ -3840,17 +3868,59 @@ function buildLexBodyRecognizer(spec, constants) {
3840
3868
  };
3841
3869
  }
3842
3870
 
3871
+ // src/table/run-support.ts
3872
+ function lineCol(ctx, offset) {
3873
+ const starts = ctx._lineStarts ?? [0];
3874
+ let lo = 0, hi = starts.length - 1;
3875
+ while (lo < hi) {
3876
+ const mid = lo + hi + 1 >> 1;
3877
+ if (starts[mid] <= offset) lo = mid;
3878
+ else hi = mid - 1;
3879
+ }
3880
+ return [lo + 1, offset - starts[lo] + 1];
3881
+ }
3882
+ function spanLines(ctx, start, end) {
3883
+ const s = lineCol(ctx, start), e = lineCol(ctx, end);
3884
+ return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
3885
+ }
3886
+ function rawEntry(v, input, s, e) {
3887
+ if (typeof v === "object" && v !== null) {
3888
+ const tg = v._tag;
3889
+ if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
3890
+ }
3891
+ return {
3892
+ _tag: "leaf",
3893
+ value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
3894
+ span: { start: s, end: e }
3895
+ };
3896
+ }
3897
+ function lead(input, pos) {
3898
+ if (pos >= input.length) return -1;
3899
+ const c = input.charCodeAt(pos);
3900
+ if (c < 55296 || c > 56319) return c;
3901
+ return input.codePointAt(pos) ?? c;
3902
+ }
3903
+ var EMPTY_KIDS = Object.freeze([]);
3904
+ var EMPTY_TRIVIA = Object.freeze([]);
3905
+ function collapseEmpty(ctx, build, input, pos, end, readsRaw) {
3906
+ const collected = ctx._cstBuf !== void 0 || ctx._cstChildren !== void 0;
3907
+ if (collected) popCstChild(ctx);
3908
+ const raw = readsRaw ? [rawEntry(void 0, input, pos, end)] : EMPTY_KIDS;
3909
+ const nd = build(EMPTY_KIDS, void 0, { start: pos, end }, raw, EMPTY_TRIVIA, void 0);
3910
+ if (collected) pushCstChild(ctx, nd, ctx._cstBuf?.noRaw === true ? void 0 : rawEntry(nd, input, pos, end));
3911
+ return nd;
3912
+ }
3913
+
3843
3914
  // src/table/lex-program.ts
3844
3915
  var LEX_NODE_TERMINAL = 0;
3845
3916
  var LEX_NODE_SEQUENCE2 = 1;
3846
3917
  var LEX_NODE_SEQUENCE3 = 2;
3847
3918
  var LEX_NODE_SEQUENCE4 = 3;
3848
3919
  var LEX_NODE_SEQUENCE5 = 4;
3849
- var LEX_NODE_CHOICE2 = 5;
3850
- var LEX_NODE_CHOICE4 = 6;
3851
- var LEX_NODE_CHOICE8 = 7;
3920
+ var LEX_NODE_CHOICE = 5;
3852
3921
  var LEX_NODE_NOT = 8;
3853
3922
  var LEX_NODE_OPTIONAL = 9;
3923
+ var LEX_NODE_REPEAT = 10;
3854
3924
  function lexProgramDigest(words) {
3855
3925
  let hash = 2166136261;
3856
3926
  for (const word of words) {
@@ -3879,85 +3949,114 @@ function trackLexLines(ctx, input, end) {
3879
3949
  ctx._lineScannedTo = end;
3880
3950
  }
3881
3951
  function terminalNode(matcher, failure, tracksLines) {
3882
- const match = (input, pos) => {
3883
- const result = matcher(input, pos);
3884
- return result < 0 ? -1 : result / 2;
3885
- };
3886
3952
  return {
3887
- match,
3953
+ match: (input, pos) => {
3954
+ const result = matcher(input, pos);
3955
+ return result < 0 ? -1 : result / 2;
3956
+ },
3888
3957
  run: (input, pos, ctx) => {
3889
- const end = match(input, pos);
3890
- if (end < 0) {
3958
+ const result = matcher(input, pos);
3959
+ if (result < 0) {
3891
3960
  ctx._fe = pos;
3892
3961
  ctx._fx = failure;
3893
3962
  if (ctx._probe !== void 0) failAt(ctx, ctx._fx, pos);
3894
3963
  return -1;
3895
3964
  }
3965
+ const end = result / 2;
3896
3966
  if (tracksLines) trackLexLines(ctx, input, end);
3897
3967
  return end;
3898
3968
  }
3899
3969
  };
3900
3970
  }
3901
3971
  function sequence2(a, b) {
3972
+ const am = a.match, bm = b.match, ar = a.run, br = b.run;
3902
3973
  return {
3903
3974
  match: (input, pos) => {
3904
- const e0 = a.match(input, pos);
3905
- return e0 < 0 ? -1 : b.match(input, e0);
3975
+ const e0 = am(input, pos);
3976
+ return e0 < 0 ? -1 : bm(input, e0);
3906
3977
  },
3907
3978
  run: (input, pos, ctx) => {
3908
- const e0 = a.run(input, pos, ctx);
3979
+ const e0 = ar(input, pos, ctx);
3909
3980
  if (e0 < 0) return -1;
3910
3981
  ctx._fc = false;
3911
- return b.run(input, e0, ctx);
3982
+ return br(input, e0, ctx);
3912
3983
  }
3913
3984
  };
3914
3985
  }
3915
3986
  function sequence3(a, b, c) {
3987
+ const am = a.match, bm = b.match, cm = c.match, ar = a.run, br = b.run, cr = c.run;
3916
3988
  return {
3917
3989
  match: (input, pos) => {
3918
- const e0 = a.match(input, pos);
3990
+ const e0 = am(input, pos);
3919
3991
  if (e0 < 0) return -1;
3920
- const e1 = b.match(input, e0);
3921
- return e1 < 0 ? -1 : c.match(input, e1);
3992
+ const e1 = bm(input, e0);
3993
+ return e1 < 0 ? -1 : cm(input, e1);
3922
3994
  },
3923
3995
  run: (input, pos, ctx) => {
3924
- const e0 = a.run(input, pos, ctx);
3996
+ const e0 = ar(input, pos, ctx);
3925
3997
  if (e0 < 0) return -1;
3926
3998
  ctx._fc = false;
3927
- const e1 = b.run(input, e0, ctx);
3999
+ const e1 = br(input, e0, ctx);
3928
4000
  if (e1 < 0) return -1;
3929
4001
  ctx._fc = false;
3930
- return c.run(input, e1, ctx);
4002
+ return cr(input, e1, ctx);
3931
4003
  }
3932
4004
  };
3933
4005
  }
3934
4006
  function sequence4(a, b, c, d) {
3935
- const abc = sequence3(a, b, c);
4007
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match;
4008
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run;
3936
4009
  return {
3937
4010
  match: (input, pos) => {
3938
- const end = abc.match(input, pos);
3939
- return end < 0 ? -1 : d.match(input, end);
4011
+ const e0 = am(input, pos);
4012
+ if (e0 < 0) return -1;
4013
+ const e1 = bm(input, e0);
4014
+ if (e1 < 0) return -1;
4015
+ const e2 = cm(input, e1);
4016
+ return e2 < 0 ? -1 : dm(input, e2);
3940
4017
  },
3941
4018
  run: (input, pos, ctx) => {
3942
- const end = abc.run(input, pos, ctx);
3943
- if (end < 0) return -1;
4019
+ const e0 = ar(input, pos, ctx);
4020
+ if (e0 < 0) return -1;
4021
+ ctx._fc = false;
4022
+ const e1 = br(input, e0, ctx);
4023
+ if (e1 < 0) return -1;
4024
+ ctx._fc = false;
4025
+ const e2 = cr(input, e1, ctx);
4026
+ if (e2 < 0) return -1;
3944
4027
  ctx._fc = false;
3945
- return d.run(input, end, ctx);
4028
+ return dr(input, e2, ctx);
3946
4029
  }
3947
4030
  };
3948
4031
  }
3949
4032
  function sequence5(a, b, c, d, e) {
3950
- const abcd = sequence4(a, b, c, d);
4033
+ const am = a.match, bm = b.match, cm = c.match, dm = d.match, em = e.match;
4034
+ const ar = a.run, br = b.run, cr = c.run, dr = d.run, er = e.run;
3951
4035
  return {
3952
4036
  match: (input, pos) => {
3953
- const end = abcd.match(input, pos);
3954
- return end < 0 ? -1 : e.match(input, end);
4037
+ const e0 = am(input, pos);
4038
+ if (e0 < 0) return -1;
4039
+ const e1 = bm(input, e0);
4040
+ if (e1 < 0) return -1;
4041
+ const e2 = cm(input, e1);
4042
+ if (e2 < 0) return -1;
4043
+ const e3 = dm(input, e2);
4044
+ return e3 < 0 ? -1 : em(input, e3);
3955
4045
  },
3956
4046
  run: (input, pos, ctx) => {
3957
- const end = abcd.run(input, pos, ctx);
3958
- if (end < 0) return -1;
4047
+ const e0 = ar(input, pos, ctx);
4048
+ if (e0 < 0) return -1;
4049
+ ctx._fc = false;
4050
+ const e1 = br(input, e0, ctx);
4051
+ if (e1 < 0) return -1;
4052
+ ctx._fc = false;
4053
+ const e2 = cr(input, e1, ctx);
4054
+ if (e2 < 0) return -1;
3959
4055
  ctx._fc = false;
3960
- return e.run(input, end, ctx);
4056
+ const e3 = dr(input, e2, ctx);
4057
+ if (e3 < 0) return -1;
4058
+ ctx._fc = false;
4059
+ return er(input, e3, ctx);
3961
4060
  }
3962
4061
  };
3963
4062
  }
@@ -3970,9 +4069,9 @@ function appendExpected(acc, values) {
3970
4069
  function choiceNode(arms, classes, armExpected, choiceExpected) {
3971
4070
  let matchTail = () => -1;
3972
4071
  for (let i = arms.length - 1; i >= 0; i--) {
3973
- const arm = arms[i], next = matchTail;
4072
+ const armMatch = arms[i].match, next = matchTail;
3974
4073
  matchTail = (input, pos) => {
3975
- const end = arm.match(input, pos);
4074
+ const end = armMatch(input, pos);
3976
4075
  return end < 0 ? next(input, pos) : end;
3977
4076
  };
3978
4077
  }
@@ -3982,7 +4081,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
3982
4081
  return -1;
3983
4082
  };
3984
4083
  for (let i = arms.length - 1; i >= 0; i--) {
3985
- const arm = arms[i], cls = classes[i], staticExpected = armExpected[i], next = tail;
4084
+ const armRun = arms[i].run, cls = classes[i], staticExpected = armExpected[i], next = tail;
3986
4085
  tail = (input, pos, ctx, lead2, acc, best) => {
3987
4086
  if (cls !== void 0 && !classHas(cls, lead2)) {
3988
4087
  return next(
@@ -3995,7 +4094,7 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
3995
4094
  );
3996
4095
  }
3997
4096
  ctx._fc = false;
3998
- const end = arm.run(input, pos, ctx);
4097
+ const end = armRun(input, pos, ctx);
3999
4098
  if (end >= 0) return end;
4000
4099
  const at = ctx._fe ?? pos;
4001
4100
  if (at > best) {
@@ -4022,11 +4121,58 @@ function choiceNode(arms, classes, armExpected, choiceExpected) {
4022
4121
  )
4023
4122
  };
4024
4123
  }
4124
+ function exclusiveChoiceNode(arms, classes, choiceFx) {
4125
+ const ascii = (classes.length <= 128 ? new Int8Array(128) : new Int32Array(128)).fill(-1);
4126
+ const hi = [];
4127
+ for (let i = 0; i < classes.length; i++) {
4128
+ const cls = classes[i];
4129
+ for (let c = 0; c < 128; c++) if (cls.ascii[c] === 1) ascii[c] = i;
4130
+ for (let r = 0; r < cls.hi.length; r += 2) hi.push(cls.hi[r], cls.hi[r + 1], i);
4131
+ }
4132
+ const select = (code) => {
4133
+ if (code < 0) return -1;
4134
+ if (code < 128) return ascii[code];
4135
+ for (let r = 0; r < hi.length; r += 3) if (code >= hi[r] && code <= hi[r + 1]) return hi[r + 2];
4136
+ return -1;
4137
+ };
4138
+ let matchArm = () => -1;
4139
+ let selectRun = () => -1;
4140
+ for (let i = arms.length - 1; i >= 0; i--) {
4141
+ const armMatch = arms[i].match, armRun = arms[i].run, nextMatch = matchArm, nextRun = selectRun;
4142
+ matchArm = (selected, input, pos) => selected === i ? armMatch(input, pos) : nextMatch(selected, input, pos);
4143
+ selectRun = (selected, input, pos, ctx) => selected === i ? armRun(input, pos, ctx) : nextRun(selected, input, pos, ctx);
4144
+ }
4145
+ const runArm = (input, pos, ctx) => {
4146
+ const arm = select(lead(input, pos));
4147
+ if (arm >= 0) {
4148
+ ctx._fc = false;
4149
+ const end = selectRun(arm, input, pos, ctx);
4150
+ if (end >= 0) return end;
4151
+ if (committed(ctx)) return -1;
4152
+ const failed = ctx._fx;
4153
+ if (failed !== void 0 && failed.length > 0) {
4154
+ ctx._fe = pos;
4155
+ return -1;
4156
+ }
4157
+ }
4158
+ ctx._fe = pos;
4159
+ ctx._fx = choiceFx;
4160
+ return -1;
4161
+ };
4162
+ return {
4163
+ match: (input, pos) => {
4164
+ const arm = select(lead(input, pos));
4165
+ return arm < 0 ? -1 : matchArm(arm, input, pos);
4166
+ },
4167
+ run: runArm
4168
+ };
4169
+ }
4025
4170
  function notNode(body, failure) {
4171
+ const bodyMatch = body.match;
4026
4172
  return {
4027
- match: (input, pos) => body.match(input, pos) < 0 ? pos : -1,
4173
+ match: (input, pos) => bodyMatch(input, pos) < 0 ? pos : -1,
4028
4174
  run: (input, pos, ctx) => {
4029
- if (body.match(input, pos) < 0) return pos;
4175
+ if (bodyMatch(input, pos) < 0) return pos;
4030
4176
  ctx._fe = pos;
4031
4177
  ctx._fx = failure;
4032
4178
  return -1;
@@ -4034,18 +4180,57 @@ function notNode(body, failure) {
4034
4180
  };
4035
4181
  }
4036
4182
  function optionalNode(body) {
4183
+ const bodyMatch = body.match, bodyRun = body.run;
4037
4184
  return {
4038
4185
  match: (input, pos) => {
4039
- const end = body.match(input, pos);
4186
+ const end = bodyMatch(input, pos);
4040
4187
  return end < 0 ? pos : end;
4041
4188
  },
4042
4189
  run: (input, pos, ctx) => {
4043
4190
  ctx._fc = false;
4044
- const end = body.run(input, pos, ctx);
4191
+ const end = bodyRun(input, pos, ctx);
4045
4192
  return end < 0 && !committed(ctx) ? pos : end;
4046
4193
  }
4047
4194
  };
4048
4195
  }
4196
+ function repeatNode(item, min, max) {
4197
+ const itemMatch = item.match, itemRun = item.run;
4198
+ return {
4199
+ match: (input, pos) => {
4200
+ let cur = pos;
4201
+ let count = 0;
4202
+ for (; ; ) {
4203
+ if (max >= 0 && count >= max) break;
4204
+ const optional2 = count >= min && (count > 0 || min === 0);
4205
+ if (optional2 && cur >= input.length) break;
4206
+ const end = itemMatch(input, cur);
4207
+ if (end < 0 || optional2 && end === cur) break;
4208
+ cur = end;
4209
+ count++;
4210
+ }
4211
+ return count < min ? -1 : cur;
4212
+ },
4213
+ run: (input, pos, ctx) => {
4214
+ let cur = pos;
4215
+ let count = 0;
4216
+ for (; ; ) {
4217
+ if (max >= 0 && count >= max) break;
4218
+ const optional2 = count >= min && (count > 0 || min === 0);
4219
+ if (optional2 && cur >= input.length) break;
4220
+ ctx._fc = false;
4221
+ const end = itemRun(input, cur, ctx);
4222
+ if (end < 0) {
4223
+ if (committed(ctx)) return -1;
4224
+ break;
4225
+ }
4226
+ if (optional2 && end === cur) break;
4227
+ cur = end;
4228
+ count++;
4229
+ }
4230
+ return count < min ? -1 : cur;
4231
+ }
4232
+ };
4233
+ }
4049
4234
  function fixedTreeRunner(words, matchers, classes, expected) {
4050
4235
  const stack = [];
4051
4236
  const pop = () => {
@@ -4073,9 +4258,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
4073
4258
  else stack.push(sequence5(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4]));
4074
4259
  continue;
4075
4260
  }
4076
- if (op >= LEX_NODE_CHOICE2 && op <= LEX_NODE_CHOICE8) {
4077
- const count = op === LEX_NODE_CHOICE2 ? 2 : op === LEX_NODE_CHOICE4 ? 4 : 8;
4261
+ if (op === LEX_NODE_CHOICE) {
4262
+ const count = words[at++];
4263
+ const exclusive = words[at++];
4264
+ if (exclusive !== 0 && exclusive !== 1) throw new TypeError("table lexical tree choice has an invalid dispatch mode");
4078
4265
  const choiceFx = expected[words[at++]];
4266
+ if (!Number.isInteger(count) || count < 2 || count > stack.length) {
4267
+ throw new TypeError("table lexical tree choice has an invalid arm count");
4268
+ }
4079
4269
  if (choiceFx === void 0) throw new TypeError("table lexical tree choice has an invalid expected set");
4080
4270
  const armClasses = [];
4081
4271
  const armFx = [];
@@ -4088,7 +4278,7 @@ function fixedTreeRunner(words, matchers, classes, expected) {
4088
4278
  armFx.push(fx);
4089
4279
  }
4090
4280
  const arms = Array.from({ length: count }, pop).reverse();
4091
- stack.push(choiceNode(arms, armClasses, armFx, choiceFx));
4281
+ stack.push(exclusive === 1 ? exclusiveChoiceNode(arms, armClasses, choiceFx) : choiceNode(arms, armClasses, armFx, choiceFx));
4092
4282
  continue;
4093
4283
  }
4094
4284
  if (op === LEX_NODE_NOT) {
@@ -4101,6 +4291,14 @@ function fixedTreeRunner(words, matchers, classes, expected) {
4101
4291
  stack.push(optionalNode(pop()));
4102
4292
  continue;
4103
4293
  }
4294
+ if (op === LEX_NODE_REPEAT) {
4295
+ const min = words[at++], max = words[at++];
4296
+ if (!Number.isInteger(min) || min < 0 || !Number.isInteger(max) || max >= 0 && max < min) {
4297
+ throw new TypeError("table lexical tree repeat has invalid bounds");
4298
+ }
4299
+ stack.push(repeatNode(pop(), min, max));
4300
+ continue;
4301
+ }
4104
4302
  throw new TypeError("table lexical tree has an unknown fixed body");
4105
4303
  }
4106
4304
  if (stack.length !== 1) throw new TypeError("table lexical tree does not resolve to one root body");
@@ -4469,143 +4667,764 @@ function resolveTable(prog) {
4469
4667
  return built;
4470
4668
  }
4471
4669
 
4472
- // src/analysis/gating.ts
4473
- var choiceArms = (c) => c.arms;
4474
- function childrenOf(d) {
4475
- switch (d.tag) {
4476
- case "sequence":
4477
- case "choice":
4478
- return d.parsers;
4479
- case "dispatch":
4480
- return [
4481
- d.selector,
4482
- ...d.cases.map((c) => c.parser),
4483
- ...d.matchers ? d.matchers.map((c) => c.parser) : [],
4484
- ...d.otherwise === void 0 ? [] : [d.otherwise]
4485
- ];
4486
- case "sepBy":
4487
- return [d.parser, d.separator];
4488
- case "recover":
4489
- return [d.parser, d.sentinel];
4490
- case "scanTo":
4491
- return [
4492
- d.sentinel,
4493
- ...d.skip,
4494
- ...d.recoverAt === void 0 ? [] : [d.recoverAt],
4495
- ...d.stopAt === void 0 ? [] : [d.stopAt]
4496
- ];
4497
- case "grammar":
4498
- return d.triviaParser ? [d.parser, d.triviaParser] : [d.parser];
4499
- case "routed":
4500
- return d.fallback ? [d.fallback] : [];
4501
- case "lines":
4502
- return [d.prefix, d.body, ...d.first === void 0 ? [] : [d.first], ...d.lazy === void 0 ? [] : [d.lazy]];
4503
- case "columns":
4504
- return [];
4505
- // A `lazy` is a REFERENCE, not a subtree. Descending through it would make
4506
- // every rule's walk cover the whole reachable grammar — site paths become
4507
- // nonsense, and a structural hash includes half the grammar. Treated as a
4508
- // leaf, keyed by the rule name it refers to, which is also the right
4509
- // semantics: two productions referencing `g.Ident` really do fill that slot
4510
- // the same way.
4511
- case "lazy":
4512
- case "literal":
4513
- case "regex":
4514
- case "keywords":
4515
- case "guard":
4516
- case "adjacency":
4517
- case "unknown":
4518
- return [];
4519
- default: {
4520
- const rec = d;
4521
- return rec.parser ? [rec.parser] : [];
4522
- }
4523
- }
4670
+ // src/combinators/adjacency.ts
4671
+ function adjacencyOf(p) {
4672
+ return p._def.tag === "adjacency" ? p._def : null;
4524
4673
  }
4525
- var isAny = (fs) => fs.kind === "any";
4526
- function intersection(a, b) {
4527
- if (a.kind === "any") return b;
4528
- if (b.kind === "any") return a;
4529
- if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
4530
- const ranges = [];
4531
- for (const ra of a.ranges) for (const rb of b.ranges) {
4532
- const lo = Math.max(ra.lo, rb.lo);
4533
- const hi = Math.min(ra.hi, rb.hi);
4534
- if (lo <= hi) ranges.push({ lo, hi });
4535
- }
4536
- return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
4674
+ function adjacencyExpected(def) {
4675
+ if (def.polarity === "adjacent") return "adjacent";
4676
+ return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
4537
4677
  }
4538
- function combine(sets) {
4539
- let acc = { kind: "empty" };
4540
- for (const s of sets) {
4541
- if (s.kind === "any") return { kind: "any" };
4542
- if (s.kind === "empty") continue;
4543
- acc = acc.kind === "ranges" ? { kind: "ranges", ranges: [...acc.ranges, ...s.ranges] } : s;
4544
- }
4545
- return acc;
4678
+ function holdsAdjacency(input, cur, ctx, def) {
4679
+ return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
4546
4680
  }
4547
- var ch = (c) => c >= 32 && c < 127 ? `'${String.fromCharCode(c)}'` : `\\u${c}`;
4548
- function firstSetToString(fs) {
4549
- if (fs.kind === "any") return "ANY";
4550
- if (fs.kind === "empty") return "(empty)";
4551
- return fs.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
4681
+ function adjacencyHolds(input, cur, ctx, negated, kinds) {
4682
+ const end = probeTriviaEnd(input, cur, ctx);
4683
+ if (!negated) return end === cur;
4684
+ if (end === cur) return false;
4685
+ if (kinds === void 0) return true;
4686
+ const want = resolveAdjacencyKindMask(ctx.trivia, kinds);
4687
+ const spec = analyzeLabeledTrivia(ctx.trivia);
4688
+ return (triviaKindMaskAt(input, cur, spec, ctx.state) & want) !== 0;
4552
4689
  }
4553
- var ruleNameOf = (p) => p._ruleName;
4554
- var KEYWORD_REGEX_RE = /^\^?[@#.-]?[A-Za-z][\w-]*(\(\?![^)]*\))?\$?$/;
4555
- var SUGGESTIONS = {
4556
- "broad-recognizer": "This arm can begin with any character, so no single-character test can rule it out. The parser has to enter it \u2014 set up, try, and undo \u2014 at every position it reaches, instead of skipping it for free.\nTo fix: make the arm begin with a fixed character, word or keyword. If it is meant to be a catch-all that matches anything, leave it and add the choice to the accept list at the end.",
4557
- "leading-not": "This arm begins with a not(...) check, which matches nothing and so says nothing about which character the arm starts with. The parser then cannot rule the arm out and enters it everywhere.\nTo fix: put the term that actually consumes text first and keep not(...) after it as a trailing boundary. If you need to REQUIRE something ahead without consuming it, use peek(X) \u2014 it checks the same thing but still tells parseman that the arm starts with X.",
4558
- "nullable-prefix": "This arm begins with something optional \u2014 an optional(...) or a repeat that allows zero items \u2014 so the arm can also start with whatever comes AFTER it, and that is broad enough that no character rules the arm out.\nTo fix: give the optional part its own arm so each arm has a definite beginning, or require at least one item. A plain sepBy(item, sep) also matches nothing at all; pass { min: 1 } when the list must not be empty.",
4559
- "cross-artifact-ref": "This arm hands off to another rule, and that rule has the same problem \u2014 it can begin with any character \u2014 so the cost is inherited rather than caused here.\nTo fix: run this check on the rule it refers to and fix it there. One rule given a definite beginning fixes every choice that uses it.",
4560
- "opaque-wrapper": "This arm begins with a wrapper that only inspects parser state (a gate/withCtx/recover) and consumes no text, so it says nothing about which character the arm starts with.\nTo fix: put a term that actually matches text in front of the wrapper.",
4561
- "ref-cycle": "This arm refers back to itself through a cycle of rules, and parseman could not work out a definite first character for any of them.\nTo fix: make sure the base case of the recursion begins with a fixed character or keyword, so the cycle has somewhere definite to start."
4562
- };
4563
- function refineSuggestion(cause, arm) {
4564
- if (cause !== "broad-recognizer") return SUGGESTIONS[cause];
4565
- const lead2 = peelToLeading(arm);
4566
- const d = lead2._def;
4567
- if (d.tag === "regex" && KEYWORD_REGEX_RE.test(d.source)) {
4568
- return `This arm matches the fixed word \`${d.source}\` with a regular expression, and parseman cannot always tell from a regular expression which character it starts with.
4569
- To fix: write it as word('\u2026') or keywords([\u2026]) instead. They match exactly the same text and compile to the same character scan, but they also tell parseman the first character, which is what lets the parser skip this arm when it cannot match.`;
4570
- }
4571
- if (d.tag === "scanTo") {
4572
- return "This arm ends in a scanTo(...) catch-all, which reads forward until it finds something and so can begin at any character. The parser can never rule it out. That is usually exactly what you want from a fallback.\nTo fix: usually nothing. Add this choice to the accept list at the end so the check keeps flagging the choices that are real problems.";
4573
- }
4574
- return SUGGESTIONS[cause];
4690
+ function adjacencyFail(pos, def) {
4691
+ return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
4575
4692
  }
4576
- function classifyBroadArm(arm, resolve) {
4577
- const seen = /* @__PURE__ */ new Set();
4578
- const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
4579
- const walk = (p) => {
4580
- if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
4581
- seen.add(p);
4582
- const d = p._def;
4583
- switch (d.tag) {
4584
- case "literal":
4585
- case "regex":
4586
- case "keywords":
4587
- return isAny(p._meta.firstSet) ? { cause: "broad-recognizer", detail: `broad recognizer (${d.tag})` } : null;
4588
- case "not":
4589
- return { cause: "leading-not", detail: "leading not(...) (first-set ANY)" };
4590
- // peek() CARRIES its body's first-set, so it is only broad when the body is
4591
- // (or the body is nullable) — walk in for the real cause.
4592
- case "peek":
4593
- return walk(d.parser);
4594
- case "scanTo":
4595
- return { cause: "broad-recognizer", detail: "scanTo (any first char)" };
4596
- // A run opens with its first line's prefix.
4597
- case "lines":
4598
- return walk(d.first ?? d.prefix);
4599
- // `guard` (the `gate()` state predicate) has a genuinely-`any` first-set of
4600
- // its own — it is the poison. `withCtx`/`recover` FORWARD their inner
4601
- // first-set (see firstSetOf), so a broad result comes from the inner parser:
4602
- // walk into it for a precise cause.
4603
- case "guard":
4604
- return { cause: "opaque-wrapper", detail: `opaque wrapper (${d.tag})` };
4605
- // Zero-width and dropped from a sequence's first-set (isZeroWidthAssertion),
4606
- // so it is never the reason an arm is broad — but it can be reached as the
4607
- // sole term of a degenerate arm. Report it precisely rather than as a wrapper.
4608
- case "adjacency":
4693
+ var NO_STANDALONE_PARSE = "adjacency assertions are boundary tests: use adjacent()/notAdjacent() as a NON-FIRST term of a sequence(), where the preceding term defines the gap being asserted.";
4694
+ function adjacencyMisuse(polarity) {
4695
+ return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
4696
+ }
4697
+ function adjacencyCombinator(def) {
4698
+ const meta = {
4699
+ // Zero-width and never leading (sequence() rejects index 0), so it contributes
4700
+ // no first char. `isZeroWidthAssertion` drops it from a sequence's first-set
4701
+ // rather than letting `any` poison the enclosing choice's dispatch.
4702
+ firstSet: { kind: "any" },
4703
+ canMatchNewline: false,
4704
+ isTrivia: false
4705
+ };
4706
+ return {
4707
+ _tag: "adjacency",
4708
+ _meta: meta,
4709
+ _def: def,
4710
+ parse() {
4711
+ throw adjacencyMisuse(def.polarity);
4712
+ }
4713
+ };
4714
+ }
4715
+ function adjacent() {
4716
+ return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
4717
+ }
4718
+ function notAdjacent(options) {
4719
+ const kinds = options?.kinds;
4720
+ if (kinds !== void 0) {
4721
+ if (!Array.isArray(kinds) || kinds.length === 0) {
4722
+ throw new TypeError("notAdjacent({ kinds }): kinds must be a non-empty array of trivia category names.");
4723
+ }
4724
+ for (const k of kinds) {
4725
+ if (typeof k !== "string" || k.length === 0) {
4726
+ throw new TypeError(`notAdjacent({ kinds }): every kind must be a non-empty string, got ${JSON.stringify(k)}.`);
4727
+ }
4728
+ }
4729
+ }
4730
+ return adjacencyCombinator(
4731
+ kinds === void 0 ? { tag: "adjacency", polarity: "notAdjacent" } : { tag: "adjacency", polarity: "notAdjacent", kinds: [...kinds] }
4732
+ );
4733
+ }
4734
+
4735
+ // src/combinators/sequence.ts
4736
+ function sequence(...parsers) {
4737
+ let adjacency = null;
4738
+ for (let i = 0; i < parsers.length; i++) {
4739
+ const a = adjacencyOf(parsers[i]);
4740
+ if (a === null) continue;
4741
+ if (i === 0) {
4742
+ throw new TypeError(
4743
+ `sequence(): ${a.polarity}() cannot be the FIRST term \u2014 an adjacency assertion tests the gap after the PRECEDING term. Put a concrete term first.`
4744
+ );
4745
+ }
4746
+ ;
4747
+ (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
4748
+ }
4749
+ const hasAdjacency = adjacency !== null;
4750
+ let leading = null;
4751
+ for (let i = 1; i < parsers.length; i++) {
4752
+ if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
4753
+ }
4754
+ const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
4755
+ const meta = {
4756
+ // Union through the nullable prefix — a leading optional()/many() lets a later
4757
+ // term's first char start the sequence. Just `parsers[0]` under-approximates.
4758
+ firstSet: sequenceFirstSet(parsers),
4759
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
4760
+ isTrivia: false
4761
+ };
4762
+ const def = { tag: "sequence", parsers };
4763
+ const scalarParsers = parsers.map(scalarOf);
4764
+ const parseScalar = (input, pos, ctx) => {
4765
+ let cur = pos;
4766
+ if (strictArity !== 0) {
4767
+ cur = scalarParsers[0](input, cur, ctx);
4768
+ if (cur < 0) return cur;
4769
+ const first = ctx._sv;
4770
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
4771
+ cur = scalarParsers[1](input, cur, ctx);
4772
+ if (cur < 0) return cur;
4773
+ const second = ctx._sv;
4774
+ if (strictArity === 2) {
4775
+ ctx._sv = def.valueUnused ? void 0 : [first, second];
4776
+ return cur;
4777
+ }
4778
+ if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
4779
+ cur = scalarParsers[2](input, cur, ctx);
4780
+ if (cur < 0) return cur;
4781
+ ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
4782
+ return cur;
4783
+ }
4784
+ const values = def.valueUnused ? void 0 : [];
4785
+ for (let i = 0; i < scalarParsers.length; i++) {
4786
+ let termPos = cur;
4787
+ if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
4788
+ const end = scalarParsers[i](input, termPos, ctx);
4789
+ if (end < 0) return end;
4790
+ if (values !== void 0) values.push(ctx._sv);
4791
+ if (end > termPos || termPos === cur) cur = end;
4792
+ }
4793
+ ctx._sv = values;
4794
+ return cur;
4795
+ };
4796
+ let followSentinels;
4797
+ return {
4798
+ _tag: "sequence",
4799
+ _meta: meta,
4800
+ _def: def,
4801
+ _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
4802
+ parse(input, pos, ctx) {
4803
+ const tolerant = ctx._tolerant === true;
4804
+ if (tolerant) {
4805
+ followSentinels ??= parsers.map((_, i) => firstSetSentinel(
4806
+ parsers.slice(i + 1).reduce(
4807
+ (set, parser2) => union(set, firstSetOf(parser2)),
4808
+ { kind: "empty" }
4809
+ )
4810
+ ));
4811
+ }
4812
+ const inheritedSync = ctx._sync;
4813
+ const deferredTrivia = needsDeferredTriviaCommit(ctx);
4814
+ const values = def.valueUnused ? void 0 : [];
4815
+ let cur = pos;
4816
+ try {
4817
+ for (let i = 0; i < parsers.length; i++) {
4818
+ if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
4819
+ const assertion = adjacency?.[i];
4820
+ if (assertion) {
4821
+ if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
4822
+ if (values !== void 0) values.push(null);
4823
+ continue;
4824
+ }
4825
+ let termPos = cur;
4826
+ const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
4827
+ const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
4828
+ const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
4829
+ if (ctx.trivia && i > 0) {
4830
+ termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
4831
+ }
4832
+ const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
4833
+ const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
4834
+ const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
4835
+ if (leading?.[i] === true) LEAD.at = cur;
4836
+ const result = parsers[i].parse(input, termPos, ctx);
4837
+ if (!result.ok) return result;
4838
+ if (values !== void 0) values.push(result.value);
4839
+ if (result.span.end > termPos || termPos === cur) cur = result.span.end;
4840
+ else if (deferredTrivia) {
4841
+ rollbackScannedTriviaAt(
4842
+ ctx,
4843
+ markTlog,
4844
+ scanTlog,
4845
+ markLog,
4846
+ scanLog,
4847
+ markRootLog,
4848
+ scanRootLog
4849
+ );
4850
+ }
4851
+ }
4852
+ } finally {
4853
+ if (tolerant) ctx._sync = inheritedSync;
4854
+ }
4855
+ return {
4856
+ ok: true,
4857
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
4858
+ value: values ?? void 0,
4859
+ span: { start: pos, end: cur }
4860
+ };
4861
+ }
4862
+ };
4863
+ }
4864
+
4865
+ // src/compiler/degradation.ts
4866
+ function formatDegradation(d) {
4867
+ return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
4868
+ }
4869
+ var DETAIL_CAP = 8;
4870
+ function formatDegradations(list) {
4871
+ const byCode = /* @__PURE__ */ new Map();
4872
+ for (const d of list) {
4873
+ const bucket = byCode.get(d.code);
4874
+ if (bucket) bucket.push(d);
4875
+ else byCode.set(d.code, [d]);
4876
+ }
4877
+ const out = [];
4878
+ for (const [code, items] of byCode) {
4879
+ for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
4880
+ if (items.length > DETAIL_CAP) {
4881
+ out.push(
4882
+ `[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
4883
+ );
4884
+ }
4885
+ }
4886
+ return out;
4887
+ }
4888
+ var _sinks = [];
4889
+ function beginDegradationCapture() {
4890
+ _sinks.push(/* @__PURE__ */ new Map());
4891
+ }
4892
+ function degradationCaptureDepth() {
4893
+ return _sinks.length;
4894
+ }
4895
+ function unwindDegradationCapture(depth) {
4896
+ const found = [];
4897
+ while (_sinks.length > depth) {
4898
+ const sink = _sinks.pop();
4899
+ found.unshift(...sink.values());
4900
+ }
4901
+ return found;
4902
+ }
4903
+ function resolveDegradationLevel(explicit) {
4904
+ if (explicit !== void 0) return explicit;
4905
+ const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
4906
+ if (env === "off" || env === "warn" || env === "error") return env;
4907
+ return "warn";
4908
+ }
4909
+ function degradationKey(d) {
4910
+ return JSON.stringify([d.code, d.where, d.subject]);
4911
+ }
4912
+ function recordDegradation(d) {
4913
+ const level = resolveDegradationLevel();
4914
+ if (level === "off") return;
4915
+ const key = degradationKey(d);
4916
+ const sink = _sinks[_sinks.length - 1];
4917
+ if (sink) {
4918
+ if (!sink.has(key)) sink.set(key, d);
4919
+ return;
4920
+ }
4921
+ if (_immediate.has(key)) return;
4922
+ _immediate.add(key);
4923
+ if (level === "error") throw new Error(`parseman: degraded compilation path
4924
+ ${formatDegradation(d)}`);
4925
+ console.warn(formatDegradation(d));
4926
+ }
4927
+ var _immediate = /* @__PURE__ */ new Set();
4928
+ function beginCompileDegradationDrain() {
4929
+ if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
4930
+ };
4931
+ const depth = degradationCaptureDepth();
4932
+ beginDegradationCapture();
4933
+ return (report) => {
4934
+ const found = unwindDegradationCapture(depth);
4935
+ if (!report || found.length === 0) return;
4936
+ const fresh = found.filter((d) => {
4937
+ const k = degradationKey(d);
4938
+ if (_immediate.has(k)) return false;
4939
+ _immediate.add(k);
4940
+ return true;
4941
+ });
4942
+ if (fresh.length === 0) return;
4943
+ const lines2 = formatDegradations(fresh);
4944
+ if (resolveDegradationLevel() === "error") {
4945
+ throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
4946
+ ${lines2.join("\n")}`);
4947
+ }
4948
+ for (const l of lines2) console.warn(l);
4949
+ };
4950
+ }
4951
+
4952
+ // src/compiler/build-arity.ts
4953
+ function cstOutputHost(build) {
4954
+ return build?._parsemanCstOutput === true;
4955
+ }
4956
+ var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
4957
+ var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
4958
+ var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
4959
+ var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
4960
+ function confirmedBuildArity(src) {
4961
+ const s = src.trim();
4962
+ if (NATIVE_CODE_RE.test(s)) return null;
4963
+ if (/\barguments\b/.test(s)) return null;
4964
+ if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
4965
+ const inner = paramListText(s);
4966
+ if (inner === null) return null;
4967
+ if (inner.trim() === "") return 0;
4968
+ const parts = splitTopLevel(inner);
4969
+ if (parts === null) return null;
4970
+ for (const part of parts) {
4971
+ if (!isConfirmableParam(part.trim())) return null;
4972
+ }
4973
+ return parts.length;
4974
+ }
4975
+ function paramListText(s) {
4976
+ const open = PARAM_LIST_OPEN_RE.exec(s);
4977
+ if (!open) return null;
4978
+ const start = open[0].length;
4979
+ const end = matchingParen(s, start);
4980
+ if (end === null) return null;
4981
+ if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
4982
+ return s.slice(start, end);
4983
+ }
4984
+ function matchingParen(s, start) {
4985
+ let depth = 0;
4986
+ for (let i = start; i < s.length; i++) {
4987
+ const c = s[i];
4988
+ if (c === '"' || c === "'" || c === "`") {
4989
+ const close = skipString(s, i);
4990
+ if (close === null) return null;
4991
+ i = close;
4992
+ continue;
4993
+ }
4994
+ if (c === "(" || c === "[" || c === "{") depth++;
4995
+ else if (c === "]" || c === "}") {
4996
+ if (--depth < 0) return null;
4997
+ } else if (c === ")") {
4998
+ if (depth === 0) return i;
4999
+ depth--;
5000
+ }
5001
+ }
5002
+ return null;
5003
+ }
5004
+ function skipString(s, open) {
5005
+ const quote = s[open];
5006
+ for (let i = open + 1; i < s.length; i++) {
5007
+ if (s[i] === "\\") {
5008
+ i++;
5009
+ continue;
5010
+ }
5011
+ if (s[i] === quote) return i;
5012
+ }
5013
+ return null;
5014
+ }
5015
+ function splitTopLevel(inner) {
5016
+ const parts = [];
5017
+ let depth = 0;
5018
+ let angle = 0;
5019
+ let last = 0;
5020
+ for (let i = 0; i < inner.length; i++) {
5021
+ const c = inner[i];
5022
+ if (c === "=" && inner[i + 1] === ">") {
5023
+ i++;
5024
+ continue;
5025
+ }
5026
+ if (c === '"' || c === "'" || c === "`") {
5027
+ const close = skipString(inner, i);
5028
+ if (close === null) return null;
5029
+ i = close;
5030
+ continue;
5031
+ }
5032
+ if (c === "(" || c === "[" || c === "{") depth++;
5033
+ else if (c === ")" || c === "]" || c === "}") {
5034
+ if (--depth < 0) return null;
5035
+ } else if (c === "<") angle++;
5036
+ else if (c === ">") {
5037
+ if (--angle < 0) return null;
5038
+ } else if (c === "," && depth === 0 && angle === 0) {
5039
+ parts.push(inner.slice(last, i));
5040
+ last = i + 1;
5041
+ }
5042
+ }
5043
+ if (depth !== 0 || angle !== 0) return null;
5044
+ parts.push(inner.slice(last));
5045
+ return parts;
5046
+ }
5047
+ function isConfirmableParam(part) {
5048
+ const head = PARAM_HEAD_RE.exec(part);
5049
+ if (!head) return false;
5050
+ const rest = part.slice(head[0].length);
5051
+ if (rest === "") return true;
5052
+ if (rest[0] !== ":") return false;
5053
+ return !hasDefaultAssign(rest.slice(1));
5054
+ }
5055
+ function hasDefaultAssign(annotation) {
5056
+ for (let i = 0; i < annotation.length; i++) {
5057
+ if (annotation[i] !== "=") continue;
5058
+ if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
5059
+ i++;
5060
+ continue;
5061
+ }
5062
+ const prev = annotation[i - 1];
5063
+ if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
5064
+ return true;
5065
+ }
5066
+ return false;
5067
+ }
5068
+ function buildAnalysisSrc(def) {
5069
+ return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
5070
+ }
5071
+ var RESOLVER_REASONS = {
5072
+ "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
5073
+ "arguments": "its body references `arguments`",
5074
+ "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
5075
+ "not-a-function": "the binding it names is not a function declaration",
5076
+ "unresolved-import": "its module could not be resolved or parsed",
5077
+ "not-found": "the name did not resolve to any binding",
5078
+ "computed": "it is a computed expression",
5079
+ "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
5080
+ "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
5081
+ };
5082
+ function unconfirmableReason(def, src) {
5083
+ const declared = def.buildArityUnresolved;
5084
+ if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
5085
+ const s = src.trim();
5086
+ const params = s.slice(0, s.indexOf(")") + 1);
5087
+ if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
5088
+ if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
5089
+ if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
5090
+ return "it names a binding this build could not resolve to a function declaration";
5091
+ }
5092
+ return "its parameter list could not be parsed";
5093
+ }
5094
+ function confirmedArityForDef(def) {
5095
+ if (def.buildArity !== void 0) return def.buildArity;
5096
+ const src = buildAnalysisSrc(def);
5097
+ const arity = confirmedBuildArity(src);
5098
+ if (arity !== null) return arity;
5099
+ const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
5100
+ recordDegradation({
5101
+ code: "build-arity-unconfirmed",
5102
+ severity: "warn",
5103
+ where: `node("${def.type ?? "<inferred>"}")`,
5104
+ subject,
5105
+ fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and hands it \`_ctx.state\` on every match`,
5106
+ otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
5107
+ });
5108
+ return null;
5109
+ }
5110
+ function buildReadsRaw(def) {
5111
+ if (!def.build) return true;
5112
+ if (def.buildRawUnused === true) return false;
5113
+ const arity = confirmedArityForDef(def);
5114
+ if (arity === null) return true;
5115
+ return arity >= 4;
5116
+ }
5117
+ function buildReadsTrivia(def) {
5118
+ if (!def.build) return true;
5119
+ const arity = confirmedArityForDef(def);
5120
+ if (arity === null) return true;
5121
+ return arity >= 5;
5122
+ }
5123
+ function buildReadsState(def) {
5124
+ if (!def.build) return true;
5125
+ const arity = confirmedArityForDef(def);
5126
+ if (arity === null) return true;
5127
+ return arity >= 6;
5128
+ }
5129
+
5130
+ // src/combinators/token.ts
5131
+ function semanticLeafValue(_ctx, _input, _start, _end, value) {
5132
+ return value;
5133
+ }
5134
+ function sourceLeafValue(ctx, input, start, end, value) {
5135
+ return cstOutputHost(ctx.build) ? input.slice(start, end) : value;
5136
+ }
5137
+ function token(root) {
5138
+ const meta = {
5139
+ firstSet: root._meta.firstSet,
5140
+ canMatchNewline: root._meta.canMatchNewline,
5141
+ isTrivia: false
5142
+ };
5143
+ return {
5144
+ _tag: "token",
5145
+ _meta: meta,
5146
+ _def: { tag: "token", parser: root },
5147
+ parse(input, pos, ctx) {
5148
+ const savedTrivia = ctx.trivia;
5149
+ const savedKinds = ctx.triviaKindLabels;
5150
+ const savedBuf = ctx._cstBuf;
5151
+ const savedChildren = ctx._cstChildren;
5152
+ const savedLeaves = ctx._cstLeaves;
5153
+ const savedRaw = ctx._cstRawChildren;
5154
+ const savedTriviaLog = ctx._cstTriviaLog;
5155
+ const savedOuterTriviaLog = ctx._triviaLog;
5156
+ const savedRootTriviaLog = ctx._rootTriviaLog;
5157
+ const wasCapturing = cstCaptureActive(ctx);
5158
+ ctx.trivia = void 0;
5159
+ ctx.triviaKindLabels = void 0;
5160
+ ctx._cstBuf = void 0;
5161
+ ctx._cstChildren = void 0;
5162
+ ctx._cstLeaves = void 0;
5163
+ ctx._cstRawChildren = void 0;
5164
+ ctx._cstTriviaLog = void 0;
5165
+ ctx._triviaLog = void 0;
5166
+ ctx._rootTriviaLog = void 0;
5167
+ let result;
5168
+ try {
5169
+ result = root.parse(input, pos, ctx);
5170
+ } finally {
5171
+ ctx.trivia = savedTrivia;
5172
+ ctx.triviaKindLabels = savedKinds;
5173
+ ctx._cstBuf = savedBuf;
5174
+ ctx._cstChildren = savedChildren;
5175
+ ctx._cstLeaves = savedLeaves;
5176
+ ctx._cstRawChildren = savedRaw;
5177
+ ctx._cstTriviaLog = savedTriviaLog;
5178
+ ctx._triviaLog = savedOuterTriviaLog;
5179
+ ctx._rootTriviaLog = savedRootTriviaLog;
5180
+ }
5181
+ if (!result.ok) return result;
5182
+ const span = result.span;
5183
+ const value = input.slice(pos, span.end);
5184
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
5185
+ return { ok: true, value, span };
5186
+ }
5187
+ };
5188
+ }
5189
+ function makeLeaf(root, fn, sourceCstValue) {
5190
+ const cstValue = sourceCstValue ? sourceLeafValue : semanticLeafValue;
5191
+ const meta = {
5192
+ firstSet: root._meta.firstSet,
5193
+ canMatchNewline: root._meta.canMatchNewline,
5194
+ isTrivia: false
5195
+ };
5196
+ return {
5197
+ _tag: "leaf",
5198
+ _meta: meta,
5199
+ _def: {
5200
+ tag: "leaf",
5201
+ parser: root,
5202
+ fn,
5203
+ ...sourceCstValue ? { cstValue: "source" } : {}
5204
+ },
5205
+ parse(input, pos, ctx) {
5206
+ const savedBuf = ctx._cstBuf;
5207
+ const savedChildren = ctx._cstChildren;
5208
+ const savedLeaves = ctx._cstLeaves;
5209
+ const savedRaw = ctx._cstRawChildren;
5210
+ const savedTriviaLog = ctx._cstTriviaLog;
5211
+ const savedOuterTriviaLog = ctx._triviaLog;
5212
+ const wasCapturing = cstCaptureActive(ctx);
5213
+ ctx._cstBuf = void 0;
5214
+ ctx._cstChildren = void 0;
5215
+ ctx._cstLeaves = void 0;
5216
+ ctx._cstRawChildren = void 0;
5217
+ ctx._cstTriviaLog = void 0;
5218
+ ctx._triviaLog = void 0;
5219
+ let result;
5220
+ try {
5221
+ result = root.parse(input, pos, ctx);
5222
+ } finally {
5223
+ ctx._cstBuf = savedBuf;
5224
+ ctx._cstChildren = savedChildren;
5225
+ ctx._cstLeaves = savedLeaves;
5226
+ ctx._cstRawChildren = savedRaw;
5227
+ ctx._cstTriviaLog = savedTriviaLog;
5228
+ ctx._triviaLog = savedOuterTriviaLog;
5229
+ }
5230
+ if (!result.ok) return result;
5231
+ const value = fn(result.value, result.span);
5232
+ if (wasCapturing) pushCstLeaf(ctx, {
5233
+ _tag: "leaf",
5234
+ value: cstValue(ctx, input, pos, result.span.end, value),
5235
+ span: result.span
5236
+ });
5237
+ return { ok: true, value, span: result.span };
5238
+ }
5239
+ };
5240
+ }
5241
+ function leaf(root, fn) {
5242
+ return makeLeaf(root, fn, false);
5243
+ }
5244
+ function sourceLeaf(root, fn) {
5245
+ return makeLeaf(root, fn, true);
5246
+ }
5247
+
5248
+ // src/combinators/attempt.ts
5249
+ function containOption(options) {
5250
+ if (options === void 0) return false;
5251
+ for (const key of Object.keys(options)) {
5252
+ if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
5253
+ }
5254
+ if (options.contain !== void 0 && typeof options.contain !== "boolean") {
5255
+ throw new TypeError("attempt(): `contain` must be a boolean");
5256
+ }
5257
+ return options.contain === true;
5258
+ }
5259
+ function attempt(parser2, options) {
5260
+ const contain = containOption(options);
5261
+ const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
5262
+ let failExpected;
5263
+ return {
5264
+ _tag: "attempt",
5265
+ _meta: parser2._meta,
5266
+ _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
5267
+ parse(input, pos, ctx) {
5268
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
5269
+ if (failExpected === void 0) {
5270
+ const e = deriveExpected(parser2);
5271
+ failExpected = e.length > 0 ? e : [parser2._tag];
5272
+ }
5273
+ return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
5274
+ }
5275
+ const mark = saveCstMark(ctx);
5276
+ const log = ctx._triviaLog?.length;
5277
+ const rootLog = ctx._rootTriviaLog?.length;
5278
+ const split = ctx._columnsSplit;
5279
+ const result = parser2.parse(input, pos, ctx);
5280
+ if (result.ok) return result;
5281
+ rollbackCstCapture(ctx, mark);
5282
+ ctx._columnsSplit = split;
5283
+ if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
5284
+ if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
5285
+ if (result.committed && !contain) return result;
5286
+ return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
5287
+ }
5288
+ };
5289
+ }
5290
+
5291
+ // src/analysis/gating.ts
5292
+ var choiceArms = (c) => c.arms;
5293
+ function childrenOf(d) {
5294
+ switch (d.tag) {
5295
+ case "sequence":
5296
+ case "choice":
5297
+ return d.parsers;
5298
+ case "dispatch":
5299
+ return [
5300
+ d.selector,
5301
+ ...d.cases.map((c) => c.parser),
5302
+ ...d.matchers ? d.matchers.map((c) => c.parser) : [],
5303
+ ...d.otherwise === void 0 ? [] : [d.otherwise]
5304
+ ];
5305
+ case "sepBy":
5306
+ return [d.parser, d.separator];
5307
+ case "recover":
5308
+ return [d.parser, d.sentinel];
5309
+ case "scanTo":
5310
+ return [
5311
+ d.sentinel,
5312
+ ...d.skip,
5313
+ ...d.recoverAt === void 0 ? [] : [d.recoverAt],
5314
+ ...d.stopAt === void 0 ? [] : [d.stopAt]
5315
+ ];
5316
+ case "grammar":
5317
+ return d.triviaParser ? [d.parser, d.triviaParser] : [d.parser];
5318
+ case "routed":
5319
+ return d.fallback ? [d.fallback] : [];
5320
+ case "lines":
5321
+ return [d.prefix, d.body, ...d.first === void 0 ? [] : [d.first], ...d.lazy === void 0 ? [] : [d.lazy]];
5322
+ case "columns":
5323
+ return [];
5324
+ // A `lazy` is a REFERENCE, not a subtree. Descending through it would make
5325
+ // every rule's walk cover the whole reachable grammar — site paths become
5326
+ // nonsense, and a structural hash includes half the grammar. Treated as a
5327
+ // leaf, keyed by the rule name it refers to, which is also the right
5328
+ // semantics: two productions referencing `g.Ident` really do fill that slot
5329
+ // the same way.
5330
+ case "lazy":
5331
+ case "literal":
5332
+ case "regex":
5333
+ case "keywords":
5334
+ case "guard":
5335
+ case "adjacency":
5336
+ case "unknown":
5337
+ return [];
5338
+ default: {
5339
+ const rec = d;
5340
+ return rec.parser ? [rec.parser] : [];
5341
+ }
5342
+ }
5343
+ }
5344
+ var isAny = (fs) => fs.kind === "any";
5345
+ function intersection(a, b) {
5346
+ if (a.kind === "any") return b;
5347
+ if (b.kind === "any") return a;
5348
+ if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
5349
+ const ranges = [];
5350
+ for (const ra of a.ranges) for (const rb of b.ranges) {
5351
+ const lo = Math.max(ra.lo, rb.lo);
5352
+ const hi = Math.min(ra.hi, rb.hi);
5353
+ if (lo <= hi) ranges.push({ lo, hi });
5354
+ }
5355
+ return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
5356
+ }
5357
+ function combine(sets) {
5358
+ let acc = { kind: "empty" };
5359
+ for (const s of sets) {
5360
+ if (s.kind === "any") return { kind: "any" };
5361
+ if (s.kind === "empty") continue;
5362
+ acc = acc.kind === "ranges" ? { kind: "ranges", ranges: [...acc.ranges, ...s.ranges] } : s;
5363
+ }
5364
+ return acc;
5365
+ }
5366
+ var ch = (c) => c >= 32 && c < 127 ? `'${String.fromCharCode(c)}'` : `\\u${c}`;
5367
+ function firstSetToString(fs) {
5368
+ if (fs.kind === "any") return "ANY";
5369
+ if (fs.kind === "empty") return "(empty)";
5370
+ return fs.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
5371
+ }
5372
+ var ruleNameOf = (p) => p._ruleName;
5373
+ var KEYWORD_REGEX_RE = /^\^?[@#.-]?[A-Za-z][\w-]*(\(\?![^)]*\))?\$?$/;
5374
+ var SUGGESTIONS = {
5375
+ "broad-recognizer": "This arm can begin with any character, so no single-character test can rule it out. The parser has to enter it \u2014 set up, try, and undo \u2014 at every position it reaches, instead of skipping it for free.\nTo fix: make the arm begin with a fixed character, word or keyword. If it is meant to be a catch-all that matches anything, leave it and add the choice to the accept list at the end.",
5376
+ "leading-not": "This arm begins with a not(...) check, which matches nothing and so says nothing about which character the arm starts with. The parser then cannot rule the arm out and enters it everywhere.\nTo fix: put the term that actually consumes text first and keep not(...) after it as a trailing boundary. If you need to REQUIRE something ahead without consuming it, use peek(X) \u2014 it checks the same thing but still tells parseman that the arm starts with X.",
5377
+ "nullable-prefix": "This arm begins with something optional \u2014 an optional(...) or a repeat that allows zero items \u2014 so the arm can also start with whatever comes AFTER it, and that is broad enough that no character rules the arm out.\nTo fix: give the optional part its own arm so each arm has a definite beginning, or require at least one item. A plain sepBy(item, sep) also matches nothing at all; pass { min: 1 } when the list must not be empty.",
5378
+ "cross-artifact-ref": "This arm hands off to another rule, and that rule has the same problem \u2014 it can begin with any character \u2014 so the cost is inherited rather than caused here.\nTo fix: run this check on the rule it refers to and fix it there. One rule given a definite beginning fixes every choice that uses it.",
5379
+ "opaque-wrapper": "This arm begins with a wrapper that only inspects parser state (a gate/withCtx/recover) and consumes no text, so it says nothing about which character the arm starts with.\nTo fix: put a term that actually matches text in front of the wrapper.",
5380
+ "ref-cycle": "This arm refers back to itself through a cycle of rules, and parseman could not work out a definite first character for any of them.\nTo fix: make sure the base case of the recursion begins with a fixed character or keyword, so the cycle has somewhere definite to start."
5381
+ };
5382
+ function refineSuggestion(cause, arm) {
5383
+ if (cause !== "broad-recognizer") return SUGGESTIONS[cause];
5384
+ const lead2 = peelToLeading(arm);
5385
+ const d = lead2._def;
5386
+ if (d.tag === "regex" && KEYWORD_REGEX_RE.test(d.source)) {
5387
+ return `This arm matches the fixed word \`${d.source}\` with a regular expression, and parseman cannot always tell from a regular expression which character it starts with.
5388
+ To fix: write it as word('\u2026') or keywords([\u2026]) instead. They match exactly the same text and compile to the same character scan, but they also tell parseman the first character, which is what lets the parser skip this arm when it cannot match.`;
5389
+ }
5390
+ if (d.tag === "scanTo") {
5391
+ return "This arm ends in a scanTo(...) catch-all, which reads forward until it finds something and so can begin at any character. The parser can never rule it out. That is usually exactly what you want from a fallback.\nTo fix: usually nothing. Add this choice to the accept list at the end so the check keeps flagging the choices that are real problems.";
5392
+ }
5393
+ return SUGGESTIONS[cause];
5394
+ }
5395
+ function classifyBroadArm(arm, resolve) {
5396
+ const seen = /* @__PURE__ */ new Set();
5397
+ const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
5398
+ const walk = (p) => {
5399
+ if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
5400
+ seen.add(p);
5401
+ const d = p._def;
5402
+ switch (d.tag) {
5403
+ case "literal":
5404
+ case "regex":
5405
+ case "keywords":
5406
+ return isAny(p._meta.firstSet) ? { cause: "broad-recognizer", detail: `broad recognizer (${d.tag})` } : null;
5407
+ case "not":
5408
+ return { cause: "leading-not", detail: "leading not(...) (first-set ANY)" };
5409
+ // peek() CARRIES its body's first-set, so it is only broad when the body is
5410
+ // (or the body is nullable) — walk in for the real cause.
5411
+ case "peek":
5412
+ return walk(d.parser);
5413
+ case "scanTo":
5414
+ return { cause: "broad-recognizer", detail: "scanTo (any first char)" };
5415
+ // A run opens with its first line's prefix.
5416
+ case "lines":
5417
+ return walk(d.first ?? d.prefix);
5418
+ // `guard` (the `gate()` state predicate) has a genuinely-`any` first-set of
5419
+ // its own — it is the poison. `withCtx`/`recover` FORWARD their inner
5420
+ // first-set (see firstSetOf), so a broad result comes from the inner parser:
5421
+ // walk into it for a precise cause.
5422
+ case "guard":
5423
+ return { cause: "opaque-wrapper", detail: `opaque wrapper (${d.tag})` };
5424
+ // Zero-width and dropped from a sequence's first-set (isZeroWidthAssertion),
5425
+ // so it is never the reason an arm is broad — but it can be reached as the
5426
+ // sole term of a degenerate arm. Report it precisely rather than as a wrapper.
5427
+ case "adjacency":
4609
5428
  return { cause: "broad-recognizer", detail: `${d.polarity}() (zero-width assertion)` };
4610
5429
  // attempt/withCtx/recover FORWARD their inner first-set (transparent for
4611
5430
  // dispatch), so a broad result comes from the inner parser — walk into it.
@@ -5245,284 +6064,124 @@ function reachesMarked(root, successors, memo) {
5245
6064
  const k = visit(child);
5246
6065
  if (low[k] < low[at]) low[at] = low[k];
5247
6066
  if (found[k]) found[at] = true;
5248
- }
5249
- }
5250
- if (low[at] === at) {
5251
- const answer = found[at];
5252
- let member;
5253
- do {
5254
- member = stack.pop();
5255
- memo.set(member, answer);
5256
- } while (member !== node2);
5257
- }
5258
- return at;
5259
- };
5260
- return found[visit(root)];
5261
- }
5262
-
5263
- // src/compiler/degradation.ts
5264
- function formatDegradation(d) {
5265
- return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
5266
- }
5267
- var DETAIL_CAP = 8;
5268
- function formatDegradations(list) {
5269
- const byCode = /* @__PURE__ */ new Map();
5270
- for (const d of list) {
5271
- const bucket = byCode.get(d.code);
5272
- if (bucket) bucket.push(d);
5273
- else byCode.set(d.code, [d]);
5274
- }
5275
- const out = [];
5276
- for (const [code, items] of byCode) {
5277
- for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
5278
- if (items.length > DETAIL_CAP) {
5279
- out.push(
5280
- `[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
5281
- );
5282
- }
5283
- }
5284
- return out;
5285
- }
5286
- var _sinks = [];
5287
- function beginDegradationCapture() {
5288
- _sinks.push(/* @__PURE__ */ new Map());
5289
- }
5290
- function degradationCaptureDepth() {
5291
- return _sinks.length;
5292
- }
5293
- function unwindDegradationCapture(depth) {
5294
- const found = [];
5295
- while (_sinks.length > depth) {
5296
- const sink = _sinks.pop();
5297
- found.unshift(...sink.values());
5298
- }
5299
- return found;
5300
- }
5301
- function resolveDegradationLevel(explicit) {
5302
- if (explicit !== void 0) return explicit;
5303
- const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
5304
- if (env === "off" || env === "warn" || env === "error") return env;
5305
- return "warn";
5306
- }
5307
- function degradationKey(d) {
5308
- return JSON.stringify([d.code, d.where, d.subject]);
5309
- }
5310
- function recordDegradation(d) {
5311
- const level = resolveDegradationLevel();
5312
- if (level === "off") return;
5313
- const key = degradationKey(d);
5314
- const sink = _sinks[_sinks.length - 1];
5315
- if (sink) {
5316
- if (!sink.has(key)) sink.set(key, d);
5317
- return;
5318
- }
5319
- if (_immediate.has(key)) return;
5320
- _immediate.add(key);
5321
- if (level === "error") throw new Error(`parseman: degraded compilation path
5322
- ${formatDegradation(d)}`);
5323
- console.warn(formatDegradation(d));
5324
- }
5325
- var _immediate = /* @__PURE__ */ new Set();
5326
- function beginCompileDegradationDrain() {
5327
- if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
5328
- };
5329
- const depth = degradationCaptureDepth();
5330
- beginDegradationCapture();
5331
- return (report) => {
5332
- const found = unwindDegradationCapture(depth);
5333
- if (!report || found.length === 0) return;
5334
- const fresh = found.filter((d) => {
5335
- const k = degradationKey(d);
5336
- if (_immediate.has(k)) return false;
5337
- _immediate.add(k);
5338
- return true;
5339
- });
5340
- if (fresh.length === 0) return;
5341
- const lines2 = formatDegradations(fresh);
5342
- if (resolveDegradationLevel() === "error") {
5343
- throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
5344
- ${lines2.join("\n")}`);
5345
- }
5346
- for (const l of lines2) console.warn(l);
5347
- };
5348
- }
5349
-
5350
- // src/compiler/build-arity.ts
5351
- function cstOutputHost(build) {
5352
- return build?._parsemanCstOutput === true;
5353
- }
5354
- var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
5355
- var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
5356
- var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
5357
- var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
5358
- function confirmedBuildArity(src) {
5359
- const s = src.trim();
5360
- if (NATIVE_CODE_RE.test(s)) return null;
5361
- if (/\barguments\b/.test(s)) return null;
5362
- if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
5363
- const inner = paramListText(s);
5364
- if (inner === null) return null;
5365
- if (inner.trim() === "") return 0;
5366
- const parts = splitTopLevel(inner);
5367
- if (parts === null) return null;
5368
- for (const part of parts) {
5369
- if (!isConfirmableParam(part.trim())) return null;
5370
- }
5371
- return parts.length;
5372
- }
5373
- function paramListText(s) {
5374
- const open = PARAM_LIST_OPEN_RE.exec(s);
5375
- if (!open) return null;
5376
- const start = open[0].length;
5377
- const end = matchingParen(s, start);
5378
- if (end === null) return null;
5379
- if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
5380
- return s.slice(start, end);
5381
- }
5382
- function matchingParen(s, start) {
5383
- let depth = 0;
5384
- for (let i = start; i < s.length; i++) {
5385
- const c = s[i];
5386
- if (c === '"' || c === "'" || c === "`") {
5387
- const close = skipString(s, i);
5388
- if (close === null) return null;
5389
- i = close;
5390
- continue;
5391
- }
5392
- if (c === "(" || c === "[" || c === "{") depth++;
5393
- else if (c === "]" || c === "}") {
5394
- if (--depth < 0) return null;
5395
- } else if (c === ")") {
5396
- if (depth === 0) return i;
5397
- depth--;
5398
- }
5399
- }
5400
- return null;
5401
- }
5402
- function skipString(s, open) {
5403
- const quote = s[open];
5404
- for (let i = open + 1; i < s.length; i++) {
5405
- if (s[i] === "\\") {
5406
- i++;
5407
- continue;
5408
- }
5409
- if (s[i] === quote) return i;
5410
- }
5411
- return null;
5412
- }
5413
- function splitTopLevel(inner) {
5414
- const parts = [];
5415
- let depth = 0;
5416
- let angle = 0;
5417
- let last = 0;
5418
- for (let i = 0; i < inner.length; i++) {
5419
- const c = inner[i];
5420
- if (c === "=" && inner[i + 1] === ">") {
5421
- i++;
5422
- continue;
5423
- }
5424
- if (c === '"' || c === "'" || c === "`") {
5425
- const close = skipString(inner, i);
5426
- if (close === null) return null;
5427
- i = close;
5428
- continue;
5429
- }
5430
- if (c === "(" || c === "[" || c === "{") depth++;
5431
- else if (c === ")" || c === "]" || c === "}") {
5432
- if (--depth < 0) return null;
5433
- } else if (c === "<") angle++;
5434
- else if (c === ">") {
5435
- if (--angle < 0) return null;
5436
- } else if (c === "," && depth === 0 && angle === 0) {
5437
- parts.push(inner.slice(last, i));
5438
- last = i + 1;
6067
+ }
5439
6068
  }
5440
- }
5441
- if (depth !== 0 || angle !== 0) return null;
5442
- parts.push(inner.slice(last));
5443
- return parts;
6069
+ if (low[at] === at) {
6070
+ const answer = found[at];
6071
+ let member;
6072
+ do {
6073
+ member = stack.pop();
6074
+ memo.set(member, answer);
6075
+ } while (member !== node2);
6076
+ }
6077
+ return at;
6078
+ };
6079
+ return found[visit(root)];
5444
6080
  }
5445
- function isConfirmableParam(part) {
5446
- const head = PARAM_HEAD_RE.exec(part);
5447
- if (!head) return false;
5448
- const rest = part.slice(head[0].length);
5449
- if (rest === "") return true;
5450
- if (rest[0] !== ":") return false;
5451
- return !hasDefaultAssign(rest.slice(1));
6081
+
6082
+ // src/table/factor-choice.ts
6083
+ var DERIVED = /* @__PURE__ */ new Set(["_tag", "_meta", "_def", "_parseScalar", "_stickyRegex", "parse"]);
6084
+ function isCombinator(v) {
6085
+ return typeof v === "object" && v !== null && "_def" in v && "_meta" in v;
6086
+ }
6087
+ function sameComb(a, b, depth) {
6088
+ if (a === b) return true;
6089
+ if (depth > 32 || a._tag !== b._tag) return false;
6090
+ for (const k of Object.keys(a)) if (!DERIVED.has(k)) return false;
6091
+ for (const k of Object.keys(b)) if (!DERIVED.has(k)) return false;
6092
+ return sameFields(a._def, b._def, depth, void 0);
6093
+ }
6094
+ function sameValue(u, v, depth) {
6095
+ if (u === v) return true;
6096
+ if (isCombinator(u) && isCombinator(v)) return sameComb(u, v, depth + 1);
6097
+ if (Array.isArray(u) && Array.isArray(v)) return u.length === v.length && u.every((x, i) => sameValue(x, v[i], depth));
6098
+ if (typeof u === "object" && u !== null && typeof v === "object" && v !== null && Object.getPrototypeOf(u) === Object.prototype && Object.getPrototypeOf(v) === Object.prototype) {
6099
+ return sameFields(u, v, depth, void 0);
6100
+ }
6101
+ return false;
5452
6102
  }
5453
- function hasDefaultAssign(annotation) {
5454
- for (let i = 0; i < annotation.length; i++) {
5455
- if (annotation[i] !== "=") continue;
5456
- if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
5457
- i++;
6103
+ function sameFields(x, y, depth, skip) {
6104
+ const kx = Object.keys(x).filter((k) => k !== skip && x[k] !== void 0);
6105
+ const ky = Object.keys(y).filter((k) => k !== skip && y[k] !== void 0);
6106
+ if (kx.length !== ky.length) return false;
6107
+ for (const k of kx) {
6108
+ if (!(k in y)) return false;
6109
+ const u = x[k];
6110
+ const v = y[k];
6111
+ if (k === "fn" && typeof u === "function" && typeof v === "function" && u !== v) {
6112
+ if (typeof x.fnSrc !== "string" || x.fnSrc === "" || x.fnSrc !== y.fnSrc) return false;
5458
6113
  continue;
5459
6114
  }
5460
- const prev = annotation[i - 1];
5461
- if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
5462
- return true;
6115
+ if (!sameValue(u, v, depth)) return false;
5463
6116
  }
5464
- return false;
5465
- }
5466
- function buildAnalysisSrc(def) {
5467
- return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
6117
+ return true;
5468
6118
  }
5469
- var RESOLVER_REASONS = {
5470
- "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
5471
- "arguments": "its body references `arguments`",
5472
- "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
5473
- "not-a-function": "the binding it names is not a function declaration",
5474
- "unresolved-import": "its module could not be resolved or parsed",
5475
- "not-found": "the name did not resolve to any binding",
5476
- "computed": "it is a computed expression",
5477
- "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
5478
- "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
5479
- };
5480
- function unconfirmableReason(def, src) {
5481
- const declared = def.buildArityUnresolved;
5482
- if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
5483
- const s = src.trim();
5484
- const params = s.slice(0, s.indexOf(")") + 1);
5485
- if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
5486
- if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
5487
- if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
5488
- return "it names a binding this build could not resolve to a function declaration";
6119
+ function rewrap(w, body) {
6120
+ const d = w._def;
6121
+ let out;
6122
+ if (d.tag === "leaf") {
6123
+ out = d.cstValue === "source" ? sourceLeaf(body, d.fn) : leaf(body, d.fn);
6124
+ if (d.fnSrc !== void 0) out._def.fnSrc = d.fnSrc;
6125
+ } else if (d.tag === "grammar") {
6126
+ out = d.clearTrivia === true ? noTrivia(body) : parser({ trivia: d.triviaParser ?? null }, body);
6127
+ } else return void 0;
6128
+ return sameFields(d, out._def, 0, "parser") ? out : void 0;
6129
+ }
6130
+ function unusedOf(seq) {
6131
+ return seq._def.tag === "sequence" && seq._def.valueUnused === true;
6132
+ }
6133
+ function never(c) {
6134
+ const t2 = c._def.tag;
6135
+ return t2 === "optional" || t2 === "many";
6136
+ }
6137
+ function factorSharedEnds(d) {
6138
+ const arms = d.parsers;
6139
+ if (arms.length < 2) return void 0;
6140
+ if (d.strategy.tag !== "firstMatch" && d.strategy.tag !== "sharedPrefix") return void 0;
6141
+ if (d.gates.some((g) => g !== null) || d.autoNot.some((a) => a !== null)) return void 0;
6142
+ const shapes = [];
6143
+ for (const arm of arms) {
6144
+ const wrappers = [];
6145
+ let c = arm;
6146
+ while ((c._def.tag === "leaf" || c._def.tag === "grammar") && wrappers.length < 4) {
6147
+ wrappers.push(c);
6148
+ c = c._def.parser;
6149
+ }
6150
+ if (c._def.tag !== "sequence" || c._def.parsers.length < 2) return void 0;
6151
+ shapes.push({ wrappers, terms: c._def.parsers, seq: c });
6152
+ }
6153
+ const first = shapes[0];
6154
+ const n = first.terms.length;
6155
+ for (const s of shapes) {
6156
+ if (s.wrappers.length !== first.wrappers.length || s.terms.length !== n) return void 0;
6157
+ if (unusedOf(s.seq) !== unusedOf(first.seq)) return void 0;
6158
+ for (let j = 0; j < s.wrappers.length; j++) {
6159
+ const a = first.wrappers[j]._def;
6160
+ const b = s.wrappers[j]._def;
6161
+ if (a.tag !== b.tag || !sameFields(a, b, 0, "parser")) return void 0;
6162
+ }
6163
+ }
6164
+ let at = -1;
6165
+ for (let i = 0; i < n; i++) {
6166
+ if (shapes.every((s) => sameComb(s.terms[i], first.terms[i], 0))) continue;
6167
+ if (at >= 0) return void 0;
6168
+ at = i;
6169
+ }
6170
+ if (at < 0) return void 0;
6171
+ for (let i = at + 1; i < n; i++) if (!never(first.terms[i])) return void 0;
6172
+ if (arms.some((a) => mayCommitFailure(a))) return void 0;
6173
+ const middle = choice(...shapes.map((s) => s.terms[at]));
6174
+ if (middle._def.tag === "choice" && middle._def.autoNot.some((a) => a !== null)) return void 0;
6175
+ const st = middle._def.tag === "choice" ? middle._def.strategy : void 0;
6176
+ if (st === void 0 || st.tag !== "firstMatch" && st.tag !== "sharedPrefix" && !(st.tag === "literalsLongestFirst" && st.sortedIndices.every((x, i) => x === i))) return void 0;
6177
+ let out = sequence(
6178
+ ...[...first.terms.slice(0, at), middle, ...first.terms.slice(at + 1)]
6179
+ );
6180
+ if (unusedOf(first.seq)) {
6181
+ out._def.valueUnused = true;
5489
6182
  }
5490
- return "its parameter list could not be parsed";
5491
- }
5492
- function confirmedArityForDef(def) {
5493
- if (def.buildArity !== void 0) return def.buildArity;
5494
- const src = buildAnalysisSrc(def);
5495
- const arity = confirmedBuildArity(src);
5496
- if (arity !== null) return arity;
5497
- const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
5498
- recordDegradation({
5499
- code: "build-arity-unconfirmed",
5500
- severity: "warn",
5501
- where: `node("${def.type ?? "<inferred>"}")`,
5502
- subject,
5503
- fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and hands it \`_ctx.state\` on every match`,
5504
- otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
5505
- });
5506
- return null;
5507
- }
5508
- function buildReadsRaw(def) {
5509
- if (!def.build) return true;
5510
- if (def.buildRawUnused === true) return false;
5511
- const arity = confirmedArityForDef(def);
5512
- if (arity === null) return true;
5513
- return arity >= 4;
5514
- }
5515
- function buildReadsTrivia(def) {
5516
- if (!def.build) return true;
5517
- const arity = confirmedArityForDef(def);
5518
- if (arity === null) return true;
5519
- return arity >= 5;
5520
- }
5521
- function buildReadsState(def) {
5522
- if (!def.build) return true;
5523
- const arity = confirmedArityForDef(def);
5524
- if (arity === null) return true;
5525
- return arity >= 6;
6183
+ for (let j = first.wrappers.length - 1; j >= 0 && out !== void 0; j--) out = rewrap(first.wrappers[j], out);
6184
+ return out === void 0 ? void 0 : attempt(out);
5526
6185
  }
5527
6186
 
5528
6187
  // src/compiler/fields.ts
@@ -5650,10 +6309,16 @@ function branchUsesRouted(branch) {
5650
6309
  return branch.usesRouted === true || parserUsesRouted(branch.parser);
5651
6310
  }
5652
6311
  function asciiFoldKey(key) {
5653
- let out = "";
5654
- for (let i = 0; i < key.length; i++) {
6312
+ let i = 0;
6313
+ for (; i < key.length; i++) {
5655
6314
  const c = key.charCodeAt(i);
5656
- out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
6315
+ if (c >= 65 && c <= 90) break;
6316
+ }
6317
+ if (i === key.length) return key;
6318
+ let out = key.slice(0, i);
6319
+ for (; i < key.length; i++) {
6320
+ const c = key.charCodeAt(i);
6321
+ out += c >= 65 && c <= 90 ? String.fromCharCode(c + 32) : key[i];
5657
6322
  }
5658
6323
  return out;
5659
6324
  }
@@ -5701,6 +6366,7 @@ var OP_SCOPE_PLAIN = 41;
5701
6366
  var OP_LEX_BODY = 42;
5702
6367
  var OP_LEX_PROGRAM = 43;
5703
6368
  var OP_SOURCE_LEAF = 44;
6369
+ var OP_RGATE = 45;
5704
6370
  var OP_DISPATCH = 25;
5705
6371
  var OP_ROUTED = 26;
5706
6372
  var OP_NAMES = {
@@ -5720,6 +6386,7 @@ var OP_NAMES = {
5720
6386
  [OP_PEEK]: "PEEK",
5721
6387
  [OP_LEAF]: "LEAF",
5722
6388
  [OP_SOURCE_LEAF]: "SOURCE_LEAF",
6389
+ [OP_RGATE]: "RGATE",
5723
6390
  [OP_EMPTY]: "EMPTY",
5724
6391
  [OP_LIT_TRACK]: "LIT_TRACK",
5725
6392
  [OP_RX_TRACK]: "RX_TRACK",
@@ -5750,71 +6417,6 @@ var OP_NAMES = {
5750
6417
  [OP_LEX_PROGRAM]: "LEX_PROGRAM"
5751
6418
  };
5752
6419
 
5753
- // src/combinators/adjacency.ts
5754
- function adjacencyOf(p) {
5755
- return p._def.tag === "adjacency" ? p._def : null;
5756
- }
5757
- function adjacencyExpected(def) {
5758
- if (def.polarity === "adjacent") return "adjacent";
5759
- return def.kinds === void 0 ? "notAdjacent" : `notAdjacent(${def.kinds.join("|")})`;
5760
- }
5761
- function holdsAdjacency(input, cur, ctx, def) {
5762
- return adjacencyHolds(input, cur, ctx, def.polarity === "notAdjacent", def.kinds);
5763
- }
5764
- function adjacencyHolds(input, cur, ctx, negated, kinds) {
5765
- const end = probeTriviaEnd(input, cur, ctx);
5766
- if (!negated) return end === cur;
5767
- if (end === cur) return false;
5768
- if (kinds === void 0) return true;
5769
- const want = resolveAdjacencyKindMask(ctx.trivia, kinds);
5770
- const spec = analyzeLabeledTrivia(ctx.trivia);
5771
- return (triviaKindMaskAt(input, cur, spec, ctx.state) & want) !== 0;
5772
- }
5773
- function adjacencyFail(pos, def) {
5774
- return { ok: false, expected: [adjacencyExpected(def)], span: { start: pos, end: pos } };
5775
- }
5776
- var NO_STANDALONE_PARSE = "adjacency assertions are boundary tests: use adjacent()/notAdjacent() as a NON-FIRST term of a sequence(), where the preceding term defines the gap being asserted.";
5777
- function adjacencyMisuse(polarity) {
5778
- return new TypeError(`${polarity}(): ${NO_STANDALONE_PARSE}`);
5779
- }
5780
- function adjacencyCombinator(def) {
5781
- const meta = {
5782
- // Zero-width and never leading (sequence() rejects index 0), so it contributes
5783
- // no first char. `isZeroWidthAssertion` drops it from a sequence's first-set
5784
- // rather than letting `any` poison the enclosing choice's dispatch.
5785
- firstSet: { kind: "any" },
5786
- canMatchNewline: false,
5787
- isTrivia: false
5788
- };
5789
- return {
5790
- _tag: "adjacency",
5791
- _meta: meta,
5792
- _def: def,
5793
- parse() {
5794
- throw adjacencyMisuse(def.polarity);
5795
- }
5796
- };
5797
- }
5798
- function adjacent() {
5799
- return adjacencyCombinator({ tag: "adjacency", polarity: "adjacent" });
5800
- }
5801
- function notAdjacent(options) {
5802
- const kinds = options?.kinds;
5803
- if (kinds !== void 0) {
5804
- if (!Array.isArray(kinds) || kinds.length === 0) {
5805
- throw new TypeError("notAdjacent({ kinds }): kinds must be a non-empty array of trivia category names.");
5806
- }
5807
- for (const k of kinds) {
5808
- if (typeof k !== "string" || k.length === 0) {
5809
- throw new TypeError(`notAdjacent({ kinds }): every kind must be a non-empty string, got ${JSON.stringify(k)}.`);
5810
- }
5811
- }
5812
- }
5813
- return adjacencyCombinator(
5814
- kinds === void 0 ? { tag: "adjacency", polarity: "notAdjacent" } : { tag: "adjacency", polarity: "notAdjacent", kinds: [...kinds] }
5815
- );
5816
- }
5817
-
5818
6420
  // src/combinators/node.ts
5819
6421
  function unwrapChild(child) {
5820
6422
  return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
@@ -6017,7 +6619,10 @@ function selectOptionalSuffixLexBody(ir) {
6017
6619
  const token2 = { strategy: "token", estimatedOps: 2, body };
6018
6620
  return token2.estimatedOps < character.estimatedOps ? token2 : character;
6019
6621
  }
6020
- function directTokenBodyParser(parser2, resolve) {
6622
+ function reinstallsRuleTrivia(reference, target) {
6623
+ return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
6624
+ }
6625
+ function directTokenBodyParser(parser2, resolve, scope) {
6021
6626
  const outer = parser2._def;
6022
6627
  if (outer.tag !== "token") return void 0;
6023
6628
  let body = outer.parser;
@@ -6027,12 +6632,13 @@ function directTokenBodyParser(parser2, resolve) {
6027
6632
  const wrapper = body._def;
6028
6633
  if (wrapper.tag === "grammar") {
6029
6634
  if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
6635
+ if (scope !== void 0) scope.cleared = true;
6030
6636
  body = wrapper.parser;
6031
6637
  continue;
6032
6638
  }
6033
6639
  if (wrapper.tag === "lazy") {
6034
6640
  const target = resolvedLazyTarget(body, resolve);
6035
- if (target === void 0) return void 0;
6641
+ if (target === void 0 || reinstallsRuleTrivia(body, target)) return void 0;
6036
6642
  body = target;
6037
6643
  continue;
6038
6644
  }
@@ -6204,7 +6810,7 @@ function directNot2TokenBody(parser2, resolve) {
6204
6810
  terminal
6205
6811
  };
6206
6812
  }
6207
- function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6813
+ function directFixedLexNode(parser2, resolve, active, pureOnly = false, cleared = false) {
6208
6814
  let current = parser2;
6209
6815
  const wrappers = /* @__PURE__ */ new Set();
6210
6816
  while (!wrappers.has(current)) {
@@ -6212,7 +6818,7 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6212
6818
  const def = current._def;
6213
6819
  if (def.tag === "lazy") {
6214
6820
  const target = resolvedLazyTarget(current, resolve);
6215
- if (target === void 0) return void 0;
6821
+ if (target === void 0 || reinstallsRuleTrivia(current, target)) return void 0;
6216
6822
  current = target;
6217
6823
  continue;
6218
6824
  }
@@ -6230,30 +6836,33 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6230
6836
  if (terminal !== void 0) return { kind: "terminal", terminal };
6231
6837
  const def = current._def;
6232
6838
  if (def.tag === "grammar") {
6839
+ if (def.triviaParser === void 0 && def.captureTrivia !== true && def.rootCapture !== "opaque" && def.constructionCaptureTriviaKinds === void 0) {
6840
+ return directFixedLexNode(def.parser, resolve, active, pureOnly, cleared || def.clearTrivia === true);
6841
+ }
6233
6842
  if (!pureOnly || def.parser._def.tag !== "token" && (def.clearTrivia !== true || def.triviaParser !== void 0 || def.captureTrivia === true || def.rootCapture === "opaque")) return void 0;
6234
- return directFixedLexNode(def.parser, resolve, active, true);
6843
+ return directFixedLexNode(def.parser, resolve, active, true, cleared);
6235
6844
  }
6236
6845
  if (def.tag === "sequence") {
6237
6846
  if (def.parsers.length < 2 || def.parsers.length > 5) return void 0;
6238
- const parts = def.parsers.map((part) => directFixedLexNode(part, resolve, active, pureOnly));
6847
+ const parts = def.parsers.map((part) => directFixedLexNode(part, resolve, active, pureOnly, cleared));
6239
6848
  if (parts.some((part) => part === void 0)) return void 0;
6240
6849
  return { kind: "sequence", parts };
6241
6850
  }
6242
6851
  if (def.tag === "choice") {
6243
- if (def.parsers.length !== 2 && def.parsers.length !== 4 && def.parsers.length !== 8 || def.strategy.tag !== "firstMatch" || def.gates.some((gate) => gate !== null) || def.autoNot.some((check) => check !== null)) return void 0;
6244
- const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve, active, pureOnly));
6852
+ if (def.parsers.length < 2 || def.strategy.tag !== "firstMatch" || def.gates.some((gate) => gate !== null) || def.autoNot.some((check) => check !== null)) return void 0;
6853
+ const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve, active, pureOnly, cleared));
6245
6854
  if (arms.some((arm) => arm === void 0)) return void 0;
6246
- const final = classifyFinalChoice(def.parsers, resolve);
6247
6855
  return {
6248
6856
  kind: "choice",
6249
6857
  arms,
6250
- firstSets: final.firstSets,
6858
+ parsers: def.parsers,
6859
+ cleared,
6251
6860
  armExpected: def.parsers.map(deriveExpected),
6252
6861
  expected: def.parsers.flatMap(deriveExpected)
6253
6862
  };
6254
6863
  }
6255
6864
  if (def.tag === "not") {
6256
- const body = directFixedLexNode(def.parser, resolve, active, true);
6865
+ const body = directFixedLexNode(def.parser, resolve, active, true, cleared);
6257
6866
  return body === void 0 ? void 0 : {
6258
6867
  kind: "not",
6259
6868
  body,
@@ -6261,18 +6870,28 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false) {
6261
6870
  };
6262
6871
  }
6263
6872
  if (def.tag === "optional") {
6264
- const body = directFixedLexNode(def.parser, resolve, active, pureOnly);
6873
+ const body = directFixedLexNode(def.parser, resolve, active, pureOnly, cleared);
6265
6874
  return body === void 0 ? void 0 : { kind: "optional", body };
6266
6875
  }
6876
+ if (def.tag === "many" || def.tag === "oneOrMore") {
6877
+ const body = directFixedLexNode(def.parser, resolve, active, pureOnly, cleared);
6878
+ return body === void 0 ? void 0 : {
6879
+ kind: "repeat",
6880
+ body,
6881
+ min: def.tag === "many" ? 0 : def.min,
6882
+ max: def.max ?? -1
6883
+ };
6884
+ }
6267
6885
  return void 0;
6268
6886
  } finally {
6269
6887
  active.delete(current);
6270
6888
  }
6271
6889
  }
6272
6890
  function directFixedTokenBody(parser2, resolve) {
6273
- const body = directTokenBodyParser(parser2, resolve);
6891
+ const scope = { cleared: false };
6892
+ const body = directTokenBodyParser(parser2, resolve, scope);
6274
6893
  if (body === void 0) return void 0;
6275
- const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set());
6894
+ const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope.cleared);
6276
6895
  return root === void 0 ? void 0 : { kind: "fixed-tree", root };
6277
6896
  }
6278
6897
  function directBalancedTokenBody(parser2, resolve) {
@@ -6519,13 +7138,16 @@ var Encoder = class {
6519
7138
  }
6520
7139
  case "choice": {
6521
7140
  for (const arm of node2.arms) if (!emitNode(arm)) return false;
6522
- const op = node2.arms.length === 2 ? LEX_NODE_CHOICE2 : node2.arms.length === 4 ? LEX_NODE_CHOICE4 : node2.arms.length === 8 ? LEX_NODE_CHOICE8 : -1;
6523
- if (op < 0) return false;
6524
- words.push(op, this.expected(node2.expected));
7141
+ const final = classifyFinalChoice(
7142
+ node2.parsers,
7143
+ this.refResolver(),
7144
+ node2.cleared ? void 0 : this.activeTrivia
7145
+ );
7146
+ const classes = final.firstSets.map((first, i) => final.nullable[i] ? -1 : this.charClass(first));
7147
+ const exclusive = final.exclusive && classes.every((cls) => cls >= 0);
7148
+ words.push(LEX_NODE_CHOICE, node2.arms.length, exclusive ? 1 : 0, this.expected(node2.expected));
6525
7149
  for (let i = 0; i < node2.arms.length; i++) {
6526
- const first = node2.firstSets[i];
6527
- words.push(first.kind === "ranges" ? this.charClass(first) : -1);
6528
- words.push(this.expected(node2.armExpected[i]));
7150
+ words.push(classes[i], this.expected(node2.armExpected[i]));
6529
7151
  }
6530
7152
  return true;
6531
7153
  }
@@ -6537,6 +7159,10 @@ var Encoder = class {
6537
7159
  if (!emitNode(node2.body)) return false;
6538
7160
  words.push(LEX_NODE_OPTIONAL);
6539
7161
  return true;
7162
+ case "repeat":
7163
+ if (!emitNode(node2.body)) return false;
7164
+ words.push(LEX_NODE_REPEAT, node2.min, node2.max);
7165
+ return true;
6540
7166
  }
6541
7167
  };
6542
7168
  if (!emitNode(body.root)) return void 0;
@@ -7042,6 +7668,51 @@ var Encoder = class {
7042
7668
  if (!hasOwnTriviaBoundary(target)) return ip;
7043
7669
  return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
7044
7670
  }
7671
+ /**
7672
+ * The `OP_RGATE` operands of a choice arm that opens with `routed()`, or
7673
+ * `undefined`. Through `node()`/scope wrappers and first sequence terms, the
7674
+ * arm's next term after the routed token is found; the gate is that term's
7675
+ * first characters, with the trivia in force at the boundary before it, so
7676
+ * the arm is entered only where it can get past the token. The term must be
7677
+ * unable to match empty or to commit, so a miss is exactly that term failing
7678
+ * at the token's end with its own set.
7679
+ */
7680
+ routedArmGate(arm) {
7681
+ const walk = (p, trivia2, depth) => {
7682
+ if (depth > 16) return void 0;
7683
+ const d = p._def;
7684
+ switch (d.tag) {
7685
+ case "routed":
7686
+ return "end";
7687
+ case "node":
7688
+ return walk(d.parser, trivia2, depth + 1);
7689
+ case "grammar":
7690
+ return walk(d.parser, d.clearTrivia === true ? void 0 : d.triviaParser ?? trivia2, depth + 1);
7691
+ case "sequence": {
7692
+ const head = d.parsers[0];
7693
+ if (head === void 0) return void 0;
7694
+ const r = walk(head, trivia2, depth + 1);
7695
+ if (r !== "end") return r;
7696
+ const next2 = d.parsers[1];
7697
+ return next2 === void 0 ? "end" : { next: next2, boundary: trivia2 };
7698
+ }
7699
+ default:
7700
+ return void 0;
7701
+ }
7702
+ };
7703
+ const follow = walk(arm, this.activeTrivia, 0);
7704
+ if (follow === void 0 || follow === "end") return void 0;
7705
+ const rr = this.refResolver();
7706
+ const { next, boundary } = follow;
7707
+ if (matchesEmpty(next, /* @__PURE__ */ new Set(), rr) || mayCommitFailure(next, rr, this.commitFailureMemo)) return void 0;
7708
+ const nextDef = next._def;
7709
+ if (nextDef.tag !== "literal" && nextDef.tag !== "regex" && nextDef.tag !== "keywords" && nextDef.tag !== "label") return void 0;
7710
+ const first = firstSetOf(next, /* @__PURE__ */ new Set(), rr, boundary);
7711
+ const cls = this.charClass(boundary === void 0 ? first : union(first, firstSetOf(boundary, /* @__PURE__ */ new Set(), rr)));
7712
+ if (cls < 0) return void 0;
7713
+ const miss = nextDef.tag === "label" ? deriveExpected(next) : directTerminalFailureExpected(nextDef);
7714
+ return { cls, fx: this.expected(miss) };
7715
+ }
7045
7716
  node(p) {
7046
7717
  const lazyRef = p._def.tag === "lazy";
7047
7718
  const scopeKey = lazyRef ? this.activeTrivia : void 0;
@@ -7166,6 +7837,10 @@ var Encoder = class {
7166
7837
  return head;
7167
7838
  }
7168
7839
  case "choice": {
7840
+ if (this.plan === void 0) {
7841
+ const factored = factorSharedEnds(d);
7842
+ if (factored !== void 0) return this.node(factored).ip;
7843
+ }
7169
7844
  if (d.strategy.tag === "greedyClassify") {
7170
7845
  const superIndex = d.strategy.superIndex;
7171
7846
  const sup = this.node(d.parsers[superIndex]).ip;
@@ -7189,9 +7864,12 @@ var Encoder = class {
7189
7864
  const kids = arms.map((c, k) => {
7190
7865
  const src = order[k];
7191
7866
  const checks = d.autoNot[src];
7192
- const inner = this.node(c).ip;
7193
- const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
7194
7867
  const gate = d.gates[src];
7868
+ const plain2 = (checks === null || checks === void 0 || checks.length === 0) && (gate === null || gate === void 0);
7869
+ const routedGate = plain2 ? this.routedArmGate(c) : void 0;
7870
+ const body = this.node(c).ip;
7871
+ const inner = routedGate === void 0 ? body : this.emit(OP_RGATE, routedGate.cls, body, routedGate.fx);
7872
+ const ip = checks === null || checks === void 0 || checks.length === 0 ? inner : this.reject(inner, checks);
7195
7873
  const gated = gate === null || gate === void 0 ? ip : this.emit(OP_ARMGATE, this.fn(gate, d.gateSrcs?.[src] ?? null), ip, this.expected(deriveExpected(c)));
7196
7874
  return this.covWrap(gated, armCovIds?.[src], 1);
7197
7875
  });
@@ -7515,6 +8193,7 @@ var Encoder = class {
7515
8193
  const slots = (ip) => {
7516
8194
  switch (this.code[ip]) {
7517
8195
  case OP_GATE:
8196
+ case OP_RGATE:
7518
8197
  return [ip + 2];
7519
8198
  case OP_RULE:
7520
8199
  case OP_OPT:
@@ -8742,6 +9421,7 @@ function childSlots(code, ip, out) {
8742
9421
  case OP_LEAF:
8743
9422
  case OP_SOURCE_LEAF:
8744
9423
  case OP_ARMGATE:
9424
+ case OP_RGATE:
8745
9425
  out.push(code[ip + 2]);
8746
9426
  return true;
8747
9427
  // `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
@@ -8825,6 +9505,42 @@ function reachableSites(code, roots) {
8825
9505
  }
8826
9506
  return seen;
8827
9507
  }
9508
+ function passCollapse(code, ip, hostCst) {
9509
+ const flags = code[ip + 3];
9510
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return false;
9511
+ if (flags !== 32 && flags !== 34) return false;
9512
+ let at = code[ip + 2];
9513
+ for (let n = 0; n < 8; n++) {
9514
+ const op = code[at];
9515
+ if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[at + 3] === 0) at = code[at + 2];
9516
+ else if (op === OP_RULE) at = code[at + 1];
9517
+ else break;
9518
+ }
9519
+ return code[at] === OP_NODE;
9520
+ }
9521
+ function gatedPassCollapse(code, ip, hostCst) {
9522
+ const flags = code[ip + 3];
9523
+ if (hostCst || code[ip] !== OP_NODE || code[ip + 1] < 0 || code[ip + 4] >= 0) return void 0;
9524
+ if (flags !== 32 && flags !== 34) return void 0;
9525
+ const seq = code[ip + 2];
9526
+ if (code[seq] !== OP_SEQ && code[seq] !== OP_SEQV) return void 0;
9527
+ const n = code[seq + 1];
9528
+ if (n < 2) return void 0;
9529
+ const leads = [];
9530
+ const lits = [];
9531
+ for (let i = 0; i < n - 1; i++) {
9532
+ const t2 = code[seq + 2 + i];
9533
+ if (code[t2] !== OP_OPT && code[t2] !== OP_NOT) return void 0;
9534
+ const g = code[t2 + 1];
9535
+ if (code[g] === OP_GATE) leads.push(g);
9536
+ else if (code[g] === OP_LIT) lits.push(code[g + 1]);
9537
+ else return void 0;
9538
+ }
9539
+ const last = code[seq + 2 + n - 1];
9540
+ let at = last;
9541
+ for (let k = 0; k < 8 && (code[at] === OP_GATE || code[at] === OP_RULE); k++) at = code[at] === OP_RULE ? code[at + 1] : code[at + 2];
9542
+ return code[at] === OP_NODE ? { leads, lits, last } : void 0;
9543
+ }
8828
9544
  function transfer(code, ip, at, hostCst) {
8829
9545
  const op = code[ip];
8830
9546
  if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
@@ -8836,14 +9552,18 @@ function transfer(code, ip, at, hostCst) {
8836
9552
  }
8837
9553
  if (op === OP_NODE || op === OP_NODE_TRACK) {
8838
9554
  const flags = code[ip + 3];
9555
+ if (passCollapse(code, ip, hostCst)) return at;
9556
+ const gated = gatedPassCollapse(code, ip, hostCst) !== void 0;
8839
9557
  const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
8840
9558
  if (directChildren) {
8841
- return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
9559
+ const framed2 = { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
9560
+ return gated ? meet(at, framed2) : framed2;
8842
9561
  }
8843
9562
  const cap = (flags & 4) !== 0 || hostCst ? CAP_ON : CAP_OFF;
8844
9563
  const raw = !hostCst && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags & 2) !== 0 ? RAW_OMIT : RAW_CAPTURE;
8845
9564
  if (at.buf && raw === at.raw && cap === at.cap) return at;
8846
- return { tri: at.tri, buf: true, raw, cap };
9565
+ const framed = { tri: at.tri, buf: true, raw, cap };
9566
+ return gated ? meet(at, framed) : framed;
8847
9567
  }
8848
9568
  if (op === OP_TOKEN) {
8849
9569
  if (at.tri === TRI_NONE && !at.buf) return at;
@@ -8881,6 +9601,40 @@ function computeSiteLabels(code, roots, hostCst) {
8881
9601
  }
8882
9602
  return { at: (ip) => labels.get(ip) ?? TOP };
8883
9603
  }
9604
+ function scopeIsIdentity(code, ip, at) {
9605
+ const op = code[ip];
9606
+ if (op !== OP_SCOPE_PLAIN && !(op === OP_SCOPE && code[ip + 3] === 0)) return false;
9607
+ const ki = code[ip + 1];
9608
+ return at.tri === (ki < 0 ? TRI_NONE : ki);
9609
+ }
9610
+ function scanHandoffNeeded(code, ip, labels) {
9611
+ const seen = /* @__PURE__ */ new Set();
9612
+ const stack = [ip];
9613
+ const kids = [];
9614
+ while (stack.length > 0) {
9615
+ const at = stack.pop();
9616
+ if (seen.has(at)) continue;
9617
+ seen.add(at);
9618
+ const l = labels.at(at);
9619
+ if (l.tri === TRI_UNKNOWN) return true;
9620
+ const op = code[at];
9621
+ if (op === OP_SCAN) return true;
9622
+ if (op === OP_TOKEN || op === OP_SCOPE_CAP) continue;
9623
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE) && !(code[at + 1] >= 0 && l.tri === code[at + 1] && (op === OP_SCOPE_PLAIN || code[at + 3] === 0))) continue;
9624
+ kids.length = 0;
9625
+ if (!childSlots(code, at, kids)) return true;
9626
+ for (const c of kids) stack.push(c);
9627
+ }
9628
+ return false;
9629
+ }
9630
+ function triviaLeadRanges(tri, trivia2) {
9631
+ if (tri === TRI_NONE) return [];
9632
+ if (tri < 0) return void 0;
9633
+ const fs = trivia2[tri]?._meta.firstSet;
9634
+ if (fs === void 0) return void 0;
9635
+ if (fs.kind === "empty") return [];
9636
+ return fs.kind === "ranges" && fs.ranges !== void 0 ? fs.ranges : void 0;
9637
+ }
8884
9638
 
8885
9639
  // src/table/scalar-terminal.ts
8886
9640
  function makeScalarRecognizer(op, spec) {
@@ -8918,6 +9672,12 @@ function scalarTerminalNotChild(code, ip) {
8918
9672
  const op = code[child];
8919
9673
  return op === OP_RX || op === OP_LIT ? child : -1;
8920
9674
  }
9675
+ function scalarTerminalPeekChild(code, ip) {
9676
+ if (code[ip] !== OP_PEEK) return -1;
9677
+ const child = code[ip + 1];
9678
+ const op = code[child];
9679
+ return op === OP_RX || op === OP_LIT ? child : -1;
9680
+ }
8921
9681
  function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, throughPeek = false) {
8922
9682
  const seen = /* @__PURE__ */ new Set();
8923
9683
  let at = ip;
@@ -9095,6 +9855,59 @@ function leadingTriviaFieldAt(code, k, ip) {
9095
9855
  return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
9096
9856
  }
9097
9857
 
9858
+ // src/table/hold-gap.ts
9859
+ var WRAPPERS = /* @__PURE__ */ new Set([
9860
+ OP_NODE,
9861
+ OP_XFORM,
9862
+ OP_LEAF,
9863
+ OP_SOURCE_LEAF,
9864
+ OP_TOKEN,
9865
+ OP_SCOPE,
9866
+ OP_SCOPE_CAP,
9867
+ OP_SCOPE_PLAIN,
9868
+ OP_FIELD,
9869
+ OP_LABEL,
9870
+ OP_EXPECT,
9871
+ OP_WITHCTX,
9872
+ OP_RULE,
9873
+ OP_ATTEMPT,
9874
+ OP_COV
9875
+ ]);
9876
+ function rowNullable(code, k, ip, memo) {
9877
+ const hit = memo.get(ip);
9878
+ if (hit !== void 0) return hit;
9879
+ memo.set(ip, true);
9880
+ const op = code[ip];
9881
+ const kids = [];
9882
+ let out = true;
9883
+ if (op === OP_GATE) out = false;
9884
+ else if (op === OP_LIT || op === OP_LIT_CI) out = k[code[ip + 1]].length === 0;
9885
+ else if (op === OP_RX) {
9886
+ const re = k[code[ip + 1]];
9887
+ out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
9888
+ } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
9889
+ childSlots(code, ip, kids);
9890
+ out = kids.every((c) => rowNullable(code, k, c, memo));
9891
+ } else if (op === OP_CHOICE) {
9892
+ childSlots(code, ip, kids);
9893
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
9894
+ } else if (op === OP_REP || op === OP_REPV) {
9895
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
9896
+ } else if (WRAPPERS.has(op)) {
9897
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
9898
+ }
9899
+ memo.set(ip, out);
9900
+ return out;
9901
+ }
9902
+ function holdsGap(code, k, base, n, i, memo) {
9903
+ if (i < 1 || i + 1 >= n) return false;
9904
+ const term = code[base + i];
9905
+ if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
9906
+ const next = code[base + i + 1];
9907
+ if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
9908
+ return !rowNullable(code, k, next, memo);
9909
+ }
9910
+
9098
9911
  // src/table/emit-assembly.ts
9099
9912
  var Unemittable = class extends Error {
9100
9913
  construct;
@@ -9175,7 +9988,10 @@ var EMITTED_PARAMS = [
9175
9988
  "triviaFieldCapture",
9176
9989
  // Appended for the deferred-commit trivia skip (`trivia-gap.ts`); old
9177
9990
  // factories ignore it.
9178
- "skipDeferredTrivia"
9991
+ "skipDeferredTrivia",
9992
+ // Appended for the pass-through collapse (`run-support.ts`); old factories
9993
+ // ignore it.
9994
+ "collapseEmpty"
9179
9995
  ];
9180
9996
  var RUNTIME_PRELUDE = `
9181
9997
  let _pfScan=null
@@ -9372,6 +10188,24 @@ ${fast}
9372
10188
  ${scanned}
9373
10189
  }`;
9374
10190
  }
10191
+ function emitHoldTerm(callee, dst, t2, l, skip) {
10192
+ const fast = `const ${t2}v=${callee}(input,cur,ctx)
10193
+ if(${t2}v===FAIL)return FAIL
10194
+ ${dst}=${t2}v
10195
+ cur=EC.e`;
10196
+ if (l.tri === TRI_NONE) return fast;
10197
+ const held = `const ${t2}s=${skip}(input,cur,ctx)
10198
+ const ${t2}v=${callee}(input,${t2}s,ctx)
10199
+ if(${t2}v===FAIL)return FAIL
10200
+ ${dst}=${t2}v
10201
+ cur=${t2}s`;
10202
+ if (l.tri !== TRI_UNKNOWN) return held;
10203
+ return `if(ctx.trivia===undefined){
10204
+ ${fast}
10205
+ }else{
10206
+ ${held}
10207
+ }`;
10208
+ }
9375
10209
  function leadSkip(hasTrivia, leadTrivia, skip) {
9376
10210
  if (hasTrivia === "false") return "{}";
9377
10211
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -9413,6 +10247,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
9413
10247
  const reachable = [...reachableSites(code, roots)];
9414
10248
  const labels = computeSiteLabels(code, roots, hostCst);
9415
10249
  const scalarSpecs = /* @__PURE__ */ new Set();
10250
+ const nullable2 = /* @__PURE__ */ new Map();
9416
10251
  const largeChoiceScalarSpecs = /* @__PURE__ */ new Set();
9417
10252
  const largeChoiceLiteralFamilies = /* @__PURE__ */ new Map();
9418
10253
  const largeChoiceScalarSequences = /* @__PURE__ */ new Map();
@@ -9737,9 +10572,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9737
10572
  const op = code[ip];
9738
10573
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
9739
10574
  if (op === OP_RULE) return code[ip + 1];
9740
- if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
9741
- return code[ip + 2];
9742
- }
10575
+ if (scopeIsIdentity(code, ip, labels.at(ip))) return code[ip + 2];
9743
10576
  return void 0;
9744
10577
  }
9745
10578
  function lower(ip, fname) {
@@ -9861,6 +10694,22 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
9861
10694
  return `${head}
9862
10695
  if(${gateMissTest(ip)}){ctx._fe=pos;ctx._fx=${xf};return FAIL}
9863
10696
  return ${child}(input,pos,ctx)
10697
+ }`;
10698
+ }
10699
+ case OP_RGATE: {
10700
+ const child = link(code[ip + 2]);
10701
+ if (cfg.tolerant || cfg.probe) return `${head}
10702
+ return ${child}(input,pos,ctx)
10703
+ }`;
10704
+ const resolved = t2.cc[code[ip + 1]];
10705
+ const ci = classes.push([resolved]) - 1;
10706
+ classPlan.push([code[ip + 1]]);
10707
+ const cls = hoist("cl", `CLS[${ci}][0]`);
10708
+ const xf = fxRef(code[ip + 3]);
10709
+ return `${head}
10710
+ const it=ctx._routed
10711
+ if(it!==undefined&&it.span.start===pos&&!classHas(${cls},lead(input,it.span.end))){ctx._fe=it.span.end;ctx._fx=${xf};return FAIL}
10712
+ return ${child}(input,pos,ctx)
9864
10713
  }`;
9865
10714
  }
9866
10715
  case OP_ARMGATE: {
@@ -10135,23 +10984,33 @@ return FAIL
10135
10984
  const p = tmp();
10136
10985
  return `${head}
10137
10986
  ${lookaheadMiss(code[ip + 1], "EC.e=pos;return null")}${emitMark(p, L.buf, L.raw, sinks)}
10138
- const v=${child}(input,pos,ctx)
10987
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
10139
10988
  ${emitRollback(p, L.buf, L.raw, sinks)}
10140
- if(v===FAIL){EC.e=pos;return null}
10989
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){EC.e=pos;return null}
10141
10990
  ctx._fe=pos
10142
10991
  ctx._fx=${xf}
10143
10992
  return FAIL
10144
10993
  }`;
10145
10994
  }
10146
10995
  case OP_PEEK: {
10996
+ const scalarChild = scalarTerminalPeekChild(code, ip);
10997
+ if (scalarChild >= 0) {
10998
+ const recognize = recognizerRef(code[scalarChild + 1]);
10999
+ const xf2 = fxRef(code[ip + 2]);
11000
+ return `${head}
11001
+ if(${recognize}(input,pos)<0){ctx._fe=pos;ctx._fx=${xf2};return FAIL}
11002
+ EC.e=pos
11003
+ return null
11004
+ }`;
11005
+ }
10147
11006
  const child = link(code[ip + 1]);
10148
11007
  const xf = fxRef(code[ip + 2]);
10149
11008
  const p = tmp();
10150
11009
  return `${head}
10151
11010
  ${lookaheadMiss(code[ip + 1], `ctx._fe=pos;ctx._fx=${xf};return FAIL`)}${emitMark(p, L.buf, L.raw, sinks)}
10152
- const v=${child}(input,pos,ctx)
11011
+ ${cfg.probe ? "const pb=ctx._probe?.best\n" : ""}const v=${child}(input,pos,ctx)
10153
11012
  ${emitRollback(p, L.buf, L.raw, sinks)}
10154
- if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
11013
+ ${cfg.probe ? "if(ctx._probe!==undefined)ctx._probe.best=pb??null\n" : ""}if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
10155
11014
  EC.e=pos
10156
11015
  return null
10157
11016
  }`;
@@ -10222,7 +11081,7 @@ return v
10222
11081
  );
10223
11082
  } else {
10224
11083
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
10225
- parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L)));
11084
+ parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L)));
10226
11085
  }
10227
11086
  names.push(vn);
10228
11087
  }
@@ -10705,6 +11564,26 @@ return nd
10705
11564
  const trailingTrivia = (flags & 128) !== 0;
10706
11565
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
10707
11566
  const leanFlags = flags & ~128;
11567
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
11568
+ return `${head}
11569
+ const v=${child}(input,pos,ctx)
11570
+ if(v!==undefined)return v
11571
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
11572
+ }`;
11573
+ }
11574
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
11575
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(labels.at(code[ip + 2]).tri, t2.trivia);
11576
+ const gp = gated !== void 0 && triviaLead !== void 0 && triviaLead.length <= 16 ? `const gc=lead(input,pos)
11577
+ if(!(${[
11578
+ ...gated.leads.map((g) => `!(${gateMissTest(g)})`),
11579
+ ...gated.lits.map((i) => `gc===${k[i].codePointAt(0)}`),
11580
+ ...triviaLead.map((r) => r.lo === r.hi ? `gc===${r.lo}` : `(gc>=${r.lo}&&gc<=${r.hi})`)
11581
+ ].join("||") || "false"})){
11582
+ const gv=${link(gated.last)}(input,pos,ctx)
11583
+ if(gv!==undefined)return gv
11584
+ return collapseEmpty(ctx,${build},input,pos,EC.e,${flags === 32})
11585
+ }
11586
+ ` : "";
10708
11587
  if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
10709
11588
  const fields = flags === 18;
10710
11589
  const collapseChildren = flags === 34;
@@ -10739,7 +11618,7 @@ sCh.push(nd)
10739
11618
  if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
10740
11619
  }`;
10741
11620
  return `${head}
10742
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11621
+ ${gp}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
10743
11622
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
10744
11623
  const flat=[]
10745
11624
  ctx._cstBuf=undefined
@@ -10814,7 +11693,7 @@ const hostKids=kids
10814
11693
  const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
10815
11694
  const tlog=buf.tl??EMPTY_TLOG`;
10816
11695
  return `${head}
10817
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
11696
+ ${!hostCst && !tracked ? gp : ""}const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
10818
11697
  const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
10819
11698
  ${openCapture}
10820
11699
  ctx.captureTrivia=${captureWide}
@@ -10884,9 +11763,15 @@ ext:[${externals.join(",")}],
10884
11763
  bind:function(xs,ps){_xScan=xs
10885
11764
  ${externals.map((ip, i) => `_xp${ip}=ps[${i}]`).join("\n")}},
10886
11765
  scan:function(s){const o=_pfScan;_pfScan=s;return o}`;
11766
+ const scannerFor = (ip) => {
11767
+ const ki = labels.at(ip).tri;
11768
+ if (ki === TRI_UNKNOWN) return "_pfScan";
11769
+ if (ki === TRI_NONE) return "null";
11770
+ return swapLegal && !triviaLabelled[ki] && t2.triviaScan[ki] != null ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
11771
+ };
10887
11772
  const externalDefs = select === void 0 ? "" : `let _xScan
10888
11773
  ${externals.map((ip) => `let _xp${ip}
10889
- function _px${ip}(input,pos,ctx){const o=_xScan(_pfScan);const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
11774
+ function _px${ip}(input,pos,ctx){const o=_xScan(${scannerFor(ip)});const v=_xp${ip}(input,pos,ctx);_xScan(o);return v}`).join("\n")}
10890
11775
  `;
10891
11776
  const source = `${RUNTIME_PRELUDE}${needsNoRawPrelude ? NO_RAW_RUNTIME_PRELUDE : ""}
10892
11777
  ${prelude.join("\n")}
@@ -11203,136 +12088,6 @@ function literal(value, opts = {}) {
11203
12088
  };
11204
12089
  }
11205
12090
 
11206
- // src/combinators/sequence.ts
11207
- function sequence(...parsers) {
11208
- let adjacency = null;
11209
- for (let i = 0; i < parsers.length; i++) {
11210
- const a = adjacencyOf(parsers[i]);
11211
- if (a === null) continue;
11212
- if (i === 0) {
11213
- throw new TypeError(
11214
- `sequence(): ${a.polarity}() cannot be the FIRST term \u2014 an adjacency assertion tests the gap after the PRECEDING term. Put a concrete term first.`
11215
- );
11216
- }
11217
- ;
11218
- (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
11219
- }
11220
- const hasAdjacency = adjacency !== null;
11221
- let leading = null;
11222
- for (let i = 1; i < parsers.length; i++) {
11223
- if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
11224
- }
11225
- const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
11226
- const meta = {
11227
- // Union through the nullable prefix — a leading optional()/many() lets a later
11228
- // term's first char start the sequence. Just `parsers[0]` under-approximates.
11229
- firstSet: sequenceFirstSet(parsers),
11230
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
11231
- isTrivia: false
11232
- };
11233
- const def = { tag: "sequence", parsers };
11234
- const scalarParsers = parsers.map(scalarOf);
11235
- const parseScalar = (input, pos, ctx) => {
11236
- let cur = pos;
11237
- if (strictArity !== 0) {
11238
- cur = scalarParsers[0](input, cur, ctx);
11239
- if (cur < 0) return cur;
11240
- const first = ctx._sv;
11241
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
11242
- cur = scalarParsers[1](input, cur, ctx);
11243
- if (cur < 0) return cur;
11244
- const second = ctx._sv;
11245
- if (strictArity === 2) {
11246
- ctx._sv = def.valueUnused ? void 0 : [first, second];
11247
- return cur;
11248
- }
11249
- if (ctx.trivia) cur = advanceTrivia(input, cur, ctx);
11250
- cur = scalarParsers[2](input, cur, ctx);
11251
- if (cur < 0) return cur;
11252
- ctx._sv = def.valueUnused ? void 0 : [first, second, ctx._sv];
11253
- return cur;
11254
- }
11255
- const values = def.valueUnused ? void 0 : [];
11256
- for (let i = 0; i < scalarParsers.length; i++) {
11257
- let termPos = cur;
11258
- if (i > 0 && ctx.trivia) termPos = advanceTrivia(input, cur, ctx);
11259
- const end = scalarParsers[i](input, termPos, ctx);
11260
- if (end < 0) return end;
11261
- if (values !== void 0) values.push(ctx._sv);
11262
- if (end > termPos || termPos === cur) cur = end;
11263
- }
11264
- ctx._sv = values;
11265
- return cur;
11266
- };
11267
- let followSentinels;
11268
- return {
11269
- _tag: "sequence",
11270
- _meta: meta,
11271
- _def: def,
11272
- _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
11273
- parse(input, pos, ctx) {
11274
- const tolerant = ctx._tolerant === true;
11275
- if (tolerant) {
11276
- followSentinels ??= parsers.map((_, i) => firstSetSentinel(
11277
- parsers.slice(i + 1).reduce(
11278
- (set, parser2) => union(set, firstSetOf(parser2)),
11279
- { kind: "empty" }
11280
- )
11281
- ));
11282
- }
11283
- const inheritedSync = ctx._sync;
11284
- const deferredTrivia = needsDeferredTriviaCommit(ctx);
11285
- const values = def.valueUnused ? void 0 : [];
11286
- let cur = pos;
11287
- try {
11288
- for (let i = 0; i < parsers.length; i++) {
11289
- if (tolerant) ctx._sync = followSentinels[i] ?? inheritedSync;
11290
- const assertion = adjacency?.[i];
11291
- if (assertion) {
11292
- if (!holdsAdjacency(input, cur, ctx, assertion)) return adjacencyFail(cur, assertion);
11293
- if (values !== void 0) values.push(null);
11294
- continue;
11295
- }
11296
- let termPos = cur;
11297
- const markTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11298
- const markLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11299
- const markRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11300
- if (ctx.trivia && i > 0) {
11301
- termPos = deferredTrivia ? commitTriviaScan(scanTriviaCompact(input, cur, ctx)) : advanceTrivia(input, cur, ctx);
11302
- }
11303
- const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
11304
- const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
11305
- const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
11306
- if (leading?.[i] === true) LEAD.at = cur;
11307
- const result = parsers[i].parse(input, termPos, ctx);
11308
- if (!result.ok) return result;
11309
- if (values !== void 0) values.push(result.value);
11310
- if (result.span.end > termPos || termPos === cur) cur = result.span.end;
11311
- else if (deferredTrivia) {
11312
- rollbackScannedTriviaAt(
11313
- ctx,
11314
- markTlog,
11315
- scanTlog,
11316
- markLog,
11317
- scanLog,
11318
- markRootLog,
11319
- scanRootLog
11320
- );
11321
- }
11322
- }
11323
- } finally {
11324
- if (tolerant) ctx._sync = inheritedSync;
11325
- }
11326
- return {
11327
- ok: true,
11328
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
11329
- value: values ?? void 0,
11330
- span: { start: pos, end: cur }
11331
- };
11332
- }
11333
- };
11334
- }
11335
-
11336
12091
  // src/combinators/ref.ts
11337
12092
  function withRuleTrivia(trivia2, ctx, run) {
11338
12093
  const savedLabels = ctx.triviaKindLabels;
@@ -11358,164 +12113,46 @@ function ref() {
11358
12113
  const slot = {
11359
12114
  _tag: "lazy",
11360
12115
  _meta: meta,
11361
- _def: {
11362
- tag: "lazy",
11363
- thunk: () => {
11364
- if (!resolved) throw UNDEFINED_REF;
11365
- return resolved;
11366
- }
11367
- },
11368
- _parseScalar(input, pos, ctx) {
11369
- const scalar = resolvedScalar;
11370
- if (!scalar) throw new Error("ref<T>() used before .define() was called");
11371
- const gt = meta.grammarTrivia;
11372
- if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
11373
- return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
11374
- }
11375
- return scalar(input, pos, ctx);
11376
- },
11377
- parse(input, pos, ctx) {
11378
- const parser2 = resolved;
11379
- if (!parser2) throw new Error("ref<T>() used before .define() was called");
11380
- const gt = meta.grammarTrivia;
11381
- if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
11382
- return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
11383
- }
11384
- return parser2.parse(input, pos, ctx);
11385
- },
11386
- define(p) {
11387
- if (resolved) throw new Error("ref<T>() already defined");
11388
- resolved = p;
11389
- resolvedScalar = scalarOf(p);
11390
- ownBoundary = hasOwnTriviaBoundary(p);
11391
- meta.firstSet = p._meta.firstSet;
11392
- meta.canMatchNewline = p._meta.canMatchNewline;
11393
- meta.isTrivia = p._meta.isTrivia;
11394
- if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
11395
- else delete meta.triviaKindLabels;
11396
- if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
11397
- else delete meta.disjoint;
11398
- }
11399
- };
11400
- return slot;
11401
- }
11402
-
11403
- // src/combinators/token.ts
11404
- function semanticLeafValue(_ctx, _input, _start, _end, value) {
11405
- return value;
11406
- }
11407
- function sourceLeafValue(ctx, input, start, end, value) {
11408
- return cstOutputHost(ctx.build) ? input.slice(start, end) : value;
11409
- }
11410
- function token(root) {
11411
- const meta = {
11412
- firstSet: root._meta.firstSet,
11413
- canMatchNewline: root._meta.canMatchNewline,
11414
- isTrivia: false
11415
- };
11416
- return {
11417
- _tag: "token",
11418
- _meta: meta,
11419
- _def: { tag: "token", parser: root },
11420
- parse(input, pos, ctx) {
11421
- const savedTrivia = ctx.trivia;
11422
- const savedKinds = ctx.triviaKindLabels;
11423
- const savedBuf = ctx._cstBuf;
11424
- const savedChildren = ctx._cstChildren;
11425
- const savedLeaves = ctx._cstLeaves;
11426
- const savedRaw = ctx._cstRawChildren;
11427
- const savedTriviaLog = ctx._cstTriviaLog;
11428
- const savedOuterTriviaLog = ctx._triviaLog;
11429
- const savedRootTriviaLog = ctx._rootTriviaLog;
11430
- const wasCapturing = cstCaptureActive(ctx);
11431
- ctx.trivia = void 0;
11432
- ctx.triviaKindLabels = void 0;
11433
- ctx._cstBuf = void 0;
11434
- ctx._cstChildren = void 0;
11435
- ctx._cstLeaves = void 0;
11436
- ctx._cstRawChildren = void 0;
11437
- ctx._cstTriviaLog = void 0;
11438
- ctx._triviaLog = void 0;
11439
- ctx._rootTriviaLog = void 0;
11440
- let result;
11441
- try {
11442
- result = root.parse(input, pos, ctx);
11443
- } finally {
11444
- ctx.trivia = savedTrivia;
11445
- ctx.triviaKindLabels = savedKinds;
11446
- ctx._cstBuf = savedBuf;
11447
- ctx._cstChildren = savedChildren;
11448
- ctx._cstLeaves = savedLeaves;
11449
- ctx._cstRawChildren = savedRaw;
11450
- ctx._cstTriviaLog = savedTriviaLog;
11451
- ctx._triviaLog = savedOuterTriviaLog;
11452
- ctx._rootTriviaLog = savedRootTriviaLog;
11453
- }
11454
- if (!result.ok) return result;
11455
- const span = result.span;
11456
- const value = input.slice(pos, span.end);
11457
- if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
11458
- return { ok: true, value, span };
11459
- }
11460
- };
11461
- }
11462
- function makeLeaf(root, fn, sourceCstValue) {
11463
- const cstValue = sourceCstValue ? sourceLeafValue : semanticLeafValue;
11464
- const meta = {
11465
- firstSet: root._meta.firstSet,
11466
- canMatchNewline: root._meta.canMatchNewline,
11467
- isTrivia: false
11468
- };
11469
- return {
11470
- _tag: "leaf",
11471
- _meta: meta,
11472
- _def: {
11473
- tag: "leaf",
11474
- parser: root,
11475
- fn,
11476
- ...sourceCstValue ? { cstValue: "source" } : {}
12116
+ _def: {
12117
+ tag: "lazy",
12118
+ thunk: () => {
12119
+ if (!resolved) throw UNDEFINED_REF;
12120
+ return resolved;
12121
+ }
12122
+ },
12123
+ _parseScalar(input, pos, ctx) {
12124
+ const scalar = resolvedScalar;
12125
+ if (!scalar) throw new Error("ref<T>() used before .define() was called");
12126
+ const gt = meta.grammarTrivia;
12127
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
12128
+ return withRuleTrivia(gt, ctx, () => scalar(input, pos, ctx));
12129
+ }
12130
+ return scalar(input, pos, ctx);
11477
12131
  },
11478
12132
  parse(input, pos, ctx) {
11479
- const savedBuf = ctx._cstBuf;
11480
- const savedChildren = ctx._cstChildren;
11481
- const savedLeaves = ctx._cstLeaves;
11482
- const savedRaw = ctx._cstRawChildren;
11483
- const savedTriviaLog = ctx._cstTriviaLog;
11484
- const savedOuterTriviaLog = ctx._triviaLog;
11485
- const wasCapturing = cstCaptureActive(ctx);
11486
- ctx._cstBuf = void 0;
11487
- ctx._cstChildren = void 0;
11488
- ctx._cstLeaves = void 0;
11489
- ctx._cstRawChildren = void 0;
11490
- ctx._cstTriviaLog = void 0;
11491
- ctx._triviaLog = void 0;
11492
- let result;
11493
- try {
11494
- result = root.parse(input, pos, ctx);
11495
- } finally {
11496
- ctx._cstBuf = savedBuf;
11497
- ctx._cstChildren = savedChildren;
11498
- ctx._cstLeaves = savedLeaves;
11499
- ctx._cstRawChildren = savedRaw;
11500
- ctx._cstTriviaLog = savedTriviaLog;
11501
- ctx._triviaLog = savedOuterTriviaLog;
12133
+ const parser2 = resolved;
12134
+ if (!parser2) throw new Error("ref<T>() used before .define() was called");
12135
+ const gt = meta.grammarTrivia;
12136
+ if (gt !== void 0 && ownBoundary && ctx.trivia === void 0) {
12137
+ return withRuleTrivia(gt, ctx, () => parser2.parse(input, pos, ctx));
11502
12138
  }
11503
- if (!result.ok) return result;
11504
- const value = fn(result.value, result.span);
11505
- if (wasCapturing) pushCstLeaf(ctx, {
11506
- _tag: "leaf",
11507
- value: cstValue(ctx, input, pos, result.span.end, value),
11508
- span: result.span
11509
- });
11510
- return { ok: true, value, span: result.span };
12139
+ return parser2.parse(input, pos, ctx);
12140
+ },
12141
+ define(p) {
12142
+ if (resolved) throw new Error("ref<T>() already defined");
12143
+ resolved = p;
12144
+ resolvedScalar = scalarOf(p);
12145
+ ownBoundary = hasOwnTriviaBoundary(p);
12146
+ meta.firstSet = p._meta.firstSet;
12147
+ meta.canMatchNewline = p._meta.canMatchNewline;
12148
+ meta.isTrivia = p._meta.isTrivia;
12149
+ if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
12150
+ else delete meta.triviaKindLabels;
12151
+ if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
12152
+ else delete meta.disjoint;
11511
12153
  }
11512
12154
  };
11513
- }
11514
- function leaf(root, fn) {
11515
- return makeLeaf(root, fn, false);
11516
- }
11517
- function sourceLeaf(root, fn) {
11518
- return makeLeaf(root, fn, true);
12155
+ return slot;
11519
12156
  }
11520
12157
 
11521
12158
  // src/combinators/scanTo.ts
@@ -11826,37 +12463,120 @@ function clearOf(ranges, input, from, to) {
11826
12463
  return true;
11827
12464
  }
11828
12465
 
11829
- // src/table/run-support.ts
11830
- function lineCol(ctx, offset) {
11831
- const starts = ctx._lineStarts ?? [0];
11832
- let lo = 0, hi = starts.length - 1;
11833
- while (lo < hi) {
11834
- const mid = lo + hi + 1 >> 1;
11835
- if (starts[mid] <= offset) lo = mid;
11836
- else hi = mid - 1;
12466
+ // src/table/fail-clean.ts
12467
+ function passChild(code, ip) {
12468
+ switch (code[ip]) {
12469
+ case OP_RULE:
12470
+ case OP_LABEL:
12471
+ case OP_COV:
12472
+ case OP_TOKEN:
12473
+ return code[ip + 1];
12474
+ case OP_GATE:
12475
+ case OP_NODE:
12476
+ case OP_NODE_TRACK:
12477
+ case OP_XFORM:
12478
+ case OP_FIELD:
12479
+ case OP_SCOPE:
12480
+ case OP_SCOPE_CAP:
12481
+ case OP_SCOPE_PLAIN:
12482
+ case OP_WITHCTX:
12483
+ case OP_LEAF:
12484
+ case OP_SOURCE_LEAF:
12485
+ return code[ip + 2];
12486
+ default:
12487
+ return -1;
11837
12488
  }
11838
- return [lo + 1, offset - starts[lo] + 1];
11839
- }
11840
- function spanLines(ctx, start, end) {
11841
- const s = lineCol(ctx, start), e = lineCol(ctx, end);
11842
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
11843
12489
  }
11844
- function rawEntry(v, input, s, e) {
11845
- if (typeof v === "object" && v !== null) {
11846
- const tg = v._tag;
11847
- if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
11848
- }
11849
- return {
11850
- _tag: "leaf",
11851
- value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
11852
- span: { start: s, end: e }
12490
+ function seqCount(code, ip) {
12491
+ const op = code[ip];
12492
+ return op === OP_SEQ || op === OP_SEQV ? ip + 1 : op === OP_SEQX ? ip + 2 : -1;
12493
+ }
12494
+ function failCleanAnalysis(code) {
12495
+ const cleanAt = new Uint8Array(code.length);
12496
+ const neverAt = new Uint8Array(code.length);
12497
+ const neverFails = (ip) => {
12498
+ const hit = neverAt[ip];
12499
+ if (hit !== 0) return hit === 1;
12500
+ neverAt[ip] = 3;
12501
+ let out = false;
12502
+ const op = code[ip];
12503
+ if (op === OP_OPT || op === OP_EMPTY || op === OP_EXPECT) out = true;
12504
+ else if (op === OP_REP || op === OP_REPV) out = code[ip + 2] === 0;
12505
+ else {
12506
+ const at = seqCount(code, ip);
12507
+ if (at >= 0) {
12508
+ out = true;
12509
+ for (let i = 1, n = code[at]; out && i <= n; i++) out = neverFails(code[at + i]);
12510
+ } else if (op !== OP_GATE) {
12511
+ const c = passChild(code, ip);
12512
+ out = c >= 0 && neverFails(c);
12513
+ }
12514
+ }
12515
+ neverAt[ip] = out ? 1 : 2;
12516
+ return out;
11853
12517
  };
11854
- }
11855
- function lead(input, pos) {
11856
- if (pos >= input.length) return -1;
11857
- const c = input.charCodeAt(pos);
11858
- if (c < 55296 || c > 56319) return c;
11859
- return input.codePointAt(pos) ?? c;
12518
+ const clean = (ip) => {
12519
+ const hit = cleanAt[ip];
12520
+ if (hit !== 0) return hit === 1;
12521
+ cleanAt[ip] = 3;
12522
+ let out = false;
12523
+ switch (code[ip]) {
12524
+ // A terminal pushes its leaf only on a match; NOT/PEEK/ATTEMPT restore
12525
+ // their own mark; OPT, EMPTY and EXPECT do not fail uncommitted.
12526
+ case OP_LIT:
12527
+ case OP_RX:
12528
+ case OP_LIT_TRACK:
12529
+ case OP_RX_TRACK:
12530
+ case OP_LIT_CI:
12531
+ case OP_LIT_CI_TRACK:
12532
+ case OP_GUARD:
12533
+ case OP_NOT:
12534
+ case OP_PEEK:
12535
+ case OP_ATTEMPT:
12536
+ case OP_EMPTY:
12537
+ case OP_OPT:
12538
+ case OP_EXPECT:
12539
+ out = true;
12540
+ break;
12541
+ // Min 0 does not fail uncommitted; min 1 fails only with no item kept, and
12542
+ // restores the failed item itself.
12543
+ case OP_REP:
12544
+ case OP_REPV:
12545
+ out = code[ip + 2] <= 1;
12546
+ break;
12547
+ // Only the first term may fail: a later one fails after the terms before it
12548
+ // wrote, and after the trivia scanned in front of it.
12549
+ case OP_SEQ:
12550
+ case OP_SEQV:
12551
+ case OP_SEQX: {
12552
+ const at = seqCount(code, ip);
12553
+ const n = code[at];
12554
+ out = n > 0 && clean(code[at + 1]);
12555
+ for (let i = 2; out && i <= n; i++) out = neverFails(code[at + i]);
12556
+ break;
12557
+ }
12558
+ case OP_CHOICE: {
12559
+ out = true;
12560
+ for (let i = 0, n = code[ip + 2]; out && i < n; i++) out = clean(code[ip + 4 + i]);
12561
+ break;
12562
+ }
12563
+ case OP_ROUTED:
12564
+ out = code[ip + 1] < 0 || clean(code[ip + 1]);
12565
+ break;
12566
+ // An arm's failure and the fallback's are committed; only the selector's is
12567
+ // not, and without a fallback an unknown key fails after the selector wrote.
12568
+ case OP_DISPATCH:
12569
+ out = code[ip + 3] >= 0 && clean(code[ip + 1]);
12570
+ break;
12571
+ default: {
12572
+ const c = passChild(code, ip);
12573
+ out = c >= 0 && clean(c);
12574
+ }
12575
+ }
12576
+ cleanAt[ip] = out ? 1 : 2;
12577
+ return out;
12578
+ };
12579
+ return clean;
11860
12580
  }
11861
12581
 
11862
12582
  // src/cst/host-mode.ts
@@ -12008,6 +12728,7 @@ function assemble(t2, prog, cfg) {
12008
12728
  const swapLegal = !cfg.trackLines;
12009
12729
  const hostCst = cfg.hostCst;
12010
12730
  const REC = prog.rec === 1 && cfg.tolerant;
12731
+ const PROBE = cfg.probe;
12011
12732
  const sentinels = /* @__PURE__ */ new Map();
12012
12733
  function sentinelFor(cls) {
12013
12734
  if (cls < 0) return void 0;
@@ -12053,6 +12774,8 @@ function assemble(t2, prog, cfg) {
12053
12774
  }
12054
12775
  const memo = /* @__PURE__ */ new Map();
12055
12776
  const reached = /* @__PURE__ */ new Set();
12777
+ const NULLABLE = /* @__PURE__ */ new Map();
12778
+ const CLEAN = REC ? () => false : failCleanAnalysis(code);
12056
12779
  function pushLeaf(ctx, value, s, e) {
12057
12780
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
12058
12781
  pushCstLeaf(ctx, lf);
@@ -12251,6 +12974,22 @@ function assemble(t2, prog, cfg) {
12251
12974
  return node2;
12252
12975
  };
12253
12976
  }
12977
+ function passCollapseNode(child, build, readsRaw) {
12978
+ return (input, pos, ctx) => {
12979
+ const v = child(input, pos, ctx);
12980
+ if (v !== void 0) return v;
12981
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
12982
+ };
12983
+ }
12984
+ function gatedPassCollapseNode(blockers, last, classic, build, readsRaw) {
12985
+ return (input, pos, ctx) => {
12986
+ const c = lead(input, pos);
12987
+ for (let i = 0; i < blockers.length; i++) if (classHas2(blockers[i], c)) return classic(input, pos, ctx);
12988
+ const v = last(input, pos, ctx);
12989
+ if (v !== void 0) return v;
12990
+ return collapseEmpty(ctx, build, input, pos, EC.e, readsRaw);
12991
+ };
12992
+ }
12254
12993
  function plainProjectNode(child, projection, type) {
12255
12994
  return (input, pos, ctx) => {
12256
12995
  const sCh = ctx._cstChildren;
@@ -12621,21 +13360,27 @@ function assemble(t2, prog, cfg) {
12621
13360
  }
12622
13361
  function dispatchBranch(child, usesRouted) {
12623
13362
  if (!usesRouted) {
12624
- return (input, _pos, selEnd, key, _selectorMark, ctx) => {
12625
- const mark = saveTriviaMark(ctx);
13363
+ return (input, _pos, selEnd, key, ctx) => {
13364
+ const need = markCst(ctx);
13365
+ const mRaw = MRAW;
13366
+ const mTl = MTL;
13367
+ const mLv = MLV;
13368
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
13369
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
13370
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13371
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
12626
13372
  const v = child(input, selEnd, ctx);
12627
13373
  if (v === FAIL) {
12628
- rollbackTrivia(ctx, mark);
13374
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12629
13375
  ctx._fc = true;
12630
13376
  return FAIL;
12631
13377
  }
12632
13378
  return [key, v];
12633
13379
  };
12634
13380
  }
12635
- return (input, pos, selEnd, key, selectorMark, ctx) => {
13381
+ return (input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
12636
13382
  const savedRouted = ctx._routed;
12637
- rollbackTrivia(ctx, selectorMark);
12638
- const mark = saveTriviaMark(ctx);
13383
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12639
13384
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
12640
13385
  let v;
12641
13386
  try {
@@ -12644,7 +13389,7 @@ function assemble(t2, prog, cfg) {
12644
13389
  ctx._routed = savedRouted;
12645
13390
  }
12646
13391
  if (v === FAIL) {
12647
- rollbackTrivia(ctx, mark);
13392
+ if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12648
13393
  ctx._fc = true;
12649
13394
  return FAIL;
12650
13395
  }
@@ -12652,12 +13397,12 @@ function assemble(t2, prog, cfg) {
12652
13397
  };
12653
13398
  }
12654
13399
  function dispatchArmBlock(start, a0, a1, a2, a3, next) {
12655
- return (arm, input, pos, selEnd, key, selectorMark, ctx) => {
12656
- if (arm === start) return a0(input, pos, selEnd, key, selectorMark, ctx);
12657
- if (arm === start + 1) return a1(input, pos, selEnd, key, selectorMark, ctx);
12658
- if (arm === start + 2) return a2(input, pos, selEnd, key, selectorMark, ctx);
12659
- if (arm === start + 3) return a3(input, pos, selEnd, key, selectorMark, ctx);
12660
- return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, selectorMark, ctx);
13400
+ return (arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
13401
+ if (arm === start) return a0(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13402
+ if (arm === start + 1) return a1(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13403
+ if (arm === start + 2) return a2(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13404
+ if (arm === start + 3) return a3(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
13405
+ return next === void 0 ? FAIL : next(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
12661
13406
  };
12662
13407
  }
12663
13408
  function trackLinesInto(ctx, input, end) {
@@ -12676,7 +13421,7 @@ function assemble(t2, prog, cfg) {
12676
13421
  if (flight !== void 0) return flight.fwd;
12677
13422
  const selected = HYBRID?.byIp[ip];
12678
13423
  if (selected !== void 0) {
12679
- const piece2 = hybridPiece(selected);
13424
+ const piece2 = scanHandoffNeeded(code, ip, closureLabels) ? hybridPiece(selected) : selected;
12680
13425
  memo.set(ip, piece2);
12681
13426
  reached.add(ip);
12682
13427
  return piece2;
@@ -12687,14 +13432,55 @@ function assemble(t2, prog, cfg) {
12687
13432
  target = p;
12688
13433
  } };
12689
13434
  inFlight.set(ip, holder);
12690
- const op = code[ip];
12691
- const piece = (op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && closureLabels.at(ip).tri === code[ip + 1] ? link(code[ip + 2]) : countedPiece(lower(ip), ip);
13435
+ const piece = scopeIsIdentity(code, ip, closureLabels.at(ip)) ? link(code[ip + 2]) : countedPiece(lookaheadLedNode(ip) ?? lower(ip), ip);
12692
13436
  inFlight.delete(ip);
12693
13437
  holder.set(piece);
12694
13438
  memo.set(ip, piece);
12695
13439
  reached.add(ip);
12696
13440
  return piece;
12697
13441
  }
13442
+ let FIRST_DECIDED;
13443
+ let NODE_BODY;
13444
+ const DECIDED = (_input, pos) => {
13445
+ EC.e = pos;
13446
+ return null;
13447
+ };
13448
+ function lookaheadLedNode(ip) {
13449
+ const op = code[ip];
13450
+ if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
13451
+ if (passCollapse(code, ip, hostCst) || gatedPassCollapse(code, ip, hostCst) !== void 0) return void 0;
13452
+ const body = code[ip + 2];
13453
+ const bop = code[body];
13454
+ if (bop !== OP_SEQ && bop !== OP_SEQV && bop !== OP_SEQX) return void 0;
13455
+ const base = bop === OP_SEQX ? body + 3 : body + 2;
13456
+ if (code[bop === OP_SEQX ? body + 2 : body + 1] < 2) return void 0;
13457
+ const first = code[base];
13458
+ const negative = code[first] === OP_NOT;
13459
+ const terminal = negative ? scalarTerminalNotChild(code, first) : code[first] === OP_PEEK ? scalarTerminalPeekChild(code, first) : -1;
13460
+ if (terminal < 0) return void 0;
13461
+ const recognize = scalarFor(terminal);
13462
+ const xf = fx[code[first + 2]];
13463
+ FIRST_DECIDED = DECIDED;
13464
+ NODE_BODY = lower(body);
13465
+ const node2 = lower(ip);
13466
+ NODE_BODY = void 0;
13467
+ return negative ? (input, pos, ctx) => {
13468
+ if (recognize(input, pos) >= 0) {
13469
+ ctx._fe = pos;
13470
+ ctx._fx = xf;
13471
+ EC.e = pos;
13472
+ return FAIL;
13473
+ }
13474
+ return node2(input, pos, ctx);
13475
+ } : (input, pos, ctx) => {
13476
+ if (recognize(input, pos) < 0) {
13477
+ ctx._fe = pos;
13478
+ ctx._fx = xf;
13479
+ return FAIL;
13480
+ }
13481
+ return node2(input, pos, ctx);
13482
+ };
13483
+ }
12698
13484
  function lower(ip) {
12699
13485
  const op = code[ip];
12700
13486
  switch (op) {
@@ -13239,8 +14025,10 @@ function assemble(t2, prog, cfg) {
13239
14025
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13240
14026
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13241
14027
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14028
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13242
14029
  const v = child(input, pos, ctx);
13243
14030
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14031
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13244
14032
  if (v === FAIL) {
13245
14033
  EC.e = pos;
13246
14034
  return null;
@@ -13251,6 +14039,20 @@ function assemble(t2, prog, cfg) {
13251
14039
  };
13252
14040
  }
13253
14041
  case OP_PEEK: {
14042
+ const scalarChild = scalarTerminalPeekChild(code, ip);
14043
+ if (scalarChild >= 0) {
14044
+ const recognize = scalarFor(scalarChild);
14045
+ const xf2 = fx[code[ip + 2]];
14046
+ return (input, pos, ctx) => {
14047
+ if (recognize(input, pos) < 0) {
14048
+ ctx._fe = pos;
14049
+ ctx._fx = xf2;
14050
+ return FAIL;
14051
+ }
14052
+ EC.e = pos;
14053
+ return null;
14054
+ };
14055
+ }
13254
14056
  const child = link(code[ip + 1]);
13255
14057
  const xf = fx[code[ip + 2]];
13256
14058
  const gate = lookaheadClass(code[ip + 1]);
@@ -13268,8 +14070,10 @@ function assemble(t2, prog, cfg) {
13268
14070
  const mEr = need ? ctx._errors?.length ?? 0 : 0;
13269
14071
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13270
14072
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14073
+ const probeBest = PROBE ? ctx._probe?.best : void 0;
13271
14074
  const v = child(input, pos, ctx);
13272
14075
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14076
+ if (PROBE && ctx._probe !== void 0) ctx._probe.best = probeBest ?? null;
13273
14077
  if (v === FAIL) {
13274
14078
  ctx._fe = pos;
13275
14079
  ctx._fx = xf;
@@ -13282,12 +14086,13 @@ function assemble(t2, prog, cfg) {
13282
14086
  case OP_OPT: {
13283
14087
  const child = link(code[ip + 1]);
13284
14088
  const gate = lookaheadClass(code[ip + 1]);
14089
+ const childClean = CLEAN(code[ip + 1]);
13285
14090
  return (input, pos, ctx) => {
13286
14091
  if (gate !== null && !classHas2(gate, lead(input, pos))) {
13287
14092
  EC.e = pos;
13288
14093
  return null;
13289
14094
  }
13290
- const need = markCst(ctx);
14095
+ const need = !childClean && markCst(ctx);
13291
14096
  const mRaw = MRAW;
13292
14097
  const mTl = MTL;
13293
14098
  const mLv = MLV;
@@ -13485,6 +14290,9 @@ function assemble(t2, prog, cfg) {
13485
14290
  const projection = reducer < 0 ? ~reducer : -1;
13486
14291
  const fn = fused && projection < 0 ? fns[reducer] : void 0;
13487
14292
  const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm;
14293
+ const decided = FIRST_DECIDED;
14294
+ FIRST_DECIDED = void 0;
14295
+ const linkFirst = () => decided ?? link(code[base]);
13488
14296
  const runnerBlock = (count, r0, r1, r2, r3, next) => {
13489
14297
  if (count === 1) return (input, cur, ctx, values, inherited) => {
13490
14298
  cur = r0(input, cur, ctx, inherited);
@@ -13530,7 +14338,7 @@ function assemble(t2, prog, cfg) {
13530
14338
  };
13531
14339
  };
13532
14340
  if (REC) {
13533
- const first2 = link(code[base]);
14341
+ const first2 = linkFirst();
13534
14342
  const firstSync = sentinelFor(code[base + n]);
13535
14343
  const runnerAt = (i) => {
13536
14344
  const sync = sentinelFor(code[base + n + i]);
@@ -13566,13 +14374,13 @@ function assemble(t2, prog, cfg) {
13566
14374
  const bindRunners = (start) => {
13567
14375
  const count = Math.min(4, n - start);
13568
14376
  const at = (offset) => runnerAt(start + offset);
13569
- const never = () => -1;
14377
+ const never2 = () => -1;
13570
14378
  return runnerBlock(
13571
14379
  count,
13572
14380
  at(0),
13573
- count > 1 ? at(1) : never,
13574
- count > 2 ? at(2) : never,
13575
- count > 3 ? at(3) : never,
14381
+ count > 1 ? at(1) : never2,
14382
+ count > 2 ? at(2) : never2,
14383
+ count > 3 ? at(3) : never2,
13576
14384
  start + count < n ? bindRunners(start + count) : void 0
13577
14385
  );
13578
14386
  };
@@ -13622,15 +14430,31 @@ function assemble(t2, prog, cfg) {
13622
14430
  let hasAdj = false;
13623
14431
  for (let i = 1; i < n; i++) {
13624
14432
  const kidIp = code[base + i];
13625
- if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp)) {
14433
+ if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp) || holdsGap(code, k, base, n, i, NULLABLE)) {
13626
14434
  hasAdj = true;
13627
14435
  break;
13628
14436
  }
13629
14437
  }
13630
14438
  if (hasAdj) {
13631
- const first2 = link(code[base]);
14439
+ const first2 = linkFirst();
13632
14440
  const runnerAt = (i) => {
13633
14441
  const kidIp = code[base + i];
14442
+ if (holdsGap(code, k, base, n, i, NULLABLE)) {
14443
+ const kid = link(kidIp);
14444
+ return (input, cur, ctx) => {
14445
+ if (ctx.trivia === void 0) {
14446
+ const v2 = kid(input, cur, ctx);
14447
+ if (v2 === FAIL) return -1;
14448
+ TERMV = v2;
14449
+ return EC.e;
14450
+ }
14451
+ const scanEnd = skipTrivia(input, cur, ctx);
14452
+ const v = kid(input, scanEnd, ctx);
14453
+ if (v === FAIL) return -1;
14454
+ TERMV = v;
14455
+ return scanEnd;
14456
+ };
14457
+ }
13634
14458
  if (code[kidIp] !== OP_ADJ) {
13635
14459
  const kid = link(kidIp);
13636
14460
  if (leadingTriviaFieldAt(code, k, kidIp)) {
@@ -13655,13 +14479,13 @@ function assemble(t2, prog, cfg) {
13655
14479
  const bindRunners = (start) => {
13656
14480
  const count = Math.min(4, n - start);
13657
14481
  const at = (offset) => runnerAt(start + offset);
13658
- const never = () => -1;
14482
+ const never2 = () => -1;
13659
14483
  return runnerBlock(
13660
14484
  count,
13661
14485
  at(0),
13662
- count > 1 ? at(1) : never,
13663
- count > 2 ? at(2) : never,
13664
- count > 3 ? at(3) : never,
14486
+ count > 1 ? at(1) : never2,
14487
+ count > 2 ? at(2) : never2,
14488
+ count > 3 ? at(3) : never2,
13665
14489
  start + count < n ? bindRunners(start + count) : void 0
13666
14490
  );
13667
14491
  };
@@ -13698,7 +14522,7 @@ function assemble(t2, prog, cfg) {
13698
14522
  };
13699
14523
  }
13700
14524
  if (n === 1) {
13701
- const k0 = link(code[base]);
14525
+ const k0 = linkFirst();
13702
14526
  if (fused) {
13703
14527
  return (input, pos, ctx) => {
13704
14528
  const v = k0(input, pos, ctx);
@@ -13720,7 +14544,7 @@ function assemble(t2, prog, cfg) {
13720
14544
  };
13721
14545
  }
13722
14546
  if (n === 2) {
13723
- const k0 = link(code[base]), k1 = link(code[base + 1]);
14547
+ const k0 = linkFirst(), k1 = link(code[base + 1]);
13724
14548
  if (fused) {
13725
14549
  return (input, pos, ctx) => {
13726
14550
  const v0 = k0(input, pos, ctx);
@@ -13751,7 +14575,7 @@ function assemble(t2, prog, cfg) {
13751
14575
  };
13752
14576
  }
13753
14577
  if (n === 3) {
13754
- const k0 = link(code[base]), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
14578
+ const k0 = linkFirst(), k1 = link(code[base + 1]), k2 = link(code[base + 2]);
13755
14579
  if (fused) {
13756
14580
  return (input, pos, ctx) => {
13757
14581
  const v0 = k0(input, pos, ctx);
@@ -13845,7 +14669,7 @@ function assemble(t2, prog, cfg) {
13845
14669
  start + count < n ? bind(start + count) : void 0
13846
14670
  );
13847
14671
  };
13848
- const first = link(code[base]);
14672
+ const first = linkFirst();
13849
14673
  const tail = bind(1);
13850
14674
  const runDirectTerms = (input, pos, ctx, values) => {
13851
14675
  const v0 = first(input, pos, ctx);
@@ -13884,6 +14708,8 @@ function assemble(t2, prog, cfg) {
13884
14708
  const n = code[ip + 2];
13885
14709
  const choiceFx = fx[code[ip + 3]];
13886
14710
  const base = ip + 4;
14711
+ for (let i = 0; i < n; i++) link(code[base + i]);
14712
+ const armsClean = CLEAN(ip);
13887
14713
  if (table.exclusive) {
13888
14714
  const ascii = table.ascii;
13889
14715
  const hi = table.hi;
@@ -14023,7 +14849,7 @@ function assemble(t2, prog, cfg) {
14023
14849
  if (n === 3) addGate(g2, 4);
14024
14850
  return (input, pos, ctx) => {
14025
14851
  const c = lead(input, pos);
14026
- const need = markCst(ctx);
14852
+ const need = !armsClean && markCst(ctx);
14027
14853
  const mRaw = MRAW;
14028
14854
  const mTl = MTL;
14029
14855
  const mLv = MLV;
@@ -14240,7 +15066,7 @@ function assemble(t2, prog, cfg) {
14240
15066
  if (pn !== 0) {
14241
15067
  return (input, pos, ctx) => {
14242
15068
  const c = lead(input, pos);
14243
- const need = markCst(ctx);
15069
+ const need = !armsClean && markCst(ctx);
14244
15070
  const mRaw = MRAW;
14245
15071
  const mTl = MTL;
14246
15072
  const mLv = MLV;
@@ -14297,7 +15123,7 @@ function assemble(t2, prog, cfg) {
14297
15123
  }
14298
15124
  return (input, pos, ctx) => {
14299
15125
  const c = lead(input, pos);
14300
- const need = markCst(ctx);
15126
+ const need = !armsClean && markCst(ctx);
14301
15127
  const mRaw = MRAW;
14302
15128
  const mTl = MTL;
14303
15129
  const mLv = MLV;
@@ -14345,7 +15171,7 @@ function assemble(t2, prog, cfg) {
14345
15171
  }
14346
15172
  return (input, pos, ctx) => {
14347
15173
  const c = lead(input, pos);
14348
- const need = markCst(ctx);
15174
+ const need = !armsClean && markCst(ctx);
14349
15175
  const mRaw = MRAW;
14350
15176
  const mTl = MTL;
14351
15177
  const mLv = MLV;
@@ -14399,6 +15225,21 @@ function assemble(t2, prog, cfg) {
14399
15225
  return lit(input, pos, ctx);
14400
15226
  };
14401
15227
  }
15228
+ case OP_RGATE: {
15229
+ const cls = cc[code[ip + 1]];
15230
+ const xf = fx[code[ip + 3]];
15231
+ const child = link(code[ip + 2]);
15232
+ if (cfg.tolerant || cfg.probe) return child;
15233
+ return (input, pos, ctx) => {
15234
+ const item = ctx._routed;
15235
+ if (item !== void 0 && item.span.start === pos && !classHas2(cls, lead(input, item.span.end))) {
15236
+ ctx._fe = item.span.end;
15237
+ ctx._fx = xf;
15238
+ return FAIL;
15239
+ }
15240
+ return child(input, pos, ctx);
15241
+ };
15242
+ }
14402
15243
  case OP_ARMGATE: {
14403
15244
  const pred = fns[code[ip + 1]];
14404
15245
  const child = link(code[ip + 2]);
@@ -14467,6 +15308,7 @@ function assemble(t2, prog, cfg) {
14467
15308
  const itemClass = !REC && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
14468
15309
  const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
14469
15310
  const skipBeforeFirst = sepIp < 0 && min === 0;
15311
+ const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
14470
15312
  if (REC) {
14471
15313
  const itemFx2 = fx[code[ip + 6]];
14472
15314
  const sepSent = sentinelFor(code[ip + 7]);
@@ -14563,6 +15405,8 @@ function assemble(t2, prog, cfg) {
14563
15405
  const out = collect ? [] : void 0;
14564
15406
  const hasTrivia = ctx.trivia !== void 0;
14565
15407
  const needMark = rollbackNeeded(ctx);
15408
+ const markLater = needMark && (!itemClean || hasTrivia);
15409
+ const markFirst = needMark && (!itemClean || hasTrivia && skipBeforeFirst);
14566
15410
  const gateItems = itemMayStart !== void 0 && ctx._probe === void 0;
14567
15411
  let cur = pos;
14568
15412
  let count = 0;
@@ -14570,14 +15414,15 @@ function assemble(t2, prog, cfg) {
14570
15414
  if (max >= 0 && count >= max) break;
14571
15415
  if (sep !== void 0 && count > 0 && count >= min && cur >= input.length) break;
14572
15416
  if (count >= min && sep === void 0 && !hasTrivia && gateItems && !itemMayStart(input, cur)) break;
14573
- if (needMark) markCst(ctx);
14574
- const mRaw = needMark ? MRAW : 0;
14575
- const mTl = needMark ? MTL : 0;
14576
- const mLv = needMark ? MLV : 0;
14577
- const mFl = needMark ? ctx._fields?.length ?? 0 : 0;
14578
- const mEr = needMark ? ctx._errors?.length ?? 0 : 0;
14579
- const mLog = needMark ? ctx._triviaLog?.length ?? 0 : 0;
14580
- const mRoot = needMark ? ctx._rootTriviaLog?.length ?? 0 : 0;
15417
+ const markIt = count > 0 ? markLater : markFirst;
15418
+ if (markIt) markCst(ctx);
15419
+ const mRaw = markIt ? MRAW : 0;
15420
+ const mTl = markIt ? MTL : 0;
15421
+ const mLv = markIt ? MLV : 0;
15422
+ const mFl = markIt ? ctx._fields?.length ?? 0 : 0;
15423
+ const mEr = markIt ? ctx._errors?.length ?? 0 : 0;
15424
+ const mLog = markIt ? ctx._triviaLog?.length ?? 0 : 0;
15425
+ const mRoot = markIt ? ctx._rootTriviaLog?.length ?? 0 : 0;
14581
15426
  let itemStart = cur;
14582
15427
  let sepEnd = -1;
14583
15428
  const viaRepItem = sep === void 0 && count >= min && (count > 0 || skipBeforeFirst);
@@ -14589,7 +15434,7 @@ function assemble(t2, prog, cfg) {
14589
15434
  if (sepLeads) LEAD.at = cur;
14590
15435
  const sv = sep(input, sp, ctx);
14591
15436
  if (sv === FAIL) {
14592
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15437
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14593
15438
  if (committed3(ctx)) return FAIL;
14594
15439
  break;
14595
15440
  }
@@ -14600,25 +15445,25 @@ function assemble(t2, prog, cfg) {
14600
15445
  itemStart = skipTrivia(input, itemStart, ctx);
14601
15446
  }
14602
15447
  if (itemStart >= input.length && viaRepItem) {
14603
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15448
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14604
15449
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14605
15450
  break;
14606
15451
  }
14607
15452
  if (count >= min && gateItems && !itemMayStart(input, itemStart)) {
14608
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15453
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14609
15454
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14610
15455
  break;
14611
15456
  }
14612
15457
  ctx._fc = false;
14613
15458
  const v = child(input, itemStart, ctx);
14614
15459
  if (v === FAIL) {
14615
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15460
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14616
15461
  if (committed3(ctx)) return FAIL;
14617
15462
  if (trailingAllowed && sepEnd >= 0) cur = sepEnd;
14618
15463
  break;
14619
15464
  }
14620
15465
  if (EC.e === itemStart && viaRepItem) {
14621
- if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
15466
+ if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14622
15467
  break;
14623
15468
  }
14624
15469
  if (out !== void 0) out.push(v);
@@ -14692,7 +15537,14 @@ function assemble(t2, prog, cfg) {
14692
15537
  const runArm = n === 0 ? void 0 : bindArms(0);
14693
15538
  const runOther = other === void 0 ? void 0 : dispatchBranch(other, otherRouted);
14694
15539
  return (input, pos, ctx) => {
14695
- const selectorMark = saveTriviaMark(ctx);
15540
+ const need = markCst(ctx);
15541
+ const mRaw = MRAW;
15542
+ const mTl = MTL;
15543
+ const mLv = MLV;
15544
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
15545
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
15546
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
15547
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
14696
15548
  const selVal = selector(input, pos, ctx);
14697
15549
  if (selVal === FAIL) return FAIL;
14698
15550
  const selEnd = EC.e;
@@ -14704,9 +15556,9 @@ function assemble(t2, prog, cfg) {
14704
15556
  ctx._fx = expected;
14705
15557
  return FAIL;
14706
15558
  }
14707
- return runOther(input, pos, selEnd, key, selectorMark, ctx);
15559
+ return runOther(input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14708
15560
  }
14709
- return runArm(arm, input, pos, selEnd, key, selectorMark, ctx);
15561
+ return runArm(arm, input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
14710
15562
  };
14711
15563
  }
14712
15564
  /* ── node ────────────────────────────────────────────────────────────── */
@@ -14742,7 +15594,8 @@ function assemble(t2, prog, cfg) {
14742
15594
  return nd;
14743
15595
  };
14744
15596
  }
14745
- const child = link(code[ip + 2]);
15597
+ const child = NODE_BODY ?? link(code[ip + 2]);
15598
+ NODE_BODY = void 0;
14746
15599
  const proj = code[ip + 4];
14747
15600
  const buildIdx = code[ip + 1];
14748
15601
  const type = k[code[ip + 5]];
@@ -14766,6 +15619,30 @@ function assemble(t2, prog, cfg) {
14766
15619
  if (build !== void 0 && proj < 0 && flags === 18) {
14767
15620
  return childrenOnlyFieldsBuildNode(child, build);
14768
15621
  }
15622
+ if (build !== void 0 && passCollapse(code, ip, hostCst)) {
15623
+ return passCollapseNode(child, build, flags === 32);
15624
+ }
15625
+ const gated = build !== void 0 && !cfg.tolerant && !cfg.probe ? gatedPassCollapse(code, ip, hostCst) : void 0;
15626
+ const triviaLead = gated === void 0 ? void 0 : triviaLeadRanges(closureLabels.at(code[ip + 2]).tri, trivia2);
15627
+ if (build !== void 0 && gated !== void 0 && triviaLead !== void 0) {
15628
+ const classic = flags === 32 ? collapseBuildNode(child, build) : childrenOnlyCollapseBuildNode(child, build);
15629
+ return gatedPassCollapseNode(
15630
+ [
15631
+ ...gated.leads.map((g) => cc[code[g + 1]]),
15632
+ resolveClass(encodeClassSpec([
15633
+ ...triviaLead,
15634
+ ...gated.lits.map((i) => {
15635
+ const c = k[i].codePointAt(0);
15636
+ return { lo: c, hi: c };
15637
+ })
15638
+ ]))
15639
+ ],
15640
+ link(gated.last),
15641
+ classic,
15642
+ build,
15643
+ flags === 32
15644
+ );
15645
+ }
14769
15646
  if (build !== void 0 && proj < 0 && flags === 32) {
14770
15647
  return collapseBuildNode(child, build);
14771
15648
  }
@@ -14914,6 +15791,8 @@ function assemble(t2, prog, cfg) {
14914
15791
  }
14915
15792
  const notChild = scalarTerminalNotChild(code, ip);
14916
15793
  if (notChild >= 0) scalarFor(notChild);
15794
+ const peekChild = scalarTerminalPeekChild(code, ip);
15795
+ if (peekChild >= 0) scalarFor(peekChild);
14917
15796
  }
14918
15797
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
14919
15798
  if (pre !== void 0) {
@@ -14973,7 +15852,8 @@ function assemble(t2, prog, cfg) {
14973
15852
  t2.lexPrograms,
14974
15853
  LEAD,
14975
15854
  triviaFieldCapture,
14976
- skipDeferredTrivia
15855
+ skipDeferredTrivia,
15856
+ collapseEmpty
14977
15857
  );
14978
15858
  emitReached = new Set(pre.reached);
14979
15859
  if (emitted.ext !== void 0) HYBRID = emitted;
@@ -15059,7 +15939,8 @@ function assemble(t2, prog, cfg) {
15059
15939
  t2.lexPrograms,
15060
15940
  LEAD,
15061
15941
  triviaFieldCapture,
15062
- skipDeferredTrivia
15942
+ skipDeferredTrivia,
15943
+ collapseEmpty
15063
15944
  );
15064
15945
  emitReached = em.reached;
15065
15946
  } catch (e) {
@@ -15326,7 +16207,7 @@ function emitClassPool(classes) {
15326
16207
  if (classes.length < 2) return array;
15327
16208
  const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
15328
16209
  if (delimiter === void 0) return array;
15329
- const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
16210
+ const split = `/* @__PURE__ */ ${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
15330
16211
  return split.length < array.length ? split : array;
15331
16212
  }
15332
16213
  function emitConst(v) {
@@ -17185,16 +18066,16 @@ function ownSource(fn) {
17185
18066
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
17186
18067
  }
17187
18068
  function compile(target, second, third) {
17188
- if (!isCombinator(target)) return compileMap(target, second);
18069
+ if (!isCombinator2(target)) return compileMap(target, second);
17189
18070
  return compileRoot(target, second, third);
17190
18071
  }
17191
- function isCombinator(x) {
18072
+ function isCombinator2(x) {
17192
18073
  return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
17193
18074
  }
17194
18075
  function compileMap(grammar, opts = {}) {
17195
18076
  const entries = [];
17196
18077
  for (const [key, value] of Object.entries(grammar)) {
17197
- if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
18078
+ if (!isCombinator2(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
17198
18079
  if (value._def.tag === "lazy") {
17199
18080
  try {
17200
18081
  value._def.thunk();
@@ -17508,49 +18389,6 @@ function digestValue(value, prefix = "", options) {
17508
18389
  return sha.digest("hex");
17509
18390
  }
17510
18391
 
17511
- // src/combinators/attempt.ts
17512
- function containOption(options) {
17513
- if (options === void 0) return false;
17514
- for (const key of Object.keys(options)) {
17515
- if (key !== "contain") throw new TypeError(`attempt(): unknown option ${JSON.stringify(key)}`);
17516
- }
17517
- if (options.contain !== void 0 && typeof options.contain !== "boolean") {
17518
- throw new TypeError("attempt(): `contain` must be a boolean");
17519
- }
17520
- return options.contain === true;
17521
- }
17522
- function attempt(parser2, options) {
17523
- const contain = containOption(options);
17524
- const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
17525
- let failExpected;
17526
- return {
17527
- _tag: "attempt",
17528
- _meta: parser2._meta,
17529
- _def: contain ? { tag: "attempt", parser: parser2, contain: true } : { tag: "attempt", parser: parser2 },
17530
- parse(input, pos, ctx) {
17531
- if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
17532
- if (failExpected === void 0) {
17533
- const e = deriveExpected(parser2);
17534
- failExpected = e.length > 0 ? e : [parser2._tag];
17535
- }
17536
- return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
17537
- }
17538
- const mark = saveCstMark(ctx);
17539
- const log = ctx._triviaLog?.length;
17540
- const rootLog = ctx._rootTriviaLog?.length;
17541
- const split = ctx._columnsSplit;
17542
- const result = parser2.parse(input, pos, ctx);
17543
- if (result.ok) return result;
17544
- rollbackCstCapture(ctx, mark);
17545
- ctx._columnsSplit = split;
17546
- if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
17547
- if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
17548
- if (result.committed && !contain) return result;
17549
- return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
17550
- }
17551
- };
17552
- }
17553
-
17554
18392
  // src/combinators/not.ts
17555
18393
  function not(combinator) {
17556
18394
  const meta = {