parseman 0.47.0 → 0.47.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 (57) hide show
  1. package/dist/analysis/diagnostics.cjs +133 -45
  2. package/dist/analysis/diagnostics.cjs.map +2 -2
  3. package/dist/analysis/diagnostics.js +133 -45
  4. package/dist/analysis/diagnostics.js.map +2 -2
  5. package/dist/cli/index.cjs +133 -45
  6. package/dist/cli/index.cjs.map +2 -2
  7. package/dist/cli/index.js +133 -45
  8. package/dist/cli/index.js.map +2 -2
  9. package/dist/combinators/first-set.d.ts.map +1 -1
  10. package/dist/combinators/sequence.d.ts.map +1 -1
  11. package/dist/combinators/trivia-skip.d.ts +5 -0
  12. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  13. package/dist/index.cjs +134 -46
  14. package/dist/index.cjs.map +2 -2
  15. package/dist/index.js +134 -46
  16. package/dist/index.js.map +2 -2
  17. package/dist/language-service/index.cjs +3 -1
  18. package/dist/language-service/index.cjs.map +1 -1
  19. package/dist/language-service/index.js +3 -1
  20. package/dist/language-service/index.js.map +1 -1
  21. package/dist/plugin/index.cjs +134 -46
  22. package/dist/plugin/index.cjs.map +2 -2
  23. package/dist/plugin/index.js +134 -46
  24. package/dist/plugin/index.js.map +2 -2
  25. package/dist/spec/index.cjs +55 -7
  26. package/dist/spec/index.cjs.map +1 -1
  27. package/dist/spec/index.js +55 -7
  28. package/dist/spec/index.js.map +1 -1
  29. package/dist/table/assemble.d.ts.map +1 -1
  30. package/dist/table/emit-assembly.d.ts +2 -2
  31. package/dist/table/emit-assembly.d.ts.map +1 -1
  32. package/dist/table/emit.d.ts.map +1 -1
  33. package/dist/table/exec.d.ts.map +1 -1
  34. package/dist/table/index.cjs +1566 -1478
  35. package/dist/table/index.cjs.map +3 -3
  36. package/dist/table/index.js +1566 -1478
  37. package/dist/table/index.js.map +3 -3
  38. package/dist/table/ops.d.ts +8 -1
  39. package/dist/table/ops.d.ts.map +1 -1
  40. package/dist/table/program.d.ts +4 -1
  41. package/dist/table/program.d.ts.map +1 -1
  42. package/dist/version.d.ts +1 -1
  43. package/package.json +2 -1
  44. package/src/combinators/first-set.ts +29 -3
  45. package/src/combinators/sequence.ts +23 -7
  46. package/src/combinators/trivia-skip.ts +31 -0
  47. package/src/table/assemble.ts +30 -18
  48. package/src/table/child-slots.ts +2 -2
  49. package/src/table/emit-assembly.ts +36 -25
  50. package/src/table/emit.ts +12 -1
  51. package/src/table/encode.ts +4 -4
  52. package/src/table/exec.ts +20 -12
  53. package/src/table/ops.ts +9 -1
  54. package/src/table/program.ts +22 -1
  55. package/src/table/site-labels.ts +2 -2
  56. package/src/table/stamp.ts +2 -2
  57. package/src/version.ts +1 -1
