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
package/dist/cli/index.js CHANGED
@@ -6,6 +6,35 @@ import { resolve, relative, join, extname } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
  import * as nodeModule from "node:module";
8
8
 
9
+ // src/lead-ranges.ts
10
+ function rangesHaveLead(ranges, code) {
11
+ for (const r of ranges) if (code >= r.lo && code <= r.hi) return true;
12
+ if (code <= 65535) return false;
13
+ const high = 55296 + (code - 65536 >> 10);
14
+ for (const r of ranges) if (high >= r.lo && high <= r.hi) return true;
15
+ return false;
16
+ }
17
+ function leadRanges(ranges) {
18
+ let out;
19
+ for (const r of ranges) {
20
+ const lo = Math.max(r.lo, 55296), hi = Math.min(r.hi, 56319);
21
+ if (lo <= hi) (out ??= [...ranges]).push({ lo: 65536 + (lo - 55296 << 10), hi: 65536 + (hi - 55296 << 10) + 1023 });
22
+ }
23
+ return out ?? ranges;
24
+ }
25
+ function implicitLeadsDropped(ranges) {
26
+ const implied = leadRanges(ranges.filter((r) => r.lo <= 65535)).filter((r) => r.lo > 65535);
27
+ const out = [];
28
+ for (const r of ranges) {
29
+ let pieces = [{ lo: r.lo, hi: r.hi }];
30
+ if (r.hi > 65535) for (const c of implied) {
31
+ 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 }] : []]);
32
+ }
33
+ out.push(...pieces);
34
+ }
35
+ return out;
36
+ }
37
+
9
38
  // src/combinators/first-set.ts
