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
@@ -87,6 +87,13 @@ function empty() {
87
87
  function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
88
88
  if (seen.has(p)) return true;
89
89
  seen.add(p);
90
+ try {
91
+ return matchesEmptyBody(p, seen, resolve);
92
+ } finally {
93
+ seen.delete(p);
94
+ }
95
+ }
96
+ function matchesEmptyBody(p, seen, resolve) {
90
97
  const me = (c) => matchesEmpty(c, seen, resolve);
91
98
  const d = p._def;
92
99
  switch (d.tag) {
@@ -188,6 +195,13 @@ function sequenceFirstSet(parsers) {
188
195
  function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
189
196
  if (seen.has(p)) return any();
190
197
  seen.add(p);
198
+ try {
199
+ return firstSetBody(p, seen, resolve);
200
+ } finally {
201
+ seen.delete(p);
202
+ }
203
+ }
204
+ function firstSetBody(p, seen, resolve) {
191
205
  const fs = (c) => firstSetOf(c, seen, resolve);
192
206
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
193
207
  const d = p._def;
@@ -1514,6 +1528,23 @@ function rollbackTrivia(ctx, mark) {
1514
1528
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1515
1529
  if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
1516
1530
  }
1531
+ function removeNumberRange(values, start, end) {
1532
+ if (values === void 0 || end <= start) return;
1533
+ if (values.length > end) values.copyWithin(start, end);
1534
+ values.length -= end - start;
1535
+ }
1536
+ function rollbackScannedTriviaAt(ctx, tlogStart, tlogEnd, logStart, logEnd, rootLogStart, rootLogEnd) {
1537
+ const b = ctx._cstBuf;
1538
+ if (b !== void 0) {
1539
+ const tlog = b.tl;
1540
+ removeNumberRange(tlog, tlogStart, tlogEnd);
1541
+ if (tlog !== void 0 && tlog.length === 0) b.tl = void 0;
1542
+ } else {
1543
+ removeNumberRange(ctx._cstTriviaLog, tlogStart, tlogEnd);
1544
+ }
1545
+ removeNumberRange(ctx._triviaLog, logStart, logEnd);
1546
+ removeNumberRange(ctx._rootTriviaLog, rootLogStart, rootLogEnd);
1547
+ }
1517
1548
  function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1518
1549
  const probeCtx = createDetachedParseContext(ctx.trackLines, ctx.state);
1519
1550
  probeCtx._lineIndex = ctx._lineIndex;
@@ -2173,7 +2204,9 @@ function sequence(...parsers) {
2173
2204
  continue;
2174
2205
  }
2175
2206
  if (ctx.trivia && i > 0) {
2176
- const mark = saveTriviaMark(ctx);
2207
+ const mTlog = cstTlLen(ctx);
2208
+ const mLog = ctx._triviaLog?.length ?? 0;
2209
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2177
2210
  let scanEnd;
2178
2211
  if (needsDeferredTriviaCommit(ctx)) {
2179
2212
  const scan = scanTrivia(input, cur, ctx);
@@ -2182,10 +2215,13 @@ function sequence(...parsers) {
2182
2215
  } else {
2183
2216
  scanEnd = advanceTrivia(input, cur, ctx);
2184
2217
  }
2218
+ const scanTlog = cstTlLen(ctx);
2219
+ const scanLog = ctx._triviaLog?.length ?? 0;
2220
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2185
2221
  const result2 = parsers[i].parse(input, scanEnd, ctx);
2186
2222
  if (!result2.ok) return result2;
2187
2223
  if (result2.span.end > scanEnd) cur = result2.span.end;
2188
- else rollbackTrivia(ctx, mark);
2224
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
2189
2225
  if (values !== void 0) values.push(result2.value);
2190
2226
  continue;
2191
2227
  }
@@ -2216,7 +2252,9 @@ function sequence(...parsers) {
2216
2252
  }
2217
2253
  if (ctx.trivia && i > 0) {
2218
2254
  let scanEnd;
2219
- const mark = saveTriviaMark(ctx);
2255
+ const mTlog = cstTlLen(ctx);
2256
+ const mLog = ctx._triviaLog?.length ?? 0;
2257
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2220
2258
  if (needsDeferredTriviaCommit(ctx)) {
2221
2259
  const scan = scanTrivia(input, cur, ctx);
2222
2260
  scan.commit();
@@ -2224,10 +2262,13 @@ function sequence(...parsers) {
2224
2262
  } else {
2225
2263
  scanEnd = advanceTrivia(input, cur, ctx);
2226
2264
  }
2265
+ const scanTlog = cstTlLen(ctx);
2266
+ const scanLog = ctx._triviaLog?.length ?? 0;
2267
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2227
2268
  const result2 = parsers[i].parse(input, scanEnd, ctx);
2228
2269
  if (!result2.ok) return result2;
2229
2270
  if (result2.span.end > scanEnd) cur = result2.span.end;
2230
- else rollbackTrivia(ctx, mark);
2271
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
2231
2272
  if (values !== void 0) values.push(result2.value);
2232
2273
  continue;
2233
2274
  }
@@ -2255,7 +2296,9 @@ function sequence(...parsers) {
2255
2296
  for (let i = 0; i < parsers.length; i++) {
2256
2297
  if (ctx.trivia && i > 0) {
2257
2298
  let scanEnd;
2258
- let mark = saveTriviaMark(ctx);
2299
+ const mTlog = cstTlLen(ctx);
2300
+ const mLog = ctx._triviaLog?.length ?? 0;
2301
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
2259
2302
  if (needsDeferredTriviaCommit(ctx)) {
2260
2303
  const scan = scanTrivia(input, cur, ctx);
2261
2304
  scan.commit();
@@ -2263,12 +2306,15 @@ function sequence(...parsers) {
2263
2306
  } else {
2264
2307
  scanEnd = advanceTrivia(input, cur, ctx);
2265
2308
  }
2309
+ const scanTlog = cstTlLen(ctx);
2310
+ const scanLog = ctx._triviaLog?.length ?? 0;
2311
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
2266
2312
  const result2 = parsers[i].parse(input, scanEnd, ctx);
2267
2313
  if (!result2.ok) return result2;
2268
2314
  if (result2.span.end > scanEnd) {
2269
2315
  cur = result2.span.end;
2270
2316
  } else {
2271
- rollbackTrivia(ctx, mark);
2317
+ rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
2272
2318
  }
2273
2319
  if (values !== void 0) values.push(result2.value);
2274
2320
  continue;
@@ -3602,6 +3648,7 @@ var OP_LIVE = 37;
3602
3648
  var OP_ATTEMPT = 38;
3603
3649
  var OP_LABEL = 39;
3604
3650
  var OP_COV = 40;
3651
+ var OP_SCOPE_PLAIN = 41;
3605
3652
  var OP_DISPATCH = 25;
3606
3653
  var OP_ROUTED = 26;
3607
3654
  var OP_NAMES = {
@@ -3644,515 +3691,844 @@ var OP_NAMES = {
3644
3691
  [OP_LIVE]: "LIVE",
3645
3692
  [OP_ATTEMPT]: "ATTEMPT",
3646
3693
  [OP_LABEL]: "LABEL",
3647
- [OP_COV]: "COV"
3694
+ [OP_COV]: "COV",
3695
+ [OP_SCOPE_PLAIN]: "SCOPE_PLAIN"
3648
3696
  };
3649
3697
 
3650
- // src/table/scan-shapes.ts
3651
- var BACKSLASH = 92;
3652
- var META2 = new Set("()[]{}*+?|^$.".split(""));
3653
- function classToRanges(cls) {
3654
- if (cls === "\\d") return shorthandRanges("d");
3655
- if (cls === "\\w") return shorthandRanges("w");
3656
- if (cls === "\\s") return shorthandRanges("s");
3657
- const body = cls.slice(1, -1);
3658
- if (body.startsWith("^")) return null;
3659
- return parseClassRanges(body);
3698
+ // src/table/program.ts
3699
+ function closureArtifact(prog) {
3700
+ return { ...prog, asm: [] };
3660
3701
  }
3661
- var foldEq = (cVar, cp) => {
3662
- if (cp >= 65 && cp <= 90) return `(${cVar} | 32) === ${cp + 32}`;
3663
- if (cp >= 97 && cp <= 122) return `(${cVar} | 32) === ${cp}`;
3664
- return `${cVar} === ${cp}`;
3665
- };
3666
- function parseStringShape(source) {
3667
- const q2 = source[0];
3668
- if (q2 === void 0 || q2 === "\\" || META2.has(q2)) return null;
3669
- if (source.length < 3 || source[source.length - 1] !== q2) return null;
3670
- const inner = source.slice(1, -1);
3671
- const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
3672
- const ESC = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
3673
- let body;
3674
- let esc;
3675
- let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC}\\)\\*$`).exec(inner);
3676
- if (m) {
3677
- body = m[1];
3678
- esc = m[2];
3679
- } else {
3680
- m = new RegExp(`^\\((?:\\?:)?${ESC}\\|${CLS}\\)\\*$`).exec(inner);
3681
- if (m) {
3682
- esc = m[1];
3683
- body = m[2];
3684
- }
3702
+ function covKindCode(kind) {
3703
+ switch (kind) {
3704
+ case "rule":
3705
+ return 0;
3706
+ case "choice-arm":
3707
+ return 1;
3708
+ case "dispatch-arm":
3709
+ return 2;
3710
+ case "label":
3711
+ return 3;
3685
3712
  }
3686
- if (body === void 0 || esc === void 0) return null;
3687
- const excluded = parseClassRanges(body);
3688
- if (!excluded) return null;
3689
- const qcp = q2.codePointAt(0);
3690
- const inSet = (cp) => excluded.some(([lo, hi]) => cp >= lo && cp <= hi);
3691
- if (!inSet(qcp) || !inSet(BACKSLASH)) return null;
3692
- return { kind: "string", quote: qcp, excluded, escLineTerm: esc !== "." };
3693
3713
  }
3694
- function parseSeqParts(source) {
3695
- const parts = [];
3696
- let lit = [];
3697
- const flush = () => {
3698
- if (lit.length) {
3699
- parts.push({ part: "lit", cps: lit, optional: false });
3700
- lit = [];
3701
- }
3702
- };
3703
- const braceQuant = (at) => {
3704
- const close = source.indexOf("}", at);
3705
- if (close === -1) return null;
3706
- const body = source.slice(at + 1, close);
3707
- const m = /^(\d+)(,(\d*)?)?$/.exec(body);
3708
- if (!m) return null;
3709
- const min = Number(m[1]);
3710
- const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
3711
- if (max < 1 || min > max) return null;
3712
- return { min, max, len: close - at + 1 };
3714
+ function covKindName(code) {
3715
+ switch (code) {
3716
+ case 0:
3717
+ return "rule";
3718
+ case 1:
3719
+ return "choice-arm";
3720
+ case 2:
3721
+ return "dispatch-arm";
3722
+ case 3:
3723
+ return "label";
3724
+ }
3725
+ }
3726
+ function covDefinitions(prog) {
3727
+ return (prog.cov ?? []).map(([id, kind]) => ({ id, kind: covKindName(kind) }));
3728
+ }
3729
+ function expandCompact(p) {
3730
+ if ("code" in p) return p;
3731
+ return ownTableProgram({
3732
+ code: p.c,
3733
+ k: p.k,
3734
+ cc: p.x,
3735
+ fx: p.e,
3736
+ disp: p.d,
3737
+ rules: p.r,
3738
+ fns: p.f,
3739
+ lines: p.l ?? 0,
3740
+ dsp: p.p ?? [],
3741
+ ...p.lb === void 0 ? {} : { labels: p.lb },
3742
+ ...p.rc === void 0 ? {} : { classified: p.rc },
3743
+ ...p.h === void 0 ? {} : { hostMode: p.h },
3744
+ ...p.tv === void 0 ? {} : { triviaSpecs: p.tv },
3745
+ ...p.sc === void 0 ? {} : { scans: p.sc },
3746
+ ...p.ss === void 0 ? {} : { scanSkip: p.ss },
3747
+ ...p.so === void 0 ? {} : { scanSkipOf: p.so },
3748
+ ...p.rv === void 0 ? {} : { rec: p.rv },
3749
+ ...p.cv === void 0 ? {} : { cov: p.cv },
3750
+ ...p.a === void 0 ? {} : { asm: p.a }
3751
+ });
3752
+ }
3753
+ function validateDispatchSpec(spec, arity, fallbackRouted) {
3754
+ const invalid = (arms) => {
3755
+ for (const arm of arms) if (!Number.isInteger(arm) || arm < 0 || arm >= arity) return true;
3756
+ return false;
3713
3757
  };
3714
- const runFrom = (ranges, negated, at) => {
3715
- const q2 = source[at];
3716
- if (q2 === "+") {
3717
- parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
3718
- return 1;
3758
+ 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]]))) {
3759
+ throw new TypeError("table: malformed dispatch");
3760
+ }
3761
+ }
3762
+ var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
3763
+ function ownTableProgram(prog, resolved) {
3764
+ return { ...prog, [TABLE_RUNTIME]: { resolved } };
3765
+ }
3766
+ var WIDE_CLASS_PREFIX_LO = 65535;
3767
+ var WIDE_CLASS_PREFIX_HI = 0;
3768
+ function validateClassRange(lo, hi) {
3769
+ for (const cp of [lo, hi]) {
3770
+ if (!Number.isInteger(cp) || cp < 0 || cp > 1114111) {
3771
+ throw new TypeError(`table char-class endpoint is outside Unicode: ${cp}`);
3719
3772
  }
3720
- if (q2 === "*") {
3721
- parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
3722
- return 1;
3773
+ }
3774
+ if (lo > hi) {
3775
+ throw new TypeError(`table char-class range is descending: ${lo} > ${hi}`);
3776
+ }
3777
+ }
3778
+ function encodeClassSpec(ranges) {
3779
+ let wide = false;
3780
+ for (const range of ranges) {
3781
+ validateClassRange(range.lo, range.hi);
3782
+ if (range.hi > 65535) wide = true;
3783
+ }
3784
+ if (!wide) {
3785
+ let spec2 = "";
3786
+ for (const range of ranges) spec2 += String.fromCharCode(range.lo, range.hi);
3787
+ return spec2;
3788
+ }
3789
+ let spec = String.fromCharCode(WIDE_CLASS_PREFIX_LO, WIDE_CLASS_PREFIX_HI);
3790
+ for (const range of ranges) {
3791
+ spec += String.fromCharCode(
3792
+ range.lo >>> 16,
3793
+ range.lo & 65535,
3794
+ range.hi >>> 16,
3795
+ range.hi & 65535
3796
+ );
3797
+ }
3798
+ return spec;
3799
+ }
3800
+ function decodeClassSpec(spec) {
3801
+ if (spec.charCodeAt(0) === WIDE_CLASS_PREFIX_LO && spec.charCodeAt(1) === WIDE_CLASS_PREFIX_HI) {
3802
+ if ((spec.length - 2) % 4 !== 0) throw new TypeError("table char-class spec has a truncated wide range");
3803
+ if (spec.length === 2) throw new TypeError("table char-class spec has a wide prefix but no ranges");
3804
+ const ranges2 = [];
3805
+ for (let i = 2; i < spec.length; i += 4) {
3806
+ const lo = spec.charCodeAt(i) * 65536 + spec.charCodeAt(i + 1);
3807
+ const hi = spec.charCodeAt(i + 2) * 65536 + spec.charCodeAt(i + 3);
3808
+ validateClassRange(lo, hi);
3809
+ ranges2.push({ lo, hi });
3723
3810
  }
3724
- if (q2 === "?") {
3725
- parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
3726
- return 1;
3811
+ return ranges2;
3812
+ }
3813
+ if (spec.length % 2 !== 0) throw new TypeError("table char-class spec has an unmatched range endpoint");
3814
+ const ranges = [];
3815
+ for (let i = 0; i < spec.length; i += 2) {
3816
+ const lo = spec.charCodeAt(i);
3817
+ const hi = spec.charCodeAt(i + 1);
3818
+ validateClassRange(lo, hi);
3819
+ ranges.push({ lo, hi });
3820
+ }
3821
+ return ranges;
3822
+ }
3823
+ function resolveClass(spec) {
3824
+ const ascii = new Uint8Array(128);
3825
+ const hi = [];
3826
+ for (const { lo, hi: up } of decodeClassSpec(spec)) {
3827
+ if (lo < 128) for (let c = lo; c <= Math.min(up, 127); c++) ascii[c] = 1;
3828
+ if (up >= 128) hi.push(Math.max(lo, 128), up);
3829
+ }
3830
+ return { ascii, hi };
3831
+ }
3832
+ function classHas(cls, code) {
3833
+ if (code < 0) return false;
3834
+ if (code < 128) return cls.ascii[code] === 1;
3835
+ const hi = cls.hi;
3836
+ for (let i = 0; i < hi.length; i += 2) if (code >= hi[i] && code <= hi[i + 1]) return true;
3837
+ return false;
3838
+ }
3839
+ function resolveDispatch(arms, cc) {
3840
+ const ascii = new Uint8Array(128);
3841
+ const hi = [];
3842
+ const open = [];
3843
+ const armCls = [];
3844
+ let exclusive = true;
3845
+ let hiOwners = 0;
3846
+ for (let a = 0; a < arms.length; a++) {
3847
+ const ci = arms[a];
3848
+ if (ci < 0) {
3849
+ open.push(a);
3850
+ armCls.push(null);
3851
+ exclusive = false;
3852
+ continue;
3727
3853
  }
3728
- if (q2 === "{") {
3729
- const b = braceQuant(at);
3730
- if (b) {
3731
- parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
3732
- return b.len;
3733
- }
3854
+ const cls = cc[ci];
3855
+ armCls.push(cls);
3856
+ for (let c = 0; c < 128; c++) {
3857
+ if (cls.ascii[c] !== 1) continue;
3858
+ if (ascii[c] === 0) ascii[c] = a + 1;
3859
+ else exclusive = false;
3734
3860
  }
3735
- parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
3736
- return 0;
3737
- };
3738
- let i = 0;
3739
- while (i < source.length) {
3740
- const ch2 = source[i];
3741
- if (ch2 === "[") {
3742
- let k = i + 1;
3743
- const neg = source[k] === "^";
3744
- if (neg) k++;
3745
- let body = "";
3746
- while (k < source.length && source[k] !== "]") {
3747
- if (source[k] === "\\") {
3748
- body += source[k] + (source[k + 1] ?? "");
3749
- k += 2;
3750
- } else {
3751
- body += source[k];
3752
- k++;
3753
- }
3754
- }
3755
- if (source[k] !== "]") return null;
3756
- const ranges = parseClassRanges(body);
3757
- if (!ranges) return null;
3758
- flush();
3759
- i = k + 1;
3760
- i += runFrom(ranges, neg, i);
3761
- continue;
3861
+ if (cls.hi.length > 0 && ++hiOwners > 1) exclusive = false;
3862
+ for (let i = 0; i < cls.hi.length; i += 2) hi.push(cls.hi[i], cls.hi[i + 1], a);
3863
+ }
3864
+ return { ascii, hi, open, armCls, exclusive };
3865
+ }
3866
+ function buildTrivia(spec) {
3867
+ if (spec.live !== void 0) return spec.live;
3868
+ if (spec.plain !== void 0) return trivia(regex(new RegExp(spec.plain[0], spec.plain[1])));
3869
+ if (spec.alts !== void 0) {
3870
+ const [head, ...rest] = spec.alts.map(([source, flags]) => regex(new RegExp(source, flags)));
3871
+ if (head === void 0) throw new TypeError("trivia spec has an EMPTY alternation, which matches nothing");
3872
+ const body = rest.length === 0 ? head : choice(head, ...rest);
3873
+ return trivia(many(body, { min: spec.min ?? 1 }));
3874
+ }
3875
+ const arms = {};
3876
+ for (const [name, source, flags] of spec.arms) arms[name] = regex(new RegExp(source, flags));
3877
+ return classifiedTrivia(arms);
3878
+ }
3879
+ function resolveTable(prog) {
3880
+ const owner = prog[TABLE_RUNTIME];
3881
+ const hit = owner?.resolved;
3882
+ if (hit !== void 0) return hit;
3883
+ const cc = prog.cc.map(resolveClass);
3884
+ const triviaBuilt = (prog.triviaSpecs ?? []).map(buildTrivia);
3885
+ const built = {
3886
+ prog,
3887
+ code: Int32Array.from(prog.code),
3888
+ k: prog.k,
3889
+ fns: prog.fns,
3890
+ cc,
3891
+ fx: prog.fx,
3892
+ disp: prog.disp.map((d) => resolveDispatch(d, cc)),
3893
+ trivia: triviaBuilt,
3894
+ triviaScan: triviaBuilt.map(fastTriviaScanner),
3895
+ triviaLabelled: triviaBuilt.map((t) => t._meta.triviaKindLabels !== void 0),
3896
+ dsp: prog.dsp.map((d) => ({
3897
+ byKey: new Map(d.key.map((x, i) => [x, d.keyArm[i]])),
3898
+ byFold: new Map(d.fold.map((x, i) => [x, d.foldArm[i]])),
3899
+ match: d.match,
3900
+ routed: d.routed,
3901
+ expected: d.expected
3902
+ })),
3903
+ rules: prog.rules
3904
+ };
3905
+ if (owner !== void 0) owner.resolved = built;
3906
+ return built;
3907
+ }
3908
+ var FOLDED_RUNTIME = /* @__PURE__ */ Symbol("parseman.foldedRuntime");
3909
+ function ownFoldedProgram(base, variants) {
3910
+ return { base, variants, [FOLDED_RUNTIME]: { byName: /* @__PURE__ */ new Map() } };
3911
+ }
3912
+ var SHARED_FIELDS = [
3913
+ "k",
3914
+ "cc",
3915
+ "fx",
3916
+ "disp",
3917
+ "dsp",
3918
+ "rules",
3919
+ "labels",
3920
+ "classified",
3921
+ "scanSkip",
3922
+ "scanSkipOf",
3923
+ "scans",
3924
+ "triviaSpecs",
3925
+ "runtimeOnly",
3926
+ // `rec` is a property of the GRAMMAR BUILD, not of the trackLines/hostMode
3927
+ // axis a fold varies — every variant of one export is encoded with the same
3928
+ // recovery setting, and a mismatch is two tables, which is what the refusal says.
3929
+ "rec",
3930
+ // `cov` is a property of the GRAMMAR and its coverage plan, for the same reason
3931
+ // `rec` is a property of the build: the plan is built from the rule map, which
3932
+ // every variant of one export shares. It ships ONCE, and a variant that
3933
+ // disagrees is two tables — which is what the refusal says.
3934
+ "cov"
3935
+ ];
3936
+ function foldPrograms(programs, baseName) {
3937
+ const suppliedBase = programs[baseName];
3938
+ if (suppliedBase === void 0) throw new TypeError(`foldPrograms: no program named ${JSON.stringify(baseName)}`);
3939
+ const base = closureArtifact(suppliedBase);
3940
+ const variants = {};
3941
+ for (const name of Object.keys(programs)) {
3942
+ const p = programs[name];
3943
+ if (p.asm !== void 0 && p.asm.length > 0) {
3944
+ throw new TypeError(
3945
+ `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.`
3946
+ );
3762
3947
  }
3763
- if (ch2 === "\\") {
3764
- const e = source[i + 1];
3765
- if (e === "d" || e === "w" || e === "s") {
3766
- flush();
3767
- i += 2;
3768
- i += runFrom(shorthandRanges(e), false, i);
3769
- continue;
3770
- }
3771
- const uni = readUnicodeEscape(source, i);
3772
- let cp2;
3773
- if (uni) {
3774
- cp2 = uni.cp;
3775
- i = uni.next;
3776
- } else if (e === void 0) return null;
3777
- else if (e in CLASS_ESCAPES) {
3778
- cp2 = CLASS_ESCAPES[e];
3779
- i += 2;
3780
- } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
3781
- else {
3782
- cp2 = e.codePointAt(0);
3783
- i += 2;
3784
- }
3785
- if (source[i] === "?") {
3786
- flush();
3787
- parts.push({ part: "lit", cps: [cp2], optional: true });
3788
- i++;
3789
- } else lit.push(cp2);
3790
- continue;
3948
+ if (p.code.length !== base.code.length) {
3949
+ throw new TypeError(
3950
+ `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.`
3951
+ );
3791
3952
  }
3792
- if (ch2 === "(") {
3793
- if (source[i + 1] !== "?" || source[i + 2] !== ":") return null;
3794
- let k = i + 3;
3795
- let depth = 1;
3796
- while (k < source.length && depth > 0) {
3797
- const c2 = source[k];
3798
- if (c2 === "\\") {
3799
- k += 2;
3800
- continue;
3801
- }
3802
- if (c2 === "[") {
3803
- let j = k + 1;
3804
- if (source[j] === "^") j++;
3805
- while (j < source.length && source[j] !== "]") {
3806
- if (source[j] === "\\") j += 2;
3807
- else j++;
3808
- }
3809
- if (source[j] !== "]") return null;
3810
- k = j + 1;
3811
- continue;
3812
- }
3813
- if (c2 === "(") depth++;
3814
- else if (c2 === ")") depth--;
3815
- k++;
3816
- }
3817
- if (depth !== 0) return null;
3818
- const body = source.slice(i + 3, k - 1);
3819
- const inner = parseScanShape(body);
3820
- if (!inner || !groupInnerSafe(inner)) return null;
3821
- const q2 = source[k];
3822
- if (q2 === "{") return null;
3823
- flush();
3824
- if (q2 === "+") {
3825
- if (shapeCanBeEmpty(inner)) return null;
3826
- parts.push({ part: "group", inner, min: 1, unbounded: true });
3827
- i = k + 1;
3828
- } else if (q2 === "*") {
3829
- if (shapeCanBeEmpty(inner)) return null;
3830
- parts.push({ part: "group", inner, min: 0, unbounded: true });
3831
- i = k + 1;
3832
- } else if (q2 === "?") {
3833
- parts.push({ part: "group", inner, min: 0, unbounded: false });
3834
- i = k + 1;
3835
- } else {
3836
- parts.push({ part: "group", inner, min: 1, unbounded: false });
3837
- i = k;
3953
+ for (const f of SHARED_FIELDS) {
3954
+ if (JSON.stringify(p[f]) !== JSON.stringify(base[f])) {
3955
+ throw new TypeError(
3956
+ `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.`
3957
+ );
3838
3958
  }
3839
- continue;
3840
3959
  }
3841
- if (META2.has(ch2)) return null;
3842
- const cp = ch2.codePointAt(0);
3843
- i += ch2.length;
3844
- if (source[i] === "?") {
3845
- flush();
3846
- parts.push({ part: "lit", cps: [cp], optional: true });
3847
- i++;
3848
- } else lit.push(cp);
3849
- }
3850
- flush();
3851
- return parts.length ? parts : null;
3852
- }
3853
- function seqIsUnambiguous(parts) {
3854
- let hasMandatory = false;
3855
- for (let k = 0; k < parts.length; k++) {
3856
- const p = parts[k];
3857
- const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
3858
- if (mandatory) hasMandatory = true;
3859
- if (p.part === "group") {
3860
- const exposure = groupPartExposure(p);
3861
- if (exposure === "unsupported") {
3862
- const trailingOnce = k === parts.length - 1 && p.min === 1 && !p.unbounded;
3863
- if (!trailingOnce) return false;
3864
- } else if (exposure !== null) {
3865
- if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
3866
- }
3960
+ if (p.fns.length !== base.fns.length || p.fns.some((f, i) => f !== base.fns[i])) {
3961
+ throw new TypeError(
3962
+ `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.`
3963
+ );
3867
3964
  }
3868
- const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
3869
- if (needsDisjoint) {
3870
- const rest = seqFirstAccept(parts.slice(k + 1));
3871
- if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
3965
+ const at = [];
3966
+ const to = [];
3967
+ let prev = 0;
3968
+ for (let i = 0; i < p.code.length; i++) {
3969
+ if (p.code[i] === base.code[i]) continue;
3970
+ at.push(i - prev);
3971
+ to.push(p.code[i]);
3972
+ prev = i;
3872
3973
  }
3974
+ variants[name] = {
3975
+ at,
3976
+ to,
3977
+ ...p.lines === void 0 ? {} : { lines: p.lines },
3978
+ ...p.hostMode === void 0 ? {} : { hostMode: p.hostMode }
3979
+ };
3873
3980
  }
3874
- return hasMandatory;
3875
- }
3876
- function rangesOverlap(a, b) {
3877
- return a.some(([lo, hi]) => b.some(([lo2, hi2]) => lo <= hi2 && lo2 <= hi));
3878
- }
3879
- function rangesSubset(sub, sup) {
3880
- return sub.every(([lo, hi]) => sup.some(([lo2, hi2]) => lo >= lo2 && hi <= hi2));
3881
- }
3882
- function classSubset(t, u) {
3883
- if (!t.negated && !u.negated) return rangesSubset(t.ranges, u.ranges);
3884
- if (!t.negated && u.negated) return !rangesOverlap(t.ranges, u.ranges);
3885
- if (t.negated && !u.negated) return false;
3886
- return rangesSubset(u.ranges, t.ranges);
3887
- }
3888
- function classDisjoint(t, u) {
3889
- if (!t.negated && !u.negated) return !rangesOverlap(t.ranges, u.ranges);
3890
- if (!t.negated && u.negated) return rangesSubset(t.ranges, u.ranges);
3891
- if (t.negated && !u.negated) return rangesSubset(u.ranges, t.ranges);
3892
- return false;
3893
- }
3894
- function firstSetsDisjoint(a, b) {
3895
- if (a === "any" || b === "any") return false;
3896
- return classDisjoint(a, b);
3981
+ return ownFoldedProgram(base, variants);
3897
3982
  }
3898
- function fixedClassSeq(shape) {
3899
- if (shape.kind === "litFold") {
3900
- return shape.open.map((cp) => {
3901
- const other = cp >= 65 && cp <= 90 ? cp + 32 : cp >= 97 && cp <= 122 ? cp - 32 : cp;
3902
- 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 };
3903
- });
3904
- }
3905
- if (shape.kind !== "seq") return null;
3906
- const out = [];
3907
- for (const p of shape.parts) {
3908
- if (p.part === "lit") {
3909
- if (p.optional) return null;
3910
- for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
3911
- } else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
3912
- for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
3913
- } else {
3914
- return null;
3915
- }
3916
- }
3917
- return out.length ? out : null;
3918
- }
3919
- function altFixedMutuallyExclusive(shape) {
3920
- if (shape.kind !== "alt" || shape.disjoint) return false;
3921
- const lists = [];
3922
- for (const arm of shape.arms) {
3923
- const f = fixedClassSeq(arm);
3924
- if (!f) return false;
3925
- lists.push(f);
3983
+ function unfoldVariant(folded, name) {
3984
+ const byName = folded[FOLDED_RUNTIME]?.byName;
3985
+ const hit = byName?.get(name);
3986
+ if (hit !== void 0) return hit;
3987
+ const d = folded.variants[name];
3988
+ if (d === void 0) {
3989
+ throw new TypeError(
3990
+ `unfoldVariant: no variant ${JSON.stringify(name)}. This table carries: ${Object.keys(folded.variants).map((n) => JSON.stringify(n)).join(", ")}.`
3991
+ );
3926
3992
  }
3927
- for (let i = 0; i < lists.length; i++) {
3928
- for (let j = 0; j < lists.length; j++) {
3929
- if (i === j) continue;
3930
- const a = lists[i];
3931
- const b = lists[j];
3932
- if (a.length > b.length) continue;
3933
- let disjointAt = false;
3934
- for (let p = 0; p < a.length; p++) {
3935
- if (classDisjoint(a[p], b[p])) {
3936
- disjointAt = true;
3937
- break;
3938
- }
3939
- }
3940
- if (!disjointAt) return false;
3941
- }
3993
+ const base = folded.base;
3994
+ const code = [...base.code];
3995
+ let ip = 0;
3996
+ for (let i = 0; i < d.at.length; i++) {
3997
+ ip += d.at[i];
3998
+ code[ip] = d.to[i];
3942
3999
  }
3943
- return true;
3944
- }
3945
- function groupPartExposure(part) {
3946
- const innerWiggle = trailingBacktrackClass(part.inner);
3947
- if (innerWiggle === "unsupported") return "unsupported";
3948
- const requiredOnce = !part.unbounded && part.min === 1;
3949
- if (requiredOnce) return innerWiggle;
3950
- const dropExposed = shapeFirstAccept(part.inner);
3951
- if (dropExposed === "any") return "unsupported";
3952
- if (innerWiggle === null) return dropExposed;
3953
- const unioned = unionCharSets([innerWiggle, dropExposed]);
3954
- return unioned === "any" ? "unsupported" : unioned;
4000
+ const raw = {
4001
+ ...base,
4002
+ code,
4003
+ ...d.lines === void 0 ? {} : { lines: d.lines },
4004
+ ...d.hostMode === void 0 ? {} : { hostMode: d.hostMode }
4005
+ };
4006
+ const prog = ownTableProgram(raw);
4007
+ const owner = prog[TABLE_RUNTIME];
4008
+ owner.resolved = { ...resolveTable(base), prog, code: Int32Array.from(code) };
4009
+ byName?.set(name, prog);
4010
+ return prog;
3955
4011
  }
3956
- function trailingBacktrackClass(shape) {
3957
- if (shape.kind === "chars") return { ranges: shape.ranges, negated: false };
3958
- if (shape.kind === "ident") return { ranges: shape.tail, negated: false };
3959
- if (shape.kind === "litFold") return null;
3960
- if (shape.kind === "seq") {
3961
- const last = shape.parts[shape.parts.length - 1];
3962
- if (last.part === "lit") {
3963
- return last.optional ? "unsupported" : null;
3964
- }
3965
- if (last.part === "run") {
3966
- if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
3967
- return null;
3968
- }
3969
- return groupPartExposure(last);
3970
- }
3971
- if (shape.kind === "alt") {
3972
- if (!shape.disjoint) return altFixedMutuallyExclusive(shape) ? null : "unsupported";
3973
- const classes = shape.arms.map(trailingBacktrackClass);
3974
- if (classes.some((c) => c === "unsupported")) return "unsupported";
3975
- const concrete = classes.filter((c) => c !== null);
3976
- if (concrete.length === 0) return null;
3977
- const unioned = unionCharSets(concrete);
3978
- return unioned === "any" ? "unsupported" : unioned;
4012
+ function expandCompactFolded(f) {
4013
+ const variants = {};
4014
+ for (const name of Object.keys(f.v)) {
4015
+ const d = f.v[name];
4016
+ variants[name] = {
4017
+ at: d.a ?? [],
4018
+ to: d.t ?? [],
4019
+ ...d.l === void 0 ? {} : { lines: d.l },
4020
+ ...d.h === void 0 ? {} : { hostMode: d.h }
4021
+ };
3979
4022
  }
3980
- return "unsupported";
3981
- }
3982
- function lookaheadUnambiguous(inner, operand, negative) {
3983
- const tail = trailingBacktrackClass(inner);
3984
- if (tail === "unsupported") return false;
3985
- if (tail === null) return true;
3986
- return negative ? classSubset(tail, operand) : classDisjoint(tail, operand);
4023
+ return ownFoldedProgram(expandCompact(f.b), variants);
3987
4024
  }
3988
- function stripTrailingLookahead(source) {
3989
- if (!source.endsWith(")")) return null;
3990
- for (const negative of [true, false]) {
3991
- const lead2 = negative ? "(?!" : "(?=";
3992
- const idx = source.lastIndexOf(lead2);
3993
- if (idx === -1) continue;
3994
- const operand = parseClassOperand(source.slice(idx + lead2.length, -1));
3995
- if (!operand) continue;
3996
- return { base: source.slice(0, idx), ranges: operand.ranges, classNegated: operand.negated, negative };
3997
- }
3998
- return null;
4025
+
4026
+ // src/table/scan-shapes.ts
4027
+ var BACKSLASH = 92;
4028
+ var META2 = new Set("()[]{}*+?|^$.".split(""));
4029
+ function classToRanges(cls) {
4030
+ if (cls === "\\d") return shorthandRanges("d");
4031
+ if (cls === "\\w") return shorthandRanges("w");
4032
+ if (cls === "\\s") return shorthandRanges("s");
4033
+ const body = cls.slice(1, -1);
4034
+ if (body.startsWith("^")) return null;
4035
+ return parseClassRanges(body);
3999
4036
  }
4000
- function unwrapOuterGroup(source) {
4001
- while (source.startsWith("(?:")) {
4002
- let depth = 1;
4003
- let i = 3;
4004
- let ok = true;
4005
- while (i < source.length && depth > 0) {
4006
- const ch2 = source[i];
4007
- if (ch2 === "\\") {
4008
- i += 2;
4009
- continue;
4010
- }
4011
- if (ch2 === "[") {
4012
- let j = i + 1;
4013
- if (source[j] === "^") j++;
4014
- while (j < source.length && source[j] !== "]") {
4015
- if (source[j] === "\\") j += 2;
4016
- else j++;
4017
- }
4018
- if (source[j] !== "]") {
4019
- ok = false;
4020
- break;
4021
- }
4022
- i = j + 1;
4023
- continue;
4024
- }
4025
- if (ch2 === "(") depth++;
4026
- else if (ch2 === ")") depth--;
4027
- i++;
4037
+ var foldEq = (cVar, cp) => {
4038
+ if (cp >= 65 && cp <= 90) return `(${cVar} | 32) === ${cp + 32}`;
4039
+ if (cp >= 97 && cp <= 122) return `(${cVar} | 32) === ${cp}`;
4040
+ return `${cVar} === ${cp}`;
4041
+ };
4042
+ function parseStringShape(source) {
4043
+ const q2 = source[0];
4044
+ if (q2 === void 0 || q2 === "\\" || META2.has(q2)) return null;
4045
+ if (source.length < 3 || source[source.length - 1] !== q2) return null;
4046
+ const inner = source.slice(1, -1);
4047
+ const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
4048
+ const ESC = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
4049
+ let body;
4050
+ let esc;
4051
+ let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC}\\)\\*$`).exec(inner);
4052
+ if (m) {
4053
+ body = m[1];
4054
+ esc = m[2];
4055
+ } else {
4056
+ m = new RegExp(`^\\((?:\\?:)?${ESC}\\|${CLS}\\)\\*$`).exec(inner);
4057
+ if (m) {
4058
+ esc = m[1];
4059
+ body = m[2];
4028
4060
  }
4029
- if (!ok || depth !== 0 || i !== source.length) break;
4030
- source = source.slice(3, -1);
4031
4061
  }
4032
- return source;
4062
+ if (body === void 0 || esc === void 0) return null;
4063
+ const excluded = parseClassRanges(body);
4064
+ if (!excluded) return null;
4065
+ const qcp = q2.codePointAt(0);
4066
+ const inSet = (cp) => excluded.some(([lo, hi]) => cp >= lo && cp <= hi);
4067
+ if (!inSet(qcp) || !inSet(BACKSLASH)) return null;
4068
+ return { kind: "string", quote: qcp, excluded, escLineTerm: esc !== "." };
4033
4069
  }
4034
- function splitTopLevelAlternation(source) {
4035
- const body = unwrapOuterGroup(source);
4070
+ function parseSeqParts(source) {
4036
4071
  const parts = [];
4037
- let depth = 0;
4038
- let last = 0;
4039
- let i = 0;
4040
- while (i < body.length) {
4041
- const ch2 = body[i];
4042
- if (ch2 === "\\") {
4043
- i += 2;
4044
- continue;
4072
+ let lit = [];
4073
+ const flush = () => {
4074
+ if (lit.length) {
4075
+ parts.push({ part: "lit", cps: lit, optional: false });
4076
+ lit = [];
4045
4077
  }
4046
- if (ch2 === "[") {
4047
- let j = i + 1;
4048
- if (body[j] === "^") j++;
4049
- while (j < body.length && body[j] !== "]") {
4050
- if (body[j] === "\\") j += 2;
4051
- else j++;
4052
- }
4053
- if (body[j] !== "]") return null;
4054
- i = j + 1;
4055
- continue;
4078
+ };
4079
+ const braceQuant = (at) => {
4080
+ const close = source.indexOf("}", at);
4081
+ if (close === -1) return null;
4082
+ const body = source.slice(at + 1, close);
4083
+ const m = /^(\d+)(,(\d*)?)?$/.exec(body);
4084
+ if (!m) return null;
4085
+ const min = Number(m[1]);
4086
+ const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
4087
+ if (max < 1 || min > max) return null;
4088
+ return { min, max, len: close - at + 1 };
4089
+ };
4090
+ const runFrom = (ranges, negated, at) => {
4091
+ const q2 = source[at];
4092
+ if (q2 === "+") {
4093
+ parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
4094
+ return 1;
4056
4095
  }
4057
- if (ch2 === "(") {
4058
- depth++;
4059
- i++;
4060
- continue;
4096
+ if (q2 === "*") {
4097
+ parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
4098
+ return 1;
4061
4099
  }
4062
- if (ch2 === ")") {
4063
- depth--;
4064
- if (depth < 0) return null;
4065
- i++;
4100
+ if (q2 === "?") {
4101
+ parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
4102
+ return 1;
4103
+ }
4104
+ if (q2 === "{") {
4105
+ const b = braceQuant(at);
4106
+ if (b) {
4107
+ parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
4108
+ return b.len;
4109
+ }
4110
+ }
4111
+ parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
4112
+ return 0;
4113
+ };
4114
+ let i = 0;
4115
+ while (i < source.length) {
4116
+ const ch2 = source[i];
4117
+ if (ch2 === "[") {
4118
+ let k = i + 1;
4119
+ const neg = source[k] === "^";
4120
+ if (neg) k++;
4121
+ let body = "";
4122
+ while (k < source.length && source[k] !== "]") {
4123
+ if (source[k] === "\\") {
4124
+ body += source[k] + (source[k + 1] ?? "");
4125
+ k += 2;
4126
+ } else {
4127
+ body += source[k];
4128
+ k++;
4129
+ }
4130
+ }
4131
+ if (source[k] !== "]") return null;
4132
+ const ranges = parseClassRanges(body);
4133
+ if (!ranges) return null;
4134
+ flush();
4135
+ i = k + 1;
4136
+ i += runFrom(ranges, neg, i);
4066
4137
  continue;
4067
4138
  }
4068
- if (ch2 === "|" && depth === 0) {
4069
- parts.push(body.slice(last, i));
4070
- last = i + 1;
4071
- i++;
4139
+ if (ch2 === "\\") {
4140
+ const e = source[i + 1];
4141
+ if (e === "d" || e === "w" || e === "s") {
4142
+ flush();
4143
+ i += 2;
4144
+ i += runFrom(shorthandRanges(e), false, i);
4145
+ continue;
4146
+ }
4147
+ const uni = readUnicodeEscape(source, i);
4148
+ let cp2;
4149
+ if (uni) {
4150
+ cp2 = uni.cp;
4151
+ i = uni.next;
4152
+ } else if (e === void 0) return null;
4153
+ else if (e in CLASS_ESCAPES) {
4154
+ cp2 = CLASS_ESCAPES[e];
4155
+ i += 2;
4156
+ } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
4157
+ else {
4158
+ cp2 = e.codePointAt(0);
4159
+ i += 2;
4160
+ }
4161
+ if (source[i] === "?") {
4162
+ flush();
4163
+ parts.push({ part: "lit", cps: [cp2], optional: true });
4164
+ i++;
4165
+ } else lit.push(cp2);
4072
4166
  continue;
4073
4167
  }
4074
- i++;
4168
+ if (ch2 === "(") {
4169
+ if (source[i + 1] !== "?" || source[i + 2] !== ":") return null;
4170
+ let k = i + 3;
4171
+ let depth = 1;
4172
+ while (k < source.length && depth > 0) {
4173
+ const c2 = source[k];
4174
+ if (c2 === "\\") {
4175
+ k += 2;
4176
+ continue;
4177
+ }
4178
+ if (c2 === "[") {
4179
+ let j = k + 1;
4180
+ if (source[j] === "^") j++;
4181
+ while (j < source.length && source[j] !== "]") {
4182
+ if (source[j] === "\\") j += 2;
4183
+ else j++;
4184
+ }
4185
+ if (source[j] !== "]") return null;
4186
+ k = j + 1;
4187
+ continue;
4188
+ }
4189
+ if (c2 === "(") depth++;
4190
+ else if (c2 === ")") depth--;
4191
+ k++;
4192
+ }
4193
+ if (depth !== 0) return null;
4194
+ const body = source.slice(i + 3, k - 1);
4195
+ const inner = parseScanShape(body);
4196
+ if (!inner || !groupInnerSafe(inner)) return null;
4197
+ const q2 = source[k];
4198
+ if (q2 === "{") return null;
4199
+ flush();
4200
+ if (q2 === "+") {
4201
+ if (shapeCanBeEmpty(inner)) return null;
4202
+ parts.push({ part: "group", inner, min: 1, unbounded: true });
4203
+ i = k + 1;
4204
+ } else if (q2 === "*") {
4205
+ if (shapeCanBeEmpty(inner)) return null;
4206
+ parts.push({ part: "group", inner, min: 0, unbounded: true });
4207
+ i = k + 1;
4208
+ } else if (q2 === "?") {
4209
+ parts.push({ part: "group", inner, min: 0, unbounded: false });
4210
+ i = k + 1;
4211
+ } else {
4212
+ parts.push({ part: "group", inner, min: 1, unbounded: false });
4213
+ i = k;
4214
+ }
4215
+ continue;
4216
+ }
4217
+ if (META2.has(ch2)) return null;
4218
+ const cp = ch2.codePointAt(0);
4219
+ i += ch2.length;
4220
+ if (source[i] === "?") {
4221
+ flush();
4222
+ parts.push({ part: "lit", cps: [cp], optional: true });
4223
+ i++;
4224
+ } else lit.push(cp);
4075
4225
  }
4076
- if (depth !== 0) return null;
4077
- parts.push(body.slice(last));
4078
- if (parts.length < 2 || parts.some((p) => p.length === 0)) return null;
4079
- return parts;
4226
+ flush();
4227
+ return parts.length ? parts : null;
4080
4228
  }
4081
- function shapeCanBeEmpty(shape) {
4082
- if (shape.kind === "chars") return !shape.minOne;
4083
- if (shape.kind === "lookahead") return shapeCanBeEmpty(shape.inner);
4084
- if (shape.kind === "alt") return shape.arms.some(shapeCanBeEmpty);
4085
- return false;
4229
+ function seqIsUnambiguous(parts) {
4230
+ let hasMandatory = false;
4231
+ for (let k = 0; k < parts.length; k++) {
4232
+ const p = parts[k];
4233
+ const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
4234
+ if (mandatory) hasMandatory = true;
4235
+ if (p.part === "group") {
4236
+ const exposure = groupPartExposure(p);
4237
+ if (exposure === "unsupported") {
4238
+ const trailingOnce = k === parts.length - 1 && p.min === 1 && !p.unbounded;
4239
+ if (!trailingOnce) return false;
4240
+ } else if (exposure !== null) {
4241
+ if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
4242
+ }
4243
+ }
4244
+ const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
4245
+ if (needsDisjoint) {
4246
+ const rest = seqFirstAccept(parts.slice(k + 1));
4247
+ if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
4248
+ }
4249
+ }
4250
+ return hasMandatory;
4086
4251
  }
4087
- function unionCharSets(sets) {
4088
- if (sets.some((s) => s === "any")) return "any";
4089
- const concrete = sets;
4090
- if (concrete.length === 1) return concrete[0];
4091
- if (concrete.some((s) => s.negated)) return "any";
4092
- return { ranges: concrete.flatMap((s) => s.ranges), negated: false };
4252
+ function rangesOverlap(a, b) {
4253
+ return a.some(([lo, hi]) => b.some(([lo2, hi2]) => lo <= hi2 && lo2 <= hi));
4093
4254
  }
4094
- function partFirstAccept(part) {
4095
- if (part.part === "lit") return { ranges: [[part.cps[0], part.cps[0]]], negated: false };
4096
- if (part.part === "run") return { ranges: part.ranges, negated: part.negated };
4097
- return shapeFirstAccept(part.inner);
4255
+ function rangesSubset(sub, sup) {
4256
+ return sub.every(([lo, hi]) => sup.some(([lo2, hi2]) => lo >= lo2 && hi <= hi2));
4098
4257
  }
4099
- function seqFirstAccept(parts) {
4100
- const sets = [];
4101
- for (const p of parts) {
4102
- const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
4103
- sets.push(partFirstAccept(p));
4104
- if (mandatory) break;
4105
- }
4106
- return unionCharSets(sets);
4258
+ function classSubset(t, u) {
4259
+ if (!t.negated && !u.negated) return rangesSubset(t.ranges, u.ranges);
4260
+ if (!t.negated && u.negated) return !rangesOverlap(t.ranges, u.ranges);
4261
+ if (t.negated && !u.negated) return false;
4262
+ return rangesSubset(u.ranges, t.ranges);
4107
4263
  }
4108
- function groupInnerSafe(shape) {
4109
- if (shape.kind === "chars" || shape.kind === "ident" || shape.kind === "seq" || shape.kind === "litFold") return true;
4110
- if (shape.kind === "lookahead") return groupInnerSafe(shape.inner);
4111
- if (shape.kind === "alt") return true;
4264
+ function classDisjoint(t, u) {
4265
+ if (!t.negated && !u.negated) return !rangesOverlap(t.ranges, u.ranges);
4266
+ if (!t.negated && u.negated) return rangesSubset(t.ranges, u.ranges);
4267
+ if (t.negated && !u.negated) return rangesSubset(u.ranges, t.ranges);
4112
4268
  return false;
4113
4269
  }
4114
- function shapeFirstAccept(shape) {
4115
- if (shapeCanBeEmpty(shape)) return "any";
4116
- switch (shape.kind) {
4117
- case "chars":
4118
- return { ranges: shape.ranges, negated: false };
4119
- case "ident":
4120
- return { ranges: shape.head, negated: false };
4121
- case "until":
4122
- return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4123
- case "delimited":
4124
- return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4125
- case "string":
4126
- return { ranges: [[shape.quote, shape.quote]], negated: false };
4127
- case "litFold": {
4128
- const cp = shape.open[0];
4129
- if (cp >= 65 && cp <= 90) return { ranges: [[cp, cp], [cp + 32, cp + 32]], negated: false };
4130
- if (cp >= 97 && cp <= 122) return { ranges: [[cp, cp], [cp - 32, cp - 32]], negated: false };
4131
- return { ranges: [[cp, cp]], negated: false };
4132
- }
4133
- case "seq":
4134
- return seqFirstAccept(shape.parts);
4135
- case "lookahead":
4136
- return shapeFirstAccept(shape.inner);
4137
- // zero-width — doesn't change first-char acceptance
4138
- case "alt": {
4139
- const sets = shape.firsts.map((f) => f === null ? "any" : f);
4140
- return unionCharSets(sets);
4141
- }
4142
- }
4270
+ function firstSetsDisjoint(a, b) {
4271
+ if (a === "any" || b === "any") return false;
4272
+ return classDisjoint(a, b);
4143
4273
  }
4144
- function allPairsDisjoint(sets) {
4145
- for (let i = 0; i < sets.length; i++) {
4146
- const a = sets[i];
4147
- if (a === "any") return false;
4148
- for (let j = i + 1; j < sets.length; j++) {
4149
- const b = sets[j];
4150
- if (b === "any" || !classDisjoint(a, b)) return false;
4274
+ function fixedClassSeq(shape) {
4275
+ if (shape.kind === "litFold") {
4276
+ return shape.open.map((cp) => {
4277
+ const other = cp >= 65 && cp <= 90 ? cp + 32 : cp >= 97 && cp <= 122 ? cp - 32 : cp;
4278
+ 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 };
4279
+ });
4280
+ }
4281
+ if (shape.kind !== "seq") return null;
4282
+ const out = [];
4283
+ for (const p of shape.parts) {
4284
+ if (p.part === "lit") {
4285
+ if (p.optional) return null;
4286
+ for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
4287
+ } else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
4288
+ for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
4289
+ } else {
4290
+ return null;
4151
4291
  }
4152
4292
  }
4153
- return true;
4293
+ return out.length ? out : null;
4154
4294
  }
4155
- function parseAlternation(source) {
4295
+ function altFixedMutuallyExclusive(shape) {
4296
+ if (shape.kind !== "alt" || shape.disjoint) return false;
4297
+ const lists = [];
4298
+ for (const arm of shape.arms) {
4299
+ const f = fixedClassSeq(arm);
4300
+ if (!f) return false;
4301
+ lists.push(f);
4302
+ }
4303
+ for (let i = 0; i < lists.length; i++) {
4304
+ for (let j = 0; j < lists.length; j++) {
4305
+ if (i === j) continue;
4306
+ const a = lists[i];
4307
+ const b = lists[j];
4308
+ if (a.length > b.length) continue;
4309
+ let disjointAt = false;
4310
+ for (let p = 0; p < a.length; p++) {
4311
+ if (classDisjoint(a[p], b[p])) {
4312
+ disjointAt = true;
4313
+ break;
4314
+ }
4315
+ }
4316
+ if (!disjointAt) return false;
4317
+ }
4318
+ }
4319
+ return true;
4320
+ }
4321
+ function groupPartExposure(part) {
4322
+ const innerWiggle = trailingBacktrackClass(part.inner);
4323
+ if (innerWiggle === "unsupported") return "unsupported";
4324
+ const requiredOnce = !part.unbounded && part.min === 1;
4325
+ if (requiredOnce) return innerWiggle;
4326
+ const dropExposed = shapeFirstAccept(part.inner);
4327
+ if (dropExposed === "any") return "unsupported";
4328
+ if (innerWiggle === null) return dropExposed;
4329
+ const unioned = unionCharSets([innerWiggle, dropExposed]);
4330
+ return unioned === "any" ? "unsupported" : unioned;
4331
+ }
4332
+ function trailingBacktrackClass(shape) {
4333
+ if (shape.kind === "chars") return { ranges: shape.ranges, negated: false };
4334
+ if (shape.kind === "ident") return { ranges: shape.tail, negated: false };
4335
+ if (shape.kind === "litFold") return null;
4336
+ if (shape.kind === "seq") {
4337
+ const last = shape.parts[shape.parts.length - 1];
4338
+ if (last.part === "lit") {
4339
+ return last.optional ? "unsupported" : null;
4340
+ }
4341
+ if (last.part === "run") {
4342
+ if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
4343
+ return null;
4344
+ }
4345
+ return groupPartExposure(last);
4346
+ }
4347
+ if (shape.kind === "alt") {
4348
+ if (!shape.disjoint) return altFixedMutuallyExclusive(shape) ? null : "unsupported";
4349
+ const classes = shape.arms.map(trailingBacktrackClass);
4350
+ if (classes.some((c) => c === "unsupported")) return "unsupported";
4351
+ const concrete = classes.filter((c) => c !== null);
4352
+ if (concrete.length === 0) return null;
4353
+ const unioned = unionCharSets(concrete);
4354
+ return unioned === "any" ? "unsupported" : unioned;
4355
+ }
4356
+ return "unsupported";
4357
+ }
4358
+ function lookaheadUnambiguous(inner, operand, negative) {
4359
+ const tail = trailingBacktrackClass(inner);
4360
+ if (tail === "unsupported") return false;
4361
+ if (tail === null) return true;
4362
+ return negative ? classSubset(tail, operand) : classDisjoint(tail, operand);
4363
+ }
4364
+ function stripTrailingLookahead(source) {
4365
+ if (!source.endsWith(")")) return null;
4366
+ for (const negative of [true, false]) {
4367
+ const lead2 = negative ? "(?!" : "(?=";
4368
+ const idx = source.lastIndexOf(lead2);
4369
+ if (idx === -1) continue;
4370
+ const operand = parseClassOperand(source.slice(idx + lead2.length, -1));
4371
+ if (!operand) continue;
4372
+ return { base: source.slice(0, idx), ranges: operand.ranges, classNegated: operand.negated, negative };
4373
+ }
4374
+ return null;
4375
+ }
4376
+ function unwrapOuterGroup(source) {
4377
+ while (source.startsWith("(?:")) {
4378
+ let depth = 1;
4379
+ let i = 3;
4380
+ let ok = true;
4381
+ while (i < source.length && depth > 0) {
4382
+ const ch2 = source[i];
4383
+ if (ch2 === "\\") {
4384
+ i += 2;
4385
+ continue;
4386
+ }
4387
+ if (ch2 === "[") {
4388
+ let j = i + 1;
4389
+ if (source[j] === "^") j++;
4390
+ while (j < source.length && source[j] !== "]") {
4391
+ if (source[j] === "\\") j += 2;
4392
+ else j++;
4393
+ }
4394
+ if (source[j] !== "]") {
4395
+ ok = false;
4396
+ break;
4397
+ }
4398
+ i = j + 1;
4399
+ continue;
4400
+ }
4401
+ if (ch2 === "(") depth++;
4402
+ else if (ch2 === ")") depth--;
4403
+ i++;
4404
+ }
4405
+ if (!ok || depth !== 0 || i !== source.length) break;
4406
+ source = source.slice(3, -1);
4407
+ }
4408
+ return source;
4409
+ }
4410
+ function splitTopLevelAlternation(source) {
4411
+ const body = unwrapOuterGroup(source);
4412
+ const parts = [];
4413
+ let depth = 0;
4414
+ let last = 0;
4415
+ let i = 0;
4416
+ while (i < body.length) {
4417
+ const ch2 = body[i];
4418
+ if (ch2 === "\\") {
4419
+ i += 2;
4420
+ continue;
4421
+ }
4422
+ if (ch2 === "[") {
4423
+ let j = i + 1;
4424
+ if (body[j] === "^") j++;
4425
+ while (j < body.length && body[j] !== "]") {
4426
+ if (body[j] === "\\") j += 2;
4427
+ else j++;
4428
+ }
4429
+ if (body[j] !== "]") return null;
4430
+ i = j + 1;
4431
+ continue;
4432
+ }
4433
+ if (ch2 === "(") {
4434
+ depth++;
4435
+ i++;
4436
+ continue;
4437
+ }
4438
+ if (ch2 === ")") {
4439
+ depth--;
4440
+ if (depth < 0) return null;
4441
+ i++;
4442
+ continue;
4443
+ }
4444
+ if (ch2 === "|" && depth === 0) {
4445
+ parts.push(body.slice(last, i));
4446
+ last = i + 1;
4447
+ i++;
4448
+ continue;
4449
+ }
4450
+ i++;
4451
+ }
4452
+ if (depth !== 0) return null;
4453
+ parts.push(body.slice(last));
4454
+ if (parts.length < 2 || parts.some((p) => p.length === 0)) return null;
4455
+ return parts;
4456
+ }
4457
+ function shapeCanBeEmpty(shape) {
4458
+ if (shape.kind === "chars") return !shape.minOne;
4459
+ if (shape.kind === "lookahead") return shapeCanBeEmpty(shape.inner);
4460
+ if (shape.kind === "alt") return shape.arms.some(shapeCanBeEmpty);
4461
+ return false;
4462
+ }
4463
+ function unionCharSets(sets) {
4464
+ if (sets.some((s) => s === "any")) return "any";
4465
+ const concrete = sets;
4466
+ if (concrete.length === 1) return concrete[0];
4467
+ if (concrete.some((s) => s.negated)) return "any";
4468
+ return { ranges: concrete.flatMap((s) => s.ranges), negated: false };
4469
+ }
4470
+ function partFirstAccept(part) {
4471
+ if (part.part === "lit") return { ranges: [[part.cps[0], part.cps[0]]], negated: false };
4472
+ if (part.part === "run") return { ranges: part.ranges, negated: part.negated };
4473
+ return shapeFirstAccept(part.inner);
4474
+ }
4475
+ function seqFirstAccept(parts) {
4476
+ const sets = [];
4477
+ for (const p of parts) {
4478
+ const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
4479
+ sets.push(partFirstAccept(p));
4480
+ if (mandatory) break;
4481
+ }
4482
+ return unionCharSets(sets);
4483
+ }
4484
+ function groupInnerSafe(shape) {
4485
+ if (shape.kind === "chars" || shape.kind === "ident" || shape.kind === "seq" || shape.kind === "litFold") return true;
4486
+ if (shape.kind === "lookahead") return groupInnerSafe(shape.inner);
4487
+ if (shape.kind === "alt") return true;
4488
+ return false;
4489
+ }
4490
+ function shapeFirstAccept(shape) {
4491
+ if (shapeCanBeEmpty(shape)) return "any";
4492
+ switch (shape.kind) {
4493
+ case "chars":
4494
+ return { ranges: shape.ranges, negated: false };
4495
+ case "ident":
4496
+ return { ranges: shape.head, negated: false };
4497
+ case "until":
4498
+ return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4499
+ case "delimited":
4500
+ return { ranges: [[shape.open[0], shape.open[0]]], negated: false };
4501
+ case "string":
4502
+ return { ranges: [[shape.quote, shape.quote]], negated: false };
4503
+ case "litFold": {
4504
+ const cp = shape.open[0];
4505
+ if (cp >= 65 && cp <= 90) return { ranges: [[cp, cp], [cp + 32, cp + 32]], negated: false };
4506
+ if (cp >= 97 && cp <= 122) return { ranges: [[cp, cp], [cp - 32, cp - 32]], negated: false };
4507
+ return { ranges: [[cp, cp]], negated: false };
4508
+ }
4509
+ case "seq":
4510
+ return seqFirstAccept(shape.parts);
4511
+ case "lookahead":
4512
+ return shapeFirstAccept(shape.inner);
4513
+ // zero-width — doesn't change first-char acceptance
4514
+ case "alt": {
4515
+ const sets = shape.firsts.map((f) => f === null ? "any" : f);
4516
+ return unionCharSets(sets);
4517
+ }
4518
+ }
4519
+ }
4520
+ function allPairsDisjoint(sets) {
4521
+ for (let i = 0; i < sets.length; i++) {
4522
+ const a = sets[i];
4523
+ if (a === "any") return false;
4524
+ for (let j = i + 1; j < sets.length; j++) {
4525
+ const b = sets[j];
4526
+ if (b === "any" || !classDisjoint(a, b)) return false;
4527
+ }
4528
+ }
4529
+ return true;
4530
+ }
4531
+ function parseAlternation(source) {
4156
4532
  const parts = splitTopLevelAlternation(source);
4157
4533
  if (!parts) return null;
4158
4534
  const arms = [];
@@ -4705,6 +5081,7 @@ function childSlots(code, ip, out) {
4705
5081
  case OP_GATE:
4706
5082
  case OP_SCOPE:
4707
5083
  case OP_SCOPE_CAP:
5084
+ case OP_SCOPE_PLAIN:
4708
5085
  case OP_WITHCTX:
4709
5086
  case OP_XFORM:
4710
5087
  case OP_NODE:
@@ -4793,7 +5170,7 @@ function reachableSites(code, roots) {
4793
5170
  }
4794
5171
  function transfer(code, ip, at, hostCst) {
4795
5172
  const op = code[ip];
4796
- if (op === OP_SCOPE || op === OP_SCOPE_CAP) {
5173
+ if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
4797
5174
  const ki = code[ip + 1];
4798
5175
  const tri = ki < 0 ? TRI_NONE : ki;
4799
5176
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
@@ -4874,6 +5251,7 @@ var EMITTED_PARAMS = [
4874
5251
  "pushCstLeaf",
4875
5252
  "pushCstChild",
4876
5253
  "rollbackTriviaAt",
5254
+ "rollbackScannedTriviaAt",
4877
5255
  "failAt",
4878
5256
  "classHas",
4879
5257
  "consumeTrivia",
@@ -5017,19 +5395,24 @@ if(ctx._errors!==undefined&&ctx._errors.length!==${t}er)ctx._errors.length=${t}e
5017
5395
  if (!s.fd && !s.er) return `if(${t}n)rollbackTriviaAt(ctx,${t}raw,${t}tl,${t}lv,0,undefined,${t}lg,${t}rt)`;
5018
5396
  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)}`;
5019
5397
  }
5020
- function emitTerm(callee, dst, t, l, skip, s) {
5398
+ function emitTerm(callee, dst, t, l, skip) {
5021
5399
  const fast = `const ${t}v=${callee}(input,cur,ctx)
5022
5400
  if(${t}v===FAIL)return FAIL
5023
5401
  ${dst}=${t}v
5024
5402
  cur=EC.e`;
5025
5403
  if (l.tri === TRI_NONE) return fast;
5026
- const scanned = `${emitMark(t, l.buf, s)}
5404
+ const scanned = `const ${t}tl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
5405
+ const ${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5406
+ const ${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
5027
5407
  const ${t}s=${skip}(input,cur,ctx)
5408
+ const ${t}stl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
5409
+ const ${t}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5410
+ const ${t}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
5028
5411
  const ${t}v=${callee}(input,${t}s,ctx)
5029
5412
  if(${t}v===FAIL)return FAIL
5030
5413
  ${dst}=${t}v
5031
5414
  if(EC.e>${t}s)cur=EC.e
5032
- else{${emitRollback(t, l.buf, s)}}`;
5415
+ else{rollbackScannedTriviaAt(ctx,${t}tl,${t}stl,${t}lg,${t}slg,${t}rt,${t}srt)}`;
5033
5416
  if (l.tri !== TRI_UNKNOWN) return scanned;
5034
5417
  return `if(ctx.trivia===undefined){
5035
5418
  ${fast}
@@ -5192,7 +5575,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
5192
5575
  const op = code[ip];
5193
5576
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
5194
5577
  if (op === OP_RULE) return code[ip + 1];
5195
- if (op === OP_SCOPE && code[ip + 3] === 0 && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
5578
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
5196
5579
  return code[ip + 2];
5197
5580
  }
5198
5581
  return void 0;
@@ -5243,1048 +5626,731 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
5243
5626
  tests.push(`input.charCodeAt(${at})===${f}`);
5244
5627
  }
5245
5628
  }
5246
- return `${head}
5247
- ${reads.length > 0 ? `${reads.join("\n")}
5248
- ` : ""}if(${tests.join("&&")}){
5249
- const e=pos+${s.length}
5250
- const v=input.slice(pos,e)
5251
- ${captureLeaf("v")}
5252
- ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5253
- return v
5254
- }
5255
- ctx._fe=pos;ctx._fx=${xf}
5256
- ${cfg.probe ? `failAt(ctx,${xf},pos)
5257
- ` : ""}return FAIL
5258
- }`;
5259
- }
5260
- case OP_RX:
5261
- case OP_RX_TRACK: {
5262
- const xf = fxRef(code[ip + 2]);
5263
- const track = op === OP_RX_TRACK;
5264
- const scanned = emitScan(code[ip + 1], xf, track, captureLeaf);
5265
- if (scanned !== void 0) return `${head}${scanned}}`;
5266
- const rxk = k[code[ip + 1]];
5267
- if (!(rxk instanceof RegExp) || !rxk.sticky) throw new Unemittable("a non-sticky regex row");
5268
- const re = kRef(code[ip + 1]);
5269
- return `${head}
5270
- ${re}.lastIndex=pos
5271
- if(${re}.test(input)){
5272
- const e=${re}.lastIndex
5273
- const v=input.slice(pos,e)
5274
- ${captureLeaf("v")}
5275
- ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5276
- return v
5277
- }
5278
- ctx._fe=pos;ctx._fx=${xf}
5279
- ${cfg.probe ? `failAt(ctx,${xf},pos)
5280
- ` : ""}return FAIL
5281
- }`;
5282
- }
5283
- case OP_EMPTY:
5284
- return `${head}EC.e=pos;return ''}`;
5285
- case OP_GATE: {
5286
- const child = link(code[ip + 2]);
5287
- const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
5288
- classPlan.push([code[ip + 1]]);
5289
- const cls = hoist("cl", `CLS[${ci}][0]`);
5290
- const xf = fxRef(code[ip + 3]);
5291
- return `${head}
5292
- if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5293
- return ${child}(input,pos,ctx)
5294
- }`;
5295
- }
5296
- case OP_XFORM: {
5297
- const fn = fnRef(code[ip + 1]);
5298
- const child = link(code[ip + 2]);
5299
- return `${head}
5300
- const v=${child}(input,pos,ctx)
5301
- if(v===FAIL)return FAIL
5302
- return ${fn}(v,{start:pos,end:EC.e})
5303
- }`;
5304
- }
5305
- case OP_LABEL: {
5306
- const child = link(code[ip + 1]);
5307
- const xf = fxRef(code[ip + 2]);
5308
- return `${head}
5309
- const v=${child}(input,pos,ctx)
5310
- if(v===FAIL)ctx._fx=${xf}
5311
- return v
5312
- }`;
5313
- }
5314
- case OP_FIELD: {
5315
- const name = q(k[code[ip + 1]]);
5316
- const child = link(code[ip + 2]);
5317
- return `${head}
5318
- const v=${child}(input,pos,ctx)
5319
- if(v===FAIL)return FAIL
5320
- const f=ctx._fields
5321
- if(f!==undefined)f.push({name:${name},value:v,span:{start:pos,end:EC.e}})
5322
- return v
5323
- }`;
5324
- }
5325
- case OP_EXPECT: {
5326
- const child = link(code[ip + 1]);
5327
- const xf = fxRef(code[ip + 2]);
5328
- return `${head}
5329
- const v=${child}(input,pos,ctx)
5330
- if(v!==FAIL)return v
5331
- const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "{start:pos,end:pos}"},expected:${xf}}
5332
- const es=ctx._errors
5333
- if(es!==undefined)es.push(err)
5334
- ${REC ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
5335
- EC.e=pos
5336
- return err
5337
- }`;
5338
- }
5339
- case OP_ROUTED: {
5340
- const fb = code[ip + 1];
5341
- const fallback = fb >= 0 ? link(fb) : void 0;
5342
- const push = `pushCstLeaf(ctx,{_tag:'leaf',value:it.value,span:it.span})`;
5343
- return `${head}
5344
- const it=ctx._routed
5345
- if(it===undefined||pos!==it.span.start){
5346
- ${fallback !== void 0 ? `return ${fallback}(input,pos,ctx)` : "ctx._fe=pos;ctx._fx=ROUTED_FX;return FAIL"}
5347
- }
5348
- ${L.buf ? push : `if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)${push}`}
5349
- EC.e=it.span.end
5350
- return it.value
5351
- }`;
5352
- }
5353
- case OP_SCAN: {
5354
- const si = code[ip + 1];
5355
- return `${head}
5356
- const r=SCANS[${si}].parse(input,pos,ctx)
5357
- if(!r.ok){ctx._fe=r.span.start;ctx._fx=r.expected??EMPTY_FX;return FAIL}
5358
- EC.e=r.span.end
5359
- return r.value
5360
- }`;
5361
- }
5362
- case OP_SCOPE:
5363
- case OP_SCOPE_CAP: {
5364
- const ki = code[ip + 1];
5365
- const cap = op === OP_SCOPE_CAP;
5366
- const flags = code[ip + 3];
5367
- const child = link(code[ip + 2]);
5368
- const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
5369
- const tri = ki < 0 ? "undefined" : hoist("tv", `TRIVIA[${ki}]`);
5370
- const lab = ki < 0 ? "undefined" : hoist("tl", `TRIVIA[${ki}]._meta.triviaKindLabels`);
5371
- const strict = (flags & 2) !== 0 ? "refuseUnclassifiedRootScope(ctx._rootTriviaStrictScopes)\n" : "";
5372
- const rootCap = (flags & 1) !== 0;
5373
- return `${head}
5374
- ${strict}${rootCap ? "const sR=ctx._rootTriviaCapture\nctx._rootTriviaCapture=false\n" : ""}const sT=ctx.trivia,sL=ctx.triviaKindLabels,sS=_pfScan${cap ? ",sC=ctx.captureTrivia" : ""}
5375
- _pfScan=${scanFor}
5376
- ctx.trivia=${tri}
5377
- ctx.triviaKindLabels=${lab}
5378
- ${cap ? "ctx.captureTrivia=true\n" : ""}const v=${child}(input,pos,ctx)
5379
- ${cap ? "ctx.captureTrivia=sC\n" : ""}ctx.trivia=sT
5380
- ctx.triviaKindLabels=sL
5381
- _pfScan=sS
5382
- ${rootCap ? "ctx._rootTriviaCapture=sR\n" : ""}return v
5383
- }`;
5384
- }
5385
- /* ── boundaries ──────────────────────────────────────────────────────── */
5386
- case OP_TOKEN:
5387
- case OP_LEAF: {
5388
- const isToken = op === OP_TOKEN;
5389
- const fn = isToken ? void 0 : fnRef(code[ip + 1]);
5390
- const child = link(isToken ? code[ip + 1] : code[ip + 2]);
5391
- const wasCap = L.buf ? "true" : "(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)";
5392
- return `${head}
5393
- const sBuf=ctx._cstBuf,sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
5394
- const sOtl=ctx._triviaLog
5395
- ${isToken ? "const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan,sRtl=ctx._rootTriviaLog\n" : ""}const wasCap=${wasCap}
5396
- ${isToken ? `_pfScan=null
5397
- ctx.trivia=undefined
5398
- ctx.triviaKindLabels=undefined
5399
- ` : ""}ctx._cstBuf=undefined
5400
- ctx._cstChildren=undefined
5401
- ctx._cstLeaves=undefined
5402
- ctx._cstRawChildren=undefined
5403
- ctx._cstTriviaLog=undefined
5404
- ctx._triviaLog=undefined
5405
- ${isToken ? "ctx._rootTriviaLog=undefined\n" : ""}let v
5406
- try{v=${child}(input,pos,ctx)}finally{
5407
- ${isToken ? `_pfScan=sScan
5408
- ctx.trivia=sTri
5409
- ctx.triviaKindLabels=sKinds
5410
- ctx._rootTriviaLog=sRtl
5411
- ` : ""}ctx._cstBuf=sBuf
5412
- ctx._cstChildren=sCh
5413
- ctx._cstLeaves=sLv
5414
- ctx._cstRawChildren=sRaw
5415
- ctx._cstTriviaLog=sTl
5416
- ctx._triviaLog=sOtl
5417
- }
5418
- if(v===FAIL)return FAIL
5419
- const e=EC.e
5420
- const out=${isToken ? "input.slice(pos,e)" : `${fn}(v,{start:pos,end:e})`}
5421
- if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:out,span:{start:pos,end:e}})
5422
- EC.e=e
5423
- return out
5424
- }`;
5425
- }
5426
- /* ── transaction ─────────────────────────────────────────────────────── */
5427
- case OP_ATTEMPT: {
5428
- const child = link(code[ip + 1]);
5429
- const p = tmp();
5430
- return `${head}
5431
- ${emitMark(p, L.buf, sinks)}
5432
- const v=${child}(input,pos,ctx)
5433
- if(v!==FAIL)return v
5434
- ${emitRollback(p, L.buf, sinks)}
5435
- if(ctx._fc===true)return FAIL
5436
- ctx._fe=pos
5437
- return FAIL
5438
- }`;
5439
- }
5440
- case OP_NOT: {
5441
- const child = link(code[ip + 1]);
5442
- const xf = fxRef(code[ip + 2]);
5443
- const p = tmp();
5444
- return `${head}
5445
- ${emitMark(p, L.buf, sinks)}
5446
- const v=${child}(input,pos,ctx)
5447
- ${emitRollback(p, L.buf, sinks)}
5448
- if(v===FAIL){EC.e=pos;return null}
5449
- ctx._fe=pos
5450
- ctx._fx=${xf}
5451
- return FAIL
5452
- }`;
5453
- }
5454
- case OP_PEEK: {
5455
- const child = link(code[ip + 1]);
5456
- const xf = fxRef(code[ip + 2]);
5457
- const p = tmp();
5458
- return `${head}
5459
- ${emitMark(p, L.buf, sinks)}
5460
- const v=${child}(input,pos,ctx)
5461
- ${emitRollback(p, L.buf, sinks)}
5462
- if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5463
- EC.e=pos
5464
- return null
5465
- }`;
5466
- }
5467
- case OP_OPT: {
5468
- const child = link(code[ip + 1]);
5469
- const p = tmp();
5470
- return `${head}
5471
- ${emitMark(p, L.buf, sinks)}
5472
- ctx._fc=false
5473
- const v=${child}(input,pos,ctx)
5474
- if(v===FAIL){
5475
- if(ctx._fc===true)return FAIL
5476
- ${emitRollback(p, L.buf, sinks)}
5477
- EC.e=pos
5478
- return null
5479
- }
5480
- return v
5481
- }`;
5482
- }
5483
- case OP_SEQ:
5484
- case OP_SEQV:
5485
- case OP_SEQX: {
5486
- const fused = op === OP_SEQX;
5487
- const base = fused ? ip + 3 : ip + 2;
5488
- const n = code[fused ? ip + 2 : ip + 1];
5489
- const wantValues = op !== OP_SEQV;
5490
- for (let i = 1; i < n; i++) {
5491
- if (code[code[base + i]] === OP_ADJ) {
5492
- throw new Unemittable("a sequence carrying an adjacency assertion (OP_ADJ)");
5493
- }
5494
- }
5495
- const fn = fused ? fnRef(code[ip + 1]) : void 0;
5496
- const kids = [];
5497
- for (let i = 0; i < n; i++) kids.push(link(code[base + i]));
5498
- const sy = REC ? `${tmp()}sy` : "";
5499
- const pub = (i) => {
5500
- const s = sentRef(code[base + n + i]);
5501
- return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
5502
- };
5503
- const parts = [head];
5504
- if (REC) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
5505
- parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
5506
- const close = () => REC ? `${parts.join("\n")}
5507
- }finally{ctx._sync=${sy}}
5508
- }` : `${parts.join("\n")}
5509
- }`;
5510
- if (n === 1) {
5511
- parts.push(fused ? `return ${fn}([v0],{start:pos,end:EC.e})` : wantValues ? "return [v0]" : "return undefined");
5512
- return close();
5513
- }
5514
- parts.push("let cur=EC.e");
5515
- const names = ["v0"];
5516
- for (let i = 1; i < n; i++) {
5517
- const vn = `v${i}`;
5518
- parts.push(`let ${vn}`);
5519
- if (REC) parts.push(pub(i));
5520
- parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L), sinks));
5521
- names.push(vn);
5522
- }
5523
- parts.push("EC.e=cur");
5524
- parts.push(fused ? `return ${fn}([${names.join(",")}],{start:pos,end:cur})` : wantValues ? `return [${names.join(",")}]` : "return undefined");
5525
- return close();
5526
- }
5527
- case OP_CHOICE: {
5528
- const table = disp[code[ip + 1]];
5529
- const n = code[ip + 2];
5530
- const choiceFx = fxRef(code[ip + 3]);
5531
- const base = ip + 4;
5532
- const arms = [];
5533
- for (let i = 0; i < n; i++) arms.push(link(code[base + i]));
5534
- const axi = armExpected.push(
5535
- Array.from({ length: n }, (_, i) => t.fx[code[base + n + i]])
5536
- ) - 1;
5537
- armExpectedPlan.push(Array.from({ length: n }, (_, i) => code[base + n + i]));
5538
- const afx = hoist("afx", `AFX[${axi}]`);
5539
- if (table.exclusive) {
5540
- const di = code[ip + 1];
5541
- const asc = hoist("as", `DISP[${di}].ascii`);
5542
- const hiArr = table.hi;
5543
- const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
5544
- return `${head}
5545
- const c=lead(input,pos)
5546
- let arm=-1
5547
- if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
5548
- ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
5549
- for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
5550
- if(arm>=0){
5551
- ctx._fc=false
5552
- let v
5553
- switch(arm){
5554
- ${armSwitch}
5555
- }
5556
- if(v!==FAIL)return v
5557
- if(ctx._fc===true)return FAIL
5558
- const af=ctx._fx
5559
- if(af!==undefined&&af.length>0){ctx._fe=pos;return FAIL}
5560
- }
5561
- ctx._fe=pos;ctx._fx=${choiceFx}
5562
- return FAIL
5563
- }`;
5564
- }
5565
- const ci = classes.push(Array.from({ length: n }, (_, i) => table.armCls[i] ?? null)) - 1;
5566
- classPlan.push(Array.from({ length: n }, (_, i) => prog.disp[code[ip + 1]][i] ?? -1));
5567
- const gates = classes[ci];
5568
- const gRef = hoist("g", `CLS[${ci}]`);
5569
- const maskable = n <= 32;
5570
- let maskName = "";
5571
- if (maskable) {
5572
- maskName = hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`);
5573
- maskPlan.push(ci);
5574
- }
5575
- const p = tmp();
5576
- const maskArms = arms.map((a, i) => `
5577
- if((bits&${1 << i})!==0){
5578
- ctx._fc=false
5579
- {const v=${a}(input,pos,ctx)
5580
- if(v!==FAIL)return v}
5581
- for(let j=prev;j<${i};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5582
- prev=${i + 1}
5583
- acc=_accSet(ctx._fx,acc)
5584
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5585
- ${emitRollback(p, L.buf, sinks)}
5586
- }`).join("");
5587
- const generalArms = arms.map((a, i) => `
5588
- if(${gRef}[${i}]===null||classHas(${gRef}[${i}],c)){
5589
- ctx._fc=false
5590
- {const v=${a}(input,pos,ctx)
5591
- if(v!==FAIL)return v}
5592
- acc=_accSet(ctx._fx,acc)
5593
- if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5594
- ${emitRollback(p, L.buf, sinks)}
5595
- }else acc=_accSet(${afx}[${i}],acc)`).join("");
5596
- return `${head}
5597
- const c=lead(input,pos)
5598
- ${emitMark(p, L.buf, sinks)}
5599
- let acc
5600
- ${maskable ? `if(c<128){
5601
- const bits=${maskName}[c<0?128:c]
5602
- let prev=0
5603
- ${maskArms}
5604
- for(let j=prev;j<${n};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5605
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
5606
- return FAIL
5629
+ return `${head}
5630
+ ${reads.length > 0 ? `${reads.join("\n")}
5631
+ ` : ""}if(${tests.join("&&")}){
5632
+ const e=pos+${s.length}
5633
+ const v=input.slice(pos,e)
5634
+ ${captureLeaf("v")}
5635
+ ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5636
+ return v
5607
5637
  }
5608
- ` : ""}${generalArms}
5609
- ctx._fe=pos;ctx._fx=acc??${choiceFx}
5610
- return FAIL
5638
+ ctx._fe=pos;ctx._fx=${xf}
5639
+ ${cfg.probe ? `failAt(ctx,${xf},pos)
5640
+ ` : ""}return FAIL
5611
5641
  }`;
5612
5642
  }
5613
- case OP_DISPATCH: {
5614
- const di = code[ip + 2];
5615
- const spec = dsp[di];
5616
- const selector = link(code[ip + 1]);
5617
- const otherIp = code[ip + 3];
5618
- const other = otherIp >= 0 ? link(otherIp) : void 0;
5619
- const otherRouted = code[ip + 4] === 1;
5620
- const n = code[ip + 5];
5621
- const armBase = ip + 6;
5622
- const arms = [];
5623
- for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
5624
- const bk = hoist("bk", `DSP[${di}].byKey`);
5625
- const rt = hoist("rt", `DSP[${di}].routed`);
5626
- const dx = hoist("dx", `DSP[${di}].expected`);
5627
- const claims = (m) => {
5628
- switch (m[0]) {
5629
- case 0:
5630
- return `key.startsWith(${q(m[1])})`;
5631
- case 1:
5632
- return `key.endsWith(${q(m[1])})`;
5633
- case 3:
5634
- return `asciiFoldKey(key).startsWith(${q(m[1])})`;
5635
- case 4:
5636
- return `asciiFoldKey(key).endsWith(${q(m[1])})`;
5637
- default:
5638
- return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
5639
- }
5640
- };
5641
- const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
5642
- ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}`).join("\n")}
5643
- }
5644
- `;
5645
- const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
5646
- ` : "";
5647
- const m1 = tmp();
5648
- const m2 = tmp();
5643
+ case OP_RX:
5644
+ case OP_RX_TRACK: {
5645
+ const xf = fxRef(code[ip + 2]);
5646
+ const track = op === OP_RX_TRACK;
5647
+ const scanned = emitScan(code[ip + 1], xf, track, captureLeaf);
5648
+ if (scanned !== void 0) return `${head}${scanned}}`;
5649
+ const rxk = k[code[ip + 1]];
5650
+ if (!(rxk instanceof RegExp) || !rxk.sticky) throw new Unemittable("a non-sticky regex row");
5651
+ const re = kRef(code[ip + 1]);
5649
5652
  return `${head}
5650
- ${emitMark(m1, L.buf, sinks)}
5651
- const sv=${selector}(input,pos,ctx)
5652
- if(sv===FAIL)return FAIL
5653
- const selEnd=EC.e
5654
- const key=sv
5655
- let arm=${bk}.get(key)
5656
- ${fold}${chain}let ur
5657
- if(arm===undefined){
5658
- ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : `ur=${String(otherRouted)}`}
5659
- }else ur=${rt}[arm]===1
5660
- const savedRouted=ctx._routed
5661
- ${emitMark(m2, L.buf, sinks)}
5662
- if(ur){
5663
- ${emitRollback(m1, L.buf, sinks)}
5664
- ${emitMark(m2, L.buf, sinks, false)}
5665
- ctx._routed={value:key,span:{start:pos,end:selEnd}}
5666
- }
5667
- const at=ur?pos:selEnd
5668
- let v
5669
- switch(arm){
5670
- ${arms.map((a, i) => `case ${i}:v=${a}(input,at,ctx);break`).join("\n")}
5671
- ${other === void 0 ? "" : `default:v=${other}(input,at,ctx)`}
5672
- }
5673
- if(ur)ctx._routed=savedRouted
5674
- if(v===FAIL){
5675
- ${emitRollback(m2, L.buf, sinks)}
5676
- ctx._fc=true
5677
- return FAIL
5653
+ ${re}.lastIndex=pos
5654
+ if(${re}.test(input)){
5655
+ const e=${re}.lastIndex
5656
+ const v=input.slice(pos,e)
5657
+ ${captureLeaf("v")}
5658
+ ${track ? "_trackLines(ctx,input,e)\n" : ""}EC.e=e
5659
+ return v
5678
5660
  }
5679
- return [key,v]
5661
+ ctx._fe=pos;ctx._fx=${xf}
5662
+ ${cfg.probe ? `failAt(ctx,${xf},pos)
5663
+ ` : ""}return FAIL
5680
5664
  }`;
5681
5665
  }
5682
- case OP_REP:
5683
- case OP_REPV: {
5666
+ case OP_EMPTY:
5667
+ return `${head}EC.e=pos;return ''}`;
5668
+ case OP_GATE: {
5669
+ const child = link(code[ip + 2]);
5670
+ const ci = classes.push([t.cc[code[ip + 1]]]) - 1;
5671
+ classPlan.push([code[ip + 1]]);
5672
+ const cls = hoist("cl", `CLS[${ci}][0]`);
5673
+ const xf = fxRef(code[ip + 3]);
5674
+ return `${head}
5675
+ if(!classHas(${cls},lead(input,pos))){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5676
+ return ${child}(input,pos,ctx)
5677
+ }`;
5678
+ }
5679
+ case OP_XFORM: {
5680
+ const fn = fnRef(code[ip + 1]);
5681
+ const child = link(code[ip + 2]);
5682
+ return `${head}
5683
+ const v=${child}(input,pos,ctx)
5684
+ if(v===FAIL)return FAIL
5685
+ return ${fn}(v,{start:pos,end:EC.e})
5686
+ }`;
5687
+ }
5688
+ case OP_LABEL: {
5684
5689
  const child = link(code[ip + 1]);
5685
- const min = code[ip + 2];
5686
- const max = code[ip + 3];
5687
- const sepIp = code[ip + 4];
5688
- const sep = sepIp >= 0 ? link(sepIp) : void 0;
5689
- const flags = code[ip + 5];
5690
- const keepSeparators = (flags & 2) !== 0;
5691
- const trailingAllowed = (flags & 1) !== 0;
5692
- const reportItem = (flags & 4) !== 0;
5693
- const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
5694
- const collect = op === OP_REP;
5695
- const skipBeforeFirst = sepIp < 0 && min === 0;
5696
- const p = tmp();
5697
- const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
5698
- const leadTrivia = skipBeforeFirst ? "true" : "count>0";
5699
- const skip = skipFor(L);
5700
- const knownTrivia = L.tri === TRI_NONE ? false : L.tri !== TRI_UNKNOWN ? true : void 0;
5701
- const hasTrivia = knownTrivia === void 0 ? "hasTrivia" : String(knownTrivia);
5702
- const needMark = L.buf ? "true" : "needMark";
5703
- const pfd = sinks.fd ? `${p}fd` : "0";
5704
- const per = sinks.er ? `${p}er` : "undefined";
5705
- const rb = L.buf ? `_rbBuf(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
5706
- if(ctx._fields!==undefined&&ctx._fields.length!==${p}fd)ctx._fields.length=${p}fd` : ""}${sinks.er ? `
5707
- 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)`;
5708
- const markSinks = `${sinks.fd ? `
5709
- ${p}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${sinks.er ? `
5710
- ${p}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
5711
- const markBody = L.buf ? `const b=ctx._cstBuf
5712
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
5713
- const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
5714
- const l=b.tl;${p}tl=l!==undefined?l.length:0
5715
- ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5716
- ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}` : `if(needMark){
5717
- const b=ctx._cstBuf
5718
- if(b!==undefined){
5719
- const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
5720
- const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
5721
- const l=b.tl;${p}tl=l!==undefined?l.length:0
5722
- }else{
5723
- ${p}raw=ctx._cstRawChildren!==undefined?ctx._cstRawChildren.length:0
5724
- ${p}tl=ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0
5725
- ${p}lv=ctx._cstLeaves!==undefined?ctx._cstLeaves.length:0
5726
- }
5727
- ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
5728
- ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
5690
+ const xf = fxRef(code[ip + 2]);
5691
+ return `${head}
5692
+ const v=${child}(input,pos,ctx)
5693
+ if(v===FAIL)ctx._fx=${xf}
5694
+ return v
5729
5695
  }`;
5730
- const my = `${p}my`;
5731
- const recFx = REC ? fxRef(code[ip + 6]) : "";
5732
- const sepSent = REC ? sentRef(code[ip + 7]) : "undefined";
5733
- const recSent = sep === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
5734
- const recGate = sep !== void 0 || min === 0 ? "" : `count>=${min}&&`;
5735
- const recBranch = !REC ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
5736
- ${sep === void 0 ? `${rb}
5737
- ` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
5738
- ${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
5739
- count++
5740
- cur=rr.end
5741
- continue
5742
- }
5743
- `;
5696
+ }
5697
+ case OP_FIELD: {
5698
+ const name = q(k[code[ip + 1]]);
5699
+ const child = link(code[ip + 2]);
5744
5700
  return `${head}
5745
- const out=${collect ? "[]" : "undefined"}
5746
- ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC ? `const ${my}=ctx._sync
5747
- ` : ""}let cur=pos
5748
- let count=0
5749
- for(;;){
5750
- ${max >= 0 ? `if(count>=${max})break
5751
- ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
5752
- ` : ""}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` : ""}
5753
- ${markBody}
5754
- let itemStart=cur
5755
- let sepEnd=-1
5756
- ${sep !== void 0 ? `if(count>0){
5757
- const lb=cstLeavesLen(ctx)
5758
- let sp=cur
5759
- ${hasTrivia === "false" ? "" : hasTrivia === "true" ? `sp=${skip}(input,sp,ctx)
5760
- ` : `if(hasTrivia)sp=${skip}(input,sp,ctx)
5761
- `}ctx._fc=false
5762
- const sv=${sep}(input,sp,ctx)
5763
- if(sv===FAIL){
5764
- ${rb}
5765
- if(ctx._fc===true)return FAIL
5766
- break
5767
- }
5768
- ${keepSeparators ? "" : "demoteCapturedToRaw(ctx,lb)\n"}sepEnd=EC.e
5769
- itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(input,EC.e,ctx)` : `hasTrivia?${skip}(input,EC.e,ctx):EC.e`}
5770
- }else ${leadSkip(hasTrivia, leadTrivia, skip)}
5771
- ` : `${leadSkip(hasTrivia, leadTrivia, skip)}
5772
- `}if(itemStart>=input.length&&${via}){
5773
- ${rb}
5774
- ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
5775
- }
5776
- ctx._fc=false
5777
- const v=${child}(input,itemStart,ctx)
5778
- if(v===FAIL){
5779
- ${REC ? `if(ctx._fc===true){
5780
- ${rb}
5781
- return FAIL
5782
- }
5783
- ${recBranch}${rb}` : `${rb}
5784
- if(ctx._fc===true)return FAIL`}
5785
- ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
5786
- }
5787
- if(EC.e===itemStart&&${via}){
5788
- ${rb}
5789
- break
5790
- }
5791
- ${collect ? "out.push(v)\n" : ""}cur=EC.e
5792
- count++
5793
- }
5794
- ${min > 0 ? `if(count<${min}){
5795
- ${reportItem ? `ctx._fe=cur;ctx._fx=${itemFx}
5796
- ` : ""}return FAIL
5701
+ const v=${child}(input,pos,ctx)
5702
+ if(v===FAIL)return FAIL
5703
+ const f=ctx._fields
5704
+ if(f!==undefined)f.push({name:${name},value:v,span:{start:pos,end:EC.e}})
5705
+ return v
5706
+ }`;
5707
+ }
5708
+ case OP_EXPECT: {
5709
+ const child = link(code[ip + 1]);
5710
+ const xf = fxRef(code[ip + 2]);
5711
+ return `${head}
5712
+ const v=${child}(input,pos,ctx)
5713
+ if(v!==FAIL)return v
5714
+ const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "{start:pos,end:pos}"},expected:${xf}}
5715
+ const es=ctx._errors
5716
+ if(es!==undefined)es.push(err)
5717
+ ${REC ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
5718
+ EC.e=pos
5719
+ return err
5720
+ }`;
5721
+ }
5722
+ case OP_ROUTED: {
5723
+ const fb = code[ip + 1];
5724
+ const fallback = fb >= 0 ? link(fb) : void 0;
5725
+ const push = `pushCstLeaf(ctx,{_tag:'leaf',value:it.value,span:it.span})`;
5726
+ return `${head}
5727
+ const it=ctx._routed
5728
+ if(it===undefined||pos!==it.span.start){
5729
+ ${fallback !== void 0 ? `return ${fallback}(input,pos,ctx)` : "ctx._fe=pos;ctx._fx=ROUTED_FX;return FAIL"}
5797
5730
  }
5798
- ` : ""}EC.e=cur
5799
- return out
5731
+ ${L.buf ? push : `if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)${push}`}
5732
+ EC.e=it.span.end
5733
+ return it.value
5800
5734
  }`;
5801
5735
  }
5802
- case OP_NODE:
5803
- case OP_NODE_TRACK: {
5804
- const flags = code[ip + 3];
5736
+ case OP_SCAN: {
5737
+ const si = code[ip + 1];
5738
+ return `${head}
5739
+ const r=SCANS[${si}].parse(input,pos,ctx)
5740
+ if(!r.ok){ctx._fe=r.span.start;ctx._fx=r.expected??EMPTY_FX;return FAIL}
5741
+ EC.e=r.span.end
5742
+ return r.value
5743
+ }`;
5744
+ }
5745
+ case OP_SCOPE:
5746
+ case OP_SCOPE_CAP:
5747
+ case OP_SCOPE_PLAIN: {
5748
+ const ki = code[ip + 1];
5749
+ const cap = op === OP_SCOPE_CAP;
5750
+ const flags = op === OP_SCOPE_PLAIN ? 0 : code[ip + 3];
5805
5751
  const child = link(code[ip + 2]);
5806
- const proj = code[ip + 4];
5807
- const buildIdx = code[ip + 1];
5808
- const type = k[code[ip + 5]];
5809
- const tagIdx = code[ip + 6];
5810
- const tags = tagIdx < 0 ? "undefined" : kRef(tagIdx);
5811
- const tracked = op === OP_NODE_TRACK;
5812
- const readsTrivia = (flags & 4) !== 0;
5813
- const readsState = (flags & 8) !== 0;
5814
- const hasFields = (flags & 16) !== 0;
5815
- const collapse = (flags & 32) !== 0;
5816
- const unwrap = (flags & 64) !== 0;
5817
- const trailingTrivia = (flags & 128) !== 0;
5818
- const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
5819
- const structural = build === void 0 && proj < 0;
5820
- const grammarCapture = (flags & 1) !== 0 || trailingTrivia;
5821
- const hostCapturesThisType = structural && cfg.hostCaptureTrivia !== void 0 ? cfg.hostCaptureTrivia(type) : void 0;
5822
- const wantFields = hasFields || hostCst;
5823
- const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
5824
- const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
5825
- const ty = q(type);
5826
- const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
5827
- const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
5828
- let value;
5829
- if (proj >= 0) {
5830
- value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:projectChild(kids,${proj},${ty})` : `nd=projectChild(kids,${proj},${ty})`;
5831
- } else if (build !== void 0) {
5832
- const direct = `${build}(kids,fieldMap,span,rawKids,${captureWide ? "tlog" : "EMPTY_TL"},st)`;
5833
- value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:${direct}` : `nd=${direct}`;
5834
- } else {
5835
- value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):{_tag:'node',type:${ty},span,state:st??null,children:kids}`;
5836
- }
5837
- const collapsible = keepChildren && (hostCst || build === void 0 && proj < 0);
5838
- const openCapture = keepChildren ? `const buf={}
5839
- ctx._cstBuf=buf
5840
- ctx._cstChildren=undefined
5841
- ctx._cstLeaves=undefined
5842
- ctx._cstRawChildren=undefined
5843
- ctx._cstTriviaLog=undefined` : `const buf={rawOnly:true}
5844
- ctx._cstBuf=buf
5752
+ const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
5753
+ const tri = ki < 0 ? "undefined" : hoist("tv", `TRIVIA[${ki}]`);
5754
+ const lab = ki < 0 ? "undefined" : hoist("tl", `TRIVIA[${ki}]._meta.triviaKindLabels`);
5755
+ const strict = (flags & 2) !== 0 ? "refuseUnclassifiedRootScope(ctx._rootTriviaStrictScopes)\n" : "";
5756
+ const rootCap = (flags & 1) !== 0;
5757
+ return `${head}
5758
+ ${strict}${rootCap ? "const sR=ctx._rootTriviaCapture\nctx._rootTriviaCapture=false\n" : ""}const sT=ctx.trivia,sL=ctx.triviaKindLabels,sS=_pfScan${cap ? ",sC=ctx.captureTrivia" : ""}
5759
+ _pfScan=${scanFor}
5760
+ ctx.trivia=${tri}
5761
+ ctx.triviaKindLabels=${lab}
5762
+ ${cap ? "ctx.captureTrivia=true\n" : ""}const v=${child}(input,pos,ctx)
5763
+ ${cap ? "ctx.captureTrivia=sC\n" : ""}ctx.trivia=sT
5764
+ ctx.triviaKindLabels=sL
5765
+ _pfScan=sS
5766
+ ${rootCap ? "ctx._rootTriviaCapture=sR\n" : ""}return v
5767
+ }`;
5768
+ }
5769
+ /* ── boundaries ──────────────────────────────────────────────────────── */
5770
+ case OP_TOKEN:
5771
+ case OP_LEAF: {
5772
+ const isToken = op === OP_TOKEN;
5773
+ const fn = isToken ? void 0 : fnRef(code[ip + 1]);
5774
+ const child = link(isToken ? code[ip + 1] : code[ip + 2]);
5775
+ const wasCap = L.buf ? "true" : "(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)";
5776
+ return `${head}
5777
+ const sBuf=ctx._cstBuf,sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
5778
+ const sOtl=ctx._triviaLog
5779
+ ${isToken ? "const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan,sRtl=ctx._rootTriviaLog\n" : ""}const wasCap=${wasCap}
5780
+ ${isToken ? `_pfScan=null
5781
+ ctx.trivia=undefined
5782
+ ctx.triviaKindLabels=undefined
5783
+ ` : ""}ctx._cstBuf=undefined
5845
5784
  ctx._cstChildren=undefined
5846
5785
  ctx._cstLeaves=undefined
5847
5786
  ctx._cstRawChildren=undefined
5848
- ctx._cstTriviaLog=undefined`;
5849
- const finishCapture = keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
5850
- const hostKids=kids
5851
- const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
5852
- const tlog=buf.tl??EMPTY_TLOG` : `const kids=EMPTY_CH
5853
- const hostKids=kids
5854
- const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
5855
- const tlog=buf.tl??EMPTY_TLOG`;
5856
- return `${head}
5857
- const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
5858
- const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
5859
- ${openCapture}
5860
- ctx.captureTrivia=${captureWide}
5861
- const savedFields=ctx._fields
5862
- ctx._fields=${wantFields ? "[]" : "undefined"}
5863
- ${structural ? `const savedMask=ctx._triviaCaptureMask
5864
- if(_pfHost!==undefined&&_pfHost._parsemanTriviaKinds!==undefined)ctx._triviaCaptureMask=_pfHost._parsemanTriviaKinds(${ty})
5865
- ` : ""}const v=${child}(input,pos,ctx)
5866
- ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
5867
- ` : ""}const fieldMap=${wantFields ? "buildFieldMap(ctx._fields)" : "undefined"}
5868
- ctx._fields=savedFields
5869
- ${structural ? "ctx._triviaCaptureMask=savedMask\n" : ""}${finishCapture}
5870
- ctx._cstBuf=sBuf
5787
+ ctx._cstTriviaLog=undefined
5788
+ ctx._triviaLog=undefined
5789
+ ${isToken ? "ctx._rootTriviaLog=undefined\n" : ""}let v
5790
+ try{v=${child}(input,pos,ctx)}finally{
5791
+ ${isToken ? `_pfScan=sScan
5792
+ ctx.trivia=sTri
5793
+ ctx.triviaKindLabels=sKinds
5794
+ ctx._rootTriviaLog=sRtl
5795
+ ` : ""}ctx._cstBuf=sBuf
5871
5796
  ctx._cstChildren=sCh
5872
5797
  ctx._cstLeaves=sLv
5873
5798
  ctx._cstRawChildren=sRaw
5874
5799
  ctx._cstTriviaLog=sTl
5875
- ctx.captureTrivia=sCap
5800
+ ctx._triviaLog=sOtl
5801
+ }
5876
5802
  if(v===FAIL)return FAIL
5877
- const end=EC.e
5878
- const span=${tracked ? "spanLines(ctx,pos,end)" : "{start:pos,end}"}
5879
- const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)" : "undefined"}
5880
- let nd
5881
- ${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]
5882
- else ` : ""}{${value}}
5883
- ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
5884
- EC.e=end
5885
- return nd
5803
+ const e=EC.e
5804
+ const out=${isToken ? "input.slice(pos,e)" : `${fn}(v,{start:pos,end:e})`}
5805
+ if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:out,span:{start:pos,end:e}})
5806
+ EC.e=e
5807
+ return out
5886
5808
  }`;
5887
5809
  }
5888
- default:
5889
- throw new Unemittable(`OP_${OP_NAMES[op] ?? String(op)}`);
5890
- }
5891
- }
5892
- const ruleEntries = [];
5893
- for (const [rname, entryIp] of Object.entries(prog.rules)) {
5894
- const target = link(entryIp);
5895
- const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
5896
- bodies.push(`const ${rn}=${target}`);
5897
- ruleEntries.push(`${q(rname)}:${rn}`);
5898
- }
5899
- const extra = [];
5900
- for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
5901
- const source = `${RUNTIME_PRELUDE}
5902
- ${prelude.join("\n")}
5903
- ${skipDefs.join("\n")}
5904
- ${bodies.join("\n")}
5905
- function _begin(ctx){
5906
- const host=ctx.build
5907
- if(_pfDepth>0)_pfFrames.push([_pfScan,_pfHost,EC.e])
5908
- _pfDepth++
5909
- _pfScan=null
5910
- _pfHost=host
5911
- }
5912
- function _finish(){
5913
- if(_pfDepth<=0)throw new Error('parseman emitted table assembly frame underflow')
5914
- _pfDepth--
5915
- if(_pfDepth===0)return
5916
- const prior=_pfFrames.pop()
5917
- _pfScan=prior[0]
5918
- _pfHost=prior[1]
5919
- EC.e=prior[2]
5810
+ /* ── transaction ─────────────────────────────────────────────────────── */
5811
+ case OP_ATTEMPT: {
5812
+ const child = link(code[ip + 1]);
5813
+ const p = tmp();
5814
+ return `${head}
5815
+ ${emitMark(p, L.buf, sinks)}
5816
+ const v=${child}(input,pos,ctx)
5817
+ if(v!==FAIL)return v
5818
+ ${emitRollback(p, L.buf, sinks)}
5819
+ if(ctx._fc===true)return FAIL
5820
+ ctx._fe=pos
5821
+ return FAIL
5822
+ }`;
5823
+ }
5824
+ case OP_NOT: {
5825
+ const child = link(code[ip + 1]);
5826
+ const xf = fxRef(code[ip + 2]);
5827
+ const p = tmp();
5828
+ return `${head}
5829
+ ${emitMark(p, L.buf, sinks)}
5830
+ const v=${child}(input,pos,ctx)
5831
+ ${emitRollback(p, L.buf, sinks)}
5832
+ if(v===FAIL){EC.e=pos;return null}
5833
+ ctx._fe=pos
5834
+ ctx._fx=${xf}
5835
+ return FAIL
5836
+ }`;
5837
+ }
5838
+ case OP_PEEK: {
5839
+ const child = link(code[ip + 1]);
5840
+ const xf = fxRef(code[ip + 2]);
5841
+ const p = tmp();
5842
+ return `${head}
5843
+ ${emitMark(p, L.buf, sinks)}
5844
+ const v=${child}(input,pos,ctx)
5845
+ ${emitRollback(p, L.buf, sinks)}
5846
+ if(v===FAIL){ctx._fe=pos;ctx._fx=${xf};return FAIL}
5847
+ EC.e=pos
5848
+ return null
5849
+ }`;
5850
+ }
5851
+ case OP_OPT: {
5852
+ const child = link(code[ip + 1]);
5853
+ const p = tmp();
5854
+ return `${head}
5855
+ ${emitMark(p, L.buf, sinks)}
5856
+ ctx._fc=false
5857
+ const v=${child}(input,pos,ctx)
5858
+ if(v===FAIL){
5859
+ if(ctx._fc===true)return FAIL
5860
+ ${emitRollback(p, L.buf, sinks)}
5861
+ EC.e=pos
5862
+ return null
5920
5863
  }
5921
- return{
5922
- pieces:{${ruleEntries.join(",")}},
5923
- byIp:{${extra.join(",")}},
5924
- end:function(){return EC.e},
5925
- begin:_begin,
5926
- finish:_finish
5864
+ return v
5865
+ }`;
5866
+ }
5867
+ case OP_SEQ:
5868
+ case OP_SEQV:
5869
+ case OP_SEQX: {
5870
+ const fused = op === OP_SEQX;
5871
+ const base = fused ? ip + 3 : ip + 2;
5872
+ const n = code[fused ? ip + 2 : ip + 1];
5873
+ const wantValues = op !== OP_SEQV;
5874
+ for (let i = 1; i < n; i++) {
5875
+ if (code[code[base + i]] === OP_ADJ) {
5876
+ throw new Unemittable("a sequence carrying an adjacency assertion (OP_ADJ)");
5877
+ }
5878
+ }
5879
+ const fn = fused ? fnRef(code[ip + 1]) : void 0;
5880
+ const kids = [];
5881
+ for (let i = 0; i < n; i++) kids.push(link(code[base + i]));
5882
+ const sy = REC ? `${tmp()}sy` : "";
5883
+ const pub = (i) => {
5884
+ const s = sentRef(code[base + n + i]);
5885
+ return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
5886
+ };
5887
+ const parts = [head];
5888
+ if (REC) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
5889
+ parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
5890
+ const close = () => REC ? `${parts.join("\n")}
5891
+ }finally{ctx._sync=${sy}}
5892
+ }` : `${parts.join("\n")}
5927
5893
  }`;
5928
- return {
5929
- source,
5930
- reached,
5931
- masks,
5932
- classes,
5933
- armExpected,
5934
- plan: { classes: classPlan, armExpected: armExpectedPlan, masks: maskPlan }
5935
- };
5894
+ if (n === 1) {
5895
+ parts.push(fused ? `return ${fn}([v0],{start:pos,end:EC.e})` : wantValues ? "return [v0]" : "return undefined");
5896
+ return close();
5897
+ }
5898
+ parts.push("let cur=EC.e");
5899
+ const names = ["v0"];
5900
+ for (let i = 1; i < n; i++) {
5901
+ const vn = `v${i}`;
5902
+ parts.push(`let ${vn}`);
5903
+ if (REC) parts.push(pub(i));
5904
+ parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L)));
5905
+ names.push(vn);
5906
+ }
5907
+ parts.push("EC.e=cur");
5908
+ parts.push(fused ? `return ${fn}([${names.join(",")}],{start:pos,end:cur})` : wantValues ? `return [${names.join(",")}]` : "return undefined");
5909
+ return close();
5910
+ }
5911
+ case OP_CHOICE: {
5912
+ const table = disp[code[ip + 1]];
5913
+ const n = code[ip + 2];
5914
+ const choiceFx = fxRef(code[ip + 3]);
5915
+ const base = ip + 4;
5916
+ const arms = [];
5917
+ for (let i = 0; i < n; i++) arms.push(link(code[base + i]));
5918
+ const axi = armExpected.push(
5919
+ Array.from({ length: n }, (_, i) => t.fx[code[base + n + i]])
5920
+ ) - 1;
5921
+ armExpectedPlan.push(Array.from({ length: n }, (_, i) => code[base + n + i]));
5922
+ const afx = hoist("afx", `AFX[${axi}]`);
5923
+ if (table.exclusive) {
5924
+ const di = code[ip + 1];
5925
+ const asc = hoist("as", `DISP[${di}].ascii`);
5926
+ const hiArr = table.hi;
5927
+ const armSwitch = arms.map((a, i) => `case ${i}:v=${a}(input,pos,ctx);break`).join("\n");
5928
+ return `${head}
5929
+ const c=lead(input,pos)
5930
+ let arm=-1
5931
+ if(c>=0&&c<128){const a=${asc}[c];if(a!==0)arm=a-1}
5932
+ ${hiArr.length === 0 ? "" : `else if(c>=128){const h=${hoist("hi", `DISP[${di}].hi`)}
5933
+ for(let i=0;i<h.length;i+=3){if(c>=h[i]&&c<=h[i+1]){arm=h[i+2];break}}}`}
5934
+ if(arm>=0){
5935
+ ctx._fc=false
5936
+ let v
5937
+ switch(arm){
5938
+ ${armSwitch}
5936
5939
  }
5937
-
5938
- // src/table/run-support.ts
5939
- function lineCol(ctx, offset) {
5940
- const starts = ctx._lineStarts ?? [0];
5941
- let lo = 0, hi = starts.length - 1;
5942
- while (lo < hi) {
5943
- const mid = lo + hi + 1 >> 1;
5944
- if (starts[mid] <= offset) lo = mid;
5945
- else hi = mid - 1;
5946
- }
5947
- return [lo + 1, offset - starts[lo] + 1];
5940
+ if(v!==FAIL)return v
5941
+ if(ctx._fc===true)return FAIL
5942
+ const af=ctx._fx
5943
+ if(af!==undefined&&af.length>0){ctx._fe=pos;return FAIL}
5948
5944
  }
5949
- function spanLines(ctx, start, end) {
5950
- const s = lineCol(ctx, start), e = lineCol(ctx, end);
5951
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
5945
+ ctx._fe=pos;ctx._fx=${choiceFx}
5946
+ return FAIL
5947
+ }`;
5948
+ }
5949
+ const ci = classes.push(Array.from({ length: n }, (_, i) => table.armCls[i] ?? null)) - 1;
5950
+ classPlan.push(Array.from({ length: n }, (_, i) => prog.disp[code[ip + 1]][i] ?? -1));
5951
+ const gates = classes[ci];
5952
+ const gRef = hoist("g", `CLS[${ci}]`);
5953
+ const maskable = n <= 32;
5954
+ let maskName = "";
5955
+ if (maskable) {
5956
+ maskName = hoist("mk", `MASK[${masks.push(maskForClassRow(gates)) - 1}]`);
5957
+ maskPlan.push(ci);
5958
+ }
5959
+ const p = tmp();
5960
+ const maskArms = arms.map((a, i) => `
5961
+ if((bits&${1 << i})!==0){
5962
+ ctx._fc=false
5963
+ {const v=${a}(input,pos,ctx)
5964
+ if(v!==FAIL)return v}
5965
+ for(let j=prev;j<${i};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5966
+ prev=${i + 1}
5967
+ acc=_accSet(ctx._fx,acc)
5968
+ if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5969
+ ${emitRollback(p, L.buf, sinks)}
5970
+ }`).join("");
5971
+ const generalArms = arms.map((a, i) => `
5972
+ if(${gRef}[${i}]===null||classHas(${gRef}[${i}],c)){
5973
+ ctx._fc=false
5974
+ {const v=${a}(input,pos,ctx)
5975
+ if(v!==FAIL)return v}
5976
+ acc=_accSet(ctx._fx,acc)
5977
+ if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
5978
+ ${emitRollback(p, L.buf, sinks)}
5979
+ }else acc=_accSet(${afx}[${i}],acc)`).join("");
5980
+ return `${head}
5981
+ const c=lead(input,pos)
5982
+ ${emitMark(p, L.buf, sinks)}
5983
+ let acc
5984
+ ${maskable ? `if(c<128){
5985
+ const bits=${maskName}[c<0?128:c]
5986
+ let prev=0
5987
+ ${maskArms}
5988
+ for(let j=prev;j<${n};j++)if((bits&(1<<j))===0)acc=_accSet(${afx}[j],acc)
5989
+ ctx._fe=pos;ctx._fx=acc??${choiceFx}
5990
+ return FAIL
5952
5991
  }
5953
- function rawEntry(v, input, s, e) {
5954
- if (typeof v === "object" && v !== null) {
5955
- const tg = v._tag;
5956
- if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
5957
- }
5958
- return {
5959
- _tag: "leaf",
5960
- value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
5961
- span: { start: s, end: e }
5962
- };
5992
+ ` : ""}${generalArms}
5993
+ ctx._fe=pos;ctx._fx=acc??${choiceFx}
5994
+ return FAIL
5995
+ }`;
5996
+ }
5997
+ case OP_DISPATCH: {
5998
+ const di = code[ip + 2];
5999
+ const spec = dsp[di];
6000
+ const selector = link(code[ip + 1]);
6001
+ const otherIp = code[ip + 3];
6002
+ const other = otherIp >= 0 ? link(otherIp) : void 0;
6003
+ const otherRouted = code[ip + 4] === 1;
6004
+ const n = code[ip + 5];
6005
+ validateDispatchSpec(spec, n, code[ip + 4]);
6006
+ const armBase = ip + 6;
6007
+ const arms = [];
6008
+ for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
6009
+ const bk = hoist("bk", `DSP[${di}].byKey`);
6010
+ const dx = hoist("dx", `DSP[${di}].expected`);
6011
+ const claims = (m) => {
6012
+ switch (m[0]) {
6013
+ case 0:
6014
+ return `key.startsWith(${q(m[1])})`;
6015
+ case 1:
6016
+ return `key.endsWith(${q(m[1])})`;
6017
+ case 3:
6018
+ return `asciiFoldKey(key).startsWith(${q(m[1])})`;
6019
+ case 4:
6020
+ return `asciiFoldKey(key).endsWith(${q(m[1])})`;
6021
+ default:
6022
+ return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`;
6023
+ }
6024
+ };
6025
+ const chain = spec.match.length === 0 ? "" : `if(arm===undefined){
6026
+ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}`).join("\n")}
5963
6027
  }
5964
- function lead(input, pos) {
5965
- if (pos >= input.length) return -1;
5966
- const c = input.charCodeAt(pos);
5967
- if (c < 55296 || c > 56319) return c;
5968
- return input.codePointAt(pos) ?? c;
6028
+ `;
6029
+ const fold = spec.byFold.size > 0 ? `if(arm===undefined)arm=${hoist("bf", `DSP[${di}].byFold`)}.get(asciiFoldKey(key))
6030
+ ` : "";
6031
+ const m1 = tmp();
6032
+ const m2 = tmp();
6033
+ const routedCall = (target) => `{const savedRouted=ctx._routed
6034
+ ${emitRollback(m1, L.buf, sinks)}
6035
+ ${emitMark(m2, L.buf, sinks, false)}
6036
+ ctx._routed={value:key,span:{start:pos,end:selEnd}}
6037
+ try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
6038
+ break}`;
6039
+ const plainCall = (target) => `v=${target}(input,selEnd,ctx);break`;
6040
+ const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1 ? routedCall(target) : plainCall(target)}`).join("\n");
6041
+ const fallbackCase = other === void 0 ? "" : `default:${otherRouted ? routedCall(other) : plainCall(other)}`;
6042
+ return `${head}
6043
+ ${emitMark(m1, L.buf, sinks)}
6044
+ const sv=${selector}(input,pos,ctx)
6045
+ if(sv===FAIL)return FAIL
6046
+ const selEnd=EC.e
6047
+ const key=sv
6048
+ let arm=${bk}.get(key)
6049
+ ${fold}${chain}
6050
+ if(arm===undefined){
6051
+ ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ""}
5969
6052
  }
5970
-
5971
- // src/table/program.ts
5972
- function closureArtifact(prog) {
5973
- return { ...prog, asm: [] };
6053
+ ${emitMark(m2, L.buf, sinks)}
6054
+ let v
6055
+ switch(arm){
6056
+ ${armCases}
6057
+ ${fallbackCase}
5974
6058
  }
5975
- function covKindCode(kind) {
5976
- switch (kind) {
5977
- case "rule":
5978
- return 0;
5979
- case "choice-arm":
5980
- return 1;
5981
- case "dispatch-arm":
5982
- return 2;
5983
- case "label":
5984
- return 3;
5985
- }
6059
+ if(v===FAIL){
6060
+ ${emitRollback(m2, L.buf, sinks)}
6061
+ ctx._fc=true
6062
+ return FAIL
5986
6063
  }
5987
- function covKindName(code) {
5988
- switch (code) {
5989
- case 0:
5990
- return "rule";
5991
- case 1:
5992
- return "choice-arm";
5993
- case 2:
5994
- return "dispatch-arm";
5995
- case 3:
5996
- return "label";
5997
- }
6064
+ return [key,v]
6065
+ }`;
6066
+ }
6067
+ case OP_REP:
6068
+ case OP_REPV: {
6069
+ const child = link(code[ip + 1]);
6070
+ const min = code[ip + 2];
6071
+ const max = code[ip + 3];
6072
+ const sepIp = code[ip + 4];
6073
+ const sep = sepIp >= 0 ? link(sepIp) : void 0;
6074
+ const flags = code[ip + 5];
6075
+ const keepSeparators = (flags & 2) !== 0;
6076
+ const trailingAllowed = (flags & 1) !== 0;
6077
+ const reportItem = (flags & 4) !== 0;
6078
+ const itemFx = reportItem ? fxRef(code[ip + 6]) : "EMPTY_FX";
6079
+ const collect = op === OP_REP;
6080
+ const skipBeforeFirst = sepIp < 0 && min === 0;
6081
+ const p = tmp();
6082
+ const via = sep !== void 0 ? "false" : min === 0 ? skipBeforeFirst ? "true" : "count>0" : `count>=${min}&&count>0`;
6083
+ const leadTrivia = skipBeforeFirst ? "true" : "count>0";
6084
+ const skip = skipFor(L);
6085
+ const knownTrivia = L.tri === TRI_NONE ? false : L.tri !== TRI_UNKNOWN ? true : void 0;
6086
+ const hasTrivia = knownTrivia === void 0 ? "hasTrivia" : String(knownTrivia);
6087
+ const needMark = L.buf ? "true" : "needMark";
6088
+ const pfd = sinks.fd ? `${p}fd` : "0";
6089
+ const per = sinks.er ? `${p}er` : "undefined";
6090
+ const rb = L.buf ? `_rbBuf(ctx,${p}raw,${p}tl,${p}lv,${p}lg,${p}rt)${sinks.fd ? `
6091
+ if(ctx._fields!==undefined&&ctx._fields.length!==${p}fd)ctx._fields.length=${p}fd` : ""}${sinks.er ? `
6092
+ 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)`;
6093
+ const markSinks = `${sinks.fd ? `
6094
+ ${p}fd=ctx._fields!==undefined?ctx._fields.length:0` : ""}${sinks.er ? `
6095
+ ${p}er=ctx._errors!==undefined?ctx._errors.length:0` : ""}`;
6096
+ const markBody = L.buf ? `const b=ctx._cstBuf
6097
+ const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
6098
+ const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
6099
+ const l=b.tl;${p}tl=l!==undefined?l.length:0
6100
+ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
6101
+ ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}` : `if(needMark){
6102
+ const b=ctx._cstBuf
6103
+ if(b!==undefined){
6104
+ const r=b.raw;${p}raw=r!==undefined?r.length:b.rawSingle!==undefined?1:0
6105
+ const h=b.ch;${p}lv=h!==undefined?h.length:b.single!==undefined?1:0
6106
+ const l=b.tl;${p}tl=l!==undefined?l.length:0
6107
+ }else{
6108
+ ${p}raw=ctx._cstRawChildren!==undefined?ctx._cstRawChildren.length:0
6109
+ ${p}tl=ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0
6110
+ ${p}lv=ctx._cstLeaves!==undefined?ctx._cstLeaves.length:0
5998
6111
  }
5999
- function covDefinitions(prog) {
6000
- return (prog.cov ?? []).map(([id, kind]) => ({ id, kind: covKindName(kind) }));
6112
+ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
6113
+ ${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
6114
+ }`;
6115
+ const my = `${p}my`;
6116
+ const recFx = REC ? fxRef(code[ip + 6]) : "";
6117
+ const sepSent = REC ? sentRef(code[ip + 7]) : "undefined";
6118
+ const recSent = sep === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
6119
+ const recGate = sep !== void 0 || min === 0 ? "" : `count>=${min}&&`;
6120
+ const recBranch = !REC ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
6121
+ ${sep === void 0 ? `${rb}
6122
+ ` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
6123
+ ${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
6124
+ count++
6125
+ cur=rr.end
6126
+ continue
6001
6127
  }
6002
- function expandCompact(p) {
6003
- if ("code" in p) return p;
6004
- return ownTableProgram({
6005
- code: p.c,
6006
- k: p.k,
6007
- cc: p.x,
6008
- fx: p.e,
6009
- disp: p.d,
6010
- rules: p.r,
6011
- fns: p.f,
6012
- lines: p.l ?? 0,
6013
- dsp: p.p ?? [],
6014
- ...p.lb === void 0 ? {} : { labels: p.lb },
6015
- ...p.rc === void 0 ? {} : { classified: p.rc },
6016
- ...p.h === void 0 ? {} : { hostMode: p.h },
6017
- ...p.tv === void 0 ? {} : { triviaSpecs: p.tv },
6018
- ...p.sc === void 0 ? {} : { scans: p.sc },
6019
- ...p.ss === void 0 ? {} : { scanSkip: p.ss },
6020
- ...p.so === void 0 ? {} : { scanSkipOf: p.so },
6021
- ...p.rv === void 0 ? {} : { rec: p.rv },
6022
- ...p.cv === void 0 ? {} : { cov: p.cv },
6023
- ...p.a === void 0 ? {} : { asm: p.a }
6024
- });
6128
+ `;
6129
+ return `${head}
6130
+ const out=${collect ? "[]" : "undefined"}
6131
+ ${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC ? `const ${my}=ctx._sync
6132
+ ` : ""}let cur=pos
6133
+ let count=0
6134
+ for(;;){
6135
+ ${max >= 0 ? `if(count>=${max})break
6136
+ ` : ""}${sep !== void 0 ? `if(count>0&&count>=${min}&&cur>=input.length)break
6137
+ ` : ""}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` : ""}
6138
+ ${markBody}
6139
+ let itemStart=cur
6140
+ let sepEnd=-1
6141
+ ${sep !== void 0 ? `if(count>0){
6142
+ const lb=cstLeavesLen(ctx)
6143
+ let sp=cur
6144
+ ${hasTrivia === "false" ? "" : hasTrivia === "true" ? `sp=${skip}(input,sp,ctx)
6145
+ ` : `if(hasTrivia)sp=${skip}(input,sp,ctx)
6146
+ `}ctx._fc=false
6147
+ const sv=${sep}(input,sp,ctx)
6148
+ if(sv===FAIL){
6149
+ ${rb}
6150
+ if(ctx._fc===true)return FAIL
6151
+ break
6025
6152
  }
6026
- var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
6027
- function ownTableProgram(prog, resolved) {
6028
- return { ...prog, [TABLE_RUNTIME]: { resolved } };
6153
+ ${keepSeparators ? "" : "demoteCapturedToRaw(ctx,lb)\n"}sepEnd=EC.e
6154
+ itemStart=${hasTrivia === "false" ? "EC.e" : hasTrivia === "true" ? `${skip}(input,EC.e,ctx)` : `hasTrivia?${skip}(input,EC.e,ctx):EC.e`}
6155
+ }else ${leadSkip(hasTrivia, leadTrivia, skip)}
6156
+ ` : `${leadSkip(hasTrivia, leadTrivia, skip)}
6157
+ `}if(itemStart>=input.length&&${via}){
6158
+ ${rb}
6159
+ ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
6029
6160
  }
6030
- var WIDE_CLASS_PREFIX_LO = 65535;
6031
- var WIDE_CLASS_PREFIX_HI = 0;
6032
- function validateClassRange(lo, hi) {
6033
- for (const cp of [lo, hi]) {
6034
- if (!Number.isInteger(cp) || cp < 0 || cp > 1114111) {
6035
- throw new TypeError(`table char-class endpoint is outside Unicode: ${cp}`);
6036
- }
6037
- }
6038
- if (lo > hi) {
6039
- throw new TypeError(`table char-class range is descending: ${lo} > ${hi}`);
6040
- }
6161
+ ctx._fc=false
6162
+ const v=${child}(input,itemStart,ctx)
6163
+ if(v===FAIL){
6164
+ ${REC ? `if(ctx._fc===true){
6165
+ ${rb}
6166
+ return FAIL
6041
6167
  }
6042
- function encodeClassSpec(ranges) {
6043
- let wide = false;
6044
- for (const range of ranges) {
6045
- validateClassRange(range.lo, range.hi);
6046
- if (range.hi > 65535) wide = true;
6047
- }
6048
- if (!wide) {
6049
- let spec2 = "";
6050
- for (const range of ranges) spec2 += String.fromCharCode(range.lo, range.hi);
6051
- return spec2;
6052
- }
6053
- let spec = String.fromCharCode(WIDE_CLASS_PREFIX_LO, WIDE_CLASS_PREFIX_HI);
6054
- for (const range of ranges) {
6055
- spec += String.fromCharCode(
6056
- range.lo >>> 16,
6057
- range.lo & 65535,
6058
- range.hi >>> 16,
6059
- range.hi & 65535
6060
- );
6061
- }
6062
- return spec;
6168
+ ${recBranch}${rb}` : `${rb}
6169
+ if(ctx._fc===true)return FAIL`}
6170
+ ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
6063
6171
  }
6064
- function decodeClassSpec(spec) {
6065
- if (spec.charCodeAt(0) === WIDE_CLASS_PREFIX_LO && spec.charCodeAt(1) === WIDE_CLASS_PREFIX_HI) {
6066
- if ((spec.length - 2) % 4 !== 0) throw new TypeError("table char-class spec has a truncated wide range");
6067
- if (spec.length === 2) throw new TypeError("table char-class spec has a wide prefix but no ranges");
6068
- const ranges2 = [];
6069
- for (let i = 2; i < spec.length; i += 4) {
6070
- const lo = spec.charCodeAt(i) * 65536 + spec.charCodeAt(i + 1);
6071
- const hi = spec.charCodeAt(i + 2) * 65536 + spec.charCodeAt(i + 3);
6072
- validateClassRange(lo, hi);
6073
- ranges2.push({ lo, hi });
6074
- }
6075
- return ranges2;
6076
- }
6077
- if (spec.length % 2 !== 0) throw new TypeError("table char-class spec has an unmatched range endpoint");
6078
- const ranges = [];
6079
- for (let i = 0; i < spec.length; i += 2) {
6080
- const lo = spec.charCodeAt(i);
6081
- const hi = spec.charCodeAt(i + 1);
6082
- validateClassRange(lo, hi);
6083
- ranges.push({ lo, hi });
6084
- }
6085
- return ranges;
6172
+ if(EC.e===itemStart&&${via}){
6173
+ ${rb}
6174
+ break
6086
6175
  }
6087
- function resolveClass(spec) {
6088
- const ascii = new Uint8Array(128);
6089
- const hi = [];
6090
- for (const { lo, hi: up } of decodeClassSpec(spec)) {
6091
- if (lo < 128) for (let c = lo; c <= Math.min(up, 127); c++) ascii[c] = 1;
6092
- if (up >= 128) hi.push(Math.max(lo, 128), up);
6093
- }
6094
- return { ascii, hi };
6176
+ ${collect ? "out.push(v)\n" : ""}cur=EC.e
6177
+ count++
6095
6178
  }
6096
- function classHas(cls, code) {
6097
- if (code < 0) return false;
6098
- if (code < 128) return cls.ascii[code] === 1;
6099
- const hi = cls.hi;
6100
- for (let i = 0; i < hi.length; i += 2) if (code >= hi[i] && code <= hi[i + 1]) return true;
6101
- return false;
6179
+ ${min > 0 ? `if(count<${min}){
6180
+ ${reportItem ? `ctx._fe=cur;ctx._fx=${itemFx}
6181
+ ` : ""}return FAIL
6102
6182
  }
6103
- function resolveDispatch(arms, cc) {
6104
- const ascii = new Uint8Array(128);
6105
- const hi = [];
6106
- const open = [];
6107
- const armCls = [];
6108
- let exclusive = true;
6109
- let hiOwners = 0;
6110
- for (let a = 0; a < arms.length; a++) {
6111
- const ci = arms[a];
6112
- if (ci < 0) {
6113
- open.push(a);
6114
- armCls.push(null);
6115
- exclusive = false;
6116
- continue;
6117
- }
6118
- const cls = cc[ci];
6119
- armCls.push(cls);
6120
- for (let c = 0; c < 128; c++) {
6121
- if (cls.ascii[c] !== 1) continue;
6122
- if (ascii[c] === 0) ascii[c] = a + 1;
6123
- else exclusive = false;
6183
+ ` : ""}EC.e=cur
6184
+ return out
6185
+ }`;
6186
+ }
6187
+ case OP_NODE:
6188
+ case OP_NODE_TRACK: {
6189
+ const flags = code[ip + 3];
6190
+ const child = link(code[ip + 2]);
6191
+ const proj = code[ip + 4];
6192
+ const buildIdx = code[ip + 1];
6193
+ const type = k[code[ip + 5]];
6194
+ const tagIdx = code[ip + 6];
6195
+ const tags = tagIdx < 0 ? "undefined" : kRef(tagIdx);
6196
+ const tracked = op === OP_NODE_TRACK;
6197
+ const readsTrivia = (flags & 4) !== 0;
6198
+ const readsState = (flags & 8) !== 0;
6199
+ const hasFields = (flags & 16) !== 0;
6200
+ const collapse = (flags & 32) !== 0;
6201
+ const unwrap = (flags & 64) !== 0;
6202
+ const trailingTrivia = (flags & 128) !== 0;
6203
+ const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
6204
+ const structural = build === void 0 && proj < 0;
6205
+ const grammarCapture = (flags & 1) !== 0 || trailingTrivia;
6206
+ const hostCapturesThisType = structural && cfg.hostCaptureTrivia !== void 0 ? cfg.hostCaptureTrivia(type) : void 0;
6207
+ const wantFields = hasFields || hostCst;
6208
+ const captureWide = readsTrivia || hostCst ? !structural || grammarCapture || hostCapturesThisType !== false : hostCapturesThisType === true;
6209
+ const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap;
6210
+ const ty = q(type);
6211
+ const stArg = readsState ? "st" : "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)";
6212
+ const hostCall = `_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,${stArg},${tags})`;
6213
+ let value;
6214
+ if (proj >= 0) {
6215
+ value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:projectChild(kids,${proj},${ty})` : `nd=projectChild(kids,${proj},${ty})`;
6216
+ } else if (build !== void 0) {
6217
+ const direct = `${build}(kids,fieldMap,span,rawKids,${captureWide ? "tlog" : "EMPTY_TL"},st)`;
6218
+ value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:${direct}` : `nd=${direct}`;
6219
+ } else {
6220
+ value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):{_tag:'node',type:${ty},span,state:st??null,children:kids}`;
6221
+ }
6222
+ const collapsible = keepChildren && (hostCst || build === void 0 && proj < 0);
6223
+ const openCapture = keepChildren ? `const buf={}
6224
+ ctx._cstBuf=buf
6225
+ ctx._cstChildren=undefined
6226
+ ctx._cstLeaves=undefined
6227
+ ctx._cstRawChildren=undefined
6228
+ ctx._cstTriviaLog=undefined` : `const buf={rawOnly:true}
6229
+ ctx._cstBuf=buf
6230
+ ctx._cstChildren=undefined
6231
+ ctx._cstLeaves=undefined
6232
+ ctx._cstRawChildren=undefined
6233
+ ctx._cstTriviaLog=undefined`;
6234
+ const finishCapture = keepChildren ? `const kids=buf.ch??(buf.single!==undefined?[buf.single]:EMPTY_CH)
6235
+ const hostKids=kids
6236
+ const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
6237
+ const tlog=buf.tl??EMPTY_TLOG` : `const kids=EMPTY_CH
6238
+ const hostKids=kids
6239
+ const rawKids=buf.raw??(buf.rawSingle!==undefined?[buf.rawSingle]:EMPTY_CH)
6240
+ const tlog=buf.tl??EMPTY_TLOG`;
6241
+ return `${head}
6242
+ const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
6243
+ const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf
6244
+ ${openCapture}
6245
+ ctx.captureTrivia=${captureWide}
6246
+ const savedFields=ctx._fields
6247
+ ctx._fields=${wantFields ? "[]" : "undefined"}
6248
+ ${structural ? `const savedMask=ctx._triviaCaptureMask
6249
+ if(_pfHost!==undefined&&_pfHost._parsemanTriviaKinds!==undefined)ctx._triviaCaptureMask=_pfHost._parsemanTriviaKinds(${ty})
6250
+ ` : ""}const v=${child}(input,pos,ctx)
6251
+ ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
6252
+ ` : ""}const fieldMap=${wantFields ? "buildFieldMap(ctx._fields)" : "undefined"}
6253
+ ctx._fields=savedFields
6254
+ ${structural ? "ctx._triviaCaptureMask=savedMask\n" : ""}${finishCapture}
6255
+ ctx._cstBuf=sBuf
6256
+ ctx._cstChildren=sCh
6257
+ ctx._cstLeaves=sLv
6258
+ ctx._cstRawChildren=sRaw
6259
+ ctx._cstTriviaLog=sTl
6260
+ ctx.captureTrivia=sCap
6261
+ if(v===FAIL)return FAIL
6262
+ const end=EC.e
6263
+ const span=${tracked ? "spanLines(ctx,pos,end)" : "{start:pos,end}"}
6264
+ const st=${readsState ? "(ctx.state!==undefined?Object.assign({},ctx.state):undefined)" : "undefined"}
6265
+ let nd
6266
+ ${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]
6267
+ else ` : ""}{${value}}
6268
+ ${L.buf ? "pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))" : "if(sBuf!==undefined||sCh!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))"}
6269
+ EC.e=end
6270
+ return nd
6271
+ }`;
6272
+ }
6273
+ default:
6274
+ throw new Unemittable(`OP_${OP_NAMES[op] ?? String(op)}`);
6124
6275
  }
6125
- if (cls.hi.length > 0 && ++hiOwners > 1) exclusive = false;
6126
- for (let i = 0; i < cls.hi.length; i += 2) hi.push(cls.hi[i], cls.hi[i + 1], a);
6127
6276
  }
6128
- return { ascii, hi, open, armCls, exclusive };
6129
- }
6130
- function buildTrivia(spec) {
6131
- if (spec.live !== void 0) return spec.live;
6132
- if (spec.plain !== void 0) return trivia(regex(new RegExp(spec.plain[0], spec.plain[1])));
6133
- if (spec.alts !== void 0) {
6134
- const [head, ...rest] = spec.alts.map(([source, flags]) => regex(new RegExp(source, flags)));
6135
- if (head === void 0) throw new TypeError("trivia spec has an EMPTY alternation, which matches nothing");
6136
- const body = rest.length === 0 ? head : choice(head, ...rest);
6137
- return trivia(many(body, { min: spec.min ?? 1 }));
6277
+ const ruleEntries = [];
6278
+ for (const [rname, entryIp] of Object.entries(prog.rules)) {
6279
+ const target = link(entryIp);
6280
+ const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
6281
+ bodies.push(`const ${rn}=${target}`);
6282
+ ruleEntries.push(`${q(rname)}:${rn}`);
6138
6283
  }
6139
- const arms = {};
6140
- for (const [name, source, flags] of spec.arms) arms[name] = regex(new RegExp(source, flags));
6141
- return classifiedTrivia(arms);
6284
+ const extra = [];
6285
+ for (const ip of extraIps) extra.push(`${ip}:${link(ip)}`);
6286
+ const source = `${RUNTIME_PRELUDE}
6287
+ ${prelude.join("\n")}
6288
+ ${skipDefs.join("\n")}
6289
+ ${bodies.join("\n")}
6290
+ function _begin(ctx){
6291
+ const host=ctx.build
6292
+ if(_pfDepth>0)_pfFrames.push([_pfScan,_pfHost,EC.e])
6293
+ _pfDepth++
6294
+ _pfScan=null
6295
+ _pfHost=host
6142
6296
  }
6143
- function resolveTable(prog) {
6144
- const owner = prog[TABLE_RUNTIME];
6145
- const hit = owner?.resolved;
6146
- if (hit !== void 0) return hit;
6147
- const cc = prog.cc.map(resolveClass);
6148
- const triviaBuilt = (prog.triviaSpecs ?? []).map(buildTrivia);
6149
- const built = {
6150
- prog,
6151
- code: Int32Array.from(prog.code),
6152
- k: prog.k,
6153
- fns: prog.fns,
6154
- cc,
6155
- fx: prog.fx,
6156
- disp: prog.disp.map((d) => resolveDispatch(d, cc)),
6157
- trivia: triviaBuilt,
6158
- triviaScan: triviaBuilt.map(fastTriviaScanner),
6159
- triviaLabelled: triviaBuilt.map((t) => t._meta.triviaKindLabels !== void 0),
6160
- dsp: prog.dsp.map((d) => ({
6161
- byKey: new Map(d.key.map((x, i) => [x, d.keyArm[i]])),
6162
- byFold: new Map(d.fold.map((x, i) => [x, d.foldArm[i]])),
6163
- match: d.match,
6164
- routed: d.routed,
6165
- expected: d.expected
6166
- })),
6167
- rules: prog.rules
6168
- };
6169
- if (owner !== void 0) owner.resolved = built;
6170
- return built;
6297
+ function _finish(){
6298
+ if(_pfDepth<=0)throw new Error('parseman emitted table assembly frame underflow')
6299
+ _pfDepth--
6300
+ if(_pfDepth===0)return
6301
+ const prior=_pfFrames.pop()
6302
+ _pfScan=prior[0]
6303
+ _pfHost=prior[1]
6304
+ EC.e=prior[2]
6171
6305
  }
6172
- var FOLDED_RUNTIME = /* @__PURE__ */ Symbol("parseman.foldedRuntime");
6173
- function ownFoldedProgram(base, variants) {
6174
- return { base, variants, [FOLDED_RUNTIME]: { byName: /* @__PURE__ */ new Map() } };
6306
+ return{
6307
+ pieces:{${ruleEntries.join(",")}},
6308
+ byIp:{${extra.join(",")}},
6309
+ end:function(){return EC.e},
6310
+ begin:_begin,
6311
+ finish:_finish
6312
+ }`;
6313
+ return {
6314
+ source,
6315
+ reached,
6316
+ masks,
6317
+ classes,
6318
+ armExpected,
6319
+ plan: { classes: classPlan, armExpected: armExpectedPlan, masks: maskPlan }
6320
+ };
6175
6321
  }
6176
- var SHARED_FIELDS = [
6177
- "k",
6178
- "cc",
6179
- "fx",
6180
- "disp",
6181
- "dsp",
6182
- "rules",
6183
- "labels",
6184
- "classified",
6185
- "scanSkip",
6186
- "scanSkipOf",
6187
- "scans",
6188
- "triviaSpecs",
6189
- "runtimeOnly",
6190
- // `rec` is a property of the GRAMMAR BUILD, not of the trackLines/hostMode
6191
- // axis a fold varies — every variant of one export is encoded with the same
6192
- // recovery setting, and a mismatch is two tables, which is what the refusal says.
6193
- "rec",
6194
- // `cov` is a property of the GRAMMAR and its coverage plan, for the same reason
6195
- // `rec` is a property of the build: the plan is built from the rule map, which
6196
- // every variant of one export shares. It ships ONCE, and a variant that
6197
- // disagrees is two tables — which is what the refusal says.
6198
- "cov"
6199
- ];
6200
- function foldPrograms(programs, baseName) {
6201
- const suppliedBase = programs[baseName];
6202
- if (suppliedBase === void 0) throw new TypeError(`foldPrograms: no program named ${JSON.stringify(baseName)}`);
6203
- const base = closureArtifact(suppliedBase);
6204
- const variants = {};
6205
- for (const name of Object.keys(programs)) {
6206
- const p = programs[name];
6207
- if (p.asm !== void 0 && p.asm.length > 0) {
6208
- throw new TypeError(
6209
- `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.`
6210
- );
6211
- }
6212
- if (p.code.length !== base.code.length) {
6213
- throw new TypeError(
6214
- `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.`
6215
- );
6216
- }
6217
- for (const f of SHARED_FIELDS) {
6218
- if (JSON.stringify(p[f]) !== JSON.stringify(base[f])) {
6219
- throw new TypeError(
6220
- `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.`
6221
- );
6222
- }
6223
- }
6224
- if (p.fns.length !== base.fns.length || p.fns.some((f, i) => f !== base.fns[i])) {
6225
- throw new TypeError(
6226
- `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.`
6227
- );
6228
- }
6229
- const at = [];
6230
- const to = [];
6231
- let prev = 0;
6232
- for (let i = 0; i < p.code.length; i++) {
6233
- if (p.code[i] === base.code[i]) continue;
6234
- at.push(i - prev);
6235
- to.push(p.code[i]);
6236
- prev = i;
6237
- }
6238
- variants[name] = {
6239
- at,
6240
- to,
6241
- ...p.lines === void 0 ? {} : { lines: p.lines },
6242
- ...p.hostMode === void 0 ? {} : { hostMode: p.hostMode }
6243
- };
6322
+
6323
+ // src/table/run-support.ts
6324
+ function lineCol(ctx, offset) {
6325
+ const starts = ctx._lineStarts ?? [0];
6326
+ let lo = 0, hi = starts.length - 1;
6327
+ while (lo < hi) {
6328
+ const mid = lo + hi + 1 >> 1;
6329
+ if (starts[mid] <= offset) lo = mid;
6330
+ else hi = mid - 1;
6244
6331
  }
6245
- return ownFoldedProgram(base, variants);
6332
+ return [lo + 1, offset - starts[lo] + 1];
6246
6333
  }
6247
- function unfoldVariant(folded, name) {
6248
- const byName = folded[FOLDED_RUNTIME]?.byName;
6249
- const hit = byName?.get(name);
6250
- if (hit !== void 0) return hit;
6251
- const d = folded.variants[name];
6252
- if (d === void 0) {
6253
- throw new TypeError(
6254
- `unfoldVariant: no variant ${JSON.stringify(name)}. This table carries: ${Object.keys(folded.variants).map((n) => JSON.stringify(n)).join(", ")}.`
6255
- );
6256
- }
6257
- const base = folded.base;
6258
- const code = [...base.code];
6259
- let ip = 0;
6260
- for (let i = 0; i < d.at.length; i++) {
6261
- ip += d.at[i];
6262
- code[ip] = d.to[i];
6334
+ function spanLines(ctx, start, end) {
6335
+ const s = lineCol(ctx, start), e = lineCol(ctx, end);
6336
+ return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] };
6337
+ }
6338
+ function rawEntry(v, input, s, e) {
6339
+ if (typeof v === "object" && v !== null) {
6340
+ const tg = v._tag;
6341
+ if (tg === "node" || tg === "leaf" || tg === "parseError") return v;
6263
6342
  }
6264
- const raw = {
6265
- ...base,
6266
- code,
6267
- ...d.lines === void 0 ? {} : { lines: d.lines },
6268
- ...d.hostMode === void 0 ? {} : { hostMode: d.hostMode }
6343
+ return {
6344
+ _tag: "leaf",
6345
+ value: typeof v === "string" ? v : typeof v === "object" && v !== null ? input.slice(s, e) : "",
6346
+ span: { start: s, end: e }
6269
6347
  };
6270
- const prog = ownTableProgram(raw);
6271
- const owner = prog[TABLE_RUNTIME];
6272
- owner.resolved = { ...resolveTable(base), prog, code: Int32Array.from(code) };
6273
- byName?.set(name, prog);
6274
- return prog;
6275
6348
  }
6276
- function expandCompactFolded(f) {
6277
- const variants = {};
6278
- for (const name of Object.keys(f.v)) {
6279
- const d = f.v[name];
6280
- variants[name] = {
6281
- at: d.a ?? [],
6282
- to: d.t ?? [],
6283
- ...d.l === void 0 ? {} : { lines: d.l },
6284
- ...d.h === void 0 ? {} : { hostMode: d.h }
6285
- };
6286
- }
6287
- return ownFoldedProgram(expandCompact(f.b), variants);
6349
+ function lead(input, pos) {
6350
+ if (pos >= input.length) return -1;
6351
+ const c = input.charCodeAt(pos);
6352
+ if (c < 55296 || c > 56319) return c;
6353
+ return input.codePointAt(pos) ?? c;
6288
6354
  }
6289
6355
 
6290
6356
  // src/cst/host-mode.ts
@@ -6332,7 +6398,7 @@ function committed(c) {
6332
6398
  }
6333
6399
  function stampRuleMap(prog, d, artifactMetadata = {}, resolved = resolveTable(prog)) {
6334
6400
  const triviaOfRule = (ip) => {
6335
- if (prog.code[ip] !== OP_SCOPE) return void 0;
6401
+ if (prog.code[ip] !== OP_SCOPE_PLAIN && prog.code[ip] !== OP_SCOPE) return void 0;
6336
6402
  const slot = prog.code[ip + 1];
6337
6403
  return slot < 0 ? void 0 : resolved.trivia[slot];
6338
6404
  };
@@ -6552,20 +6618,19 @@ function assemble(t, prog, cfg) {
6552
6618
  TERMV = v2;
6553
6619
  return EC.e > scanEnd2 ? EC.e : cur;
6554
6620
  }
6555
- const need = markCst(ctx);
6556
- const mRaw = MRAW;
6557
- const mTl = MTL;
6558
- const mLv = MLV;
6559
- const mFl = need ? ctx._fields?.length ?? 0 : 0;
6560
- const mEr = need ? ctx._errors?.length ?? 0 : 0;
6621
+ const need = rollbackNeeded(ctx);
6622
+ const mTl = need ? cstTlLen(ctx) : 0;
6561
6623
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
6562
6624
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
6563
6625
  const scanEnd = skipTrivia(input, cur, ctx);
6626
+ const scanTl = need ? cstTlLen(ctx) : 0;
6627
+ const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0;
6628
+ const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
6564
6629
  const v = child(input, scanEnd, ctx);
6565
6630
  if (v === FAIL) return -1;
6566
6631
  TERMV = v;
6567
6632
  if (EC.e > scanEnd) return EC.e;
6568
- if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
6633
+ if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
6569
6634
  return cur;
6570
6635
  }
6571
6636
  function committed2(c) {
@@ -6979,7 +7044,8 @@ function assemble(t, prog, cfg) {
6979
7044
  };
6980
7045
  }
6981
7046
  case OP_SCOPE:
6982
- case OP_SCOPE_CAP: {
7047
+ case OP_SCOPE_CAP:
7048
+ case OP_SCOPE_PLAIN: {
6983
7049
  const ki = code[ip + 1];
6984
7050
  const scopeTrivia = ki < 0 ? void 0 : trivia2[ki];
6985
7051
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels;
@@ -7013,7 +7079,7 @@ function assemble(t, prog, cfg) {
7013
7079
  SCAN = savedScan;
7014
7080
  return v;
7015
7081
  };
7016
- return scopeRootPolicy(scopePiece, code[ip + 3]);
7082
+ return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]);
7017
7083
  }
7018
7084
  case OP_ROUTED: {
7019
7085
  const fb = code[ip + 1];
@@ -7929,15 +7995,21 @@ function assemble(t, prog, cfg) {
7929
7995
  target = arms[arm];
7930
7996
  usesRouted = routed[arm] === 1;
7931
7997
  }
7932
- const savedRouted = ctx._routed;
7933
7998
  let mark = saveTriviaMark(ctx);
7999
+ let v;
7934
8000
  if (usesRouted) {
8001
+ const savedRouted = ctx._routed;
7935
8002
  rollbackTrivia(ctx, selectorMark);
7936
8003
  mark = saveTriviaMark(ctx);
7937
8004
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
8005
+ try {
8006
+ v = target(input, pos, ctx);
8007
+ } finally {
8008
+ ctx._routed = savedRouted;
8009
+ }
8010
+ } else {
8011
+ v = target(input, selEnd, ctx);
7938
8012
  }
7939
- const v = target(input, usesRouted ? pos : selEnd, ctx);
7940
- if (usesRouted) ctx._routed = savedRouted;
7941
8013
  if (v === FAIL) {
7942
8014
  rollbackTrivia(ctx, mark);
7943
8015
  ctx._fc = true;
@@ -8083,6 +8155,11 @@ function assemble(t, prog, cfg) {
8083
8155
  if (s.sentinel !== void 0) extraIps.push(s.sentinel[0]);
8084
8156
  }
8085
8157
  for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
8158
+ const validationRoots = [...Object.values(prog.rules), ...extraIps];
8159
+ for (const ip of reachableSites(code, validationRoots)) {
8160
+ if (code[ip] !== OP_DISPATCH) continue;
8161
+ validateDispatchSpec(dsp[code[ip + 2]], code[ip + 5], code[ip + 4]);
8162
+ }
8086
8163
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
8087
8164
  if (pre !== void 0) {
8088
8165
  const pools = rebuildPools(t.cc, t.fx, pre.plan);
@@ -8109,6 +8186,7 @@ function assemble(t, prog, cfg) {
8109
8186
  pushCstLeaf,
8110
8187
  pushCstChild,
8111
8188
  rollbackTriviaAt,
8189
+ rollbackScannedTriviaAt,
8112
8190
  failAt,
8113
8191
  classHas,
8114
8192
  consumeTrivia,
@@ -8179,6 +8257,7 @@ function assemble(t, prog, cfg) {
8179
8257
  pushCstLeaf,
8180
8258
  pushCstChild,
8181
8259
  rollbackTriviaAt,
8260
+ rollbackScannedTriviaAt,
8182
8261
  failAt,
8183
8262
  classHas,
8184
8263
  consumeTrivia,
@@ -8868,7 +8947,7 @@ var Encoder = class {
8868
8947
  this.carryTriviaMeta(amb);
8869
8948
  this.carryTriviaMeta(p);
8870
8949
  if (p._def.tag === "grammar") this.carryTriviaMeta(p._def.triviaParser);
8871
- this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE, this.triviaSlot(amb), body);
8950
+ this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), body);
8872
8951
  }
8873
8952
  /**
8874
8953
  * The row a cross-rule `g.X` reference jumps to — the target's body, RE-WRAPPED
@@ -8911,7 +8990,7 @@ var Encoder = class {
8911
8990
  const amb = p._meta.grammarTrivia ?? target._meta.grammarTrivia;
8912
8991
  if (amb === void 0 || this.activeTrivia !== void 0) return ip;
8913
8992
  if (!hasOwnTriviaBoundary(target)) return ip;
8914
- return this.emit(OP_SCOPE, this.triviaSlot(amb), ip);
8993
+ return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
8915
8994
  }
8916
8995
  node(p) {
8917
8996
  const lazyRef = p._def.tag === "lazy";
@@ -9316,6 +9395,7 @@ var Encoder = class {
9316
9395
  return [ip + 1];
9317
9396
  case OP_SCOPE:
9318
9397
  case OP_SCOPE_CAP:
9398
+ case OP_SCOPE_PLAIN:
9319
9399
  case OP_WITHCTX:
9320
9400
  case OP_XFORM:
9321
9401
  case OP_LEAF:
@@ -9455,6 +9535,14 @@ function encodeTableProgram(ruleMap, settings = {}) {
9455
9535
  function jsString(s) {
9456
9536
  return JSON.stringify(s);
9457
9537
  }
9538
+ function emitClassPool(classes) {
9539
+ const array = `[${classes.map(jsString).join(",")}]`;
9540
+ if (classes.length < 2) return array;
9541
+ const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
9542
+ if (delimiter === void 0) return array;
9543
+ const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
9544
+ return split.length < array.length ? split : array;
9545
+ }
9458
9546
  function emitConst(v) {
9459
9547
  if (v instanceof RegExp) return `/${v.source}/${v.flags}`;
9460
9548
  if (typeof v === "string") return jsString(v);
@@ -9533,7 +9621,7 @@ function programFields(prog, fns, opts = {}) {
9533
9621
  ...emitAssemblies(prog, opts.assemblies ?? []),
9534
9622
  `c:[${prog.code.join(",")}],`,
9535
9623
  `k:[${prog.k.map(emitConst).join(",")}],`,
9536
- `x:[${prog.cc.map(jsString).join(",")}],`,
9624
+ `x:${emitClassPool(prog.cc)},`,
9537
9625
  `e:[${prog.fx.map((f) => `[${f.map(jsString).join(",")}]`).join(",")}],`,
9538
9626
  `d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
9539
9627
  `r:${JSON.stringify(prog.rules)},`,