@@ -44,6 +44,13 @@ function empty() {
44
44
  function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
45
45
  if (seen.has(p)) return true;
46
46
  seen.add(p);
47
+ try {
48
+ return matchesEmptyBody(p, seen, resolve);
49
+ } finally {
50
+ seen.delete(p);
51
+ }
52
+ }
53
+ function matchesEmptyBody(p, seen, resolve) {
47
54
  const me = (c) => matchesEmpty(c, seen, resolve);
48
55
  const d = p._def;
49
56
  switch (d.tag) {
@@ -145,6 +152,13 @@ function sequenceFirstSet(parsers) {
145
152
  function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
146
153
  if (seen.has(p)) return any();
147
154
  seen.add(p);
155
+ try {
156
+ return firstSetBody(p, seen, resolve);
157
+ } finally {
158
+ seen.delete(p);
159
+ }
160
+ }
161
+ function firstSetBody(p, seen, resolve) {
148
162
  const fs = (c) => firstSetOf(c, seen, resolve);
149
163
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
150
164
  const d = p._def;
@@ -1471,6 +1485,23 @@ function rollbackTrivia(ctx, mark) {
1471
1485
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1472
1486
  if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
1473
1487
  }
1488
+ function removeNumberRange(values, start, end) {
1489
+ if (values === void 0 || end <= start) return;
1490
+ if (values.length > end) values.copyWithin(start, end);
1491
+ values.length -= end - start;
1492
+ }
1493
+ function rollbackScannedTriviaAt(ctx, tlogStart, tlogEnd, logStart, logEnd, rootLogStart, rootLogEnd) {
1494
+ const b = ctx._cstBuf;
1495
+ if (b !== void 0) {
1496
+ const tlog = b.tl;
1497
+ removeNumberRange(tlog, tlogStart, tlogEnd);
1498
+ if (tlog !== void 0 && tlog.length === 0) b.tl = void 0;
1499
+ } else {
1500
+ removeNumberRange(ctx._cstTriviaLog, tlogStart, tlogEnd);
1501
+ }
1502
+ removeNumberRange(ctx._triviaLog, logStart, logEnd);
1503
+ removeNumberRange(ctx._rootTriviaLog, rootLogStart, rootLogEnd);
1504
+ }
1474
1505
  function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1475
1506
  const probeCtx = createDetachedParseContext(ctx.trackLines, ctx.state);
1476
1507
  probeCtx._lineIndex = ctx._lineIndex;
@@ -2130,7 +2161,9 @@ function sequence(...parsers) {
2130
2161
  continue;
2131
2162
  }
2132
2163
  if (ctx.trivia && i > 0) {
2133
- const mark = saveTriviaMark(ctx);
2164
+ const mTlog = cstTlLen(ctx);
2165
+ const mLog = ctx._triviaLog?.length ?? 0;
2166
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2134
2167
  let scanEnd;
2135
2168
  if (needsDeferredTriviaCommit(ctx)) {
2136
2169
  const scan = scanTrivia(input, cur, ctx);
@@ -2139,10 +2172,13 @@ function sequence(...parsers) {
2139
2172
  } else {
2140
2173
  scanEnd = advanceTrivia(input, cur, ctx);
2141
2174
  }
2175
+ const scanTlog = cstTlLen(ctx);
2176
+ const scanLog = ctx._triviaLog?.length ?? 0;
2177
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2142
2178
  const result2 = parsers[i].parse(input, scanEnd, ctx);
2143
2179
  if (!result2.ok) return result2;
2144
2180
  if (result2.span.end > scanEnd) cur = result2.span.end;
2145
- else rollbackTrivia(ctx, mark);
2181
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
2146
2182
  if (values !== void 0) values.push(result2.value);
2147
2183
  continue;
2148
2184
  }
@@ -2173,7 +2209,9 @@ function sequence(...parsers) {
2173
2209
  }
2174
2210
  if (ctx.trivia && i > 0) {
2175
2211
  let scanEnd;
2176
- const mark = saveTriviaMark(ctx);
2212
+ const mTlog = cstTlLen(ctx);
2213
+ const mLog = ctx._triviaLog?.length ?? 0;
2214
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2177
2215
  if (needsDeferredTriviaCommit(ctx)) {
2178
2216
  const scan = scanTrivia(input, cur, ctx);
2179
2217
  scan.commit();
@@ -2181,10 +2219,13 @@ function sequence(...parsers) {
2181
2219
  } else {
2182
2220
  scanEnd = advanceTrivia(input, cur, ctx);
2183
2221
  }
2222
+ const scanTlog = cstTlLen(ctx);
2223
+ const scanLog = ctx._triviaLog?.length ?? 0;
2224
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2184
2225
  const result2 = parsers[i].parse(input, scanEnd, ctx);
2185
2226
  if (!result2.ok) return result2;
2186
2227
  if (result2.span.end > scanEnd) cur = result2.span.end;
2187
- else rollbackTrivia(ctx, mark);
2228
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
2188
2229
  if (values !== void 0) values.push(result2.value);
2189
2230
  continue;
2190
2231
  }
@@ -2212,7 +2253,9 @@ function sequence(...parsers) {
2212
2253
  for (let i = 0; i < parsers.length; i++) {
2213
2254
  if (ctx.trivia && i > 0) {
2214
2255
  let scanEnd;
2215
- let mark = saveTriviaMark(ctx);
2256
+ const mTlog = cstTlLen(ctx);
2257
+ const mLog = ctx._triviaLog?.length ?? 0;
2258
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2216
2259
  if (needsDeferredTriviaCommit(ctx)) {
2217
2260
  const scan = scanTrivia(input, cur, ctx);
2218
2261
  scan.commit();
@@ -2220,12 +2263,15 @@ function sequence(...parsers) {
2220
2263
  } else {
2221
2264
  scanEnd = advanceTrivia(input, cur, ctx);
2222
2265
  }
2266
+ const scanTlog = cstTlLen(ctx);
2267
+ const scanLog = ctx._triviaLog?.length ?? 0;
2268
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2223
2269
  const result2 = parsers[i].parse(input, scanEnd, ctx);
2224
2270
  if (!result2.ok) return result2;
2225
2271
  if (result2.span.end > scanEnd) {
2226
2272
  cur = result2.span.end;
2227
2273
  } else {
2228
- rollbackTrivia(ctx, mark);
2274
+ rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
2229
2275
  }
2230
2276
  if (values !== void 0) values.push(result2.value);
2231
2277
  continue;
@@ -3559,6 +3605,7 @@ var OP_LIVE = 37;
3559
3605
  var OP_ATTEMPT = 38;
3560
3606
  var OP_LABEL = 39;
3561
3607
  var OP_COV = 40;
3608
+ var OP_SCOPE_PLAIN = 41;
3562
3609
  var OP_DISPATCH = 25;
3563
3610
  var OP_ROUTED = 26;
3564
3611
  var OP_NAMES = {
@@ -3601,515 +3648,844 @@ var OP_NAMES = {
3601
3648
  [OP_LIVE]: "LIVE",
3602
3649
  [OP_ATTEMPT]: "ATTEMPT",
3603
3650
  [OP_LABEL]: "LABEL",
3604
- [OP_COV]: "COV"
3651
+ [OP_COV]: "COV",
3652
+ [OP_SCOPE_PLAIN]: "SCOPE_PLAIN"
3605
3653
  };
3606
3654
 
3607
- // src/table/scan-shapes.ts
3608
- var BACKSLASH = 92;
3609
- var META2 = new Set("()[]{}*+?|^$.".split(""));
3610
- function classToRanges(cls) {
3611
- if (cls === "\\d") return shorthandRanges("d");
3612
- if (cls === "\\w") return shorthandRanges("w");
3613
- if (cls === "\\s") return shorthandRanges("s");
3614
- const body = cls.slice(1, -1);
3615
- if (body.startsWith("^")) return null;
3616
- return parseClassRanges(body);
3655
+ // src/table/program.ts
3656
+ function closureArtifact(prog) {
3657
+ return { ...prog, asm: [] };
3617
3658
  }
3618
- var foldEq = (cVar, cp) => {
3619
- if (cp >= 65 && cp <= 90) return `(${cVar} | 32) === ${cp + 32}`;
3620
- if (cp >= 97 && cp <= 122) return `(${cVar} | 32) === ${cp}`;
3621
- return `${cVar} === ${cp}`;
3622
- };
3623
- function parseStringShape(source) {
3624
- const q2 = source[0];
3625
- if (q2 === void 0 || q2 === "\\" || META2.has(q2)) return null;
3626
- if (source.length < 3 || source[source.length - 1] !== q2) return null;
3627
- const inner = source.slice(1, -1);
3628
- const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
3629
- const ESC = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
3630
- let body;
3631
- let esc;
3632
- let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC}\\)\\*$`).exec(inner);
3633
- if (m) {
3634
- body = m[1];
3635
- esc = m[2];
3636
- } else {
3637
- m = new RegExp(`^\\((?:\\?:)?${ESC}\\|${CLS}\\)\\*$`).exec(inner);
3638
- if (m) {
3639
- esc = m[1];
3640
- body = m[2];
3641
- }
3659
+ function covKindCode(kind) {
3660
+ switch (kind) {
3661
+ case "rule":
3662
+ return 0;
3663
+ case "choice-arm":
3664
+ return 1;
3665
+ case "dispatch-arm":
3666
+ return 2;
3667
+ case "label":
3668
+ return 3;
3642
3669
  }
3643
- if (body === void 0 || esc === void 0) return null;
3644
- const excluded = parseClassRanges(body);
3645
- if (!excluded) return null;
3646
- const qcp = q2.codePointAt(0);
3647
- const inSet = (cp) => excluded.some(([lo, hi]) => cp >= lo && cp <= hi);
3648
- if (!inSet(qcp) || !inSet(BACKSLASH)) return null;
3649
- return { kind: "string", quote: qcp, excluded, escLineTerm: esc !== "." };
3650
3670
  }
3651
- function parseSeqParts(source) {
3652
- const parts = [];
3653
- let lit = [];
3654
- const flush = () => {
3655
- if (lit.length) {
3656
- parts.push({ part: "lit", cps: lit, optional: false });
3657
- lit = [];
3658
- }
3659
- };
3660
- const braceQuant = (at) => {
3661
- const close = source.indexOf("}", at);
3662
- if (close === -1) return null;
3663
- const body = source.slice(at + 1, close);
3664
- const m = /^(\d+)(,(\d*)?)?$/.exec(body);
3665
- if (!m) return null;
3666
- const min = Number(m[1]);
3667
- const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
3668
- if (max < 1 || min > max) return null;
3669
- return { min, max, len: close - at + 1 };
3671
+ function covKindName(code) {
3672
+ switch (code) {
3673
+ case 0:
3674
+ return "rule";
3675
+ case 1:
3676
+ return "choice-arm";
3677
+ case 2:
3678
+ return "dispatch-arm";
3679
+ case 3:
3680
+ return "label";
3681
+ }
3682
+ }
3683
+ function covDefinitions(prog) {
3684
+ return (prog.cov ?? []).map(([id, kind]) => ({ id, kind: covKindName(kind) }));
3685
+ }
3686
+ function expandCompact(p) {
3687
+ if ("code" in p) return p;
3688
+ return ownTableProgram({
3689
+ code: p.c,
3690
+ k: p.k,
3691
+ cc: p.x,
3692
+ fx: p.e,
3693
+ disp: p.d,
3694
+ rules: p.r,
3695
+ fns: p.f,
3696
+ lines: p.l ?? 0,
3697
+ dsp: p.p ?? [],
3698
+ ...p.lb === void 0 ? {} : { labels: p.lb },
3699
+ ...p.rc === void 0 ? {} : { classified: p.rc },
3700
+ ...p.h === void 0 ? {} : { hostMode: p.h },
3701
+ ...p.tv === void 0 ? {} : { triviaSpecs: p.tv },
3702
+ ...p.sc === void 0 ? {} : { scans: p.sc },
3703
+ ...p.ss === void 0 ? {} : { scanSkip: p.ss },
3704
+ ...p.so === void 0 ? {} : { scanSkipOf: p.so },
3705
+ ...p.rv === void 0 ? {} : { rec: p.rv },
3706
+ ...p.cv === void 0 ? {} : { cov: p.cv },
3707
+ ...p.a === void 0 ? {} : { asm: p.a }
3708
+ });
3709
+ }
3710
+ function validateDispatchSpec(spec, arity, fallbackRouted) {
3711
+ const invalid = (arms) => {
3712
+ for (const arm of arms) if (!Number.isInteger(arm) || arm < 0 || arm >= arity) return true;
3713
+ return false;
3670
3714
  };
3671
- const runFrom = (ranges, negated, at) => {
3672
- const q2 = source[at];
3673
- if (q2 === "+") {
3674
- parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
3675
- return 1;
3715
+ if (spec === void 0 || !Number.isInteger(arity) || arity < 0 || fallbackRouted !== 0 && fallbackRouted !== 1 || spec.routed.length !== arity || spec.routed.some((value) => value !== 0 && value !== 1) || invalid(spec.byKey.values()) || invalid(spec.byFold.values()) || spec.match.some((matcher) => invalid([matcher[3]]))) {
3716
+ throw new TypeError("table: malformed dispatch");
3717
+ }
3718
+ }
3719
+ var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
3720
+ function ownTableProgram(prog, resolved) {
3721
+ return { ...prog, [TABLE_RUNTIME]: { resolved } };
3722
+ }
3723
+ var WIDE_CLASS_PREFIX_LO = 65535;
3724
+ var WIDE_CLASS_PREFIX_HI = 0;
3725
+ function validateClassRange(lo, hi) {
3726
+ for (const cp of [lo, hi]) {
3727
+ if (!Number.isInteger(cp) || cp < 0 || cp > 1114111) {
3728
+ throw new TypeError(`table char-class endpoint is outside Unicode: ${cp}`);
3676
3729
  }
3677
- if (q2 === "*") {
3678
- parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
3679
- return 1;
3730
+ }
3731
+ if (lo > hi) {
3732
+ throw new TypeError(`table char-class range is descending: ${lo} > ${hi}`);
3733
+ }
3734
+ }
3735
+ function encodeClassSpec(ranges) {
3736
+ let wide = false;
3737
+ for (const range of ranges) {
3738
+ validateClassRange(range.lo, range.hi);
3739
+ if (range.hi > 65535) wide = true;
3740
+ }
3741
+ if (!wide) {
3742
+ let spec2 = "";
3743
+ for (const range of ranges) spec2 += String.fromCharCode(range.lo, range.hi);
3744
+ return spec2;
3745
+ }
3746
+ let spec = String.fromCharCode(WIDE_CLASS_PREFIX_LO, WIDE_CLASS_PREFIX_HI);
3747
+ for (const range of ranges) {
3748
+ spec += String.fromCharCode(
3749
+ range.lo >>> 16,
3750
+ range.lo & 65535,
3751
+ range.hi >>> 16,
3752
+ range.hi & 65535
3753
+ );
3754
+ }
3755
+ return spec;
3756
+ }
3757
+ function decodeClassSpec(spec) {
3758
+ if (spec.charCodeAt(0) === WIDE_CLASS_PREFIX_LO && spec.charCodeAt(1) === WIDE_CLASS_PREFIX_HI) {
3759
+ if ((spec.length - 2) % 4 !== 0) throw new TypeError("table char-class spec has a truncated wide range");
3760
+ if (spec.length === 2) throw new TypeError("table char-class spec has a wide prefix but no ranges");
3761
+ const ranges2 = [];
3762
+ for (let i = 2; i < spec.length; i += 4) {
3763
+ const lo = spec.charCodeAt(i) * 65536 + spec.charCodeAt(i + 1);
3764
+ const hi = spec.charCodeAt(i + 2) * 65536 + spec.charCodeAt(i + 3);
3765
+ validateClassRange(lo, hi);
3766
+ ranges2.push({ lo, hi });
3680
3767
  }
3681
- if (q2 === "?") {
3682
- parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
3683
- return 1;
3768
+ return ranges2;
3769
+ }
3770
+ if (spec.length % 2 !== 0) throw new TypeError("table char-class spec has an unmatched range endpoint");
3771
+ const ranges = [];
3772
+ for (let i = 0; i < spec.length; i += 2) {
3773
+ const lo = spec.charCodeAt(i);
3774
+ const hi = spec.charCodeAt(i + 1);
3775
+ validateClassRange(lo, hi);
3776
+ ranges.push({ lo, hi });
3777
+ }
3778
+ return ranges;
3779
+ }
3780
+ function resolveClass(spec) {
3781
+ const ascii = new Uint8Array(128);
3782
+ const hi = [];
3783
+ for (const { lo, hi: up } of decodeClassSpec(spec)) {
3784
+ if (lo < 128) for (let c = lo; c <= Math.min(up, 127); c++) ascii[c] = 1;
3785
+ if (up >= 128) hi.push(Math.max(lo, 128), up);
3786
+ }
3787
+ return { ascii, hi };
3788
+ }
3789
+ function classHas(cls, code) {
3790
+ if (code < 0) return false;
3791
+ if (code < 128) return cls.ascii[code] === 1;
3792
+ const hi = cls.hi;
3793
+ for (let i = 0; i < hi.length; i += 2) if (code >= hi[i] && code <= hi[i + 1]) return true;
3794
+ return false;
3795
+ }
3796
+ function resolveDispatch(arms, cc) {
3797
+ const ascii = new Uint8Array(128);
3798
+ const hi = [];
3799
+ const open = [];
3800
+ const armCls = [];
3801
+ let exclusive = true;
3802
+ let hiOwners = 0;
3803
+ for (let a = 0; a < arms.length; a++) {
3804
+ const ci = arms[a];
3805
+ if (ci < 0) {
3806
+ open.push(a);
3807
+ armCls.push(null);
3808
+ exclusive = false;
3809
+ continue;
3684
3810
  }
3685
- if (q2 === "{") {
3686
- const b = braceQuant(at);
3687
- if (b) {
3688
- parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
3689
- return b.len;
3690
- }
3811
+ const cls = cc[ci];
3812
+ armCls.push(cls);
3813
+ for (let c = 0; c < 128; c++) {
3814
+ if (cls.ascii[c] !== 1) continue;
3815
+ if (ascii[c] === 0) ascii[c] = a + 1;
3816
+ else exclusive = false;
3691
3817
  }
3692
- parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
3693
- return 0;
3694
- };
3695
- let i = 0;
3696
- while (i < source.length) {
3697
- const ch2 = source[i];
3698
- if (ch2 === "[") {
3699
- let k = i + 1;
3700
- const neg = source[k] === "^";
3701
- if (neg) k++;
3702
- let body = "";
3703
- while (k < source.length && source[k] !== "]") {
3704
- if (source[k] === "\\") {
3705
- body += source[k] + (source[k + 1] ?? "");
3706
- k += 2;
3707
- } else {
3708
- body += source[k];
3709
- k++;
3710
- }
3711
- }
3712
- if (source[k] !== "]") return null;
3713
- const ranges = parseClassRanges(body);
3714
- if (!ranges) return null;
3715
- flush();
3716
- i = k + 1;
3717
- i += runFrom(ranges, neg, i);
3718
- continue;
3818
+ if (cls.hi.length > 0 && ++hiOwners > 1) exclusive = false;
3819
+ for (let i = 0; i < cls.hi.length; i += 2) hi.push(cls.hi[i], cls.hi[i + 1], a);
3820
+ }
3821
+ return { ascii, hi, open, armCls, exclusive };
3822
+ }
3823
+ function buildTrivia(spec) {
3824
+ if (spec.live !== void 0) return spec.live;
3825
+ if (spec.plain !== void 0) return trivia(regex(new RegExp(spec.plain[0], spec.plain[1])));
3826
+ if (spec.alts !== void 0) {
3827
+ const [head, ...rest] = spec.alts.map(([source, flags]) => regex(new RegExp(source, flags)));
3828
+ if (head === void 0) throw new TypeError("trivia spec has an EMPTY alternation, which matches nothing");
3829
+ const body = rest.length === 0 ? head : choice(head, ...rest);
3830
+ return trivia(many(body, { min: spec.min ?? 1 }));
3831
+ }
3832
+ const arms = {};
3833
+ for (const [name, source, flags] of spec.arms) arms[name] = regex(new RegExp(source, flags));
3834
+ return classifiedTrivia(arms);
3835
+ }
3836
+ function resolveTable(prog) {
3837
+ const owner = prog[TABLE_RUNTIME];
3838
+ const hit = owner?.resolved;
3839
+ if (hit !== void 0) return hit;
3840
+ const cc = prog.cc.map(resolveClass);
3841
+ const triviaBuilt = (prog.triviaSpecs ?? []).map(buildTrivia);
3842
+ const built = {
3843
+ prog,
3844
+ code: Int32Array.from(prog.code),
3845
+ k: prog.k,
3846
+ fns: prog.fns,
3847
+ cc,
3848
+ fx: prog.fx,
3849
+ disp: prog.disp.map((d) => resolveDispatch(d, cc)),
3850
+ trivia: triviaBuilt,
3851
+ triviaScan: triviaBuilt.map(fastTriviaScanner),
3852
+ triviaLabelled: triviaBuilt.map((t) => t._meta.triviaKindLabels !== void 0),
3853
+ dsp: prog.dsp.map((d) => ({
3854
+ byKey: new Map(d.key.map((x, i) => [x, d.keyArm[i]])),
3855
+ byFold: new Map(d.fold.map((x, i) => [x, d.foldArm[i]])),
3856
+ match: d.match,
3857
+ routed: d.routed,
3858
+ expected: d.expected
3859
+ })),
3860
+ rules: prog.rules
3861
+ };
3862
+ if (owner !== void 0) owner.resolved = built;
3863
+ return built;
3864
+ }
3865
+ var FOLDED_RUNTIME = /* @__PURE__ */ Symbol("parseman.foldedRuntime");
3866
+ function ownFoldedProgram(base, variants) {
3867
+ return { base, variants, [FOLDED_RUNTIME]: { byName: /* @__PURE__ */ new Map() } };
3868
+ }
3869
+ var SHARED_FIELDS = [
3870
+ "k",
3871
+ "cc",
3872
+ "fx",
3873
+ "disp",
3874
+ "dsp",
3875
+ "rules",
3876
+ "labels",
3877
+ "classified",
3878
+ "scanSkip",
3879
+ "scanSkipOf",
3880
+ "scans",
3881
+ "triviaSpecs",
3882
+ "runtimeOnly",
3883
+ // `rec` is a property of the GRAMMAR BUILD, not of the trackLines/hostMode
3884
+ // axis a fold varies — every variant of one export is encoded with the same
3885
+ // recovery setting, and a mismatch is two tables, which is what the refusal says.
3886
+ "rec",
3887
+ // `cov` is a property of the GRAMMAR and its coverage plan, for the same reason
3888
+ // `rec` is a property of the build: the plan is built from the rule map, which
3889
+ // every variant of one export shares. It ships ONCE, and a variant that
3890
+ // disagrees is two tables — which is what the refusal says.
3891
+ "cov"
3892
+ ];
3893
+ function foldPrograms(programs, baseName) {
3894
+ const suppliedBase = programs[baseName];
3895
+ if (suppliedBase === void 0) throw new TypeError(`foldPrograms: no program named ${JSON.stringify(baseName)}`);
3896
+ const base = closureArtifact(suppliedBase);
3897
+ const variants = {};
3898
+ for (const name of Object.keys(programs)) {
3899
+ const p = programs[name];
3900
+ if (p.asm !== void 0 && p.asm.length > 0) {
3901
+ throw new TypeError(
3902
+ `foldPrograms: program ${JSON.stringify(name)} already carries pre-compiled assemblies. An assembly is emitted from a \`code\` stream and a fold overwrites \`code\` per variant, so pre-compiling must happen AFTER the fold, per variant \u2014 not before it.`
3903
+ );
3719
3904
  }
3720
- if (ch2 === "\\") {
3721
- const e = source[i + 1];
3722
- if (e === "d" || e === "w" || e === "s") {
3723
- flush();
3724
- i += 2;
3725
- i += runFrom(shorthandRanges(e), false, i);
3726
- continue;
3727
- }
3728
- const uni = readUnicodeEscape(source, i);
3729
- let cp2;
3730
- if (uni) {
3731
- cp2 = uni.cp;
3732
- i = uni.next;
3733
- } else if (e === void 0) return null;
3734
- else if (e in CLASS_ESCAPES) {
3735
- cp2 = CLASS_ESCAPES[e];
3736
- i += 2;
3737
- } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
3738
- else {
3739
- cp2 = e.codePointAt(0);
3740
- i += 2;
3741
- }
3742
- if (source[i] === "?") {
3743
- flush();
3744
- parts.push({ part: "lit", cps: [cp2], optional: true });
3745
- i++;
3746
- } else lit.push(cp2);
3747
- continue;
3905
+ if (p.code.length !== base.code.length) {
3906
+ throw new TypeError(
3907
+ `foldPrograms: variant ${JSON.stringify(name)} has ${p.code.length} code words, base ${JSON.stringify(baseName)} has ${base.code.length}. A fold overwrites words; it cannot resize the stream. These are two different tables, not one table and its edits.`
3908
+ );
3748
3909
  }
3749
- if (ch2 === "(") {
3750
- if (source[i + 1] !== "?" || source[i + 2] !== ":") return null;
3751
- let k = i + 3;
3752
- let depth = 1;
3753
- while (k < source.length && depth > 0) {
3754
- const c2 = source[k];
3755
- if (c2 === "\\") {
3756
- k += 2;
3757
- continue;
3758
- }
3759
- if (c2 === "[") {
3760
- let j = k + 1;
3761
- if (source[j] === "^") j++;
3762
- while (j < source.length && source[j] !== "]") {
3763
- if (source[j] === "\\") j += 2;
3764
- else j++;
3765
- }
3766
- if (source[j] !== "]") return null;
3767
- k = j + 1;
3768
- continue;
3769
- }
3770
- if (c2 === "(") depth++;
3771
- else if (c2 === ")") depth--;
3772
- k++;
3773
- }
3774
- if (depth !== 0) return null;
3775
- const body = source.slice(i + 3, k - 1);
3776
- const inner = parseScanShape(body);
3777
- if (!inner || !groupInnerSafe(inner)) return null;
3778
- const q2 = source[k];
3779
- if (q2 === "{") return null;
3780
- flush();
3781
- if (q2 === "+") {
3782
- if (shapeCanBeEmpty(inner)) return null;
3783
- parts.push({ part: "group", inner, min: 1, unbounded: true });
3784
- i = k + 1;
3785
- } else if (q2 === "*") {
3786
- if (shapeCanBeEmpty(inner)) return null;
3787
- parts.push({ part: "group", inner, min: 0, unbounded: true });
3788
- i = k + 1;
3789
- } else if (q2 === "?") {
3790
- parts.push({ part: "group", inner, min: 0, unbounded: false });
3791
- i = k + 1;
3792
- } else {
3793
- parts.push({ part: "group", inner, min: 1, unbounded: false });
3794
- i = k;
3910
+ for (const f of SHARED_FIELDS) {
3911
+ if (JSON.stringify(p[f]) !== JSON.stringify(base[f])) {
3912
+ throw new TypeError(
3913
+ `foldPrograms: variant ${JSON.stringify(name)} differs from base ${JSON.stringify(baseName)} in ${JSON.stringify(f)}, which the fold ships ONCE. Either the variants are not encodings of one grammar, or this field has become variant-dependent and needs its own delta.`
3914
+ );
3795
3915
  }
3796
- continue;
3797
3916
  }
3798
- if (META2.has(ch2)) return null;
3799
- const cp = ch2.codePointAt(0);
3800
- i += ch2.length;
3801
- if (source[i] === "?") {
3802
- flush();
3803
- parts.push({ part: "lit", cps: [cp], optional: true });
3804
- i++;
3805
- } else lit.push(cp);
3806
- }
3807
- flush();
3808
- return parts.length ? parts : null;
3809
- }
3810
- function seqIsUnambiguous(parts) {
3811
- let hasMandatory = false;
3812
- for (let k = 0; k < parts.length; k++) {
3813
- const p = parts[k];
3814
- const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
3815
- if (mandatory) hasMandatory = true;
3816
- if (p.part === "group") {
3817
- const exposure = groupPartExposure(p);
3818
- if (exposure === "unsupported") {
3819
- const trailingOnce = k === parts.length - 1 && p.min === 1 && !p.unbounded;
3820
- if (!trailingOnce) return false;
3821
- } else if (exposure !== null) {
3822
- if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
3823
- }
3917
+ if (p.fns.length !== base.fns.length || p.fns.some((f, i) => f !== base.fns[i])) {
3918
+ throw new TypeError(
3919
+ `foldPrograms: variant ${JSON.stringify(name)} does not share the base's reducer pool BY IDENTITY. Equal source text is not enough \u2014 two closures can print alike and capture different scopes. Encode every variant from ONE grammar export.`
3920
+ );
3824
3921
  }
3825
- const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
3826
- if (needsDisjoint) {
3827
- const rest = seqFirstAccept(parts.slice(k + 1));
3828
- if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
3922
+ const at = [];
3923
+ const to = [];
3924
+ let prev = 0;
3925
+ for (let i = 0; i < p.code.length; i++) {
3926
+ if (p.code[i] === base.code[i]) continue;
3927
+ at.push(i - prev);
3928
+ to.push(p.code[i]);
3929
+ prev = i;
3829
3930
  }
3931
+ variants[name] = {
3932
+ at,
3933
+ to,
3934
+ ...p.lines === void 0 ? {} : { lines: p.lines },
3935
+ ...p.hostMode === void 0 ? {} : { hostMode: p.hostMode }
3936
+ };
3830
3937
  }
3831
- return hasMandatory;
3832
- }
3833
- function rangesOverlap(a, b) {
3834
- return a.some(([lo, hi]) => b.some(([lo2, hi2]) => lo <= hi2 && lo2 <= hi));
3835
- }
3836
- function rangesSubset(sub, sup) {
3837
- return sub.every(([lo, hi]) => sup.some(([lo2, hi2]) => lo >= lo2 && hi <= hi2));
3838
- }
3839
- function classSubset(t, u) {
3840
- if (!t.negated && !u.negated) return rangesSubset(t.ranges, u.ranges);
3841
- if (!t.negated && u.negated) return !rangesOverlap(t.ranges, u.ranges);
3842
- if (t.negated && !u.negated) return false;
3843
- return rangesSubset(u.ranges, t.ranges);
3844
- }
3845
- function classDisjoint(t, u) {
3846
- if (!t.negated && !u.negated) return !rangesOverlap(t.ranges, u.ranges);
3847
- if (!t.negated && u.negated) return rangesSubset(t.ranges, u.ranges);
3848
- if (t.negated && !u.negated) return rangesSubset(u.ranges, t.ranges);
3849
- return false;
3850
- }
3851
- function firstSetsDisjoint(a, b) {
3852
- if (a === "any" || b === "any") return false;
3853
- return classDisjoint(a, b);
3938
+ return ownFoldedProgram(base, variants);
3854
3939
  }
3855
- function fixedClassSeq(shape) {
3856
- if (shape.kind === "litFold") {
3857
- return shape.open.map((cp) => {
3858
- const other = cp >= 65 && cp <= 90 ? cp + 32 : cp >= 97 && cp <= 122 ? cp - 32 : cp;
3859
- return other === cp ? { ranges: [[cp, cp]], negated: false } : { ranges: [[Math.min(cp, other), Math.min(cp, other)], [Math.max(cp, other), Math.max(cp, other)]], negated: false };
3860
- });
3861
- }
3862
- if (shape.kind !== "seq") return null;
3863
- const out = [];
3864
- for (const p of shape.parts) {
3865
- if (p.part === "lit") {
3866
- if (p.optional) return null;
3867
- for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
3868
- } else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
3869
- for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
3870
- } else {
3871
- return null;
3872
- }
3873
- }
3874
- return out.length ? out : null;
3875
- }
3876
- function altFixedMutuallyExclusive(shape) {
3877
- if (shape.kind !== "alt" || shape.disjoint) return false;
3878
- const lists = [];
3879
- for (const arm of shape.arms) {
3880
- const f = fixedClassSeq(arm);
3881
- if (!f) return false;
3882
- lists.push(f);
3940
+ function unfoldVariant(folded, name) {
3941
+ const byName = folded[FOLDED_RUNTIME]?.byName;
3942
+ const hit = byName?.get(name);
3943
+ if (hit !== void 0) return hit;
3944
+ const d = folded.variants[name];
3945
+ if (d === void 0) {
3946
+ throw new TypeError(
3947
+ `unfoldVariant: no variant ${JSON.stringify(name)}. This table carries: ${Object.keys(folded.variants).map((n) => JSON.stringify(n)).join(", ")}.`
3948
+ );
3883
3949
  }
3884
- for (let i = 0; i < lists.length; i++) {
3885
- for (let j = 0; j < lists.length; j++) {
3886
- if (i === j) continue;
3887
- const a = lists[i];
3888
- const b = lists[j];
3889
- if (a.length > b.length) continue;
3890
- let disjointAt = false;
3891
- for (let p = 0; p < a.length; p++) {
3892
- if (classDisjoint(a[p], b[p])) {
3893
- disjointAt = true;
3894
- break;
3895
- }
3896
- }
3897
- if (!disjointAt) return false;
3898
- }
3950
+ const base = folded.base;
3951
+ const code = [...base.code];
3952
+ let ip = 0;
3953
+ for (let i = 0; i < d.at.length; i++) {
3954
+ ip += d.at[i];
3955
+ code[ip] = d.to[i];
3899
3956
  }
3900
- return true;
3901
- }
3902
- function groupPartExposure(part) {
3903
- const innerWiggle = trailingBacktrackClass(part.inner);
3904
- if (innerWiggle === "unsupported") return "unsupported";
3905
- const requiredOnce = !part.unbounded && part.min === 1;
3906
- if (requiredOnce) return innerWiggle;
3907
- const dropExposed = shapeFirstAccept(part.inner);
3908
- if (dropExposed === "any") return "unsupported";
3909
- if (innerWiggle === null) return dropExposed;
3910
- const unioned = unionCharSets([innerWiggle, dropExposed]);
3911
- return unioned === "any" ? "unsupported" : unioned;
3957
+ const raw = {
3958
+ ...base,
3959
+ code,
3960
+ ...d.lines === void 0 ? {} : { lines: d.lines },
3961
+ ...d.hostMode === void 0 ? {} : { hostMode: d.hostMode }
3962
+ };
3963
+ const prog = ownTableProgram(raw);
3964
+ const owner = prog[TABLE_RUNTIME];
3965
+ owner.resolved = { ...resolveTable(base), prog, code: Int32Array.from(code) };
3966
+ byName?.set(name, prog);
3967
+ return prog;
3912
3968
  }
3913
- function trailingBacktrackClass(shape) {
3914
- if (shape.kind === "chars") return { ranges: shape.ranges, negated: false };
3915
- if (shape.kind === "ident") return { ranges: shape.tail, negated: false };
3916
- if (shape.kind === "litFold") return null;
3917
- if (shape.kind === "seq") {
3918
- const last = shape.parts[shape.parts.length - 1];
3919
- if (last.part === "lit") {
3920
- return last.optional ? "unsupported" : null;
3921
- }
3922
- if (last.part === "run") {
3923
- if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
3924
- return null;
3925
- }
3926
- return groupPartExposure(last);
3927
- }
3928
- if (shape.kind === "alt") {
3929
- if (!shape.disjoint) return altFixedMutuallyExclusive(shape) ? null : "unsupported";
3930
- const classes = shape.arms.map(trailingBacktrackClass);
3931
- if (classes.some((c) => c === "unsupported")) return "unsupported";
3932
- const concrete = classes.filter((c) => c !== null);
3933
- if (concrete.length === 0) return null;
3934
- const unioned = unionCharSets(concrete);
3935
- return unioned === "any" ? "unsupported" : unioned;
3969
+ function expandCompactFolded(f) {
3970
+ const variants = {};
3971
+ for (const name of Object.keys(f.v)) {
3972
+ const d = f.v[name];
3973
+ variants[name] = {
3974
+ at: d.a ?? [],
3975
+ to: d.t ?? [],
3976
+ ...d.l === void 0 ? {} : { lines: d.l },
3977
+ ...d.h === void 0 ? {} : { hostMode: d.h }
3978
+ };
3936
3979
  }
3937
- return "unsupported";
3938
- }
3939
- function lookaheadUnambiguous(inner, operand, negative) {
3940
- const tail = trailingBacktrackClass(inner);
3941
- if (tail === "unsupported") return false;
3942
- if (tail === null) return true;
3943
- return negative ? classSubset(tail, operand) : classDisjoint(tail, operand);
3980
+ return ownFoldedProgram(expandCompact(f.b), variants);
3944
3981
  }
3945
- function stripTrailingLookahead(source) {
3946
- if (!source.endsWith(")")) return null;
3947
- for (const negative of [true, false]) {
3948
- const lead2 = negative ? "(?!" : "(?=";
3949
- const idx = source.lastIndexOf(lead2);
3950
- if (idx === -1) continue;
3951
- const operand = parseClassOperand(source.slice(idx + lead2.length, -1));
3952
- if (!operand) continue;
3953
- return { base: source.slice(0, idx), ranges: operand.ranges, classNegated: operand.negated, negative };
3954
- }
3955
- return null;
3982
+
3983
+ // src/table/scan-shapes.ts
3984
+ var BACKSLASH = 92;
3985
+ var META2 = new Set("()[]{}*+?|^$.".split(""));
3986
+ function classToRanges(cls) {
3987
+ if (cls === "\\d") return shorthandRanges("d");
3988
+ if (cls === "\\w") return shorthandRanges("w");
3989
+ if (cls === "\\s") return shorthandRanges("s");
3990
+ const body = cls.slice(1, -1);
3991
+ if (body.startsWith("^")) return null;
3992
+ return parseClassRanges(body);
3956
3993
  }
3957
- function unwrapOuterGroup(source) {
3958
- while (source.startsWith("(?:")) {
3959
- let depth = 1;
3960
- let i = 3;
3961
- let ok = true;
3962
- while (i < source.length && depth > 0) {
3963
- const ch2 = source[i];
3964
- if (ch2 === "\\") {
3965
- i += 2;
3966
- continue;
3967
- }
3968
- if (ch2 === "[") {
3969
- let j = i + 1;
3970
- if (source[j] === "^") j++;
3971
- while (j < source.length && source[j] !== "]") {
3972
- if (source[j] === "\\") j += 2;
3973
- else j++;
3974
- }
3975
- if (source[j] !== "]") {
3976
- ok = false;
3977
- break;
3978
- }
3979
- i = j + 1;
3980
- continue;
3981
- }
3982
- if (ch2 === "(") depth++;
3983
- else if (ch2 === ")") depth--;
3984
- i++;
3994
+ var foldEq = (cVar, cp) => {
3995
+ if (cp >= 65 && cp <= 90) return `(${cVar} | 32) === ${cp + 32}`;
3996
+ if (cp >= 97 && cp <= 122) return `(${cVar} | 32) === ${cp}`;
3997
+ return `${cVar} === ${cp}`;
3998
+ };
3999
+ function parseStringShape(source) {
4000
+ const q2 = source[0];
4001
+ if (q2 === void 0 || q2 === "\\" || META2.has(q2)) return null;
4002
+ if (source.length < 3 || source[source.length - 1] !== q2) return null;
4003
+ const inner = source.slice(1, -1);
4004
+ const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
4005
+ const ESC = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
4006
+ let body;
4007
+ let esc;
4008
+ let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC}\\)\\*$`).exec(inner);
4009
+ if (m) {
4010
+ body = m[1];
4011
+ esc = m[2];
4012
+ } else {
4013
+ m = new RegExp(`^\\((?:\\?:)?${ESC}\\|${CLS}\\)\\*$`).exec(inner);
4014
+ if (m) {
4015
+ esc = m[1];
4016
+ body = m[2];
3985
4017
  }
3986
- if (!ok || depth !== 0 || i !== source.length) break;
3987
- source = source.slice(3, -1);
3988
4018
  }
3989
- return source;
4019
+ if (body === void 0 || esc === void 0) return null;
4020
+ const excluded = parseClassRanges(body);
4021
+ if (!excluded) return null;
4022
+ const qcp = q2.codePointAt(0);
4023
+ const inSet = (cp) => excluded.some(([lo, hi]) => cp >= lo && cp <= hi);
4024
+ if (!inSet(qcp) || !inSet(BACKSLASH)) return null;
4025
+ return { kind: "string", quote: qcp, excluded, escLineTerm: esc !== "." };
3990
4026
  }
3991
- function splitTopLevelAlternation(source) {
3992
- const body = unwrapOuterGroup(source);
4027
+ function parseSeqParts(source) {
3993
4028
  const parts = [];
3994
- let depth = 0;
3995
- let last = 0;
3996
- let i = 0;
3997
- while (i < body.length) {
3998
- const ch2 = body[i];
3999
- if (ch2 === "\\") {
4000
- i += 2;
4001
- continue;
4029
+ let lit = [];
4030
+ const flush = () => {
4031
+ if (lit.length) {
4032
+ parts.push({ part: "lit", cps: lit, optional: false });
4033
+ lit = [];
4002
4034
  }
4003
- if (ch2 === "[") {
4004
- let j = i + 1;
4005
- if (body[j] === "^") j++;
4006
- while (j < body.length && body[j] !== "]") {
4007
- if (body[j] === "\\") j += 2;
4008
- else j++;
4009
- }
4010
- if (body[j] !== "]") return null;
4011
- i = j + 1;
4012
- continue;
4035
+ };
4036
+ const braceQuant = (at) => {
4037
+ const close = source.indexOf("}", at);
4038
+ if (close === -1) return null;
4039
+ const body = source.slice(at + 1, close);
4040
+ const m = /^(\d+)(,(\d*)?)?$/.exec(body);
4041
+ if (!m) return null;
4042
+ const min = Number(m[1]);
4043
+ const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
4044
+ if (max < 1 || min > max) return null;
4045
+ return { min, max, len: close - at + 1 };
4046
+ };
4047
+ const runFrom = (ranges, negated, at) => {
4048
+ const q2 = source[at];
4049
+ if (q2 === "+") {
4050
+ parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
4051
+ return 1;
4013
4052
  }
4014
- if (ch2 === "(") {
4015
- depth++;
4016
- i++;
4017
- continue;
4053
+ if (q2 === "*") {
4054
+ parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
4055
+ return 1;
4018
4056
  }
4019
- if (ch2 === ")") {
4020
- depth--;
4021
- if (depth < 0) return null;
4022
- i++;
4057
+ if (q2 === "?") {
4058
+ parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
4059
+ return 1;
4060
+ }
4061
+ if (q2 === "{") {
4062
+ const b = braceQuant(at);
4063
+ if (b) {
4064
+ parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
4065
+ return b.len;
4066
+ }
4067
+ }
4068
+ parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
4069
+ return 0;
4070
+ };
4071
+ let i = 0;
4072
+ while (i < source.length) {
4073
+ const ch2 = source[i];
4074
+ if (ch2 === "[") {
4075
+ let k = i + 1;
4076
+ const neg = source[k] === "^";
4077
+ if (neg) k++;
4078
+ let body = "";
4079
+ while (k < source.length && source[k] !== "]") {
4080
+ if (source[k] === "\\") {
4081
+ body += source[k] + (source[k + 1] ?? "");
4082
+ k += 2;
4083
+ } else {
4084
+ body += source[k];
4085
+ k++;
4086
+ }
4087
+ }
4088
+ if (source[k] !== "]") return null;
4089
+ const ranges = parseClassRanges(body);
4090
+ if (!ranges) return null;
4091
+ flush();
4092
+ i = k + 1;
4093
+ i += runFrom(ranges, neg, i);
4023
4094
  continue;
4024
4095
  }
4025
- if (ch2 === "|" && depth === 0) {
4026
- parts.push(body.slice(last, i));
4027
- last = i + 1;
4028
- i++;
4096
+ if (ch2 === "\\") {
4097
+ const e = source[i + 1];
4098
+ if (e === "d" || e === "w" || e === "s") {
4099
+ flush();
4100
+ i += 2;
4101
+ i += runFrom(shorthandRanges(e), false, i);
4102
+ continue;
4103
+ }
4104
+ const uni = readUnicodeEscape(source, i);
4105
+ let cp2;
4106
+ if (uni) {
4107
+ cp2 = uni.cp;
4108
+ i = uni.next;
4109
+ } else if (e === void 0) return null;
4110
+ else if (e in CLASS_ESCAPES) {
4111
+ cp2 = CLASS_ESCAPES[e];
4112
+ i += 2;
4113
+ } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
4114
+ else {
4115
+ cp2 = e.codePointAt(0);
4116
+ i += 2;
4117
+ }
4118
+ if (source[i] === "?") {
4119
+ flush();
4120
+ parts.push({ part: "lit", cps: [cp2], optional: true });
4121
+ i++;
4122
+ } else lit.push(cp2);
4029
4123
  continue;
4030
4124
  }
4031
- i++;
4125
+ if (ch2 === "(") {
4126
+ if (source[i + 1] !== "?" || source[i + 2] !== ":") return null;
4127
+ let k = i + 3;
4128
+ let depth = 1;
4129
+ while (k < source.length && depth > 0) {
4130
+ const c2 = source[k];
4131
+ if (c2 === "\\") {
4132
+ k += 2;
4133
+ continue;
4134
+ }
4135
+ if (c2 === "[") {
4136
+ let j = k + 1;
4137
+ if (source[j] === "^") j++;
4138
+ while (j < source.length && source[j] !== "]") {
4139
+ if (source[j] === "\\") j += 2;
4140
+ else j++;
4141
+ }
4142
+ if (source[j] !== "]") return null;
4143
+ k = j + 1;
4144
+ continue;
4145
+ }
4146
+ if (c2 === "(") depth++;
4147
+ else if (c2 === ")") depth--;
4148
+ k++;
4149
+ }
4150
+ if (depth !== 0) return null;
4151
+ const body = source.slice(i + 3, k - 1);
4152
+ const inner = parseScanShape(body);
4153
+ if (!inner || !groupInnerSafe(inner)) return null;
4154
+ const q2 = source[k];
4155
+ if (q2 === "{") return null;
4156
+ flush();
4157
+ if (q2 === "+") {
4158
+ if (shapeCanBeEmpty(inner)) return null;
4159
+ parts.push({ part: "group", inner, min: 1, unbounded: true });
4160
+ i = k + 1;
4161
+ } else if (q2 === "*") {
4162
+ if (shapeCanBeEmpty(inner)) return null;
4163
+ parts.push({ part: "group", inner, min: 0, unbounded: true });
4164
+ i = k + 1;
4165
+ } else if (q2 === "?") {
4166
+ parts.push({ part: "group", inner, min: 0, unbounded: false });
4167
+ i = k + 1;
4168
+ } else {
4169
+ parts.push({ part: "group", inner, min: 1, unbounded: false });
4170
+ i = k;
4171
+ }
4172
+ continue;
4173
+ }
4174
+ if (META2.has(ch2)) return null;
4175
+ const cp = ch2.codePointAt(0);
4176
+ i += ch2.length;
4177
+ if (source[i] === "?") {
4178
+ flush();
4179
+ parts.push({ part: "lit", cps: [cp], optional: true });
4180
+ i++;
4181
+ } else lit.push(cp);
4032
4182
  }
4033
- if (depth !== 0) return null;
4034
- parts.push(body.slice(last));
4035
- if (parts.length < 2 || parts.some((p) => p.length === 0)) return null;
4036
- return parts;
4183
+ flush();
4184
+ return parts.length ? parts : null;
4037
4185
  }
4038
- function shapeCanBeEmpty(shape) {
4039
- if (shape.kind === "chars") return !shape.minOne;
4040
- if (shape.kind === "lookahead") return shapeCanBeEmpty(shape.inner);
4041
- if (shape.kind === "alt") return shape.arms.some(shapeCanBeEmpty);
4042
- return false;
4186
+ function seqIsUnambiguous(parts) {
4187
+ let hasMandatory = false;
4188
+ for (let k = 0; k < parts.length; k++) {
4189
+ const p = parts[k];
4190
+ const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
4191
+ if (mandatory) hasMandatory = true;
4192
+ if (p.part === "group") {
4193
+ const exposure = groupPartExposure(p);
4194
+ if (exposure === "unsupported") {
4195
+ const trailingOnce = k === parts.length - 1 && p.min === 1 && !p.unbounded;
4196
+ if (!trailingOnce) return false;
4197
+ } else if (exposure !== null) {
4198
+ if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
4199
+ }
4200
+ }
4201
+ const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
4202
+ if (needsDisjoint) {
4203
+ const rest = seqFirstAccept(parts.slice(k + 1));
4204
+ if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
4205
+ }
4206
+ }
4207
+ return hasMandatory;
4043
4208
  }
4044
- function unionCharSets(sets) {
4045
- if (sets.some((s) => s === "any")) return "any";
4046
- const concrete = sets;
4047
- if (concrete.length === 1) return concrete[0];
4048
- if (concrete.some((s) => s.negated)) return "any";
4049
- return { ranges: concrete.flatMap((s) => s.ranges), negated: false };
4209
+ function rangesOverlap(a, b) {
4210
+ return a.some(([lo, hi]) => b.some(([lo2, hi2]) => lo <= hi2 && lo2 <= hi));
4050
4211
  }
4051
- function partFirstAccept(part) {
4052
- if (part.part === "lit") return { ranges: [[part.cps[0], part.cps[0]]], negated: false };
4053
- if (part.part === "run") return { ranges: part.ranges, negated: part.negated };
4054
- return shapeFirstAccept(part.inner);
4212
+ function rangesSubset(sub, sup) {
4213
+ return sub.every(([lo, hi]) => sup.some(([lo2, hi2]) => lo >= lo2 && hi <= hi2));
4055
4214
  }
4056
- function seqFirstAccept(parts) {
4057
- const sets = [];
4058
- for (const p of parts) {
4059
- const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
4060
- sets.push(partFirstAccept(p));
4061
- if (mandatory) break;
4062
- }
4063
- return unionCharSets(sets);
4215
+ function classSubset(t, u) {
4216
+ if (!t.negated && !u.negated) return rangesSubset(t.ranges, u.ranges);
4217
+ if (!t.negated && u.negated) return !rangesOverlap(t.ranges, u.ranges);
4218
+ if (t.negated && !u.negated) return false;
4219
+ return rangesSubset(u.ranges, t.ranges);
4064
4220
  }
4065
- function groupInnerSafe(shape) {
4066
- if (shape.kind === "chars" || shape.kind === "ident" || shape.kind === "seq" || shape.kind === "litFold") return true;
4067
- if (shape.kind === "lookahead") return groupInnerSafe(shape.inner);
4068
- if (shape.kind === "alt") return true;
4221
+ function classDisjoint(t, u) {
4222
+ if (!t.negated && !u.negated) return !rangesOverlap(t.ranges, u.ranges);
4223
+ if (!t.negated && u.negated) return rangesSubset(t.ranges, u.ranges);
4224
+ if (t.negated && !u.negated) return rangesSubset(u.ranges, t.ranges);
4069
4225
  return false;
4070
4226
  }
4071
- function shapeFirstAccept(shape) {
4072
- if (shapeCanBeEmpty(shape)) return "any";
4073
- switch (shape.kind) {
4074
- case "chars":
4075
- return { ranges: shape.ranges, negated: false };
4076
- case "ident":
4077
- return { ranges: shape.head, negated: false };
4078
- case "until":
4079
- return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4080
- case "delimited":
4081
- return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4082
- case "string":
4083
- return { ranges: [[shape.quote, shape.quote]], negated: false };
4084
- case "litFold": {
4085
- const cp = shape.open[0];
4086
- if (cp >= 65 && cp <= 90) return { ranges: [[cp, cp], [cp + 32, cp + 32]], negated: false };
4087
- if (cp >= 97 && cp <= 122) return { ranges: [[cp, cp], [cp - 32, cp - 32]], negated: false };
4088
- return { ranges: [[cp, cp]], negated: false };
4089
- }
4090
- case "seq":
4091
- return seqFirstAccept(shape.parts);
4092
- case "lookahead":
4093
- return shapeFirstAccept(shape.inner);
4094
- // zero-width — doesn't change first-char acceptance
4095
- case "alt": {
4096
- const sets = shape.firsts.map((f) => f === null ? "any" : f);
4097
- return unionCharSets(sets);
4098
- }
4099
- }
4227
+ function firstSetsDisjoint(a, b) {
4228
+ if (a === "any" || b === "any") return false;
4229
+ return classDisjoint(a, b);
4100
4230
  }
4101
- function allPairsDisjoint(sets) {
4102
- for (let i = 0; i < sets.length; i++) {
4103
- const a = sets[i];
4104
- if (a === "any") return false;
4105
- for (let j = i + 1; j < sets.length; j++) {
4106
- const b = sets[j];
4107
- if (b === "any" || !classDisjoint(a, b)) return false;
4231
+ function fixedClassSeq(shape) {
4232
+ if (shape.kind === "litFold") {
4233
+ return shape.open.map((cp) => {
4234
+ const other = cp >= 65 && cp <= 90 ? cp + 32 : cp >= 97 && cp <= 122 ? cp - 32 : cp;
4235
+ return other === cp ? { ranges: [[cp, cp]], negated: false } : { ranges: [[Math.min(cp, other), Math.min(cp, other)], [Math.max(cp, other), Math.max(cp, other)]], negated: false };
4236
+ });
4237
+ }
4238
+ if (shape.kind !== "seq") return null;
4239
+ const out = [];
4240
+ for (const p of shape.parts) {
4241
+ if (p.part === "lit") {
4242
+ if (p.optional) return null;
4243
+ for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
4244
+ } else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
4245
+ for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
4246
+ } else {
4247
+ return null;
4108
4248
  }
4109
4249
  }
4110
- return true;
4250
+ return out.length ? out : null;
4111
4251
  }
4112
- function parseAlternation(source) {
4252
+ function altFixedMutuallyExclusive(shape) {
4253
+ if (shape.kind !== "alt" || shape.disjoint) return false;
4254
+ const lists = [];
4255
+ for (const arm of shape.arms) {
4256
+ const f = fixedClassSeq(arm);
4257
+ if (!f) return false;
4258
+ lists.push(f);
4259
+ }
4260
+ for (let i = 0; i < lists.length; i++) {
4261
+ for (let j = 0; j < lists.length; j++) {
4262
+ if (i === j) continue;
4263
+ const a = lists[i];
4264
+ const b = lists[j];
4265
+ if (a.length > b.length) continue;
4266
+ let disjointAt = false;
4267
+ for (let p = 0; p < a.length; p++) {
4268
+ if (classDisjoint(a[p], b[p])) {
4269
+ disjointAt = true;
4270
+ break;
4271
+ }
4272
+ }
4273
+ if (!disjointAt) return false;
4274
+ }
4275
+ }
4276
+ return true;
4277
+ }
4278
+ function groupPartExposure(part) {
4279
+ const innerWiggle = trailingBacktrackClass(part.inner);
4280
+ if (innerWiggle === "unsupported") return "unsupported";
4281
+ const requiredOnce = !part.unbounded && part.min === 1;
4282
+ if (requiredOnce) return innerWiggle;
4283
+ const dropExposed = shapeFirstAccept(part.inner);
4284
+ if (dropExposed === "any") return "unsupported";
4285
+ if (innerWiggle === null) return dropExposed;
4286
+ const unioned = unionCharSets([innerWiggle, dropExposed]);
4287
+ return unioned === "any" ? "unsupported" : unioned;
4288
+ }
4289
+ function trailingBacktrackClass(shape) {
4290
+ if (shape.kind === "chars") return { ranges: shape.ranges, negated: false };
4291
+ if (shape.kind === "ident") return { ranges: shape.tail, negated: false };
4292
+ if (shape.kind === "litFold") return null;
4293
+ if (shape.kind === "seq") {
4294
+ const last = shape.parts[shape.parts.length - 1];
4295
+ if (last.part === "lit") {
4296
+ return last.optional ? "unsupported" : null;
4297
+ }
4298
+ if (last.part === "run") {
4299
+ if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
4300
+ return null;
4301
+ }
4302
+ return groupPartExposure(last);
4303
+ }
4304
+ if (shape.kind === "alt") {
4305
+ if (!shape.disjoint) return altFixedMutuallyExclusive(shape) ? null : "unsupported";
4306
+ const classes = shape.arms.map(trailingBacktrackClass);
4307
+ if (classes.some((c) => c === "unsupported")) return "unsupported";
4308
+ const concrete = classes.filter((c) => c !== null);
4309
+ if (concrete.length === 0) return null;
4310
+ const unioned = unionCharSets(concrete);
4311
+ return unioned === "any" ? "unsupported" : unioned;
4312
+ }
4313
+ return "unsupported";
4314
+ }
4315
+ function lookaheadUnambiguous(inner, operand, negative) {
4316
+ const tail = trailingBacktrackClass(inner);
4317
+ if (tail === "unsupported") return false;
4318
+ if (tail === null) return true;
4319
+ return negative ? classSubset(tail, operand) : classDisjoint(tail, operand);
4320
+ }
4321
+ function stripTrailingLookahead(source) {
4322
+ if (!source.endsWith(")")) return null;
4323
+ for (const negative of [true, false]) {
4324
+ const lead2 = negative ? "(?!" : "(?=";
4325
+ const idx = source.lastIndexOf(lead2);
4326
+ if (idx === -1) continue;
4327
+ const operand = parseClassOperand(source.slice(idx + lead2.length, -1));
4328
+ if (!operand) continue;
4329
+ return { base: source.slice(0, idx), ranges: operand.ranges, classNegated: operand.negated, negative };
4330
+ }
4331
+ return null;
4332
+ }
4333
+ function unwrapOuterGroup(source) {
4334
+ while (source.startsWith("(?:")) {
4335
+ let depth = 1;
4336
+ let i = 3;
4337
+ let ok = true;
4338
+ while (i < source.length && depth > 0) {
4339
+ const ch2 = source[i];
4340
+ if (ch2 === "\\") {
4341
+ i += 2;
4342
+ continue;
4343
+ }
4344
+ if (ch2 === "[") {
4345
+ let j = i + 1;
4346
+ if (source[j] === "^") j++;
4347
+ while (j < source.length && source[j] !== "]") {
4348
+ if (source[j] === "\\") j += 2;
4349
+ else j++;
4350
+ }
4351
+ if (source[j] !== "]") {
4352
+ ok = false;
4353
+ break;
4354
+ }
4355
+ i = j + 1;
4356
+ continue;
4357
+ }
4358
+ if (ch2 === "(") depth++;
4359
+ else if (ch2 === ")") depth--;
4360
+ i++;
4361
+ }
4362
+ if (!ok || depth !== 0 || i !== source.length) break;
4363
+ source = source.slice(3, -1);
4364
+ }
4365
+ return source;
4366
+ }
4367
+ function splitTopLevelAlternation(source) {
4368
+ const body = unwrapOuterGroup(source);
4369
+ const parts = [];
4370
+ let depth = 0;
4371
+ let last = 0;
4372
+ let i = 0;
4373
+ while (i < body.length) {
4374
+ const ch2 = body[i];
4375
+ if (ch2 === "\\") {
4376
+ i += 2;
4377
+ continue;
4378
+ }
4379
+ if (ch2 === "[") {
4380
+ let j = i + 1;
4381
+ if (body[j] === "^") j++;
4382
+ while (j < body.length && body[j] !== "]") {
4383
+ if (body[j] === "\\") j += 2;
4384
+ else j++;
4385
+ }
4386
+ if (body[j] !== "]") return null;
4387
+ i = j + 1;
4388
+ continue;
4389
+ }
4390
+ if (ch2 === "(") {
4391
+ depth++;
4392
+ i++;
4393
+ continue;
4394
+ }
4395
+ if (ch2 === ")") {
4396
+ depth--;
4397
+ if (depth < 0) return null;
4398
+ i++;
4399
+ continue;
4400
+ }
4401
+ if (ch2 === "|" && depth === 0) {
4402
+ parts.push(body.slice(last, i));
4403
+ last = i + 1;
4404
+ i++;
4405
+ continue;
4406
+ }
4407
+ i++;
4408
+ }
4409
+ if (depth !== 0) return null;
4410
+ parts.push(body.slice(last));
4411
+ if (parts.length < 2 || parts.some((p) => p.length === 0)) return null;
4412
+ return parts;
4413
+ }
4414
+ function shapeCanBeEmpty(shape) {
4415
+ if (shape.kind === "chars") return !shape.minOne;
4416
+ if (shape.kind === "lookahead") return shapeCanBeEmpty(shape.inner);
4417
+ if (shape.kind === "alt") return shape.arms.some(shapeCanBeEmpty);
4418
+ return false;
4419
+ }
4420
+ function unionCharSets(sets) {
4421
+ if (sets.some((s) => s === "any")) return "any";
4422
+ const concrete = sets;
4423
+ if (concrete.length === 1) return concrete[0];
4424
+ if (concrete.some((s) => s.negated)) return "any";
4425
+ return { ranges: concrete.flatMap((s) => s.ranges), negated: false };
4426
+ }
4427
+ function partFirstAccept(part) {
4428
+ if (part.part === "lit") return { ranges: [[part.cps[0], part.cps[0]]], negated: false };
4429
+ if (part.part === "run") return { ranges: part.ranges, negated: part.negated };
4430
+ return shapeFirstAccept(part.inner);
4431
+ }
4432
+ function seqFirstAccept(parts) {
4433
+ const sets = [];
4434
+ for (const p of parts) {
4435
+ const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
4436
+ sets.push(partFirstAccept(p));
4437
+ if (mandatory) break;
4438
+ }
4439
+ return unionCharSets(sets);
4440
+ }
4441
+ function groupInnerSafe(shape) {
4442
+ if (shape.kind === "chars" || shape.kind === "ident" || shape.kind === "seq" || shape.kind === "litFold") return true;
4443
+ if (shape.kind === "lookahead") return groupInnerSafe(shape.inner);
4444
+ if (shape.kind === "alt") return true;
4445
+ return false;
4446
+ }
4447
+ function shapeFirstAccept(shape) {
4448
+ if (shapeCanBeEmpty(shape)) return "any";
4449
+ switch (shape.kind) {
4450
+ case "chars":
4451
+ return { ranges: shape.ranges, negated: false };
4452
+ case "ident":
4453
+ return { ranges: shape.head, negated: false };
4454
+ case "until":
4455
+ return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4456
+ case "delimited":
4457
+ return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4458
+ case "string":
4459
+ return { ranges: [[shape.quote, shape.quote]], negated: false };
4460
+ case "litFold": {
4461
+ const cp = shape.open[0];
4462
+ if (cp >= 65 && cp <= 90) return { ranges: [[cp, cp], [cp + 32, cp + 32]], negated: false };
4463
+ if (cp >= 97 && cp <= 122) return { ranges: [[cp, cp], [cp - 32, cp - 32]], negated: false };
4464
+ return { ranges: [[cp, cp]], negated: false };
4465
+ }
4466
+ case "seq":
4467
+ return seqFirstAccept(shape.parts);
4468
+ case "lookahead":
4469
+ return shapeFirstAccept(shape.inner);
4470
+ // zero-width — doesn't change first-char acceptance
4471
+ case "alt": {
4472
+ const sets = shape.firsts.map((f) => f === null ? "any" : f);
4473
+ return unionCharSets(sets);
4474
+ }
4475
+ }
4476
+ }
4477
+ function allPairsDisjoint(sets) {
4478
+ for (let i = 0; i < sets.length; i++) {
4479
+ const a = sets[i];
4480
+ if (a === "any") return false;
4481
+ for (let j = i + 1; j < sets.length; j++) {
4482
+ const b = sets[j];
4483
+ if (b === "any" || !classDisjoint(a, b)) return false;
4484
+ }
4485
+ }
4486
+ return true;
4487
+ }
4488
+ function parseAlternation(source) {
4113
4489
  const parts = splitTopLevelAlternation(source);
4114
4490
  if (!parts) return null;
4115
4491
  const arms = [];
@@ -4662,6 +5038,7 @@ function childSlots(code, ip, out) {
4662
5038
  case OP_GATE:
4663
5039
  case OP_SCOPE:
4664
5040
  case OP_SCOPE_CAP:
5041
+ case OP_SCOPE_PLAIN:
4665
5042
  case OP_WITHCTX:
4666
5043
  case OP_XFORM:
4667
5044
  case OP_NODE:
@@ -4750,7 +5127,7 @@ function reachableSites(code, roots) {
4750
5127
  }
4751
5128
  function transfer(code, ip, at, hostCst) {
4752
5129
  const op = code[ip];
4753
- if (op === OP_SCOPE || op === OP_SCOPE_CAP) {
5130
+ if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
4754
5131
  const ki = code[ip + 1];
4755
5132
  const tri = ki < 0 ? TRI_NONE : ki;
4756
5133
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
@@ -4831,6 +5208,7 @@ var EMITTED_PARAMS = [
4831
5208
  "pushCstLeaf",
4832
5209
  "pushCstChild",
4833
5210
  "rollbackTriviaAt",
5211
+ "rollbackScannedTriviaAt",
4834
5212
  "failAt",
4835
5213
  "classHas",
4836
5214
  "consumeTrivia",
@@ -4974,19 +5352,24 @@ if(ctx._errors!==undefined&&ctx._errors.length!==${t}er)ctx._errors.length=${t}e
4974
5352
  if (!s.fd && !s.er) return `if(${t}n)rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,0,undefined,${t}lg,${t}rt)`;
4975
5353
  return `if(${t}n){rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,${s.fd ? `${t}fd` : "0"},${s.er ? `${t}er` : "undefined"},${t}lg,${t}rt)}`;
4976
5354
  }
4977
- function emitTerm(callee, dst, t, l, skip, s) {
5355
+ function emitTerm(callee, dst, t, l, skip) {
4978
5356
  const fast = `const ${t}v=${callee}(input,cur,ctx)
4979
5357
  if(${t}v===FAIL)return FAIL
4980
5358
  ${dst}=${t}v
4981
5359
  cur=EC.e`;
4982
5360
  if (l.tri === TRI_NONE) return fast;
4983
- const scanned = `${emitMark(t, l.buf, s)}
5361
+ const scanned = `const ${t}tl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
5362
+ const ${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5363
+ const ${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
4984
5364
  const ${t}s=${skip}(input,cur,ctx)
5365
+ const ${t}stl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
5366
+ const ${t}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5367
+ const ${t}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
4985
5368
  const ${t}v=${callee}(input,${t}s,ctx)
4986
5369
  if(${t}v===FAIL)return FAIL
4987
5370
  ${dst}=${t}v
4988
5371
  if(EC.e>${t}s)cur=EC.e
4989
- else{${emitRollback(t, l.buf, s)}}`;
5372
+ else{rollbackScannedTriviaAt(ctx,${t}tl,${t}stl,${t}lg,${t}slg,${t}rt,${t}srt)}`;
4990
5373
  if (l.tri !== TRI_UNKNOWN) return scanned;
4991
5374
  return `if(ctx.trivia===undefined){
4992
5375
  ${fast}
@@ -5149,7 +5532,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
5149
5532
  const op = code[ip];
5150
5533
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
5151
5534
  if (op === OP_RULE) return code[ip + 1];
5152
- if (op === OP_SCOPE && code[ip + 3] === 0 && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
5535
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
5153
5536
  return code[ip + 2];
5154
5537
  }
5155
5538
  return void 0;
@@ -5200,1048 +5583,731 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
5200
5583
  tests.push(`input.charCodeAt(${at})===${f}`);
5201
5584
  }
5202
5585
  }
5203
- return `${head}
5204
- ${reads.length > 0 ? `${reads.join("\n")}
5205
- ` : ""}if(${tests.join("&&")}){
5206
- const e=pos+${s.length}
5207
- const v=input.slice(pos,e)
5208
- ${captureLeaf("v")}
5209
- ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5210
- return v
5211
- }
5212
- ctx._fe=pos;ctx._fx=${xf}
5213
- ${cfg.probe ? `failAt(ctx,${xf},pos)
5214
- ` : ""}return FAIL
5215
- }`;
5216
- }
5217
- case OP_RX:
5218
- case OP_RX_TRACK: {
5219
- const xf = fxRef(code[ip + 2]);
5220
- const track = op === OP_RX_TRACK;
5221
- const scanned = emitScan(code[ip + 1], xf, track, captureLeaf);
5222
- if (scanned !== void 0) return `${head}${scanned}}`;
5223
- const rxk = k[code[ip + 1]];
5224
- if (!(rxk instanceof RegExp) || !rxk.sticky) throw new Unemittable("a non-sticky regex row");
5225
- const re = kRef(code[ip + 1]);
5226
- return `${head}
5227
- ${re}.lastIndex=pos
5228
- if(${re}.test(input)){
5229
- const e=${re}.lastIndex
5230
- const v=input.slice(pos,e)
5231
- ${captureLeaf("v")}
5232
- ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5233
- return v
5234
- }
5235
- ctx._fe=pos;ctx._fx=${xf}
5236
- ${cfg.probe ? `failAt(ctx,${xf},pos)
5237
- ` : ""}return FAIL
5238
- }`;
5239
- }
5240
- case OP_EMPTY:
5241
- return `${head}EC.e=pos;return ''}`;
5242
- case OP_GATE: {
5243
- const child = link(code[ip + 2]);
5244
- const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
5245
- classPlan.push([code[ip + 1]]);
5246
- const cls = hoist("cl", `CLS[${ci}][0]`);
5247
- const xf = fxRef(code[ip + 3]);
5248
- return `${head}
5249
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5250
- return ${child}(input,pos,ctx)
5251
- }`;
5252
- }
5253
- case OP_XFORM: {
5254
- const fn = fnRef(code[ip + 1]);
5255
- const child = link(code[ip + 2]);
5256
- return `${head}
5257
- const v=${child}(input,pos,ctx)
5258
- if(v===FAIL)return FAIL
5259
- return ${fn}(v,{start:pos,end:EC.e})
5260
- }`;
5261
- }
5262
- case OP_LABEL: {
5263
- const child = link(code[ip + 1]);
5264
- const xf = fxRef(code[ip + 2]);
5265
- return `${head}
5266
- const v=${child}(input,pos,ctx)
5267
- if(v===FAIL)ctx._fx=${xf}
5268
- return v
5269
- }`;
5270
- }
5271
- case OP_FIELD: {
5272
- const name = q(k[code[ip + 1]]);
5273
- const child = link(code[ip + 2]);
5274
- return `${head}
5275
- const v=${child}(input,pos,ctx)
5276
- if(v===FAIL)return FAIL
5277
- const f=ctx._fields
5278
- if(f!==undefined)f.push({name:${name},value:v,span:{start:pos,end:EC.e}})
5279
- return v
5280
- }`;
5281
- }
5282
- case OP_EXPECT: {
5283
- const child = link(code[ip + 1]);
5284
- const xf = fxRef(code[ip + 2]);
5285
- return `${head}
5286
- const v=${child}(input,pos,ctx)
5287
- if(v!==FAIL)return v
5288
- const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "{start:pos,end:pos}"},expected:${xf}}
5289
- const es=ctx._errors
5290
- if(es!==undefined)es.push(err)
5291
- ${REC ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
5292
- EC.e=pos
5293
- return err
5294
- }`;
5295
- }
5296
- case OP_ROUTED: {
5297
- const fb = code[ip + 1];
5298
- const fallback = fb >= 0 ? link(fb) : void 0;
5299
- const push = `pushCstLeaf(ctx,{_tag:'leaf',value:it.value,span:it.span})`;
5300
- return `${head}
5301
- const it=ctx._routed
5302
- if(it===undefined||pos!==it.span.start){
5303
- ${fallback !== void 0 ? `return ${fallback}(input,pos,ctx)` : "ctx._fe=pos;ctx._fx=ROUTED_FX;return FAIL"}
5304
- }
5305
- ${L.buf ? push : `if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)${push}`}
5306
- EC.e=it.span.end
5307
- return it.value
5308
- }`;
5309
- }
5310
- case OP_SCAN: {
5311
- const si = code[ip + 1];
5312
- return `${head}
5313
- const r=SCANS[${si}].parse(input,pos,ctx)
5314
- if(!r.ok){ctx._fe=r.span.start;ctx._fx=r.expected??EMPTY_FX;return FAIL}
5315
- EC.e=r.span.end
5316
- return r.value
5317
- }`;
5318
- }
5319
- case OP_SCOPE:
5320
- case OP_SCOPE_CAP: {
5321
- const ki = code[ip + 1];
5322
- const cap = op === OP_SCOPE_CAP;
5323
- const flags = code[ip + 3];
5324
- const child = link(code[ip + 2]);
5325
- const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
5326
- const tri = ki < 0 ? "undefined" : hoist("tv", `TRIVIA[${ki}]`);
5327
- const lab = ki < 0 ? "undefined" : hoist("tl", `TRIVIA[${ki}]._meta.triviaKindLabels`);
5328
- const strict = (flags & 2) !== 0 ? "refuseUnclassifiedRootScope(ctx._rootTriviaStrictScopes)\n" : "";
5329
- const rootCap = (flags & 1) !== 0;
5330
- return `${head}
5331
- ${strict}${rootCap ? "const sR=ctx._rootTriviaCapture\nctx._rootTriviaCapture=false\n" : ""}const sT=ctx.trivia,sL=ctx.triviaKindLabels,sS=_pfScan${cap ? ",sC=ctx.captureTrivia" : ""}
5332
- _pfScan=${scanFor}
5333
- ctx.trivia=${tri}
5334
- ctx.triviaKindLabels=${lab}
5335
- ${cap ? "ctx.captureTrivia=true\n" : ""}const v=${child}(input,pos,ctx)
5336
- ${cap ? "ctx.captureTrivia=sC\n" : ""}ctx.trivia=sT
5337
- ctx.triviaKindLabels=sL
5338
- _pfScan=sS
5339
- ${rootCap ? "ctx._rootTriviaCapture=sR\n" : ""}return v
5340
- }`;
5341
- }
5342
- /* ── boundaries ──────────────────────────────────────────────────────── */
5343
- case OP_TOKEN:
5344
- case OP_LEAF: {
5345
- const isToken = op === OP_TOKEN;
5346
- const fn = isToken ? void 0 : fnRef(code[ip + 1]);
5347
- const child = link(isToken ? code[ip + 1] : code[ip + 2]);
5348
- const wasCap = L.buf ? "true" : "(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)";
5349
- return `${head}
5350
- const sBuf=ctx._cstBuf,sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
5351
- const sOtl=ctx._triviaLog
5352
- ${isToken ? "const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan,sRtl=ctx._rootTriviaLog\n" : ""}const wasCap=${wasCap}
5353
- ${isToken ? `_pfScan=null
5354
- ctx.trivia=undefined
5355
- ctx.triviaKindLabels=undefined
5356
- ` : ""}ctx._cstBuf=undefined
5357
- ctx._cstChildren=undefined
5358
- ctx._cstLeaves=undefined
5359
- ctx._cstRawChildren=undefined
5360
- ctx._cstTriviaLog=undefined
5361
- ctx._triviaLog=undefined
5362
- ${isToken ? "ctx._rootTriviaLog=undefined\n" : ""}let v
5363
- try{v=${child}(input,pos,ctx)}finally{
5364
- ${isToken ? `_pfScan=sScan
5365
- ctx.trivia=sTri
5366
- ctx.triviaKindLabels=sKinds
5367
- ctx._rootTriviaLog=sRtl
5368
- ` : ""}ctx._cstBuf=sBuf
5369
- ctx._cstChildren=sCh
5370
- ctx._cstLeaves=sLv
5371
- ctx._cstRawChildren=sRaw
5372
- ctx._cstTriviaLog=sTl
5373
- ctx._triviaLog=sOtl
5374
- }
5375
- if(v===FAIL)return FAIL
5376
- const e=EC.e
5377
- const out=${isToken ? "input.slice(pos,e)" : `${fn}(v,{start:pos,end:e})`}
5378
- if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:out,span:{start:pos,end:e}})
5379
- EC.e=e
5380
- return out
5381
- }`;
5382
- }
5383
- /* ── transaction ─────────────────────────────────────────────────────── */
5384
- case OP_ATTEMPT: {
5385
- const child = link(code[ip + 1]);
5386
- const p = tmp();
5387
- return `${head}
5388
- ${emitMark(p, L.buf, sinks)}
5389
- const v=${child}(input,pos,ctx)
5390
- if(v!==FAIL)return v
5391
- ${emitRollback(p, L.buf, sinks)}
5392
- if(ctx._fc===true)return FAIL
5393
- ctx._fe=pos
5394
- return FAIL
5395
- }`;
5396
- }
5397
- case OP_NOT: {
5398
- const child = link(code[ip + 1]);
5399
- const xf = fxRef(code[ip + 2]);
5400
- const p = tmp();
5401
- return `${head}
5402
- ${emitMark(p, L.buf, sinks)}
5403
- const v=${child}(input,pos,ctx)
5404
- ${emitRollback(p, L.buf, sinks)}
5405
- if(v===FAIL){EC.e=pos;return null}
5406
- ctx._fe=pos
5407
- ctx._fx=${xf}
5408
- return FAIL
5409
- }`;
5410
- }
5411
- case OP_PEEK: {
5412
- const child = link(code[ip + 1]);
5413
- const xf = fxRef(code[ip + 2]);
5414
- const p = tmp();
5415
- return `${head}
5416
- ${emitMark(p, L.buf, sinks)}
5417
- const v=${child}(input,pos,ctx)
5418
- ${emitRollback(p, L.buf, sinks)}
5419
- if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5420
- EC.e=pos
5421
- return null
5422
- }`;
5423
- }
5424
- case OP_OPT: {
5425
- const child = link(code[ip + 1]);
5426
- const p = tmp();
5427
- return `${head}
5428
- ${emitMark(p, L.buf, sinks)}
5429
- ctx._fc=false
5430
- const v=${child}(input,pos,ctx)
5431
- if(v===FAIL){
5432
- if(ctx._fc===true)return FAIL
5433
- ${emitRollback(p, L.buf, sinks)}
5434
- EC.e=pos
5435
- return null
5436
- }
5437
- return v
5438
- }`;
5439
- }
5440
- case OP_SEQ:
5441
- case OP_SEQV:
5442
- case OP_SEQX: {
5443
- const fused = op === OP_SEQX;
5444
- const base = fused ? ip + 3 : ip + 2;
5445
- const n = code[fused ? ip + 2 : ip + 1];
5446
- const wantValues = op !== OP_SEQV;
5447
- for (let i = 1; i < n; i++) {
5448
- if (code[code[base + i]] === OP_ADJ) {
5449
- throw new Unemittable("a sequence carrying an adjacency assertion (OP_ADJ)");
5450
- }
5451
- }
5452
- const fn = fused ? fnRef(code[ip + 1]) : void 0;
5453
- const kids = [];
5454
- for (let i = 0; i < n; i++) kids.push(link(code[base + i]));
5455
- const sy = REC ? `${tmp()}sy` : "";
5456
- const pub = (i) => {
5457
- const s = sentRef(code[base + n + i]);
5458
- return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
5459
- };
5460
- const parts = [head];
5461
- if (REC) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
5462
- parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
5463
- const close = () => REC ? `${parts.join("\n")}
5464
- }finally{ctx._sync=${sy}}
5465
- }` : `${parts.join("\n")}
5466
- }`;
5467
- if (n === 1) {
5468
- parts.push(fused ? `return ${fn}([v0],{start:pos,end:EC.e})` : wantValues ? "return [v0]" : "return undefined");
5469
- return close();
5470
- }
5471
- parts.push("let cur=EC.e");
5472
- const names = ["v0"];
5473
- for (let i = 1; i < n; i++) {
5474
- const vn = `v${i}`;
5475
- parts.push(`let ${vn}`);
5476
- if (REC) parts.push(pub(i));
5477
- parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L), sinks));
5478
- names.push(vn);
5479
- }
5480
- parts.push("EC.e=cur");
5481
- parts.push(fused ? `return ${fn}([${names.join(",")}],{start:pos,end:cur})` : wantValues ? `return [${names.join(",")}]` : "return undefined");
5482
- return close();
5483
- }
5484
- case OP_CHOICE: {
5485
- const table = disp[code[ip + 1]];
5486
- const n = code[ip + 2];
5487
- const choiceFx = fxRef(code[ip + 3]);
5488
- const base = ip + 4;
5489
- const arms = [];
5490
- for (let i = 0; i < n; i++) arms.push(link(code[base + i]));
5491
- const axi = armExpected.push(
5492
- Array.from({ length: n }, (_, i) => t.fx[code[base + n + i]])
5493
- ) - 1;
5494
- armExpectedPlan.push(Array.from({ length: n }, (_, i) => code[base + n + i]));
5495
- const afx = hoist("afx", `AFX[${axi}]`);
5496
- if (table.exclusive) {
5497
- const di = code[ip + 1];
5498
- const asc = hoist("as", `DISP[${di}].ascii`);
5499
- const hiArr = table.hi;
5500
- const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
5501
- return `${head}
5502
- const c=lead(input,pos)
5503
- let arm=-1
5504
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
5505
- ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
5506
- for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
5507
- if(arm>=0){
5508
- ctx._fc=false
5509
- let v
5510
- switch(arm){
5511
- ${armSwitch}
5512
- }
5513
- if(v!==FAIL)return v
5514
- if(ctx._fc===true)return FAIL
5515
- const af=ctx._fx
5516
- if(af!==undefined&&af.length>0){ctx._fe=pos;return FAIL}
5517
- }
5518
- ctx._fe=pos;ctx._fx=${choiceFx}
5519
- return FAIL
5520
- }`;
5521
- }
5522
- const ci = classes.push(Array.from({ length: n }, (_, i) => table.armCls[i] ?? null)) - 1;
5523
- classPlan.push(Array.from({ length: n }, (_, i) => prog.disp[code[ip + 1]][i] ?? -1));
5524
- const gates = classes[ci];
5525
- const gRef = hoist("g", `CLS[${ci}]`);
5526
- const maskable = n <= 32;
5527
- let maskName = "";
5528
- if (maskable) {
5529
- maskName = hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`);
5530
- maskPlan.push(ci);
5531
- }
5532
- const p = tmp();
5533
- const maskArms = arms.map((a, i) => `
5534
- if((bits&${1 << i})!==0){
5535
- ctx._fc=false
5536
- {const v=${a}(input,pos,ctx)
5537
- if(v!==FAIL)return v}
5538
- for(let j=prev;j<${i};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5539
- prev=${i + 1}
5540
- acc=_accSet(ctx._fx,acc)
5541
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5542
- ${emitRollback(p, L.buf, sinks)}
5543
- }`).join("");
5544
- const generalArms = arms.map((a, i) => `
5545
- if(${gRef}[${i}]===null||classHas(${gRef}[${i}],c)){
5546
- ctx._fc=false
5547
- {const v=${a}(input,pos,ctx)
5548
- if(v!==FAIL)return v}
5549
- acc=_accSet(ctx._fx,acc)
5550
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5551
- ${emitRollback(p, L.buf, sinks)}
5552
- }else acc=_accSet(${afx}[${i}],acc)`).join("");
5553
- return `${head}
5554
- const c=lead(input,pos)
5555
- ${emitMark(p, L.buf, sinks)}
5556
- let acc
5557
- ${maskable ? `if(c<128){
5558
- const bits=${maskName}[c<0?128:c]
5559
- let prev=0
5560
- ${maskArms}
5561
- for(let j=prev;j<${n};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5562
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
5563
- return FAIL
5586
+ return `${head}
5587
+ ${reads.length > 0 ? `${reads.join("\n")}
5588
+ ` : ""}if(${tests.join("&&")}){
5589
+ const e=pos+${s.length}
5590
+ const v=input.slice(pos,e)
5591
+ ${captureLeaf("v")}
5592
+ ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5593
+ return v
5564
5594
  }
5565
- ` : ""}${generalArms}
5566
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
5567
- return FAIL
5595
+ ctx._fe=pos;ctx._fx=${xf}
5596
+ ${cfg.probe ? `failAt(ctx,${xf},pos)
5597
+ ` : ""}return FAIL
5568
5598
  }`;
5569
5599
  }
5570
- case OP_DISPATCH: {
5571
- const di = code[ip + 2];
5572
- const spec = dsp[di];
5573
- const selector = link(code[ip + 1]);
5574
- const otherIp = code[ip + 3];
5575
- const other = otherIp >= 0 ? link(otherIp) : void 0;
5576
- const otherRouted = code[ip + 4] === 1;
5577
- const n = code[ip + 5];
5578
- const armBase = ip + 6;
5579
- const arms = [];
5580
- for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
5581
- const bk = hoist("bk", `DSP[${di}].byKey`);
5582
- const rt = hoist("rt", `DSP[${di}].routed`);
5583
- const dx = hoist("dx", `DSP[${di}].expected`);
5584
- const claims = (m) => {
5585
- switch (m[0]) {
5586
- case 0:
5587
- return `key.startsWith(${q(m[1])})`;
5588
- case 1:
5589
- return `key.endsWith(${q(m[1])})`;
5590
- case 3:
5591
- return `asciiFoldKey(key).startsWith(${q(m[1])})`;
5592
- case 4:
5593
- return `asciiFoldKey(key).endsWith(${q(m[1])})`;
5594
- default:
5595
- return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
5596
- }
5597
- };
5598
- const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
5599
- ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}`).join("\n")}
5600
- }
5601
- `;
5602
- const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
5603
- ` : "";
5604
- const m1 = tmp();
5605
- const m2 = tmp();
5600
+ case OP_RX:
5601
+ case OP_RX_TRACK: {
5602
+ const xf = fxRef(code[ip + 2]);
5603
+ const track = op === OP_RX_TRACK;
5604
+ const scanned = emitScan(code[ip + 1], xf, track, captureLeaf);
5605
+ if (scanned !== void 0) return `${head}${scanned}}`;
5606
+ const rxk = k[code[ip + 1]];
5607
+ if (!(rxk instanceof RegExp) || !rxk.sticky) throw new Unemittable("a non-sticky regex row");
5608
+ const re = kRef(code[ip + 1]);
5606
5609
  return `${head}
5607
- ${emitMark(m1, L.buf, sinks)}
5608
- const sv=${selector}(input,pos,ctx)
5609
- if(sv===FAIL)return FAIL
5610
- const selEnd=EC.e
5611
- const key=sv
5612
- let arm=${bk}.get(key)
5613
- ${fold}${chain}let ur
5614
- if(arm===undefined){
5615
- ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : `ur=${String(otherRouted)}`}
5616
- }else ur=${rt}[arm]===1
5617
- const savedRouted=ctx._routed
5618
- ${emitMark(m2, L.buf, sinks)}
5619
- if(ur){
5620
- ${emitRollback(m1, L.buf, sinks)}
5621
- ${emitMark(m2, L.buf, sinks, false)}
5622
- ctx._routed={value:key,span:{start:pos,end:selEnd}}
5623
- }
5624
- const at=ur?pos:selEnd
5625
- let v
5626
- switch(arm){
5627
- ${arms.map((a, i) => `case ${i}:v=${a}(input,at,ctx);break`).join("\n")}
5628
- ${other === void 0 ? "" : `default:v=${other}(input,at,ctx)`}
5629
- }
5630
- if(ur)ctx._routed=savedRouted
5631
- if(v===FAIL){
5632
- ${emitRollback(m2, L.buf, sinks)}
5633
- ctx._fc=true
5634
- return FAIL
5610
+ ${re}.lastIndex=pos
5611
+ if(${re}.test(input)){
5612
+ const e=${re}.lastIndex
5613
+ const v=input.slice(pos,e)
5614
+ ${captureLeaf("v")}
5615
+ ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5616
+ return v
5635
5617
  }
5636
- return [key,v]
5618
+ ctx._fe=pos;ctx._fx=${xf}
5619
+ ${cfg.probe ? `failAt(ctx,${xf},pos)
5620
+ ` : ""}return FAIL
5637
5621
  }`;
5638
5622
  }
5639
- case OP_REP:
5640
- case OP_REPV: {
5623
+ case OP_EMPTY:
5624
+ return `${head}EC.e=pos;return ''}`;
5625
+ case OP_GATE: {
5626
+ const child = link(code[ip + 2]);
5627
+ const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
5628
+ classPlan.push([code[ip + 1]]);
5629
+ const cls = hoist("cl", `CLS[${ci}][0]`);
5630
+ const xf = fxRef(code[ip + 3]);
5631
+ return `${head}
5632
+ if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5633
+ return ${child}(input,pos,ctx)
5634
+ }`;
5635
+ }
5636
+ case OP_XFORM: {
5637
+ const fn = fnRef(code[ip + 1]);
5638
+ const child = link(code[ip + 2]);
5639
+ return `${head}
5640
+ const v=${child}(input,pos,ctx)
5641
+ if(v===FAIL)return FAIL
5642
+ return ${fn}(v,{start:pos,end:EC.e})
5643
+ }`;
5644
+ }
5645
+ case OP_LABEL: {
5641
5646
  const child = link(code[ip + 1]);
5642
- const min = code[ip + 2];
5643
- const max = code[ip + 3];
5644
- const sepIp = code[ip + 4];
5645
- const sep = sepIp >= 0 ? link(sepIp) : void 0;
5646
- const flags = code[ip + 5];
5647
- const keepSeparators = (flags & 2) !== 0;
5648
- const trailingAllowed = (flags & 1) !== 0;
5649
- const reportItem = (flags & 4) !== 0;
5650
- const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
5651
- const collect = op === OP_REP;
5652
- const skipBeforeFirst = sepIp < 0 && min === 0;
5653
- const p = tmp();
5654
- const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
5655
- const leadTrivia = skipBeforeFirst ? "true" : "count>0";
5656
- const skip = skipFor(L);
5657
- const knownTrivia = L.tri === TRI_NONE ? false : L.tri !== TRI_UNKNOWN ? true : void 0;
5658
- const hasTrivia = knownTrivia === void 0 ? "hasTrivia" : String(knownTrivia);
5659
- const needMark = L.buf ? "true" : "needMark";
5660
- const pfd = sinks.fd ? `${p}fd` : "0";
5661
- const per = sinks.er ? `${p}er` : "undefined";
5662
- const rb = L.buf ? `_rbBuf(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
5663
- if(ctx._fields!==undefined&&ctx._fields.length!==${p}fd)ctx._fields.length=${p}fd` : ""}${sinks.er ? `
5664
- if(ctx._errors!==undefined&&ctx._errors.length!==${p}er)ctx._errors.length=${p}er` : ""}` : `if(needMark)rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)`;
5665
- const markSinks = `${sinks.fd ? `
5666
- ${p}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${sinks.er ? `
5667
- ${p}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
5668
- const markBody = L.buf ? `const b=ctx._cstBuf
5669
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
5670
- const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
5671
- const l=b.tl;${p}tl=l!==undefined?l.length:0
5672
- ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5673
- ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}` : `if(needMark){
5674
- const b=ctx._cstBuf
5675
- if(b!==undefined){
5676
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
5677
- const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
5678
- const l=b.tl;${p}tl=l!==undefined?l.length:0
5679
- }else{
5680
- ${p}raw=ctx._cstRawChildren!==undefined?ctx._cstRawChildren.length:0
5681
- ${p}tl=ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0
5682
- ${p}lv=ctx._cstLeaves!==undefined?ctx._cstLeaves.length:0
5683
- }
5684
- ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5685
- ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
5647
+ const xf = fxRef(code[ip + 2]);
5648
+ return `${head}
5649
+ const v=${child}(input,pos,ctx)
5650
+ if(v===FAIL)ctx._fx=${xf}
5651
+ return v
5686
5652
  }`;
5687
- const my = `${p}my`;
5688
- const recFx = REC ? fxRef(code[ip + 6]) : "";
5689
- const sepSent = REC ? sentRef(code[ip + 7]) : "undefined";
5690
- const recSent = sep === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
5691
- const recGate = sep !== void 0 || min === 0 ? "" : `count>=${min}&&`;
5692
- const recBranch = !REC ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
5693
- ${sep === void 0 ? `${rb}
5694
- ` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
5695
- ${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
5696
- count++
5697
- cur=rr.end
5698
- continue
5699
- }
5700
- `;
5653
+ }
5654
+ case OP_FIELD: {
5655
+ const name = q(k[code[ip + 1]]);
5656
+ const child = link(code[ip + 2]);
5701
5657
  return `${head}
5702
- const out=${collect ? "[]" : "undefined"}
5703
- ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC ? `const ${my}=ctx._sync
5704
- ` : ""}let cur=pos
5705
- let count=0
5706
- for(;;){
5707
- ${max >= 0 ? `if(count>=${max})break
5708
- ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
5709
- ` : ""}let ${p}raw=0,${p}tl=0,${p}lv=0,${p}lg=0,${p}rt=0${sinks.fd ? `,${p}fd=0` : ""}${sinks.er ? `,${p}er=0` : ""}
5710
- ${markBody}
5711
- let itemStart=cur
5712
- let sepEnd=-1
5713
- ${sep !== void 0 ? `if(count>0){
5714
- const lb=cstLeavesLen(ctx)
5715
- let sp=cur
5716
- ${hasTrivia === "false" ? "" : hasTrivia === "true" ? `sp=${skip}(input,sp,ctx)
5717
- ` : `if(hasTrivia)sp=${skip}(input,sp,ctx)
5718
- `}ctx._fc=false
5719
- const sv=${sep}(input,sp,ctx)
5720
- if(sv===FAIL){
5721
- ${rb}
5722
- if(ctx._fc===true)return FAIL
5723
- break
5724
- }
5725
- ${keepSeparators ? "" : "demoteCapturedToRaw(ctx,lb)\n"}sepEnd=EC.e
5726
- itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(input,EC.e,ctx)` : `hasTrivia?${skip}(input,EC.e,ctx):EC.e`}
5727
- }else ${leadSkip(hasTrivia, leadTrivia, skip)}
5728
- ` : `${leadSkip(hasTrivia, leadTrivia, skip)}
5729
- `}if(itemStart>=input.length&&${via}){
5730
- ${rb}
5731
- ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
5732
- }
5733
- ctx._fc=false
5734
- const v=${child}(input,itemStart,ctx)
5735
- if(v===FAIL){
5736
- ${REC ? `if(ctx._fc===true){
5737
- ${rb}
5738
- return FAIL
5739
- }
5740
- ${recBranch}${rb}` : `${rb}
5741
- if(ctx._fc===true)return FAIL`}
5742
- ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
5743
- }
5744
- if(EC.e===itemStart&&${via}){
5745
- ${rb}
5746
- break
5747
- }
5748
- ${collect ? "out.push(v)\n" : ""}cur=EC.e
5749
- count++
5750
- }
5751
- ${min > 0 ? `if(count<${min}){
5752
- ${reportItem ? `ctx._fe=cur;ctx._fx=${itemFx}
5753
- ` : ""}return FAIL
5658
+ const v=${child}(input,pos,ctx)
5659
+ if(v===FAIL)return FAIL
5660
+ const f=ctx._fields
5661
+ if(f!==undefined)f.push({name:${name},value:v,span:{start:pos,end:EC.e}})
5662
+ return v
5663
+ }`;
5664
+ }
5665
+ case OP_EXPECT: {
5666
+ const child = link(code[ip + 1]);
5667
+ const xf = fxRef(code[ip + 2]);
5668
+ return `${head}
5669
+ const v=${child}(input,pos,ctx)
5670
+ if(v!==FAIL)return v
5671
+ const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "{start:pos,end:pos}"},expected:${xf}}
5672
+ const es=ctx._errors
5673
+ if(es!==undefined)es.push(err)
5674
+ ${REC ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
5675
+ EC.e=pos
5676
+ return err
5677
+ }`;
5678
+ }
5679
+ case OP_ROUTED: {
5680
+ const fb = code[ip + 1];
5681
+ const fallback = fb >= 0 ? link(fb) : void 0;
5682
+ const push = `pushCstLeaf(ctx,{_tag:'leaf',value:it.value,span:it.span})`;
5683
+ return `${head}
5684
+ const it=ctx._routed
5685
+ if(it===undefined||pos!==it.span.start){
5686
+ ${fallback !== void 0 ? `return ${fallback}(input,pos,ctx)` : "ctx._fe=pos;ctx._fx=ROUTED_FX;return FAIL"}
5754
5687
  }
5755
- ` : ""}EC.e=cur
5756
- return out
5688
+ ${L.buf ? push : `if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)${push}`}
5689
+ EC.e=it.span.end
5690
+ return it.value
5757
5691
  }`;
5758
5692
  }
5759
- case OP_NODE:
5760
- case OP_NODE_TRACK: {
5761
- const flags = code[ip + 3];
5693
+ case OP_SCAN: {
5694
+ const si = code[ip + 1];
5695
+ return `${head}
5696
+ const r=SCANS[${si}].parse(input,pos,ctx)
5697
+ if(!r.ok){ctx._fe=r.span.start;ctx._fx=r.expected??EMPTY_FX;return FAIL}
5698
+ EC.e=r.span.end
5699
+ return r.value
5700
+ }`;
5701
+ }
5702
+ case OP_SCOPE:
5703
+ case OP_SCOPE_CAP:
5704
+ case OP_SCOPE_PLAIN: {
5705
+ const ki = code[ip + 1];
5706
+ const cap = op === OP_SCOPE_CAP;
5707
+ const flags = op === OP_SCOPE_PLAIN ? 0 : code[ip + 3];
5762
5708
  const child = link(code[ip + 2]);
5763
- const proj = code[ip + 4];
5764
- const buildIdx = code[ip + 1];
5765
- const type = k[code[ip + 5]];
5766
- const tagIdx = code[ip + 6];
5767
- const tags = tagIdx < 0 ? "undefined" : kRef(tagIdx);
5768
- const tracked = op === OP_NODE_TRACK;
5769
- const readsTrivia = (flags & 4) !== 0;
5770
- const readsState = (flags & 8) !== 0;
5771
- const hasFields = (flags & 16) !== 0;
5772
- const collapse = (flags & 32) !== 0;
5773
- const unwrap = (flags & 64) !== 0;
5774
- const trailingTrivia = (flags & 128) !== 0;
5775
- const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
5776
- const structural = build === void 0 && proj < 0;
5777
- const grammarCapture = (flags & 1) !== 0 || trailingTrivia;
5778
- const hostCapturesThisType = structural && cfg.hostCaptureTrivia !== void 0 ? cfg.hostCaptureTrivia(type) : void 0;
5779
- const wantFields = hasFields || hostCst;
5780
- const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
5781
- const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
5782
- const ty = q(type);
5783
- const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
5784
- const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
5785
- let value;
5786
- if (proj >= 0) {
5787
- value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:projectChild(kids,${proj},${ty})` : `nd=projectChild(kids,${proj},${ty})`;
5788
- } else if (build !== void 0) {
5789
- const direct = `${build}(kids,fieldMap,span,rawKids,${captureWide ? "tlog" : "EMPTY_TL"},st)`;
5790
- value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:${direct}` : `nd=${direct}`;
5791
- } else {
5792
- value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):{_tag:'node',type:${ty},span,state:st??null,children:kids}`;
5793
- }
5794
- const collapsible = keepChildren && (hostCst || build === void 0 && proj < 0);
5795
- const openCapture = keepChildren ? `const buf={}
5796
- ctx._cstBuf=buf
5797
- ctx._cstChildren=undefined
5798
- ctx._cstLeaves=undefined
5799
- ctx._cstRawChildren=undefined
5800
- ctx._cstTriviaLog=undefined` : `const buf={rawOnly:true}
5801
- ctx._cstBuf=buf
5709
+ const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
5710
+ const tri = ki < 0 ? "undefined" : hoist("tv", `TRIVIA[${ki}]`);
5711
+ const lab = ki < 0 ? "undefined" : hoist("tl", `TRIVIA[${ki}]._meta.triviaKindLabels`);
5712
+ const strict = (flags & 2) !== 0 ? "refuseUnclassifiedRootScope(ctx._rootTriviaStrictScopes)\n" : "";
5713
+ const rootCap = (flags & 1) !== 0;
5714
+ return `${head}
5715
+ ${strict}${rootCap ? "const sR=ctx._rootTriviaCapture\nctx._rootTriviaCapture=false\n" : ""}const sT=ctx.trivia,sL=ctx.triviaKindLabels,sS=_pfScan${cap ? ",sC=ctx.captureTrivia" : ""}
5716
+ _pfScan=${scanFor}
5717
+ ctx.trivia=${tri}
5718
+ ctx.triviaKindLabels=${lab}
5719
+ ${cap ? "ctx.captureTrivia=true\n" : ""}const v=${child}(input,pos,ctx)
5720
+ ${cap ? "ctx.captureTrivia=sC\n" : ""}ctx.trivia=sT
5721
+ ctx.triviaKindLabels=sL
5722
+ _pfScan=sS
5723
+ ${rootCap ? "ctx._rootTriviaCapture=sR\n" : ""}return v
5724
+ }`;
5725
+ }
5726
+ /* ── boundaries ──────────────────────────────────────────────────────── */
5727
+ case OP_TOKEN:
5728
+ case OP_LEAF: {
5729
+ const isToken = op === OP_TOKEN;
5730
+ const fn = isToken ? void 0 : fnRef(code[ip + 1]);
5731
+ const child = link(isToken ? code[ip + 1] : code[ip + 2]);
5732
+ const wasCap = L.buf ? "true" : "(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)";
5733
+ return `${head}
5734
+ const sBuf=ctx._cstBuf,sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
5735
+ const sOtl=ctx._triviaLog
5736
+ ${isToken ? "const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan,sRtl=ctx._rootTriviaLog\n" : ""}const wasCap=${wasCap}
5737
+ ${isToken ? `_pfScan=null
5738
+ ctx.trivia=undefined
5739
+ ctx.triviaKindLabels=undefined
5740
+ ` : ""}ctx._cstBuf=undefined
5802
5741
  ctx._cstChildren=undefined
5803
5742
  ctx._cstLeaves=undefined
5804
5743
  ctx._cstRawChildren=undefined
5805
- ctx._cstTriviaLog=undefined`;
5806
- const finishCapture = keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
5807
- const hostKids=kids
5808
- const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
5809
- const tlog=buf.tl??EMPTY_TLOG` : `const kids=EMPTY_CH
5810
- const hostKids=kids
5811
- const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
5812
- const tlog=buf.tl??EMPTY_TLOG`;
5813
- return `${head}
5814
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
5815
- const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
5816
- ${openCapture}
5817
- ctx.captureTrivia=${captureWide}
5818
- const savedFields=ctx._fields
5819
- ctx._fields=${wantFields ? "[]" : "undefined"}
5820
- ${structural ? `const savedMask=ctx._triviaCaptureMask
5821
- if(_pfHost!==undefined&&_pfHost._parsemanTriviaKinds!==undefined)ctx._triviaCaptureMask=_pfHost._parsemanTriviaKinds(${ty})
5822
- ` : ""}const v=${child}(input,pos,ctx)
5823
- ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
5824
- ` : ""}const fieldMap=${wantFields ? "buildFieldMap(ctx._fields)" : "undefined"}
5825
- ctx._fields=savedFields
5826
- ${structural ? "ctx._triviaCaptureMask=savedMask\n" : ""}${finishCapture}
5827
- ctx._cstBuf=sBuf
5744
+ ctx._cstTriviaLog=undefined
5745
+ ctx._triviaLog=undefined
5746
+ ${isToken ? "ctx._rootTriviaLog=undefined\n" : ""}let v
5747
+ try{v=${child}(input,pos,ctx)}finally{
5748
+ ${isToken ? `_pfScan=sScan
5749
+ ctx.trivia=sTri
5750
+ ctx.triviaKindLabels=sKinds
5751
+ ctx._rootTriviaLog=sRtl
5752
+ ` : ""}ctx._cstBuf=sBuf
5828
5753
  ctx._cstChildren=sCh
5829
5754
  ctx._cstLeaves=sLv
5830
5755
  ctx._cstRawChildren=sRaw
5831
5756
  ctx._cstTriviaLog=sTl
5832
- ctx.captureTrivia=sCap
5757
+ ctx._triviaLog=sOtl
5758
+ }
5833
5759
  if(v===FAIL)return FAIL
5834
- const end=EC.e
5835
- const span=${tracked ? "spanLines(ctx,pos,end)" : "{start:pos,end}"}
5836
- const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)" : "undefined"}
5837
- let nd
5838
- ${unwrap ? "if(kids.length===1)nd=unwrapChild(kids[0])\nelse " : ""}${collapse ? "if(kids.length===1)nd=kids[0]\nelse " : ""}${collapsible ? `if(_pfHost!==undefined&&_pfHost._parsemanCstCollapse!==undefined&&kids.length===1&&rawKids.length===1&&_pfHost._parsemanCstCollapse(${ty},kids[0],kids,rawKids))nd=kids[0]
5839
- else ` : ""}{${value}}
5840
- ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
5841
- EC.e=end
5842
- return nd
5760
+ const e=EC.e
5761
+ const out=${isToken ? "input.slice(pos,e)" : `${fn}(v,{start:pos,end:e})`}
5762
+ if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:out,span:{start:pos,end:e}})
5763
+ EC.e=e
5764
+ return out
5843
5765
  }`;
5844
5766
  }
5845
- default:
5846
- throw new Unemittable(`OP_${OP_NAMES[op] ?? String(op)}`);
5847
- }
5848
- }
5849
- const ruleEntries = [];
5850
- for (const [rname, entryIp] of Object.entries(prog.rules)) {
5851
- const target = link(entryIp);
5852
- const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
5853
- bodies.push(`const ${rn}=${target}`);
5854
- ruleEntries.push(`${q(rname)}:${rn}`);
5855
- }
5856
- const extra = [];
5857
- for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
5858
- const source = `${RUNTIME_PRELUDE}
5859
- ${prelude.join("\n")}
5860
- ${skipDefs.join("\n")}
5861
- ${bodies.join("\n")}
5862
- function _begin(ctx){
5863
- const host=ctx.build
5864
- if(_pfDepth>0)_pfFrames.push([_pfScan,_pfHost,EC.e])
5865
- _pfDepth++
5866
- _pfScan=null
5867
- _pfHost=host
5868
- }
5869
- function _finish(){
5870
- if(_pfDepth<=0)throw new Error('parseman emitted table assembly frame underflow')
5871
- _pfDepth--
5872
- if(_pfDepth===0)return
5873
- const prior=_pfFrames.pop()
5874
- _pfScan=prior[0]
5875
- _pfHost=prior[1]
5876
- EC.e=prior[2]
5767
+ /* ── transaction ─────────────────────────────────────────────────────── */
5768
+ case OP_ATTEMPT: {
5769
+ const child = link(code[ip + 1]);
5770
+ const p = tmp();
5771
+ return `${head}
5772
+ ${emitMark(p, L.buf, sinks)}
5773
+ const v=${child}(input,pos,ctx)
5774
+ if(v!==FAIL)return v
5775
+ ${emitRollback(p, L.buf, sinks)}
5776
+ if(ctx._fc===true)return FAIL
5777
+ ctx._fe=pos
5778
+ return FAIL
5779
+ }`;
5780
+ }
5781
+ case OP_NOT: {
5782
+ const child = link(code[ip + 1]);
5783
+ const xf = fxRef(code[ip + 2]);
5784
+ const p = tmp();
5785
+ return `${head}
5786
+ ${emitMark(p, L.buf, sinks)}
5787
+ const v=${child}(input,pos,ctx)
5788
+ ${emitRollback(p, L.buf, sinks)}
5789
+ if(v===FAIL){EC.e=pos;return null}
5790
+ ctx._fe=pos
5791
+ ctx._fx=${xf}
5792
+ return FAIL
5793
+ }`;
5794
+ }
5795
+ case OP_PEEK: {
5796
+ const child = link(code[ip + 1]);
5797
+ const xf = fxRef(code[ip + 2]);
5798
+ const p = tmp();
5799
+ return `${head}
5800
+ ${emitMark(p, L.buf, sinks)}
5801
+ const v=${child}(input,pos,ctx)
5802
+ ${emitRollback(p, L.buf, sinks)}
5803
+ if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5804
+ EC.e=pos
5805
+ return null
5806
+ }`;
5807
+ }
5808
+ case OP_OPT: {
5809
+ const child = link(code[ip + 1]);
5810
+ const p = tmp();
5811
+ return `${head}
5812
+ ${emitMark(p, L.buf, sinks)}
5813
+ ctx._fc=false
5814
+ const v=${child}(input,pos,ctx)
5815
+ if(v===FAIL){
5816
+ if(ctx._fc===true)return FAIL
5817
+ ${emitRollback(p, L.buf, sinks)}
5818
+ EC.e=pos
5819
+ return null
5877
5820
  }
5878
- return{
5879
- pieces:{${ruleEntries.join(",")}},
5880
- byIp:{${extra.join(",")}},
5881
- end:function(){return EC.e},
5882
- begin:_begin,
5883
- finish:_finish
5821
+ return v
5822
+ }`;
5823
+ }
5824
+ case OP_SEQ:
5825
+ case OP_SEQV:
5826
+ case OP_SEQX: {
5827
+ const fused = op === OP_SEQX;
5828
+ const base = fused ? ip + 3 : ip + 2;
5829
+ const n = code[fused ? ip + 2 : ip + 1];
5830
+ const wantValues = op !== OP_SEQV;
5831
+ for (let i = 1; i < n; i++) {
5832
+ if (code[code[base + i]] === OP_ADJ) {
5833
+ throw new Unemittable("a sequence carrying an adjacency assertion (OP_ADJ)");
5834
+ }
5835
+ }
5836
+ const fn = fused ? fnRef(code[ip + 1]) : void 0;
5837
+ const kids = [];
5838
+ for (let i = 0; i < n; i++) kids.push(link(code[base + i]));
5839
+ const sy = REC ? `${tmp()}sy` : "";
5840
+ const pub = (i) => {
5841
+ const s = sentRef(code[base + n + i]);
5842
+ return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
5843
+ };
5844
+ const parts = [head];
5845
+ if (REC) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
5846
+ parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
5847
+ const close = () => REC ? `${parts.join("\n")}
5848
+ }finally{ctx._sync=${sy}}
5849
+ }` : `${parts.join("\n")}
5884
5850
  }`;
5885
- return {
5886
- source,
5887
- reached,
5888
- masks,
5889
- classes,
5890
- armExpected,
5891
- plan: { classes: classPlan, armExpected: armExpectedPlan, masks: maskPlan }
5892
- };
5851
+ if (n === 1) {
5852
+ parts.push(fused ? `return ${fn}([v0],{start:pos,end:EC.e})` : wantValues ? "return [v0]" : "return undefined");
5853
+ return close();
5854
+ }
5855
+ parts.push("let cur=EC.e");
5856
+ const names = ["v0"];
5857
+ for (let i = 1; i < n; i++) {
5858
+ const vn = `v${i}`;
5859
+ parts.push(`let ${vn}`);
5860
+ if (REC) parts.push(pub(i));
5861
+ parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L)));
5862
+ names.push(vn);
5863
+ }
5864
+ parts.push("EC.e=cur");
5865
+ parts.push(fused ? `return ${fn}([${names.join(",")}],{start:pos,end:cur})` : wantValues ? `return [${names.join(",")}]` : "return undefined");
5866
+ return close();
5867
+ }
5868
+ case OP_CHOICE: {
5869
+ const table = disp[code[ip + 1]];
5870
+ const n = code[ip + 2];
5871
+ const choiceFx = fxRef(code[ip + 3]);
5872
+ const base = ip + 4;
5873
+ const arms = [];
5874
+ for (let i = 0; i < n; i++) arms.push(link(code[base + i]));
5875
+ const axi = armExpected.push(
5876
+ Array.from({ length: n }, (_, i) => t.fx[code[base + n + i]])
5877
+ ) - 1;
5878
+ armExpectedPlan.push(Array.from({ length: n }, (_, i) => code[base + n + i]));
5879
+ const afx = hoist("afx", `AFX[${axi}]`);
5880
+ if (table.exclusive) {
5881
+ const di = code[ip + 1];
5882
+ const asc = hoist("as", `DISP[${di}].ascii`);
5883
+ const hiArr = table.hi;
5884
+ const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
5885
+ return `${head}
5886
+ const c=lead(input,pos)
5887
+ let arm=-1
5888
+ if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
5889
+ ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
5890
+ for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
5891
+ if(arm>=0){
5892
+ ctx._fc=false
5893
+ let v
5894
+ switch(arm){
5895
+ ${armSwitch}
5893
5896
  }
5894
-
5895
- // src/table/run-support.ts
5896
- function lineCol(ctx, offset) {
5897
- const starts = ctx._lineStarts ?? [0];
5898
- let lo = 0, hi = starts.length - 1;
5899
- while (lo < hi) {
5900
- const mid = lo + hi + 1 >> 1;
5901
- if (starts[mid] <= offset) lo = mid;
5902
- else hi = mid - 1;
5903
- }
5904
- return [lo + 1, offset - starts[lo] + 1];
5897
+ if(v!==FAIL)return v
5898
+ if(ctx._fc===true)return FAIL
5899
+ const af=ctx._fx
5900
+ if(af!==undefined&&af.length>0){ctx._fe=pos;return FAIL}
5905
5901
  }
5906
- function spanLines(ctx, start, end) {
5907
- const s = lineCol(ctx, start), e = lineCol(ctx, end);
5908
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
5902
+ ctx._fe=pos;ctx._fx=${choiceFx}
5903
+ return FAIL
5904
+ }`;
5905
+ }
5906
+ const ci = classes.push(Array.from({ length: n }, (_, i) => table.armCls[i] ?? null)) - 1;
5907
+ classPlan.push(Array.from({ length: n }, (_, i) => prog.disp[code[ip + 1]][i] ?? -1));
5908
+ const gates = classes[ci];
5909
+ const gRef = hoist("g", `CLS[${ci}]`);
5910
+ const maskable = n <= 32;
5911
+ let maskName = "";
5912
+ if (maskable) {
5913
+ maskName = hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`);
5914
+ maskPlan.push(ci);
5915
+ }
5916
+ const p = tmp();
5917
+ const maskArms = arms.map((a, i) => `
5918
+ if((bits&${1 << i})!==0){
5919
+ ctx._fc=false
5920
+ {const v=${a}(input,pos,ctx)
5921
+ if(v!==FAIL)return v}
5922
+ for(let j=prev;j<${i};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5923
+ prev=${i + 1}
5924
+ acc=_accSet(ctx._fx,acc)
5925
+ if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5926
+ ${emitRollback(p, L.buf, sinks)}
5927
+ }`).join("");
5928
+ const generalArms = arms.map((a, i) => `
5929
+ if(${gRef}[${i}]===null||classHas(${gRef}[${i}],c)){
5930
+ ctx._fc=false
5931
+ {const v=${a}(input,pos,ctx)
5932
+ if(v!==FAIL)return v}
5933
+ acc=_accSet(ctx._fx,acc)
5934
+ if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5935
+ ${emitRollback(p, L.buf, sinks)}
5936
+ }else acc=_accSet(${afx}[${i}],acc)`).join("");
5937
+ return `${head}
5938
+ const c=lead(input,pos)
5939
+ ${emitMark(p, L.buf, sinks)}
5940
+ let acc
5941
+ ${maskable ? `if(c<128){
5942
+ const bits=${maskName}[c<0?128:c]
5943
+ let prev=0
5944
+ ${maskArms}
5945
+ for(let j=prev;j<${n};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5946
+ ctx._fe=pos;ctx._fx=acc??${choiceFx}
5947
+ return FAIL
5909
5948
  }
5910
- function rawEntry(v, input, s, e) {
5911
- if (typeof v === "object" && v !== null) {
5912
- const tg = v._tag;
5913
- if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
5914
- }
5915
- return {
5916
- _tag: "leaf",
5917
- value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
5918
- span: { start: s, end: e }
5919
- };
5949
+ ` : ""}${generalArms}
5950
+ ctx._fe=pos;ctx._fx=acc??${choiceFx}
5951
+ return FAIL
5952
+ }`;
5953
+ }
5954
+ case OP_DISPATCH: {
5955
+ const di = code[ip + 2];
5956
+ const spec = dsp[di];
5957
+ const selector = link(code[ip + 1]);
5958
+ const otherIp = code[ip + 3];
5959
+ const other = otherIp >= 0 ? link(otherIp) : void 0;
5960
+ const otherRouted = code[ip + 4] === 1;
5961
+ const n = code[ip + 5];
5962
+ validateDispatchSpec(spec, n, code[ip + 4]);
5963
+ const armBase = ip + 6;
5964
+ const arms = [];
5965
+ for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
5966
+ const bk = hoist("bk", `DSP[${di}].byKey`);
5967
+ const dx = hoist("dx", `DSP[${di}].expected`);
5968
+ const claims = (m) => {
5969
+ switch (m[0]) {
5970
+ case 0:
5971
+ return `key.startsWith(${q(m[1])})`;
5972
+ case 1:
5973
+ return `key.endsWith(${q(m[1])})`;
5974
+ case 3:
5975
+ return `asciiFoldKey(key).startsWith(${q(m[1])})`;
5976
+ case 4:
5977
+ return `asciiFoldKey(key).endsWith(${q(m[1])})`;
5978
+ default:
5979
+ return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
5980
+ }
5981
+ };
5982
+ const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
5983
+ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}`).join("\n")}
5920
5984
  }
5921
- function lead(input, pos) {
5922
- if (pos >= input.length) return -1;
5923
- const c = input.charCodeAt(pos);
5924
- if (c < 55296 || c > 56319) return c;
5925
- return input.codePointAt(pos) ?? c;
5985
+ `;
5986
+ const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
5987
+ ` : "";
5988
+ const m1 = tmp();
5989
+ const m2 = tmp();
5990
+ const routedCall = (target) => `{const savedRouted=ctx._routed
5991
+ ${emitRollback(m1, L.buf, sinks)}
5992
+ ${emitMark(m2, L.buf, sinks, false)}
5993
+ ctx._routed={value:key,span:{start:pos,end:selEnd}}
5994
+ try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
5995
+ break}`;
5996
+ const plainCall = (target) => `v=${target}(input,selEnd,ctx);break`;
5997
+ const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1 ? routedCall(target) : plainCall(target)}`).join("\n");
5998
+ const fallbackCase = other === void 0 ? "" : `default:${otherRouted ? routedCall(other) : plainCall(other)}`;
5999
+ return `${head}
6000
+ ${emitMark(m1, L.buf, sinks)}
6001
+ const sv=${selector}(input,pos,ctx)
6002
+ if(sv===FAIL)return FAIL
6003
+ const selEnd=EC.e
6004
+ const key=sv
6005
+ let arm=${bk}.get(key)
6006
+ ${fold}${chain}
6007
+ if(arm===undefined){
6008
+ ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ""}
5926
6009
  }
5927
-
5928
- // src/table/program.ts
5929
- function closureArtifact(prog) {
5930
- return { ...prog, asm: [] };
6010
+ ${emitMark(m2, L.buf, sinks)}
6011
+ let v
6012
+ switch(arm){
6013
+ ${armCases}
6014
+ ${fallbackCase}
5931
6015
  }
5932
- function covKindCode(kind) {
5933
- switch (kind) {
5934
- case "rule":
5935
- return 0;
5936
- case "choice-arm":
5937
- return 1;
5938
- case "dispatch-arm":
5939
- return 2;
5940
- case "label":
5941
- return 3;
5942
- }
6016
+ if(v===FAIL){
6017
+ ${emitRollback(m2, L.buf, sinks)}
6018
+ ctx._fc=true
6019
+ return FAIL
5943
6020
  }
5944
- function covKindName(code) {
5945
- switch (code) {
5946
- case 0:
5947
- return "rule";
5948
- case 1:
5949
- return "choice-arm";
5950
- case 2:
5951
- return "dispatch-arm";
5952
- case 3:
5953
- return "label";
5954
- }
6021
+ return [key,v]
6022
+ }`;
6023
+ }
6024
+ case OP_REP:
6025
+ case OP_REPV: {
6026
+ const child = link(code[ip + 1]);
6027
+ const min = code[ip + 2];
6028
+ const max = code[ip + 3];
6029
+ const sepIp = code[ip + 4];
6030
+ const sep = sepIp >= 0 ? link(sepIp) : void 0;
6031
+ const flags = code[ip + 5];
6032
+ const keepSeparators = (flags & 2) !== 0;
6033
+ const trailingAllowed = (flags & 1) !== 0;
6034
+ const reportItem = (flags & 4) !== 0;
6035
+ const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
6036
+ const collect = op === OP_REP;
6037
+ const skipBeforeFirst = sepIp < 0 && min === 0;
6038
+ const p = tmp();
6039
+ const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
6040
+ const leadTrivia = skipBeforeFirst ? "true" : "count>0";
6041
+ const skip = skipFor(L);
6042
+ const knownTrivia = L.tri === TRI_NONE ? false : L.tri !== TRI_UNKNOWN ? true : void 0;
6043
+ const hasTrivia = knownTrivia === void 0 ? "hasTrivia" : String(knownTrivia);
6044
+ const needMark = L.buf ? "true" : "needMark";
6045
+ const pfd = sinks.fd ? `${p}fd` : "0";
6046
+ const per = sinks.er ? `${p}er` : "undefined";
6047
+ const rb = L.buf ? `_rbBuf(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
6048
+ if(ctx._fields!==undefined&&ctx._fields.length!==${p}fd)ctx._fields.length=${p}fd` : ""}${sinks.er ? `
6049
+ if(ctx._errors!==undefined&&ctx._errors.length!==${p}er)ctx._errors.length=${p}er` : ""}` : `if(needMark)rollbackTriviaAt(ctx,${p}raw,${p}tl,${p}lv,${pfd},${per},${p}lg,${p}rt)`;
6050
+ const markSinks = `${sinks.fd ? `
6051
+ ${p}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${sinks.er ? `
6052
+ ${p}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
6053
+ const markBody = L.buf ? `const b=ctx._cstBuf
6054
+ const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
6055
+ const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
6056
+ const l=b.tl;${p}tl=l!==undefined?l.length:0
6057
+ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
6058
+ ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}` : `if(needMark){
6059
+ const b=ctx._cstBuf
6060
+ if(b!==undefined){
6061
+ const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
6062
+ const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
6063
+ const l=b.tl;${p}tl=l!==undefined?l.length:0
6064
+ }else{
6065
+ ${p}raw=ctx._cstRawChildren!==undefined?ctx._cstRawChildren.length:0
6066
+ ${p}tl=ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0
6067
+ ${p}lv=ctx._cstLeaves!==undefined?ctx._cstLeaves.length:0
5955
6068
  }
5956
- function covDefinitions(prog) {
5957
- return (prog.cov ?? []).map(([id, kind]) => ({ id, kind: covKindName(kind) }));
6069
+ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
6070
+ ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
6071
+ }`;
6072
+ const my = `${p}my`;
6073
+ const recFx = REC ? fxRef(code[ip + 6]) : "";
6074
+ const sepSent = REC ? sentRef(code[ip + 7]) : "undefined";
6075
+ const recSent = sep === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
6076
+ const recGate = sep !== void 0 || min === 0 ? "" : `count>=${min}&&`;
6077
+ const recBranch = !REC ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
6078
+ ${sep === void 0 ? `${rb}
6079
+ ` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
6080
+ ${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
6081
+ count++
6082
+ cur=rr.end
6083
+ continue
5958
6084
  }
5959
- function expandCompact(p) {
5960
- if ("code" in p) return p;
5961
- return ownTableProgram({
5962
- code: p.c,
5963
- k: p.k,
5964
- cc: p.x,
5965
- fx: p.e,
5966
- disp: p.d,
5967
- rules: p.r,
5968
- fns: p.f,
5969
- lines: p.l ?? 0,
5970
- dsp: p.p ?? [],
5971
- ...p.lb === void 0 ? {} : { labels: p.lb },
5972
- ...p.rc === void 0 ? {} : { classified: p.rc },
5973
- ...p.h === void 0 ? {} : { hostMode: p.h },
5974
- ...p.tv === void 0 ? {} : { triviaSpecs: p.tv },
5975
- ...p.sc === void 0 ? {} : { scans: p.sc },
5976
- ...p.ss === void 0 ? {} : { scanSkip: p.ss },
5977
- ...p.so === void 0 ? {} : { scanSkipOf: p.so },
5978
- ...p.rv === void 0 ? {} : { rec: p.rv },
5979
- ...p.cv === void 0 ? {} : { cov: p.cv },
5980
- ...p.a === void 0 ? {} : { asm: p.a }
5981
- });
6085
+ `;
6086
+ return `${head}
6087
+ const out=${collect ? "[]" : "undefined"}
6088
+ ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC ? `const ${my}=ctx._sync
6089
+ ` : ""}let cur=pos
6090
+ let count=0
6091
+ for(;;){
6092
+ ${max >= 0 ? `if(count>=${max})break
6093
+ ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
6094
+ ` : ""}let ${p}raw=0,${p}tl=0,${p}lv=0,${p}lg=0,${p}rt=0${sinks.fd ? `,${p}fd=0` : ""}${sinks.er ? `,${p}er=0` : ""}
6095
+ ${markBody}
6096
+ let itemStart=cur
6097
+ let sepEnd=-1
6098
+ ${sep !== void 0 ? `if(count>0){
6099
+ const lb=cstLeavesLen(ctx)
6100
+ let sp=cur
6101
+ ${hasTrivia === "false" ? "" : hasTrivia === "true" ? `sp=${skip}(input,sp,ctx)
6102
+ ` : `if(hasTrivia)sp=${skip}(input,sp,ctx)
6103
+ `}ctx._fc=false
6104
+ const sv=${sep}(input,sp,ctx)
6105
+ if(sv===FAIL){
6106
+ ${rb}
6107
+ if(ctx._fc===true)return FAIL
6108
+ break
5982
6109
  }
5983
- var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
5984
- function ownTableProgram(prog, resolved) {
5985
- return { ...prog, [TABLE_RUNTIME]: { resolved } };
6110
+ ${keepSeparators ? "" : "demoteCapturedToRaw(ctx,lb)\n"}sepEnd=EC.e
6111
+ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(input,EC.e,ctx)` : `hasTrivia?${skip}(input,EC.e,ctx):EC.e`}
6112
+ }else ${leadSkip(hasTrivia, leadTrivia, skip)}
6113
+ ` : `${leadSkip(hasTrivia, leadTrivia, skip)}
6114
+ `}if(itemStart>=input.length&&${via}){
6115
+ ${rb}
6116
+ ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
5986
6117
  }
5987
- var WIDE_CLASS_PREFIX_LO = 65535;
5988
- var WIDE_CLASS_PREFIX_HI = 0;
5989
- function validateClassRange(lo, hi) {
5990
- for (const cp of [lo, hi]) {
5991
- if (!Number.isInteger(cp) || cp < 0 || cp > 1114111) {
5992
- throw new TypeError(`table char-class endpoint is outside Unicode: ${cp}`);
5993
- }
5994
- }
5995
- if (lo > hi) {
5996
- throw new TypeError(`table char-class range is descending: ${lo} > ${hi}`);
5997
- }
6118
+ ctx._fc=false
6119
+ const v=${child}(input,itemStart,ctx)
6120
+ if(v===FAIL){
6121
+ ${REC ? `if(ctx._fc===true){
6122
+ ${rb}
6123
+ return FAIL
5998
6124
  }
5999
- function encodeClassSpec(ranges) {
6000
- let wide = false;
6001
- for (const range of ranges) {
6002
- validateClassRange(range.lo, range.hi);
6003
- if (range.hi > 65535) wide = true;
6004
- }
6005
- if (!wide) {
6006
- let spec2 = "";
6007
- for (const range of ranges) spec2 += String.fromCharCode(range.lo, range.hi);
6008
- return spec2;
6009
- }
6010
- let spec = String.fromCharCode(WIDE_CLASS_PREFIX_LO, WIDE_CLASS_PREFIX_HI);
6011
- for (const range of ranges) {
6012
- spec += String.fromCharCode(
6013
- range.lo >>> 16,
6014
- range.lo & 65535,
6015
- range.hi >>> 16,
6016
- range.hi & 65535
6017
- );
6018
- }
6019
- return spec;
6125
+ ${recBranch}${rb}` : `${rb}
6126
+ if(ctx._fc===true)return FAIL`}
6127
+ ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
6020
6128
  }
6021
- function decodeClassSpec(spec) {
6022
- if (spec.charCodeAt(0) === WIDE_CLASS_PREFIX_LO && spec.charCodeAt(1) === WIDE_CLASS_PREFIX_HI) {
6023
- if ((spec.length - 2) % 4 !== 0) throw new TypeError("table char-class spec has a truncated wide range");
6024
- if (spec.length === 2) throw new TypeError("table char-class spec has a wide prefix but no ranges");
6025
- const ranges2 = [];
6026
- for (let i = 2; i < spec.length; i += 4) {
6027
- const lo = spec.charCodeAt(i) * 65536 + spec.charCodeAt(i + 1);
6028
- const hi = spec.charCodeAt(i + 2) * 65536 + spec.charCodeAt(i + 3);
6029
- validateClassRange(lo, hi);
6030
- ranges2.push({ lo, hi });
6031
- }
6032
- return ranges2;
6033
- }
6034
- if (spec.length % 2 !== 0) throw new TypeError("table char-class spec has an unmatched range endpoint");
6035
- const ranges = [];
6036
- for (let i = 0; i < spec.length; i += 2) {
6037
- const lo = spec.charCodeAt(i);
6038
- const hi = spec.charCodeAt(i + 1);
6039
- validateClassRange(lo, hi);
6040
- ranges.push({ lo, hi });
6041
- }
6042
- return ranges;
6129
+ if(EC.e===itemStart&&${via}){
6130
+ ${rb}
6131
+ break
6043
6132
  }
6044
- function resolveClass(spec) {
6045
- const ascii = new Uint8Array(128);
6046
- const hi = [];
6047
- for (const { lo, hi: up } of decodeClassSpec(spec)) {
6048
- if (lo < 128) for (let c = lo; c <= Math.min(up, 127); c++) ascii[c] = 1;
6049
- if (up >= 128) hi.push(Math.max(lo, 128), up);
6050
- }
6051
- return { ascii, hi };
6133
+ ${collect ? "out.push(v)\n" : ""}cur=EC.e
6134
+ count++
6052
6135
  }
6053
- function classHas(cls, code) {
6054
- if (code < 0) return false;
6055
- if (code < 128) return cls.ascii[code] === 1;
6056
- const hi = cls.hi;
6057
- for (let i = 0; i < hi.length; i += 2) if (code >= hi[i] && code <= hi[i + 1]) return true;
6058
- return false;
6136
+ ${min > 0 ? `if(count<${min}){
6137
+ ${reportItem ? `ctx._fe=cur;ctx._fx=${itemFx}
6138
+ ` : ""}return FAIL
6059
6139
  }
6060
- function resolveDispatch(arms, cc) {
6061
- const ascii = new Uint8Array(128);
6062
- const hi = [];
6063
- const open = [];
6064
- const armCls = [];
6065
- let exclusive = true;
6066
- let hiOwners = 0;
6067
- for (let a = 0; a < arms.length; a++) {
6068
- const ci = arms[a];
6069
- if (ci < 0) {
6070
- open.push(a);
6071
- armCls.push(null);
6072
- exclusive = false;
6073
- continue;
6074
- }
6075
- const cls = cc[ci];
6076
- armCls.push(cls);
6077
- for (let c = 0; c < 128; c++) {
6078
- if (cls.ascii[c] !== 1) continue;
6079
- if (ascii[c] === 0) ascii[c] = a + 1;
6080
- else exclusive = false;
6140
+ ` : ""}EC.e=cur
6141
+ return out
6142
+ }`;
6143
+ }
6144
+ case OP_NODE:
6145
+ case OP_NODE_TRACK: {
6146
+ const flags = code[ip + 3];
6147
+ const child = link(code[ip + 2]);
6148
+ const proj = code[ip + 4];
6149
+ const buildIdx = code[ip + 1];
6150
+ const type = k[code[ip + 5]];
6151
+ const tagIdx = code[ip + 6];
6152
+ const tags = tagIdx < 0 ? "undefined" : kRef(tagIdx);
6153
+ const tracked = op === OP_NODE_TRACK;
6154
+ const readsTrivia = (flags & 4) !== 0;
6155
+ const readsState = (flags & 8) !== 0;
6156
+ const hasFields = (flags & 16) !== 0;
6157
+ const collapse = (flags & 32) !== 0;
6158
+ const unwrap = (flags & 64) !== 0;
6159
+ const trailingTrivia = (flags & 128) !== 0;
6160
+ const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
6161
+ const structural = build === void 0 && proj < 0;
6162
+ const grammarCapture = (flags & 1) !== 0 || trailingTrivia;
6163
+ const hostCapturesThisType = structural && cfg.hostCaptureTrivia !== void 0 ? cfg.hostCaptureTrivia(type) : void 0;
6164
+ const wantFields = hasFields || hostCst;
6165
+ const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
6166
+ const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
6167
+ const ty = q(type);
6168
+ const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
6169
+ const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
6170
+ let value;
6171
+ if (proj >= 0) {
6172
+ value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:projectChild(kids,${proj},${ty})` : `nd=projectChild(kids,${proj},${ty})`;
6173
+ } else if (build !== void 0) {
6174
+ const direct = `${build}(kids,fieldMap,span,rawKids,${captureWide ? "tlog" : "EMPTY_TL"},st)`;
6175
+ value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:${direct}` : `nd=${direct}`;
6176
+ } else {
6177
+ value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):{_tag:'node',type:${ty},span,state:st??null,children:kids}`;
6178
+ }
6179
+ const collapsible = keepChildren && (hostCst || build === void 0 && proj < 0);
6180
+ const openCapture = keepChildren ? `const buf={}
6181
+ ctx._cstBuf=buf
6182
+ ctx._cstChildren=undefined
6183
+ ctx._cstLeaves=undefined
6184
+ ctx._cstRawChildren=undefined
6185
+ ctx._cstTriviaLog=undefined` : `const buf={rawOnly:true}
6186
+ ctx._cstBuf=buf
6187
+ ctx._cstChildren=undefined
6188
+ ctx._cstLeaves=undefined
6189
+ ctx._cstRawChildren=undefined
6190
+ ctx._cstTriviaLog=undefined`;
6191
+ const finishCapture = keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
6192
+ const hostKids=kids
6193
+ const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
6194
+ const tlog=buf.tl??EMPTY_TLOG` : `const kids=EMPTY_CH
6195
+ const hostKids=kids
6196
+ const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
6197
+ const tlog=buf.tl??EMPTY_TLOG`;
6198
+ return `${head}
6199
+ const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
6200
+ const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
6201
+ ${openCapture}
6202
+ ctx.captureTrivia=${captureWide}
6203
+ const savedFields=ctx._fields
6204
+ ctx._fields=${wantFields ? "[]" : "undefined"}
6205
+ ${structural ? `const savedMask=ctx._triviaCaptureMask
6206
+ if(_pfHost!==undefined&&_pfHost._parsemanTriviaKinds!==undefined)ctx._triviaCaptureMask=_pfHost._parsemanTriviaKinds(${ty})
6207
+ ` : ""}const v=${child}(input,pos,ctx)
6208
+ ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
6209
+ ` : ""}const fieldMap=${wantFields ? "buildFieldMap(ctx._fields)" : "undefined"}
6210
+ ctx._fields=savedFields
6211
+ ${structural ? "ctx._triviaCaptureMask=savedMask\n" : ""}${finishCapture}
6212
+ ctx._cstBuf=sBuf
6213
+ ctx._cstChildren=sCh
6214
+ ctx._cstLeaves=sLv
6215
+ ctx._cstRawChildren=sRaw
6216
+ ctx._cstTriviaLog=sTl
6217
+ ctx.captureTrivia=sCap
6218
+ if(v===FAIL)return FAIL
6219
+ const end=EC.e
6220
+ const span=${tracked ? "spanLines(ctx,pos,end)" : "{start:pos,end}"}
6221
+ const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)" : "undefined"}
6222
+ let nd
6223
+ ${unwrap ? "if(kids.length===1)nd=unwrapChild(kids[0])\nelse " : ""}${collapse ? "if(kids.length===1)nd=kids[0]\nelse " : ""}${collapsible ? `if(_pfHost!==undefined&&_pfHost._parsemanCstCollapse!==undefined&&kids.length===1&&rawKids.length===1&&_pfHost._parsemanCstCollapse(${ty},kids[0],kids,rawKids))nd=kids[0]
6224
+ else ` : ""}{${value}}
6225
+ ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
6226
+ EC.e=end
6227
+ return nd
6228
+ }`;
6229
+ }
6230
+ default:
6231
+ throw new Unemittable(`OP_${OP_NAMES[op] ?? String(op)}`);
6081
6232
  }
6082
- if (cls.hi.length > 0 && ++hiOwners > 1) exclusive = false;
6083
- for (let i = 0; i < cls.hi.length; i += 2) hi.push(cls.hi[i], cls.hi[i + 1], a);
6084
6233
  }
6085
- return { ascii, hi, open, armCls, exclusive };
6086
- }
6087
- function buildTrivia(spec) {
6088
- if (spec.live !== void 0) return spec.live;
6089
- if (spec.plain !== void 0) return trivia(regex(new RegExp(spec.plain[0], spec.plain[1])));
6090
- if (spec.alts !== void 0) {
6091
- const [head, ...rest] = spec.alts.map(([source, flags]) => regex(new RegExp(source, flags)));
6092
- if (head === void 0) throw new TypeError("trivia spec has an EMPTY alternation, which matches nothing");
6093
- const body = rest.length === 0 ? head : choice(head, ...rest);
6094
- return trivia(many(body, { min: spec.min ?? 1 }));
6234
+ const ruleEntries = [];
6235
+ for (const [rname, entryIp] of Object.entries(prog.rules)) {
6236
+ const target = link(entryIp);
6237
+ const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
6238
+ bodies.push(`const ${rn}=${target}`);
6239
+ ruleEntries.push(`${q(rname)}:${rn}`);
6095
6240
  }
6096
- const arms = {};
6097
- for (const [name, source, flags] of spec.arms) arms[name] = regex(new RegExp(source, flags));
6098
- return classifiedTrivia(arms);
6241
+ const extra = [];
6242
+ for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
6243
+ const source = `${RUNTIME_PRELUDE}
6244
+ ${prelude.join("\n")}
6245
+ ${skipDefs.join("\n")}
6246
+ ${bodies.join("\n")}
6247
+ function _begin(ctx){
6248
+ const host=ctx.build
6249
+ if(_pfDepth>0)_pfFrames.push([_pfScan,_pfHost,EC.e])
6250
+ _pfDepth++
6251
+ _pfScan=null
6252
+ _pfHost=host
6099
6253
  }
6100
- function resolveTable(prog) {
6101
- const owner = prog[TABLE_RUNTIME];
6102
- const hit = owner?.resolved;
6103
- if (hit !== void 0) return hit;
6104
- const cc = prog.cc.map(resolveClass);
6105
- const triviaBuilt = (prog.triviaSpecs ?? []).map(buildTrivia);
6106
- const built = {
6107
- prog,
6108
- code: Int32Array.from(prog.code),
6109
- k: prog.k,
6110
- fns: prog.fns,
6111
- cc,
6112
- fx: prog.fx,
6113
- disp: prog.disp.map((d) => resolveDispatch(d, cc)),
6114
- trivia: triviaBuilt,
6115
- triviaScan: triviaBuilt.map(fastTriviaScanner),
6116
- triviaLabelled: triviaBuilt.map((t) => t._meta.triviaKindLabels !== void 0),
6117
- dsp: prog.dsp.map((d) => ({
6118
- byKey: new Map(d.key.map((x, i) => [x, d.keyArm[i]])),
6119
- byFold: new Map(d.fold.map((x, i) => [x, d.foldArm[i]])),
6120
- match: d.match,
6121
- routed: d.routed,
6122
- expected: d.expected
6123
- })),
6124
- rules: prog.rules
6125
- };
6126
- if (owner !== void 0) owner.resolved = built;
6127
- return built;
6254
+ function _finish(){
6255
+ if(_pfDepth<=0)throw new Error('parseman emitted table assembly frame underflow')
6256
+ _pfDepth--
6257
+ if(_pfDepth===0)return
6258
+ const prior=_pfFrames.pop()
6259
+ _pfScan=prior[0]
6260
+ _pfHost=prior[1]
6261
+ EC.e=prior[2]
6128
6262
  }
6129
- var FOLDED_RUNTIME = /* @__PURE__ */ Symbol("parseman.foldedRuntime");
6130
- function ownFoldedProgram(base, variants) {
6131
- return { base, variants, [FOLDED_RUNTIME]: { byName: /* @__PURE__ */ new Map() } };
6263
+ return{
6264
+ pieces:{${ruleEntries.join(",")}},
6265
+ byIp:{${extra.join(",")}},
6266
+ end:function(){return EC.e},
6267
+ begin:_begin,
6268
+ finish:_finish
6269
+ }`;
6270
+ return {
6271
+ source,
6272
+ reached,
6273
+ masks,
6274
+ classes,
6275
+ armExpected,
6276
+ plan: { classes: classPlan, armExpected: armExpectedPlan, masks: maskPlan }
6277
+ };
6132
6278
  }
6133
- var SHARED_FIELDS = [
6134
- "k",
6135
- "cc",
6136
- "fx",
6137
- "disp",
6138
- "dsp",
6139
- "rules",
6140
- "labels",
6141
- "classified",
6142
- "scanSkip",
6143
- "scanSkipOf",
6144
- "scans",
6145
- "triviaSpecs",
6146
- "runtimeOnly",
6147
- // `rec` is a property of the GRAMMAR BUILD, not of the trackLines/hostMode
6148
- // axis a fold varies — every variant of one export is encoded with the same
6149
- // recovery setting, and a mismatch is two tables, which is what the refusal says.
6150
- "rec",
6151
- // `cov` is a property of the GRAMMAR and its coverage plan, for the same reason
6152
- // `rec` is a property of the build: the plan is built from the rule map, which
6153
- // every variant of one export shares. It ships ONCE, and a variant that
6154
- // disagrees is two tables — which is what the refusal says.
6155
- "cov"
6156
- ];
6157
- function foldPrograms(programs, baseName) {
6158
- const suppliedBase = programs[baseName];
6159
- if (suppliedBase === void 0) throw new TypeError(`foldPrograms: no program named ${JSON.stringify(baseName)}`);
6160
- const base = closureArtifact(suppliedBase);
6161
- const variants = {};
6162
- for (const name of Object.keys(programs)) {
6163
- const p = programs[name];
6164
- if (p.asm !== void 0 && p.asm.length > 0) {
6165
- throw new TypeError(
6166
- `foldPrograms: program ${JSON.stringify(name)} already carries pre-compiled assemblies. An assembly is emitted from a \`code\` stream and a fold overwrites \`code\` per variant, so pre-compiling must happen AFTER the fold, per variant \u2014 not before it.`
6167
- );
6168
- }
6169
- if (p.code.length !== base.code.length) {
6170
- throw new TypeError(
6171
- `foldPrograms: variant ${JSON.stringify(name)} has ${p.code.length} code words, base ${JSON.stringify(baseName)} has ${base.code.length}. A fold overwrites words; it cannot resize the stream. These are two different tables, not one table and its edits.`
6172
- );
6173
- }
6174
- for (const f of SHARED_FIELDS) {
6175
- if (JSON.stringify(p[f]) !== JSON.stringify(base[f])) {
6176
- throw new TypeError(
6177
- `foldPrograms: variant ${JSON.stringify(name)} differs from base ${JSON.stringify(baseName)} in ${JSON.stringify(f)}, which the fold ships ONCE. Either the variants are not encodings of one grammar, or this field has become variant-dependent and needs its own delta.`
6178
- );
6179
- }
6180
- }
6181
- if (p.fns.length !== base.fns.length || p.fns.some((f, i) => f !== base.fns[i])) {
6182
- throw new TypeError(
6183
- `foldPrograms: variant ${JSON.stringify(name)} does not share the base's reducer pool BY IDENTITY. Equal source text is not enough \u2014 two closures can print alike and capture different scopes. Encode every variant from ONE grammar export.`
6184
- );
6185
- }
6186
- const at = [];
6187
- const to = [];
6188
- let prev = 0;
6189
- for (let i = 0; i < p.code.length; i++) {
6190
- if (p.code[i] === base.code[i]) continue;
6191
- at.push(i - prev);
6192
- to.push(p.code[i]);
6193
- prev = i;
6194
- }
6195
- variants[name] = {
6196
- at,
6197
- to,
6198
- ...p.lines === void 0 ? {} : { lines: p.lines },
6199
- ...p.hostMode === void 0 ? {} : { hostMode: p.hostMode }
6200
- };
6279
+
6280
+ // src/table/run-support.ts
6281
+ function lineCol(ctx, offset) {
6282
+ const starts = ctx._lineStarts ?? [0];
6283
+ let lo = 0, hi = starts.length - 1;
6284
+ while (lo < hi) {
6285
+ const mid = lo + hi + 1 >> 1;
6286
+ if (starts[mid] <= offset) lo = mid;
6287
+ else hi = mid - 1;
6201
6288
  }
6202
- return ownFoldedProgram(base, variants);
6289
+ return [lo + 1, offset - starts[lo] + 1];
6203
6290
  }
6204
- function unfoldVariant(folded, name) {
6205
- const byName = folded[FOLDED_RUNTIME]?.byName;
6206
- const hit = byName?.get(name);
6207
- if (hit !== void 0) return hit;
6208
- const d = folded.variants[name];
6209
- if (d === void 0) {
6210
- throw new TypeError(
6211
- `unfoldVariant: no variant ${JSON.stringify(name)}. This table carries: ${Object.keys(folded.variants).map((n) => JSON.stringify(n)).join(", ")}.`
6212
- );
6213
- }
6214
- const base = folded.base;
6215
- const code = [...base.code];
6216
- let ip = 0;
6217
- for (let i = 0; i < d.at.length; i++) {
6218
- ip += d.at[i];
6219
- code[ip] = d.to[i];
6291
+ function spanLines(ctx, start, end) {
6292
+ const s = lineCol(ctx, start), e = lineCol(ctx, end);
6293
+ return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
6294
+ }
6295
+ function rawEntry(v, input, s, e) {
6296
+ if (typeof v === "object" && v !== null) {
6297
+ const tg = v._tag;
6298
+ if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
6220
6299
  }
6221
- const raw = {
6222
- ...base,
6223
- code,
6224
- ...d.lines === void 0 ? {} : { lines: d.lines },
6225
- ...d.hostMode === void 0 ? {} : { hostMode: d.hostMode }
6300
+ return {
6301
+ _tag: "leaf",
6302
+ value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
6303
+ span: { start: s, end: e }
6226
6304
  };
6227
- const prog = ownTableProgram(raw);
6228
- const owner = prog[TABLE_RUNTIME];
6229
- owner.resolved = { ...resolveTable(base), prog, code: Int32Array.from(code) };
6230
- byName?.set(name, prog);
6231
- return prog;
6232
6305
  }
6233
- function expandCompactFolded(f) {
6234
- const variants = {};
6235
- for (const name of Object.keys(f.v)) {
6236
- const d = f.v[name];
6237
- variants[name] = {
6238
- at: d.a ?? [],
6239
- to: d.t ?? [],
6240
- ...d.l === void 0 ? {} : { lines: d.l },
6241
- ...d.h === void 0 ? {} : { hostMode: d.h }
6242
- };
6243
- }
6244
- return ownFoldedProgram(expandCompact(f.b), variants);
6306
+ function lead(input, pos) {
6307
+ if (pos >= input.length) return -1;
6308
+ const c = input.charCodeAt(pos);
6309
+ if (c < 55296 || c > 56319) return c;
6310
+ return input.codePointAt(pos) ?? c;
6245
6311
  }
6246
6312
 
6247
6313
  // src/cst/host-mode.ts
@@ -6289,7 +6355,7 @@ function committed(c) {
6289
6355
  }
6290
6356
  function stampRuleMap(prog, d, artifactMetadata = {}, resolved = resolveTable(prog)) {
6291
6357
  const triviaOfRule = (ip) => {
6292
- if (prog.code[ip] !== OP_SCOPE) return void 0;
6358
+ if (prog.code[ip] !== OP_SCOPE_PLAIN && prog.code[ip] !== OP_SCOPE) return void 0;
6293
6359
  const slot = prog.code[ip + 1];
6294
6360
  return slot < 0 ? void 0 : resolved.trivia[slot];
6295
6361
  };
@@ -6509,20 +6575,19 @@ function assemble(t, prog, cfg) {
6509
6575
  TERMV = v2;
6510
6576
  return EC.e > scanEnd2 ? EC.e : cur;
6511
6577
  }
6512
- const need = markCst(ctx);
6513
- const mRaw = MRAW;
6514
- const mTl = MTL;
6515
- const mLv = MLV;
6516
- const mFl = need ? ctx._fields?.length ?? 0 : 0;
6517
- const mEr = need ? ctx._errors?.length ?? 0 : 0;
6578
+ const need = rollbackNeeded(ctx);
6579
+ const mTl = need ? cstTlLen(ctx) : 0;
6518
6580
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
6519
6581
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
6520
6582
  const scanEnd = skipTrivia(input, cur, ctx);
6583
+ const scanTl = need ? cstTlLen(ctx) : 0;
6584
+ const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0;
6585
+ const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
6521
6586
  const v = child(input, scanEnd, ctx);
6522
6587
  if (v === FAIL) return -1;
6523
6588
  TERMV = v;
6524
6589
  if (EC.e > scanEnd) return EC.e;
6525
- if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
6590
+ if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
6526
6591
  return cur;
6527
6592
  }
6528
6593
  function committed2(c) {
@@ -6936,7 +7001,8 @@ function assemble(t, prog, cfg) {
6936
7001
  };
6937
7002
  }
6938
7003
  case OP_SCOPE:
6939
- case OP_SCOPE_CAP: {
7004
+ case OP_SCOPE_CAP:
7005
+ case OP_SCOPE_PLAIN: {
6940
7006
  const ki = code[ip + 1];
6941
7007
  const scopeTrivia = ki < 0 ? void 0 : trivia2[ki];
6942
7008
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels;
@@ -6970,7 +7036,7 @@ function assemble(t, prog, cfg) {
6970
7036
  SCAN = savedScan;
6971
7037
  return v;
6972
7038
  };
6973
- return scopeRootPolicy(scopePiece, code[ip + 3]);
7039
+ return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]);
6974
7040
  }
6975
7041
  case OP_ROUTED: {
6976
7042
  const fb = code[ip + 1];
@@ -7886,15 +7952,21 @@ function assemble(t, prog, cfg) {
7886
7952
  target = arms[arm];
7887
7953
  usesRouted = routed[arm] === 1;
7888
7954
  }
7889
- const savedRouted = ctx._routed;
7890
7955
  let mark = saveTriviaMark(ctx);
7956
+ let v;
7891
7957
  if (usesRouted) {
7958
+ const savedRouted = ctx._routed;
7892
7959
  rollbackTrivia(ctx, selectorMark);
7893
7960
  mark = saveTriviaMark(ctx);
7894
7961
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
7962
+ try {
7963
+ v = target(input, pos, ctx);
7964
+ } finally {
7965
+ ctx._routed = savedRouted;
7966
+ }
7967
+ } else {
7968
+ v = target(input, selEnd, ctx);
7895
7969
  }
7896
- const v = target(input, usesRouted ? pos : selEnd, ctx);
7897
- if (usesRouted) ctx._routed = savedRouted;
7898
7970
  if (v === FAIL) {
7899
7971
  rollbackTrivia(ctx, mark);
7900
7972
  ctx._fc = true;
@@ -8040,6 +8112,11 @@ function assemble(t, prog, cfg) {
8040
8112
  if (s.sentinel !== void 0) extraIps.push(s.sentinel[0]);
8041
8113
  }
8042
8114
  for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
8115
+ const validationRoots = [...Object.values(prog.rules), ...extraIps];
8116
+ for (const ip of reachableSites(code, validationRoots)) {
8117
+ if (code[ip] !== OP_DISPATCH) continue;
8118
+ validateDispatchSpec(dsp[code[ip + 2]], code[ip + 5], code[ip + 4]);
8119
+ }
8043
8120
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
8044
8121
  if (pre !== void 0) {
8045
8122
  const pools = rebuildPools(t.cc, t.fx, pre.plan);
@@ -8066,6 +8143,7 @@ function assemble(t, prog, cfg) {
8066
8143
  pushCstLeaf,
8067
8144
  pushCstChild,
8068
8145
  rollbackTriviaAt,
8146
+ rollbackScannedTriviaAt,
8069
8147
  failAt,
8070
8148
  classHas,
8071
8149
  consumeTrivia,
@@ -8136,6 +8214,7 @@ function assemble(t, prog, cfg) {
8136
8214
  pushCstLeaf,
8137
8215
  pushCstChild,
8138
8216
  rollbackTriviaAt,
8217
+ rollbackScannedTriviaAt,
8139
8218
  failAt,
8140
8219
  classHas,
8141
8220
  consumeTrivia,
@@ -8825,7 +8904,7 @@ var Encoder = class {
8825
8904
  this.carryTriviaMeta(amb);
8826
8905
  this.carryTriviaMeta(p);
8827
8906
  if (p._def.tag === "grammar") this.carryTriviaMeta(p._def.triviaParser);
8828
- this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE, this.triviaSlot(amb), body);
8907
+ this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), body);
8829
8908
  }
8830
8909
  /**
8831
8910
  * The row a cross-rule `g.X` reference jumps to — the target's body, RE-WRAPPED
@@ -8868,7 +8947,7 @@ var Encoder = class {
8868
8947
  const amb = p._meta.grammarTrivia ?? target._meta.grammarTrivia;
8869
8948
  if (amb === void 0 || this.activeTrivia !== void 0) return ip;
8870
8949
  if (!hasOwnTriviaBoundary(target)) return ip;
8871
- return this.emit(OP_SCOPE, this.triviaSlot(amb), ip);
8950
+ return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
8872
8951
  }
8873
8952
  node(p) {
8874
8953
  const lazyRef = p._def.tag === "lazy";
@@ -9273,6 +9352,7 @@ var Encoder = class {
9273
9352
  return [ip + 1];
9274
9353
  case OP_SCOPE:
9275
9354
  case OP_SCOPE_CAP:
9355
+ case OP_SCOPE_PLAIN:
9276
9356
  case OP_WITHCTX:
9277
9357
  case OP_XFORM:
9278
9358
  case OP_LEAF:
@@ -9412,6 +9492,14 @@ function encodeTableProgram(ruleMap, settings = {}) {
9412
9492
  function jsString(s) {
9413
9493
  return JSON.stringify(s);
9414
9494
  }
9495
+ function emitClassPool(classes) {
9496
+ const array = `[${classes.map(jsString).join(",")}]`;
9497
+ if (classes.length < 2) return array;
9498
+ const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
9499
+ if (delimiter === void 0) return array;
9500
+ const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
9501
+ return split.length < array.length ? split : array;
9502
+ }
9415
9503
  function emitConst(v) {
9416
9504
  if (v instanceof RegExp) return `/${v.source}/${v.flags}`;
9417
9505
  if (typeof v === "string") return jsString(v);
@@ -9490,7 +9578,7 @@ function programFields(prog, fns, opts = {}) {
9490
9578
  ...emitAssemblies(prog, opts.assemblies ?? []),
9491
9579
  `c:[${prog.code.join(",")}],`,
9492
9580
  `k:[${prog.k.map(emitConst).join(",")}],`,
9493
- `x:[${prog.cc.map(jsString).join(",")}],`,
9581
+ `x:${emitClassPool(prog.cc)},`,
9494
9582
  `e:[${prog.fx.map((f) => `[${f.map(jsString).join(",")}]`).join(",")}],`,
9495
9583
  `d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
9496
9584
  `r:${JSON.stringify(prog.rules)},`,