10
39
  function classifyFinalChoice(arms, resolve2, activeTrivia) {
11
40
  const firstSets = [];
@@ -67,8 +96,9 @@ function union(a, b) {
67
96
  function intersects(a, b) {
68
97
  if (a.kind === "any" || b.kind === "any") return true;
69
98
  if (a.kind === "empty" || b.kind === "empty") return false;
70
- for (const ra of a.ranges) {
71
- for (const rb of b.ranges) {
99
+ const bs = leadRanges(b.ranges);
100
+ for (const ra of leadRanges(a.ranges)) {
101
+ for (const rb of bs) {
72
102
  if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
73
103
  }
74
104
  }
@@ -84,6 +114,9 @@ function startsFirstSet(combinator, input, pos) {
84
114
  const code = input.codePointAt(pos);
85
115
  if (code === void 0) return false;
86
116
  for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
117
+ if (code <= 65535) return false;
118
+ const high = 55296 + (code - 65536 >> 10);
119
+ for (const r of fs.ranges) if (high >= r.lo && high <= r.hi) return true;
87
120
  return false;
88
121
  }
89
122
  function fromRange(lo, hi) {
@@ -184,12 +217,13 @@ function narrowBy(acc, constraint) {
184
217
  if (acc.kind === "any") return constraint;
185
218
  if (acc.kind === "empty" || constraint.kind === "empty") return { kind: "empty" };
186
219
  const ranges = [];
187
- for (const a of acc.ranges) for (const b of constraint.ranges) {
220
+ const bs = leadRanges(constraint.ranges);
221
+ for (const a of leadRanges(acc.ranges)) for (const b of bs) {
188
222
  const lo = Math.max(a.lo, b.lo);
189
223
  const hi = Math.min(a.hi, b.hi);
190
224
  if (lo <= hi) ranges.push({ lo, hi });
191
225
  }
192
- return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
226
+ return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges: implicitLeadsDropped(ranges) };
193
227
  }
194
228
  function applyAssertion(fs, assertion) {
195
229
  return assertion === null ? fs : fs.kind === "empty" ? assertion : narrowBy(fs, assertion);
@@ -987,11 +1021,17 @@ function shorthandRanges(ch2) {
987
1021
  if (ch2 === "s") return SPACE_RANGES;
988
1022
  return [[48, 57], [65, 90], [97, 122], [95, 95]];
989
1023
  }
990
- function readUnicodeEscape(body, i) {
1024
+ function readUnicodeEscape(body, i, unicode = false) {
991
1025
  if (body[i] !== "\\" || body[i + 1] !== "u") return null;
992
1026
  const hex = body.slice(i + 2, i + 6);
993
1027
  if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
994
- return { cp: Number.parseInt(hex, 16), next: i + 6 };
1028
+ const cp = Number.parseInt(hex, 16);
1029
+ if (unicode && cp >= 55296 && cp <= 56319 && body[i + 6] === "\\" && body[i + 7] === "u") {
1030
+ const lowHex = body.slice(i + 8, i + 12);
1031
+ const low = /^[0-9a-fA-F]{4}$/.test(lowHex) ? Number.parseInt(lowHex, 16) : -1;
1032
+ if (low >= 56320 && low <= 57343) return { cp: 65536 + (cp - 55296 << 10) + (low - 56320), next: i + 12 };
1033
+ }
1034
+ return { cp, next: i + 6 };
995
1035
  }
996
1036
  var META = new Set("()[]{}*+?|^$.".split(""));
997
1037
  function literalCodePoints(frag) {
@@ -1003,6 +1043,7 @@ function literalCodePoints(frag) {
1003
1043
  const e = frag[i + 1];
1004
1044
  if (e === void 0) return null;
1005
1045
  if (!(e in CLASS_ESCAPES) && /\w/.test(e)) return null;
1046
+ if (e === "0" && frag[i + 2] !== void 0 && frag[i + 2] >= "0" && frag[i + 2] <= "9") return null;
1006
1047
  out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
1007
1048
  i += 2;
1008
1049
  continue;
@@ -1043,14 +1084,14 @@ function parseClassOperand(body) {
1043
1084
  if (cps && cps.length === 1) return { ranges: [[cps[0], cps[0]]], negated: false };
1044
1085
  return null;
1045
1086
  }
1046
- function parseClassRanges(body) {
1087
+ function parseClassRanges(body, unicode = false) {
1047
1088
  const ranges = [];
1048
1089
  let i = 0;
1049
1090
  const readAtom = () => {
1050
1091
  const ch2 = body[i];
1051
1092
  if (ch2 === void 0) return null;
1052
1093
  if (ch2 === "\\") {
1053
- const uni = readUnicodeEscape(body, i);
1094
+ const uni = readUnicodeEscape(body, i, unicode);
1054
1095
  if (uni) {
1055
1096
  i = uni.next;
1056
1097
  return { cp: uni.cp };
@@ -1058,13 +1099,15 @@ function parseClassRanges(body) {
1058
1099
  const e = body[i + 1];
1059
1100
  if (e === void 0) return null;
1060
1101
  i += 2;
1102
+ if (e === "0" && body[i] !== void 0 && body[i] >= "0" && body[i] <= "9" || e >= "1" && e <= "9") return null;
1061
1103
  if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
1062
1104
  if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
1063
1105
  if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1064
1106
  return { cp: e.codePointAt(0) };
1065
1107
  }
1066
- i += ch2.length;
1067
- return { cp: ch2.codePointAt(0) };
1108
+ const cp = unicode ? body.codePointAt(i) : body.charCodeAt(i);
1109
+ i += cp > 65535 ? 2 : 1;
1110
+ return { cp };
1068
1111
  };
1069
1112
  while (i < body.length) {
1070
1113
  const lo = readAtom();
@@ -2502,9 +2545,7 @@ function firstSetSentinel(fs) {
2502
2545
  parse(input, pos) {
2503
2546
  const code = pos < input.length ? input.codePointAt(pos) : void 0;
2504
2547
  if (code !== void 0) {
2505
- for (const r of ranges) {
2506
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
2507
- }
2548
+ if (rangesHaveLead(ranges, code)) return { ok: true, value: null, span: { start: pos, end: pos } };
2508
2549
  }
2509
2550
  return { ok: false, expected: [], span: { start: pos, end: pos } };
2510
2551
  }
@@ -3321,7 +3362,7 @@ function rangesHaveNewline(ranges) {
3321
3362
  return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
3322
3363
  }
3323
3364
  var BAIL = /* @__PURE__ */ Symbol("regex-bail");
3324
- function parseRegex(src) {
3365
+ function parseRegex(src, unicode = false, sets = false) {
3325
3366
  let i = 0;
3326
3367
  const parseAlt = () => {
3327
3368
  const arms = [parseSeq()];
@@ -3391,9 +3432,11 @@ function parseRegex(src) {
3391
3432
  i++;
3392
3433
  return charNode(fromRange(123, 123), false);
3393
3434
  // a `{` with nothing to quantify is a literal brace
3394
- default:
3395
- i += ch2.length;
3396
- return charNode(fromRange(ch2.codePointAt(0), ch2.codePointAt(0)), ch2 === "\n");
3435
+ default: {
3436
+ const cp = unicode ? src.codePointAt(i) : src.charCodeAt(i);
3437
+ i += cp > 65535 ? 2 : 1;
3438
+ return charNode(fromRange(cp, cp), ch2 === "\n");
3439
+ }
3397
3440
  }
3398
3441
  };
3399
3442
  const parseGroup = () => {
@@ -3426,6 +3469,32 @@ function parseRegex(src) {
3426
3469
  let k = i + 1;
3427
3470
  const negated = src[k] === "^";
3428
3471
  if (negated) k++;
3472
+ if (sets) {
3473
+ let depth = 1;
3474
+ let nested = false;
3475
+ while (k < src.length && depth > 0) {
3476
+ const c = src[k];
3477
+ if (c === "\\") {
3478
+ if (src[k + 1] === "q") nested = true;
3479
+ k += 2;
3480
+ continue;
3481
+ }
3482
+ if (c === "[") {
3483
+ depth++;
3484
+ nested = true;
3485
+ } else if (c === "]") {
3486
+ depth--;
3487
+ if (depth === 0) break;
3488
+ } else if ((c === "-" || c === "&") && src[k + 1] === c) nested = true;
3489
+ k++;
3490
+ }
3491
+ if (src[k] !== "]") throw BAIL;
3492
+ if (nested) {
3493
+ i = k + 1;
3494
+ return charNode(any(), true);
3495
+ }
3496
+ k = i + 1 + (negated ? 1 : 0);
3497
+ }
3429
3498
  let body = "";
3430
3499
  while (k < src.length && src[k] !== "]") {
3431
3500
  if (src[k] === "\\") {
@@ -3438,7 +3507,7 @@ function parseRegex(src) {
3438
3507
  }
3439
3508
  if (src[k] !== "]") throw BAIL;
3440
3509
  i = k + 1;
3441
- const ranges = parseClassRanges(body);
3510
+ const ranges = parseClassRanges(body, unicode);
3442
3511
  if (negated) return charNode(any(), !ranges || !rangesHaveNewline(ranges));
3443
3512
  if (!ranges) return charNode(any(), true);
3444
3513
  return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
@@ -3446,9 +3515,20 @@ function parseRegex(src) {
3446
3515
  const parseEscape = () => {
3447
3516
  const e = src[i + 1];
3448
3517
  if (e === void 0) throw BAIL;
3449
- if (e === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(i + 2, i + 6))) {
3450
- const cp = Number.parseInt(src.slice(i + 2, i + 6), 16);
3451
- i += 6;
3518
+ const uni = readUnicodeEscape(src, i, unicode);
3519
+ if (uni !== null) {
3520
+ i = uni.next;
3521
+ return charNode(fromRange(uni.cp, uni.cp), uni.cp === 10);
3522
+ }
3523
+ if (e === "u" && src[i + 2] === "{") {
3524
+ const close = src.indexOf("}", i + 3);
3525
+ const hex = close < 0 ? "" : src.slice(i + 3, close);
3526
+ if (!unicode || !/^[0-9a-fA-F]{1,6}$/.test(hex)) {
3527
+ i += 2;
3528
+ return ANY;
3529
+ }
3530
+ const cp = Number.parseInt(hex, 16);
3531
+ i = close + 1;
3452
3532
  return charNode(fromRange(cp, cp), cp === 10);
3453
3533
  }
3454
3534
  if (e === "x" && /^[0-9a-fA-F]{2}$/.test(src.slice(i + 2, i + 4))) {
@@ -3456,6 +3536,16 @@ function parseRegex(src) {
3456
3536
  i += 4;
3457
3537
  return charNode(fromRange(cp, cp), cp === 10);
3458
3538
  }
3539
+ if (e === "c") {
3540
+ const x = src[i + 2];
3541
+ if (x !== void 0 && /^[A-Za-z]$/.test(x)) {
3542
+ const cp = x.charCodeAt(0) % 32;
3543
+ i += 3;
3544
+ return charNode(fromRange(cp, cp), cp === 10);
3545
+ }
3546
+ i += 2;
3547
+ return ANY;
3548
+ }
3459
3549
  i += 2;
3460
3550
  switch (e) {
3461
3551
  case "d":
@@ -3483,8 +3573,16 @@ function parseRegex(src) {
3483
3573
  return charNode(fromRange(12, 12), false);
3484
3574
  case "v":
3485
3575
  return charNode(fromRange(11, 11), false);
3576
+ // `\0` then a digit is a legacy octal escape (`\012` is a newline), not NUL.
3486
3577
  case "0":
3487
- return charNode(fromRange(0, 0), false);
3578
+ return src[i] !== void 0 && src[i] >= "0" && src[i] <= "9" ? ANY : charNode(fromRange(0, 0), false);
3579
+ // A property escape (`\p{…}`/`\P{…}`) matches one character of a class this
3580
+ // analyzer does not enumerate; `\k<name>` is a backreference, which may match empty.
3581
+ case "p":
3582
+ case "P":
3583
+ return charNode(any(), true);
3584
+ case "k":
3585
+ return ANY;
3488
3586
  default:
3489
3587
  if (e >= "1" && e <= "9") return ANY;
3490
3588
  return charNode(fromRange(e.codePointAt(0), e.codePointAt(0)), e === "\n");
@@ -3558,10 +3656,10 @@ function regexCanMatchEmpty(source) {
3558
3656
  return true;
3559
3657
  }
3560
3658
  }
3561
- function firstSetFromRegex(source) {
3659
+ function firstSetFromRegex(source, flags = "") {
3562
3660
  let ast;
3563
3661
  try {
3564
- ast = parseRegex(source);
3662
+ ast = parseRegex(source, flags.includes("u") || flags.includes("v"), flags.includes("v"));
3565
3663
  } catch {
3566
3664
  return { firstSet: any(), canMatchNewline: true };
3567
3665
  }
@@ -4304,6 +4402,9 @@ function inFirstSet(code, fs) {
4304
4402
  if (fs.kind === "any") return true;
4305
4403
  if (fs.kind === "empty") return false;
4306
4404
  for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
4405
+ if (code <= 65535) return false;
4406
+ const high = 55296 + (code - 65536 >> 10);
4407
+ for (const r of fs.ranges) if (high >= r.lo && high <= r.hi) return true;
4307
4408
  return false;
4308
4409
  }
4309
4410
  function areDisjoint(sets) {
@@ -4894,8 +4995,18 @@ function shortScanner(source, flags) {
4894
4995
  return minOne && end === pos ? null : end;
4895
4996
  };
4896
4997
  }
4998
+ function coversNonAscii(ranges) {
4999
+ let next = 128;
5000
+ for (const r of [...ranges].sort((a, b) => a.lo - b.lo)) {
5001
+ if (r.lo > next) return false;
5002
+ if (r.hi >= next) next = r.hi + 1;
5003
+ if (next > 65535) return true;
5004
+ }
5005
+ return false;
5006
+ }
4897
5007
  function asciiCaseFold(fs) {
4898
5008
  if (fs.kind !== "ranges") return fs;
5009
+ if (fs.ranges.some((r) => r.hi >= 128) && !coversNonAscii(fs.ranges)) return any();
4899
5010
  const ranges = fs.ranges.map((r) => ({ lo: r.lo, hi: r.hi }));
4900
5011
  const add = (lo, hi) => {
4901
5012
  if (lo <= hi) ranges.push({ lo, hi });
@@ -4920,7 +5031,7 @@ function regex(pattern, flags = "") {
4920
5031
  const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
4921
5032
  const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
4922
5033
  const scan = shortScanner(source, resolvedFlags);
4923
- const raw = firstSetFromRegex(source);
5034
+ const raw = firstSetFromRegex(source, resolvedFlags);
4924
5035
  const firstSet2 = !resolvedFlags.includes("i") ? raw.firstSet : resolvedFlags.includes("u") || resolvedFlags.includes("v") ? any() : asciiCaseFold(raw.firstSet);
4925
5036
  const canMatchNewline = raw.canMatchNewline;
4926
5037
  const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
@@ -5702,7 +5813,7 @@ function decodeClassSpec(spec) {
5702
5813
  function resolveClass(spec) {
5703
5814
  const ascii = new Uint8Array(128);
5704
5815
  const hi = [];
5705
- for (const { lo, hi: up } of decodeClassSpec(spec)) {
5816
+ for (const { lo, hi: up } of leadRanges(decodeClassSpec(spec))) {
5706
5817
  if (lo < 128) for (let c = lo; c <= Math.min(up, 127); c++) ascii[c] = 1;
5707
5818
  if (up >= 128) hi.push(Math.max(lo, 128), up);
5708
5819
  }
@@ -8624,6 +8735,7 @@ function parseSeqParts(source) {
8624
8735
  cp2 = uni.cp;
8625
8736
  i = uni.next;
8626
8737
  } else if (e === void 0) return null;
8738
+ else if (e >= "0" && e <= "9" && (e !== "0" || source[i + 2] !== void 0 && source[i + 2] >= "0" && source[i + 2] <= "9")) return null;
8627
8739
  else if (e in CLASS_ESCAPES) {
8628
8740
  cp2 = CLASS_ESCAPES[e];
8629
8741
  i += 2;
@@ -9173,7 +9285,7 @@ function parseScanShapeCore(source) {
9173
9285
  return null;
9174
9286
  }
9175
9287
  function scanShapeFromRegex(source, flags) {
9176
- if (/[msu]/.test(flags)) return null;
9288
+ if (/[msuv]/.test(flags)) return null;
9177
9289
  if (/i/.test(flags)) return caseFoldShape(source);
9178
9290
  return parseScanShape(source);
9179
9291
  }
@@ -9778,7 +9890,7 @@ function triviaLeadRanges(tri, trivia2) {
9778
9890
  const fs = trivia2[tri]?._meta.firstSet;
9779
9891
  if (fs === void 0) return void 0;
9780
9892
  if (fs.kind === "empty") return [];
9781
- return fs.kind === "ranges" && fs.ranges !== void 0 ? fs.ranges : void 0;
9893
+ return fs.kind === "ranges" && fs.ranges !== void 0 ? leadRanges(fs.ranges) : void 0;
9782
9894
  }
9783
9895
 
9784
9896
  // src/table/scalar-terminal.ts
@@ -10308,7 +10420,7 @@ if(ctx._errors!==undefined&&ctx._errors.length!==${t2}er)ctx._errors.length=${t2
10308
10420
  if (!s.fd && !s.er) return `if(${t2}n)rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,undefined,undefined,${t2}lg,${t2}rt)`;
10309
10421
  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)}`;
10310
10422
  }
10311
- function emitTerm(callee, dst, t2, l, skip) {
10423
+ function emitTerm(callee, dst, t2, l, skip, miss) {
10312
10424
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
10313
10425
  if(${t2}v===FAIL)return FAIL
10314
10426
  ${dst}=${t2}v
@@ -10326,7 +10438,12 @@ if(${t2}v===FAIL)return FAIL
10326
10438
  ${dst}=${t2}v
10327
10439
  if(EC.e>${t2}s)cur=EC.e
10328
10440
  else{rollbackScannedTriviaAt(ctx,${t2}tl,${t2}stl,${t2}lg,${t2}slg,${t2}rt,${t2}srt)}`;
10329
- if (l.tri !== TRI_UNKNOWN) return scanned;
10441
+ if (l.tri !== TRI_UNKNOWN) return miss === void 0 ? scanned : `const ${t2}c=input.charCodeAt(cur)
10442
+ if(${miss(`${t2}c`)}){
10443
+ ${fast}
10444
+ }else{
10445
+ ${scanned}
10446
+ }`;
10330
10447
  return `if(ctx.trivia===undefined){
10331
10448
  ${fast}
10332
10449
  }else{
@@ -10382,7 +10499,7 @@ function rebuildPools(cc, fx, disp, plan) {
10382
10499
  })
10383
10500
  };
10384
10501
  }
10385
- function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, select) {
10502
+ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, select, scanSinkNeutral = false) {
10386
10503
  const { code, k, fx, disp, dsp, triviaLabelled } = t2;
10387
10504
  const swapLegal = !cfg.trackLines;
10388
10505
  const hostCst = cfg.hostCst;
@@ -10458,7 +10575,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
10458
10575
  const op = code[ip];
10459
10576
  sinkBits.set(
10460
10577
  ip,
10461
- op === OP_SCAN ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC && (op === OP_REP || op === OP_REPV) ? 2 : 0)
10578
+ 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)
10462
10579
  );
10463
10580
  }
10464
10581
  const sinkKids = [];
@@ -10631,6 +10748,12 @@ return 1
10631
10748
  return `if(${gateMissTest(child)}){${miss}}
10632
10749
  `;
10633
10750
  }
10751
+ function triviaMiss(ki) {
10752
+ const leads = triviaLeadRanges(ki, t2.trivia);
10753
+ if (leads === void 0 || leads.length > 16) return void 0;
10754
+ if (leads.length === 0) return (c) => `${c}<55296`;
10755
+ return (c) => `${c}<55296&&!(${leads.map((r) => r.lo === r.hi ? `${c}===${r.lo}` : `(${c}>=${r.lo}&&${c}<=${r.hi})`).join("||")})`;
10756
+ }
10634
10757
  function skipFor(l) {
10635
10758
  if (l.tri < 0) return "_skipTrivia";
10636
10759
  const ki = l.tri;
@@ -10641,8 +10764,13 @@ return 1
10641
10764
  const nm = `_sk${skipPool.size}`;
10642
10765
  skipPool.set(key, nm);
10643
10766
  if (!hasScan) {
10644
- skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){return skipDeferredTrivia(input,cur,ctx)}` : `function ${nm}(input,cur,ctx){
10645
- if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
10767
+ const miss = triviaMiss(ki);
10768
+ const pre = miss === void 0 ? "" : `const c=input.charCodeAt(cur)
10769
+ if(${miss("c")})return cur
10770
+ `;
10771
+ skipDefs.push(l.buf ? `function ${nm}(input,cur,ctx){${pre === "" ? "" : `
10772
+ ${pre}`}return skipDeferredTrivia(input,cur,ctx)}` : `function ${nm}(input,cur,ctx){
10773
+ ${pre}if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
10646
10774
  return advanceTrivia(input,cur,ctx)}`);
10647
10775
  return nm;
10648
10776
  }
@@ -11226,7 +11354,7 @@ return v
11226
11354
  );
11227
11355
  } else {
11228
11356
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
11229
- parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L)));
11357
+ 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));
11230
11358
  }
11231
11359
  names.push(vn);
11232
11360
  }
@@ -12560,6 +12688,15 @@ function skipDeferredTrivia(input, cur, ctx) {
12560
12688
  if (plain2) remember(cur, scan, ctx, input, triviaP);
12561
12689
  return scan;
12562
12690
  }
12691
+ function triviaLeadTable(triviaP) {
12692
+ const fs = triviaP._meta.firstSet;
12693
+ if (fs.kind === "any") return null;
12694
+ const table = new Uint8Array(128);
12695
+ if (fs.kind === "ranges") {
12696
+ for (const r of fs.ranges) for (let c = Math.max(0, r.lo); c <= Math.min(127, r.hi); c++) table[c] = 1;
12697
+ }
12698
+ return table;
12699
+ }
12563
12700
  function clearRunEnd(input, cur, ctx, triviaP, plain2) {
12564
12701
  const rootKinds = ctx._rootTriviaKindIndex;
12565
12702
  const spec = triviaP?._meta.labeledTriviaSpec;
@@ -13216,7 +13353,23 @@ function assemble(t2, prog, cfg) {
13216
13353
  }
13217
13354
  return out;
13218
13355
  }
13356
+ const LEAD_TABLES = trivia2.map((tp) => tp === void 0 ? null : triviaLeadTable(tp));
13357
+ let LEAD_OF;
13358
+ let LEAD_TABLE = null;
13359
+ function cannotStartTrivia(input, cur, triviaP) {
13360
+ if (triviaP !== LEAD_OF) {
13361
+ LEAD_OF = triviaP;
13362
+ const slot = trivia2.indexOf(triviaP);
13363
+ LEAD_TABLE = slot >= 0 ? LEAD_TABLES[slot] : triviaLeadTable(triviaP);
13364
+ }
13365
+ const table = LEAD_TABLE;
13366
+ if (table === null) return false;
13367
+ const c = input.charCodeAt(cur);
13368
+ return c < 128 && table[c] === 0;
13369
+ }
13219
13370
  function skipTrivia(input, cur, ctx) {
13371
+ const t3 = ctx.trivia;
13372
+ if (t3 !== void 0 && cannotStartTrivia(input, cur, t3)) return cur;
13220
13373
  const s = SCAN;
13221
13374
  if (s !== null && ctx._triviaLog === void 0 && !(ctx.captureTrivia === true && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0))) {
13222
13375
  return s(input, cur);
@@ -13231,7 +13384,8 @@ function assemble(t2, prog, cfg) {
13231
13384
  const frames = [];
13232
13385
  let depth = 0;
13233
13386
  function nextTerm(child, input, cur, ctx) {
13234
- if (ctx.trivia === void 0) {
13387
+ const t3 = ctx.trivia;
13388
+ if (t3 === void 0 || cannotStartTrivia(input, cur, t3)) {
13235
13389
  const v2 = child(input, cur, ctx);
13236
13390
  if (v2 === FAIL) return -1;
13237
13391
  TERMV = v2;
@@ -13260,7 +13414,8 @@ function assemble(t2, prog, cfg) {
13260
13414
  return cur;
13261
13415
  }
13262
13416
  function nextTermBuffered(child, input, cur, ctx) {
13263
- if (ctx.trivia === void 0) {
13417
+ const t3 = ctx.trivia;
13418
+ if (t3 === void 0 || cannotStartTrivia(input, cur, t3)) {
13264
13419
  const v2 = child(input, cur, ctx);
13265
13420
  if (v2 === FAIL) return -1;
13266
13421
  TERMV = v2;
@@ -14062,6 +14217,7 @@ function assemble(t2, prog, cfg) {
14062
14217
  const scopeTrivia = ki < 0 ? void 0 : trivia2[ki];
14063
14218
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels;
14064
14219
  const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? triviaScan[ki] : null;
14220
+ const scopeLead = ki < 0 ? null : LEAD_TABLES[ki];
14065
14221
  const child = link(code[ip + 2]);
14066
14222
  const scopePiece = code[ip] === OP_SCOPE_CAP ? (input, pos, ctx) => {
14067
14223
  const saved = ctx.trivia;
@@ -14069,6 +14225,9 @@ function assemble(t2, prog, cfg) {
14069
14225
  const savedScan = SCAN;
14070
14226
  const savedCap = ctx.captureTrivia;
14071
14227
  SCAN = scanFor;
14228
+ const savedLeadOf = LEAD_OF, savedLead = LEAD_TABLE;
14229
+ LEAD_OF = scopeTrivia;
14230
+ LEAD_TABLE = scopeLead;
14072
14231
  ctx.trivia = scopeTrivia;
14073
14232
  ctx.triviaKindLabels = scopeLabels;
14074
14233
  ctx.captureTrivia = true;
@@ -14077,18 +14236,25 @@ function assemble(t2, prog, cfg) {
14077
14236
  ctx.trivia = saved;
14078
14237
  ctx.triviaKindLabels = savedLabels;
14079
14238
  SCAN = savedScan;
14239
+ LEAD_OF = savedLeadOf;
14240
+ LEAD_TABLE = savedLead;
14080
14241
  return v;
14081
14242
  } : (input, pos, ctx) => {
14082
14243
  const saved = ctx.trivia;
14083
14244
  const savedLabels = ctx.triviaKindLabels;
14084
14245
  const savedScan = SCAN;
14085
14246
  SCAN = scanFor;
14247
+ const savedLeadOf = LEAD_OF, savedLead = LEAD_TABLE;
14248
+ LEAD_OF = scopeTrivia;
14249
+ LEAD_TABLE = scopeLead;
14086
14250
  ctx.trivia = scopeTrivia;
14087
14251
  ctx.triviaKindLabels = scopeLabels;
14088
14252
  const v = child(input, pos, ctx);
14089
14253
  ctx.trivia = saved;
14090
14254
  ctx.triviaKindLabels = savedLabels;
14091
14255
  SCAN = savedScan;
14256
+ LEAD_OF = savedLeadOf;
14257
+ LEAD_TABLE = savedLead;
14092
14258
  return v;
14093
14259
  };
14094
14260
  return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]);