parseman 0.58.2 → 0.58.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/analysis/diagnostics.js +203 -37
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +203 -37
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/first-set.d.ts.map +1 -1
  6. package/dist/combinators/regex.d.ts.map +1 -1
  7. package/dist/compiler/token-capability.js +28 -4
  8. package/dist/compiler/token-capability.js.map +2 -2
  9. package/dist/compiler/token-scanner.d.ts.map +1 -1
  10. package/dist/index.js +207 -41
  11. package/dist/index.js.map +3 -3
  12. package/dist/language-service/index.js +10 -3
  13. package/dist/language-service/index.js.map +2 -2
  14. package/dist/lead-ranges.d.ts +26 -0
  15. package/dist/lead-ranges.d.ts.map +1 -0
  16. package/dist/plugin/index.js +207 -41
  17. package/dist/plugin/index.js.map +3 -3
  18. package/dist/recovery/scan.d.ts.map +1 -1
  19. package/dist/regex/classes.d.ts +5 -3
  20. package/dist/regex/classes.d.ts.map +1 -1
  21. package/dist/regex/first-set.d.ts +7 -1
  22. package/dist/regex/first-set.d.ts.map +1 -1
  23. package/dist/run/index.js +10 -3
  24. package/dist/run/index.js.map +2 -2
  25. package/dist/table/assemble.d.ts.map +1 -1
  26. package/dist/table/compile-rule-map.d.ts.map +1 -1
  27. package/dist/table/emit-assembly.d.ts +8 -1
  28. package/dist/table/emit-assembly.d.ts.map +1 -1
  29. package/dist/table/encode-baseline.d.ts.map +1 -1
  30. package/dist/table/index.js +206 -40
  31. package/dist/table/index.js.map +3 -3
  32. package/dist/table/program.d.ts.map +1 -1
  33. package/dist/table/scan-shapes.d.ts +1 -1
  34. package/dist/table/scan-shapes.d.ts.map +1 -1
  35. package/dist/table/site-labels.d.ts.map +1 -1
  36. package/dist/table/trivia-gap.d.ts +11 -1
  37. package/dist/table/trivia-gap.d.ts.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/package.json +1 -1
  40. package/src/combinators/choice.ts +4 -0
  41. package/src/combinators/first-set.ts +13 -4
  42. package/src/combinators/regex.ts +28 -9
  43. package/src/compiler/token-scanner.ts +4 -1
  44. package/src/lead-ranges.ts +53 -0
  45. package/src/recovery/scan.ts +2 -3
  46. package/src/regex/classes.ts +22 -7
  47. package/src/regex/first-set.ts +67 -12
  48. package/src/table/assemble.ts +42 -3
  49. package/src/table/compile-rule-map.ts +5 -3
  50. package/src/table/emit-assembly.ts +42 -8
  51. package/src/table/encode-baseline.ts +2 -1
  52. package/src/table/program.ts +2 -1
  53. package/src/table/scan-shapes.ts +5 -2
  54. package/src/table/site-labels.ts +2 -1
  55. package/src/table/trivia-gap.ts +19 -0
  56. package/src/version.ts +1 -1
@@ -1,3 +1,32 @@
1
+ // src/lead-ranges.ts
2
+ function rangesHaveLead(ranges, code) {
3
+ for (const r of ranges) if (code >= r.lo && code <= r.hi) return true;
4
+ if (code <= 65535) return false;
5
+ const high = 55296 + (code - 65536 >> 10);
6
+ for (const r of ranges) if (high >= r.lo && high <= r.hi) return true;
7
+ return false;
8
+ }
9
+ function leadRanges(ranges) {
10
+ let out;
11
+ for (const r of ranges) {
12
+ const lo = Math.max(r.lo, 55296), hi = Math.min(r.hi, 56319);
13
+ if (lo <= hi) (out ??= [...ranges]).push({ lo: 65536 + (lo - 55296 << 10), hi: 65536 + (hi - 55296 << 10) + 1023 });
14
+ }
15
+ return out ?? ranges;
16
+ }
17
+ function implicitLeadsDropped(ranges) {
18
+ const implied = leadRanges(ranges.filter((r) => r.lo <= 65535)).filter((r) => r.lo > 65535);
19
+ const out = [];
20
+ for (const r of ranges) {
21
+ let pieces = [{ lo: r.lo, hi: r.hi }];
22
+ if (r.hi > 65535) for (const c of implied) {
23
+ pieces = pieces.flatMap((q2) => q2.hi < c.lo || q2.lo > c.hi ? [q2] : [...q2.lo < c.lo ? [{ lo: q2.lo, hi: c.lo - 1 }] : [], ...q2.hi > c.hi ? [{ lo: c.hi + 1, hi: q2.hi }] : []]);
24
+ }
25
+ out.push(...pieces);
26
+ }
27
+ return out;
28
+ }
29
+
1
30
  // src/combinators/first-set.ts
2
31
  function classifyFinalChoice(arms, resolve, activeTrivia) {
3
32
  const firstSets = [];
@@ -59,8 +88,9 @@ function union(a, b) {
59
88
  function intersects(a, b) {
60
89
  if (a.kind === "any" || b.kind === "any") return true;
61
90
  if (a.kind === "empty" || b.kind === "empty") return false;
62
- for (const ra of a.ranges) {
63
- for (const rb of b.ranges) {
91
+ const bs = leadRanges(b.ranges);
92
+ for (const ra of leadRanges(a.ranges)) {
93
+ for (const rb of bs) {
64
94
  if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
65
95
  }
66
96
  }
@@ -76,6 +106,9 @@ function startsFirstSet(combinator, input, pos) {
76
106
  const code = input.codePointAt(pos);
77
107
  if (code === void 0) return false;
78
108
  for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
109
+ if (code <= 65535) return false;
110
+ const high = 55296 + (code - 65536 >> 10);
111
+ for (const r of fs.ranges) if (high >= r.lo && high <= r.hi) return true;
79
112
  return false;
80
113
  }
81
114
  function fromRange(lo, hi) {
@@ -176,12 +209,13 @@ function narrowBy(acc, constraint) {
176
209
  if (acc.kind === "any") return constraint;
177
210
  if (acc.kind === "empty" || constraint.kind === "empty") return { kind: "empty" };
178
211
  const ranges = [];
179
- for (const a of acc.ranges) for (const b of constraint.ranges) {
212
+ const bs = leadRanges(constraint.ranges);
213
+ for (const a of leadRanges(acc.ranges)) for (const b of bs) {
180
214
  const lo = Math.max(a.lo, b.lo);
181
215
  const hi = Math.min(a.hi, b.hi);
182
216
  if (lo <= hi) ranges.push({ lo, hi });
183
217
  }
184
- return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
218
+ return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges: implicitLeadsDropped(ranges) };
185
219
  }
186
220
  function applyAssertion(fs, assertion) {
187
221
  return assertion === null ? fs : fs.kind === "empty" ? assertion : narrowBy(fs, assertion);
@@ -717,11 +751,17 @@ function shorthandRanges(ch2) {
717
751
  if (ch2 === "s") return SPACE_RANGES;
718
752
  return [[48, 57], [65, 90], [97, 122], [95, 95]];
719
753
  }
720
- function readUnicodeEscape(body, i) {
754
+ function readUnicodeEscape(body, i, unicode = false) {
721
755
  if (body[i] !== "\\" || body[i + 1] !== "u") return null;
722
756
  const hex = body.slice(i + 2, i + 6);
723
757
  if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
724
- return { cp: Number.parseInt(hex, 16), next: i + 6 };
758
+ const cp = Number.parseInt(hex, 16);
759
+ if (unicode && cp >= 55296 && cp <= 56319 && body[i + 6] === "\\" && body[i + 7] === "u") {
760
+ const lowHex = body.slice(i + 8, i + 12);
761
+ const low = /^[0-9a-fA-F]{4}$/.test(lowHex) ? Number.parseInt(lowHex, 16) : -1;
762
+ if (low >= 56320 && low <= 57343) return { cp: 65536 + (cp - 55296 << 10) + (low - 56320), next: i + 12 };
763
+ }
764
+ return { cp, next: i + 6 };
725
765
  }
726
766
  var META = new Set("()[]{}*+?|^$.".split(""));
727
767
  function literalCodePoints(frag) {
@@ -733,6 +773,7 @@ function literalCodePoints(frag) {
733
773
  const e = frag[i + 1];
734
774
  if (e === void 0) return null;
735
775
  if (!(e in CLASS_ESCAPES) && /\w/.test(e)) return null;
776
+ if (e === "0" && frag[i + 2] !== void 0 && frag[i + 2] >= "0" && frag[i + 2] <= "9") return null;
736
777
  out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
737
778
  i += 2;
738
779
  continue;
@@ -773,14 +814,14 @@ function parseClassOperand(body) {
773
814
  if (cps && cps.length === 1) return { ranges: [[cps[0], cps[0]]], negated: false };
774
815
  return null;
775
816
  }
776
- function parseClassRanges(body) {
817
+ function parseClassRanges(body, unicode = false) {
777
818
  const ranges = [];
778
819
  let i = 0;
779
820
  const readAtom = () => {
780
821
  const ch2 = body[i];
781
822
  if (ch2 === void 0) return null;
782
823
  if (ch2 === "\\") {
783
- const uni = readUnicodeEscape(body, i);
824
+ const uni = readUnicodeEscape(body, i, unicode);
784
825
  if (uni) {
785
826
  i = uni.next;
786
827
  return { cp: uni.cp };
@@ -788,13 +829,15 @@ function parseClassRanges(body) {
788
829
  const e = body[i + 1];
789
830
  if (e === void 0) return null;
790
831
  i += 2;
832
+ if (e === "0" && body[i] !== void 0 && body[i] >= "0" && body[i] <= "9" || e >= "1" && e <= "9") return null;
791
833
  if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
792
834
  if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
793
835
  if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
794
836
  return { cp: e.codePointAt(0) };
795
837
  }
796
- i += ch2.length;
797
- return { cp: ch2.codePointAt(0) };
838
+ const cp = unicode ? body.codePointAt(i) : body.charCodeAt(i);
839
+ i += cp > 65535 ? 2 : 1;
840
+ return { cp };
798
841
  };
799
842
  while (i < body.length) {
800
843
  const lo = readAtom();
@@ -2475,9 +2518,7 @@ function firstSetSentinel(fs) {
2475
2518
  parse(input, pos) {
2476
2519
  const code = pos < input.length ? input.codePointAt(pos) : void 0;
2477
2520
  if (code !== void 0) {
2478
- for (const r of ranges) {
2479
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
2480
- }
2521
+ if (rangesHaveLead(ranges, code)) return { ok: true, value: null, span: { start: pos, end: pos } };
2481
2522
  }
2482
2523
  return { ok: false, expected: [], span: { start: pos, end: pos } };
2483
2524
  }
@@ -2915,6 +2956,9 @@ function inFirstSet(code, fs) {
2915
2956
  if (fs.kind === "any") return true;
2916
2957
  if (fs.kind === "empty") return false;
2917
2958
  for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
2959
+ if (code <= 65535) return false;
2960
+ const high = 55296 + (code - 65536 >> 10);
2961
+ for (const r of fs.ranges) if (high >= r.lo && high <= r.hi) return true;
2918
2962
  return false;
2919
2963
  }
2920
2964
  function areDisjoint(sets) {
@@ -3479,7 +3523,7 @@ function rangesHaveNewline(ranges) {
3479
3523
  return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
3480
3524
  }
3481
3525
  var BAIL = /* @__PURE__ */ Symbol("regex-bail");
3482
- function parseRegex(src) {
3526
+ function parseRegex(src, unicode = false, sets = false) {
3483
3527
  let i = 0;
3484
3528
  const parseAlt = () => {
3485
3529
  const arms = [parseSeq()];
@@ -3549,9 +3593,11 @@ function parseRegex(src) {
3549
3593
  i++;
3550
3594
  return charNode(fromRange(123, 123), false);
3551
3595
  // a `{` with nothing to quantify is a literal brace
3552
- default:
3553
- i += ch2.length;
3554
- return charNode(fromRange(ch2.codePointAt(0), ch2.codePointAt(0)), ch2 === "\n");
3596
+ default: {
3597
+ const cp = unicode ? src.codePointAt(i) : src.charCodeAt(i);
3598
+ i += cp > 65535 ? 2 : 1;
3599
+ return charNode(fromRange(cp, cp), ch2 === "\n");
3600
+ }
3555
3601
  }
3556
3602
  };
3557
3603
  const parseGroup = () => {
@@ -3584,6 +3630,32 @@ function parseRegex(src) {
3584
3630
  let k = i + 1;
3585
3631
  const negated = src[k] === "^";
3586
3632
  if (negated) k++;
3633
+ if (sets) {
3634
+ let depth = 1;
3635
+ let nested = false;
3636
+ while (k < src.length && depth > 0) {
3637
+ const c = src[k];
3638
+ if (c === "\\") {
3639
+ if (src[k + 1] === "q") nested = true;
3640
+ k += 2;
3641
+ continue;
3642
+ }
3643
+ if (c === "[") {
3644
+ depth++;
3645
+ nested = true;
3646
+ } else if (c === "]") {
3647
+ depth--;
3648
+ if (depth === 0) break;
3649
+ } else if ((c === "-" || c === "&") && src[k + 1] === c) nested = true;
3650
+ k++;
3651
+ }
3652
+ if (src[k] !== "]") throw BAIL;
3653
+ if (nested) {
3654
+ i = k + 1;
3655
+ return charNode(any(), true);
3656
+ }
3657
+ k = i + 1 + (negated ? 1 : 0);
3658
+ }
3587
3659
  let body = "";
3588
3660
  while (k < src.length && src[k] !== "]") {
3589
3661
  if (src[k] === "\\") {
@@ -3596,7 +3668,7 @@ function parseRegex(src) {
3596
3668
  }
3597
3669
  if (src[k] !== "]") throw BAIL;
3598
3670
  i = k + 1;
3599
- const ranges = parseClassRanges(body);
3671
+ const ranges = parseClassRanges(body, unicode);
3600
3672
  if (negated) return charNode(any(), !ranges || !rangesHaveNewline(ranges));
3601
3673
  if (!ranges) return charNode(any(), true);
3602
3674
  return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
@@ -3604,9 +3676,20 @@ function parseRegex(src) {
3604
3676
  const parseEscape = () => {
3605
3677
  const e = src[i + 1];
3606
3678
  if (e === void 0) throw BAIL;
3607
- if (e === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(i + 2, i + 6))) {
3608
- const cp = Number.parseInt(src.slice(i + 2, i + 6), 16);
3609
- i += 6;
3679
+ const uni = readUnicodeEscape(src, i, unicode);
3680
+ if (uni !== null) {
3681
+ i = uni.next;
3682
+ return charNode(fromRange(uni.cp, uni.cp), uni.cp === 10);
3683
+ }
3684
+ if (e === "u" && src[i + 2] === "{") {
3685
+ const close = src.indexOf("}", i + 3);
3686
+ const hex = close < 0 ? "" : src.slice(i + 3, close);
3687
+ if (!unicode || !/^[0-9a-fA-F]{1,6}$/.test(hex)) {
3688
+ i += 2;
3689
+ return ANY;
3690
+ }
3691
+ const cp = Number.parseInt(hex, 16);
3692
+ i = close + 1;
3610
3693
  return charNode(fromRange(cp, cp), cp === 10);
3611
3694
  }
3612
3695
  if (e === "x" && /^[0-9a-fA-F]{2}$/.test(src.slice(i + 2, i + 4))) {
@@ -3614,6 +3697,16 @@ function parseRegex(src) {
3614
3697
  i += 4;
3615
3698
  return charNode(fromRange(cp, cp), cp === 10);
3616
3699
  }
3700
+ if (e === "c") {
3701
+ const x = src[i + 2];
3702
+ if (x !== void 0 && /^[A-Za-z]$/.test(x)) {
3703
+ const cp = x.charCodeAt(0) % 32;
3704
+ i += 3;
3705
+ return charNode(fromRange(cp, cp), cp === 10);
3706
+ }
3707
+ i += 2;
3708
+ return ANY;
3709
+ }
3617
3710
  i += 2;
3618
3711
  switch (e) {
3619
3712
  case "d":
@@ -3641,8 +3734,16 @@ function parseRegex(src) {
3641
3734
  return charNode(fromRange(12, 12), false);
3642
3735
  case "v":
3643
3736
  return charNode(fromRange(11, 11), false);
3737
+ // `\0` then a digit is a legacy octal escape (`\012` is a newline), not NUL.
3644
3738
  case "0":
3645
- return charNode(fromRange(0, 0), false);
3739
+ return src[i] !== void 0 && src[i] >= "0" && src[i] <= "9" ? ANY : charNode(fromRange(0, 0), false);
3740
+ // A property escape (`\p{…}`/`\P{…}`) matches one character of a class this
3741
+ // analyzer does not enumerate; `\k<name>` is a backreference, which may match empty.
3742
+ case "p":
3743
+ case "P":
3744
+ return charNode(any(), true);
3745
+ case "k":
3746
+ return ANY;
3646
3747
  default:
3647
3748
  if (e >= "1" && e <= "9") return ANY;
3648
3749
  return charNode(fromRange(e.codePointAt(0), e.codePointAt(0)), e === "\n");
@@ -3716,10 +3817,10 @@ function regexCanMatchEmpty(source) {
3716
3817
  return true;
3717
3818
  }
3718
3819
  }
3719
- function firstSetFromRegex(source) {
3820
+ function firstSetFromRegex(source, flags = "") {
3720
3821
  let ast;
3721
3822
  try {
3722
- ast = parseRegex(source);
3823
+ ast = parseRegex(source, flags.includes("u") || flags.includes("v"), flags.includes("v"));
3723
3824
  } catch {
3724
3825
  return { firstSet: any(), canMatchNewline: true };
3725
3826
  }
@@ -3768,8 +3869,18 @@ function shortScanner(source, flags) {
3768
3869
  return minOne && end === pos ? null : end;
3769
3870
  };
3770
3871
  }
3872
+ function coversNonAscii(ranges) {
3873
+ let next = 128;
3874
+ for (const r of [...ranges].sort((a, b) => a.lo - b.lo)) {
3875
+ if (r.lo > next) return false;
3876
+ if (r.hi >= next) next = r.hi + 1;
3877
+ if (next > 65535) return true;
3878
+ }
3879
+ return false;
3880
+ }
3771
3881
  function asciiCaseFold(fs) {
3772
3882
  if (fs.kind !== "ranges") return fs;
3883
+ if (fs.ranges.some((r) => r.hi >= 128) && !coversNonAscii(fs.ranges)) return any();
3773
3884
  const ranges = fs.ranges.map((r) => ({ lo: r.lo, hi: r.hi }));
3774
3885
  const add = (lo, hi) => {
3775
3886
  if (lo <= hi) ranges.push({ lo, hi });
@@ -3794,7 +3905,7 @@ function regex(pattern, flags = "") {
3794
3905
  const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
3795
3906
  const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
3796
3907
  const scan = shortScanner(source, resolvedFlags);
3797
- const raw = firstSetFromRegex(source);
3908
+ const raw = firstSetFromRegex(source, resolvedFlags);
3798
3909
  const firstSet2 = !resolvedFlags.includes("i") ? raw.firstSet : resolvedFlags.includes("u") || resolvedFlags.includes("v") ? any() : asciiCaseFold(raw.firstSet);
3799
3910
  const canMatchNewline = raw.canMatchNewline;
3800
3911
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
@@ -4576,7 +4687,7 @@ function decodeClassSpec(spec) {
4576
4687
  function resolveClass(spec) {
4577
4688
  const ascii = new Uint8Array(128);
4578
4689
  const hi = [];
4579
- for (const { lo, hi: up } of decodeClassSpec(spec)) {
4690
+ for (const { lo, hi: up } of leadRanges(decodeClassSpec(spec))) {
4580
4691
  if (lo < 128) for (let c = lo; c <= Math.min(up, 127); c++) ascii[c] = 1;
4581
4692
  if (up >= 128) hi.push(Math.max(lo, 128), up);
4582
4693
  }
@@ -8479,6 +8590,7 @@ function parseSeqParts(source) {
8479
8590
  cp2 = uni.cp;
8480
8591
  i = uni.next;
8481
8592
  } else if (e === void 0) return null;
8593
+ else if (e >= "0" && e <= "9" && (e !== "0" || source[i + 2] !== void 0 && source[i + 2] >= "0" && source[i + 2] <= "9")) return null;
8482
8594
  else if (e in CLASS_ESCAPES) {
8483
8595
  cp2 = CLASS_ESCAPES[e];
8484
8596
  i += 2;
@@ -9028,7 +9140,7 @@ function parseScanShapeCore(source) {
9028
9140
  return null;
9029
9141
  }
9030
9142
  function scanShapeFromRegex(source, flags) {
9031
- if (/[msu]/.test(flags)) return null;
9143
+ if (/[msuv]/.test(flags)) return null;
9032
9144
  if (/i/.test(flags)) return caseFoldShape(source);
9033
9145
  return parseScanShape(source);
9034
9146
  }
@@ -9633,7 +9745,7 @@ function triviaLeadRanges(tri, trivia2) {
9633
9745
  const fs = trivia2[tri]?._meta.firstSet;
9634
9746
  if (fs === void 0) return void 0;
9635
9747
  if (fs.kind === "empty") return [];
9636
- return fs.kind === "ranges" && fs.ranges !== void 0 ? fs.ranges : void 0;
9748
+ return fs.kind === "ranges" && fs.ranges !== void 0 ? leadRanges(fs.ranges) : void 0;
9637
9749
  }
9638
9750
 
9639
9751
  // src/table/scalar-terminal.ts
@@ -10163,7 +10275,7 @@ if(ctx._errors!==undefined&&ctx._errors.length!==${t2}er)ctx._errors.length=${t2
10163
10275
  if (!s.fd && !s.er) return `if(${t2}n)rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,undefined,undefined,${t2}lg,${t2}rt)`;
10164
10276
  return `if(${t2}n){rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,${s.fd ? `${t2}fd` : "undefined"},${s.er ? `${t2}er` : "undefined"},${t2}lg,${t2}rt)}`;
10165
10277
  }
10166
- function emitTerm(callee, dst, t2, l, skip) {
10278
+ function emitTerm(callee, dst, t2, l, skip, miss) {
10167
10279
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
10168
10280
  if(${t2}v===FAIL)return FAIL
10169
10281
  ${dst}=${t2}v
@@ -10181,7 +10293,12 @@ if(${t2}v===FAIL)return FAIL
10181
10293
  ${dst}=${t2}v
10182
10294
  if(EC.e>${t2}s)cur=EC.e
10183
10295
  else{rollbackScannedTriviaAt(ctx,${t2}tl,${t2}stl,${t2}lg,${t2}slg,${t2}rt,${t2}srt)}`;
10184
- if (l.tri !== TRI_UNKNOWN) return scanned;
10296
+ if (l.tri !== TRI_UNKNOWN) return miss === void 0 ? scanned : `const ${t2}c=input.charCodeAt(cur)
10297
+ if(${miss(`${t2}c`)}){
10298
+ ${fast}
10299
+ }else{
10300
+ ${scanned}
10301
+ }`;
10185
10302
  return `if(ctx.trivia===undefined){
10186
10303
  ${fast}
10187
10304
  }else{
@@ -10237,7 +10354,7 @@ function rebuildPools(cc, fx, disp, plan) {
10237
10354
  })
10238
10355
  };
10239
10356
  }
10240
- function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, select) {
10357
+ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, select, scanSinkNeutral = false) {
10241
10358
  const { code, k, fx, disp, dsp, triviaLabelled } = t2;
10242
10359
  const swapLegal = !cfg.trackLines;
10243
10360
  const hostCst = cfg.hostCst;
@@ -10313,7 +10430,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
10313
10430
  const op = code[ip];
10314
10431
  sinkBits.set(
10315
10432
  ip,
10316
- op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC && (op === OP_REP || op === OP_REPV) ? 2 : 0)
10433
+ op === OP_SCAN || !scanSinkNeutral && op === OP_LEX_PROGRAM && t2.lexPrograms[code[ip + 1]].scan !== void 0 ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC && (op === OP_REP || op === OP_REPV) ? 2 : 0)
10317
10434
  );
10318
10435
  }
10319
10436
  const sinkKids = [];
@@ -10486,6 +10603,12 @@ return 1
10486
10603
  return `if(${gateMissTest(child)}){${miss}}
10487
10604
  `;
10488
10605
  }
10606
+ function triviaMiss(ki) {
10607
+ const leads = triviaLeadRanges(ki, t2.trivia);
10608
+ if (leads === void 0 || leads.length > 16) return void 0;
10609
+ if (leads.length === 0) return (c) => `${c}<55296`;
10610
+ return (c) => `${c}<55296&&!(${leads.map((r) => r.lo === r.hi ? `${c}===${r.lo}` : `(${c}>=${r.lo}&&${c}<=${r.hi})`).join("||")})`;
10611
+ }
10489
10612
  function skipFor(l) {
10490
10613
  if (l.tri < 0) return "_skipTrivia";
10491
10614
  const ki = l.tri;
@@ -10496,8 +10619,13 @@ return 1
10496
10619
  const nm = `_sk${skipPool.size}`;
10497
10620
  skipPool.set(key, nm);
10498
10621
  if (!hasScan) {
10499
- skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return skipDeferredTrivia(input,cur,ctx)}` : `function ${nm}(input,cur,ctx){
10500
- if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
10622
+ const miss = triviaMiss(ki);
10623
+ const pre = miss === void 0 ? "" : `const c=input.charCodeAt(cur)
10624
+ if(${miss("c")})return cur
10625
+ `;
10626
+ skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){${pre === "" ? "" : `
10627
+ ${pre}`}return skipDeferredTrivia(input,cur,ctx)}` : `function ${nm}(input,cur,ctx){
10628
+ ${pre}if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
10501
10629
  return advanceTrivia(input,cur,ctx)}`);
10502
10630
  return nm;
10503
10631
  }
@@ -11081,7 +11209,7 @@ return v
11081
11209
  );
11082
11210
  } else {
11083
11211
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
11084
- parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L)));
11212
+ parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
11085
11213
  }
11086
11214
  names.push(vn);
11087
11215
  }
@@ -12415,6 +12543,15 @@ function skipDeferredTrivia(input, cur, ctx) {
12415
12543
  if (plain2) remember(cur, scan, ctx, input, triviaP);
12416
12544
  return scan;
12417
12545
  }
12546
+ function triviaLeadTable(triviaP) {
12547
+ const fs = triviaP._meta.firstSet;
12548
+ if (fs.kind === "any") return null;
12549
+ const table = new Uint8Array(128);
12550
+ if (fs.kind === "ranges") {
12551
+ for (const r of fs.ranges) for (let c = Math.max(0, r.lo); c <= Math.min(127, r.hi); c++) table[c] = 1;
12552
+ }
12553
+ return table;
12554
+ }
12418
12555
  function clearRunEnd(input, cur, ctx, triviaP, plain2) {
12419
12556
  const rootKinds = ctx._rootTriviaKindIndex;
12420
12557
  const spec = triviaP?._meta.labeledTriviaSpec;
@@ -13075,7 +13212,23 @@ function assemble(t2, prog, cfg) {
13075
13212
  }
13076
13213
  return out;
13077
13214
  }
13215
+ const LEAD_TABLES = trivia2.map((tp) => tp === void 0 ? null : triviaLeadTable(tp));
13216
+ let LEAD_OF;
13217
+ let LEAD_TABLE = null;
13218
+ function cannotStartTrivia(input, cur, triviaP) {
13219
+ if (triviaP !== LEAD_OF) {
13220
+ LEAD_OF = triviaP;
13221
+ const slot = trivia2.indexOf(triviaP);
13222
+ LEAD_TABLE = slot >= 0 ? LEAD_TABLES[slot] : triviaLeadTable(triviaP);
13223
+ }
13224
+ const table = LEAD_TABLE;
13225
+ if (table === null) return false;
13226
+ const c = input.charCodeAt(cur);
13227
+ return c < 128 && table[c] === 0;
13228
+ }
13078
13229
  function skipTrivia(input, cur, ctx) {
13230
+ const t3 = ctx.trivia;
13231
+ if (t3 !== void 0 && cannotStartTrivia(input, cur, t3)) return cur;
13079
13232
  const s = SCAN;
13080
13233
  if (s !== null && ctx._triviaLog === void 0 && !(ctx.captureTrivia === true && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0))) {
13081
13234
  return s(input, cur);
@@ -13090,7 +13243,8 @@ function assemble(t2, prog, cfg) {
13090
13243
  const frames = [];
13091
13244
  let depth = 0;
13092
13245
  function nextTerm(child, input, cur, ctx) {
13093
- if (ctx.trivia === void 0) {
13246
+ const t3 = ctx.trivia;
13247
+ if (t3 === void 0 || cannotStartTrivia(input, cur, t3)) {
13094
13248
  const v2 = child(input, cur, ctx);
13095
13249
  if (v2 === FAIL) return -1;
13096
13250
  TERMV = v2;
@@ -13119,7 +13273,8 @@ function assemble(t2, prog, cfg) {
13119
13273
  return cur;
13120
13274
  }
13121
13275
  function nextTermBuffered(child, input, cur, ctx) {
13122
- if (ctx.trivia === void 0) {
13276
+ const t3 = ctx.trivia;
13277
+ if (t3 === void 0 || cannotStartTrivia(input, cur, t3)) {
13123
13278
  const v2 = child(input, cur, ctx);
13124
13279
  if (v2 === FAIL) return -1;
13125
13280
  TERMV = v2;
@@ -13921,6 +14076,7 @@ function assemble(t2, prog, cfg) {
13921
14076
  const scopeTrivia = ki < 0 ? void 0 : trivia2[ki];
13922
14077
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels;
13923
14078
  const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? triviaScan[ki] : null;
14079
+ const scopeLead = ki < 0 ? null : LEAD_TABLES[ki];
13924
14080
  const child = link(code[ip + 2]);
13925
14081
  const scopePiece = code[ip] === OP_SCOPE_CAP ? (input, pos, ctx) => {
13926
14082
  const saved = ctx.trivia;
@@ -13928,6 +14084,9 @@ function assemble(t2, prog, cfg) {
13928
14084
  const savedScan = SCAN;
13929
14085
  const savedCap = ctx.captureTrivia;
13930
14086
  SCAN = scanFor;
14087
+ const savedLeadOf = LEAD_OF, savedLead = LEAD_TABLE;
14088
+ LEAD_OF = scopeTrivia;
14089
+ LEAD_TABLE = scopeLead;
13931
14090
  ctx.trivia = scopeTrivia;
13932
14091
  ctx.triviaKindLabels = scopeLabels;
13933
14092
  ctx.captureTrivia = true;
@@ -13936,18 +14095,25 @@ function assemble(t2, prog, cfg) {
13936
14095
  ctx.trivia = saved;
13937
14096
  ctx.triviaKindLabels = savedLabels;
13938
14097
  SCAN = savedScan;
14098
+ LEAD_OF = savedLeadOf;
14099
+ LEAD_TABLE = savedLead;
13939
14100
  return v;
13940
14101
  } : (input, pos, ctx) => {
13941
14102
  const saved = ctx.trivia;
13942
14103
  const savedLabels = ctx.triviaKindLabels;
13943
14104
  const savedScan = SCAN;
13944
14105
  SCAN = scanFor;
14106
+ const savedLeadOf = LEAD_OF, savedLead = LEAD_TABLE;
14107
+ LEAD_OF = scopeTrivia;
14108
+ LEAD_TABLE = scopeLead;
13945
14109
  ctx.trivia = scopeTrivia;
13946
14110
  ctx.triviaKindLabels = scopeLabels;
13947
14111
  const v = child(input, pos, ctx);
13948
14112
  ctx.trivia = saved;
13949
14113
  ctx.triviaKindLabels = savedLabels;
13950
14114
  SCAN = savedScan;
14115
+ LEAD_OF = savedLeadOf;
14116
+ LEAD_TABLE = savedLead;
13951
14117
  return v;
13952
14118
  };
13953
14119
  return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]);