parseman 0.18.1 → 0.18.2

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.
@@ -421,13 +421,12 @@ function literal(value, opts = {}) {
421
421
  if (end > input.length) {
422
422
  return failAt(ctx, [JSON.stringify(value)], pos);
423
423
  }
424
- const slice = input.slice(pos, end);
425
- const matched = caseInsensitive ? asciiFoldEq(slice, value) : slice === value;
426
- if (matched) {
424
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
425
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
427
426
  const span = { start: pos, end };
428
- const leaf = { _tag: "leaf", value: slice, span };
427
+ const leaf = { _tag: "leaf", value: matchedValue, span };
429
428
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
430
- return { ok: true, value: slice, span };
429
+ return { ok: true, value: matchedValue, span };
431
430
  }
432
431
  return failAt(ctx, [JSON.stringify(value)], pos);
433
432
  }
@@ -440,10 +439,102 @@ function registerRegexAnalyzer(analyzer) {
440
439
  firstSetAnalyzer = analyzer;
441
440
  }
442
441
  var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
442
+ var SCAN_BAIL_AT = 64;
443
+ var SPACE_RANGES = [
444
+ [9, 13],
445
+ [32, 32],
446
+ [160, 160],
447
+ [5760, 5760],
448
+ [8192, 8202],
449
+ [8232, 8233],
450
+ [8239, 8239],
451
+ [8287, 8287],
452
+ [12288, 12288],
453
+ [65279, 65279]
454
+ ];
455
+ var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
456
+ function shorthandRanges(ch) {
457
+ if (ch === "d") return [[48, 57]];
458
+ if (ch === "s") return SPACE_RANGES;
459
+ return [[48, 57], [65, 90], [97, 122], [95, 95]];
460
+ }
461
+ function inRanges(cp, ranges) {
462
+ for (let i = 0; i < ranges.length; i++) {
463
+ const [lo, hi] = ranges[i];
464
+ if (cp >= lo && cp <= hi) return true;
465
+ }
466
+ return false;
467
+ }
468
+ function readClassRanges(body) {
469
+ if (body.startsWith("^")) return null;
470
+ const ranges = [];
471
+ let i = 0;
472
+ const readAtom = () => {
473
+ const ch = body[i];
474
+ if (ch === void 0) return null;
475
+ if (ch === "\\") {
476
+ const esc = body[i + 1];
477
+ if (esc === void 0) return null;
478
+ i += 2;
479
+ if (esc === "d" || esc === "w" || esc === "s") return { ranges: shorthandRanges(esc) };
480
+ if (esc in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[esc] };
481
+ if (esc >= "a" && esc <= "z" || esc >= "A" && esc <= "Z") return null;
482
+ return { cp: esc.charCodeAt(0) };
483
+ }
484
+ i++;
485
+ return { cp: ch.charCodeAt(0) };
486
+ };
487
+ while (i < body.length) {
488
+ const lo = readAtom();
489
+ if (!lo) return null;
490
+ if ("ranges" in lo) {
491
+ ranges.push(...lo.ranges);
492
+ continue;
493
+ }
494
+ if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
495
+ i++;
496
+ const hi = readAtom();
497
+ if (!hi || "ranges" in hi) return null;
498
+ ranges.push([lo.cp, hi.cp]);
499
+ } else {
500
+ ranges.push([lo.cp, lo.cp]);
501
+ }
502
+ }
503
+ return ranges.length ? ranges : null;
504
+ }
505
+ function shortScanner(source, flags) {
506
+ if (/[imsuvy]/.test(flags)) return null;
507
+ let ranges = null;
508
+ let quant = "";
509
+ if (source[0] === "[") {
510
+ let end = 1;
511
+ while (end < source.length && source[end] !== "]") {
512
+ if (source[end] === "\\") end += 2;
513
+ else end++;
514
+ }
515
+ if (source[end] !== "]") return null;
516
+ ranges = readClassRanges(source.slice(1, end));
517
+ quant = source.slice(end + 1);
518
+ } else if (source[0] === "\\" && (source[1] === "d" || source[1] === "w" || source[1] === "s")) {
519
+ ranges = shorthandRanges(source[1]);
520
+ quant = source.slice(2);
521
+ }
522
+ if (!ranges || quant !== "+" && quant !== "*") return null;
523
+ const minOne = quant === "+";
524
+ return (input, pos) => {
525
+ let end = pos;
526
+ while (end < input.length && inRanges(input.charCodeAt(end), ranges)) {
527
+ end++;
528
+ if (end - pos >= SCAN_BAIL_AT) return void 0;
529
+ }
530
+ return minOne && end === pos ? null : end;
531
+ };
532
+ }
443
533
  function regex(pattern, flags = "") {
444
534
  const source = typeof pattern === "string" ? pattern : pattern.source;
445
535
  const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
446
536
  const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
537
+ const scan = shortScanner(source, resolvedFlags);
447
538
  const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
448
539
  const meta = { firstSet, canMatchNewline, isTrivia: false };
449
540
  return {
@@ -451,6 +542,15 @@ function regex(pattern, flags = "") {
451
542
  _meta: meta,
452
543
  _def: { tag: "regex", source, flags: resolvedFlags },
453
544
  parse(input, pos, ctx) {
545
+ const scanEnd = scan?.(input, pos);
546
+ if (scanEnd !== void 0) {
547
+ if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
548
+ const value = input.slice(pos, scanEnd);
549
+ const span2 = { start: pos, end: scanEnd };
550
+ const leaf2 = { _tag: "leaf", value, span: span2 };
551
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf2);
552
+ return { ok: true, value, span: span2 };
553
+ }
454
554
  anchored.lastIndex = pos;
455
555
  const m = anchored.exec(input);
456
556
  if (m === null) {
@@ -631,13 +731,10 @@ function choice(...args) {
631
731
  };
632
732
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
633
733
  const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
634
- let greedyRe = null;
635
734
  let greedyLitMap = null;
636
735
  let sortedParsers = null;
736
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
637
737
  if (strategy?.tag === "greedyClassify") {
638
- const regexDef = getCoreRegexDef(parsers[strategy.superIndex]);
639
- const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
640
- greedyRe = new RegExp(regexDef.source, flags);
641
738
  greedyLitMap = /* @__PURE__ */ new Map();
642
739
  for (let i = 0; i < parsers.length; i++) {
643
740
  if (i === strategy.superIndex) continue;
@@ -662,14 +759,21 @@ function choice(...args) {
662
759
  const expected = [];
663
760
  if (disjoint && pos < input.length) {
664
761
  const code = input.codePointAt(pos);
665
- for (const parser2 of parsers) {
666
- if (inFirstSet(code, parser2._meta.firstSet)) {
667
- const result = parser2.parse(input, pos, ctx);
668
- if (result.ok) return result;
669
- expected.push(...result.expected);
670
- return { ok: false, expected, span: { start: pos, end: pos } };
762
+ let parser2 = code < 128 ? asciiDispatch?.[code] ?? null : null;
763
+ if (!parser2) {
764
+ for (const p of parsers) {
765
+ if (inFirstSet(code, p._meta.firstSet)) {
766
+ parser2 = p;
767
+ break;
768
+ }
671
769
  }
672
770
  }
771
+ if (parser2) {
772
+ const result = parser2.parse(input, pos, ctx);
773
+ if (result.ok) return result;
774
+ expected.push(...result.expected);
775
+ return { ok: false, expected, span: { start: pos, end: pos } };
776
+ }
673
777
  return {
674
778
  ok: false,
675
779
  expected: parsers.flatMap((p) => {
@@ -845,6 +949,19 @@ function areDisjoint(sets) {
845
949
  if (intersects(sets[i], sets[j])) return false;
846
950
  return true;
847
951
  }
952
+ function buildAsciiDispatch(parsers) {
953
+ const table = Array(128).fill(null);
954
+ for (const parser2 of parsers) {
955
+ const fs2 = parser2._meta.firstSet;
956
+ if (fs2.kind !== "ranges") continue;
957
+ for (const { lo, hi } of fs2.ranges) {
958
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
959
+ table[code] = parser2;
960
+ }
961
+ }
962
+ }
963
+ return table;
964
+ }
848
965
 
849
966
  // src/cst/trivia-kinds.ts
850
967
  function unwrapTrivia(p) {
@@ -966,6 +1083,7 @@ function recordTriviaChunks(ctx, chunks) {
966
1083
  // src/combinators/trivia-skip.ts
967
1084
  var NOOP_COMMIT = () => {
968
1085
  };
1086
+ var fastTriviaCache = /* @__PURE__ */ new WeakMap();
969
1087
  function needsDeferredTriviaCommit(ctx) {
970
1088
  return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
971
1089
  }
@@ -992,6 +1110,8 @@ function scanWithLabels(input, cur, ctx) {
992
1110
  function advanceTrivia(input, cur, ctx) {
993
1111
  const triviaP = ctx.trivia;
994
1112
  if (!triviaP) return cur;
1113
+ const fast = fastTriviaScanner(triviaP);
1114
+ if (fast) return fast(input, cur);
995
1115
  if (ctx.triviaKindLabels) {
996
1116
  const scan = scanWithLabels(input, cur, ctx);
997
1117
  return scan.end;
@@ -1004,6 +1124,10 @@ function scanTrivia(input, cur, ctx) {
1004
1124
  if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1005
1125
  const log = ctx._triviaLog;
1006
1126
  const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1127
+ const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1128
+ if (fast && log === void 0 && !captureTl) {
1129
+ return { end: fast(input, cur), commit: NOOP_COMMIT };
1130
+ }
1007
1131
  if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1008
1132
  return scanWithLabels(input, cur, ctx);
1009
1133
  }
@@ -1025,6 +1149,79 @@ function scanTrivia(input, cur, ctx) {
1025
1149
  const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1026
1150
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1027
1151
  }
1152
+ function fastTriviaScanner(trivia2) {
1153
+ const cached = fastTriviaCache.get(trivia2);
1154
+ if (cached !== void 0) return cached;
1155
+ const scanner = buildFastTriviaScanner(trivia2);
1156
+ fastTriviaCache.set(trivia2, scanner);
1157
+ return scanner;
1158
+ }
1159
+ function buildFastTriviaScanner(trivia2) {
1160
+ const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1161
+ const direct = regexTriviaScanner(core);
1162
+ if (direct) return direct;
1163
+ const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1164
+ if (!repeat) return null;
1165
+ const one = regexTriviaScanner(repeat);
1166
+ if (one) return loopScanner([one]);
1167
+ if (repeat._def.tag !== "choice") return null;
1168
+ const arms = repeat._def.parsers.map(regexTriviaScanner);
1169
+ if (arms.some((s) => s === null)) return null;
1170
+ return loopScanner(arms);
1171
+ }
1172
+ function loopScanner(arms) {
1173
+ return (input, cur) => {
1174
+ let pos = cur;
1175
+ scan: while (pos < input.length) {
1176
+ for (const arm of arms) {
1177
+ const end = arm(input, pos);
1178
+ if (end > pos) {
1179
+ pos = end;
1180
+ continue scan;
1181
+ }
1182
+ }
1183
+ break;
1184
+ }
1185
+ return pos;
1186
+ };
1187
+ }
1188
+ function regexTriviaScanner(parser2) {
1189
+ if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1190
+ const ws = whitespaceSource(parser2._def.source);
1191
+ if (ws) return ws;
1192
+ return blockCommentSource(parser2._def.source) ? scanBlockComment : null;
1193
+ }
1194
+ function whitespaceSource(source) {
1195
+ const m = /^\[([ \\tnrf]+)\][*+]$/.exec(source);
1196
+ if (!m) return null;
1197
+ const chars = /* @__PURE__ */ new Set();
1198
+ for (let i = 0; i < m[1].length; i++) {
1199
+ const ch = m[1][i];
1200
+ if (ch !== "\\") {
1201
+ chars.add(ch.charCodeAt(0));
1202
+ continue;
1203
+ }
1204
+ const esc = m[1][++i];
1205
+ if (esc === "t") chars.add(9);
1206
+ else if (esc === "n") chars.add(10);
1207
+ else if (esc === "r") chars.add(13);
1208
+ else if (esc === "f") chars.add(12);
1209
+ else return null;
1210
+ }
1211
+ return (input, cur) => {
1212
+ let pos = cur;
1213
+ while (pos < input.length && chars.has(input.charCodeAt(pos))) pos++;
1214
+ return pos;
1215
+ };
1216
+ }
1217
+ function blockCommentSource(source) {
1218
+ return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
1219
+ }
1220
+ function scanBlockComment(input, cur) {
1221
+ if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
1222
+ const close = input.indexOf("*/", cur + 2);
1223
+ return close === -1 ? cur : close + 2;
1224
+ }
1028
1225
 
1029
1226
  // src/combinators/sequence.ts
1030
1227
  function sequence(...parsers) {
@@ -1163,11 +1360,15 @@ function optional(combinator) {
1163
1360
  canMatchNewline: combinator._meta.canMatchNewline,
1164
1361
  isTrivia: false
1165
1362
  };
1363
+ const firstSetSkippable = !matchesEmpty(combinator);
1166
1364
  return {
1167
1365
  _tag: "optional",
1168
1366
  _meta: meta,
1169
1367
  _def: { tag: "optional", parser: combinator },
1170
1368
  parse(input, pos, ctx) {
1369
+ if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
1370
+ return { ok: true, value: null, span: { start: pos, end: pos } };
1371
+ }
1171
1372
  const mark = saveTriviaMark(ctx);
1172
1373
  const result = combinator.parse(input, pos, ctx);
1173
1374
  if (result.ok) return result;
@@ -1176,6 +1377,15 @@ function optional(combinator) {
1176
1377
  }
1177
1378
  };
1178
1379
  }
1380
+ function startsFirstSet(combinator, input, pos) {
1381
+ const fs2 = combinator._meta.firstSet;
1382
+ if (fs2.kind === "any") return true;
1383
+ if (fs2.kind === "empty") return false;
1384
+ const code = input.codePointAt(pos);
1385
+ if (code === void 0) return false;
1386
+ for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
1387
+ return false;
1388
+ }
1179
1389
  function sepBy(combinator, separator) {
1180
1390
  const meta = {
1181
1391
  firstSet: combinator._meta.firstSet,
@@ -1453,7 +1663,7 @@ function transform(combinator, fn) {
1453
1663
  parse(input, pos, ctx) {
1454
1664
  const result = combinator.parse(input, pos, ctx);
1455
1665
  if (!result.ok) return result;
1456
- return { ...result, value: fn(result.value, result.span) };
1666
+ return { ok: true, value: fn(result.value, result.span), span: result.span };
1457
1667
  }
1458
1668
  };
1459
1669
  }
@@ -1467,7 +1677,7 @@ function skip(main, skipped) {
1467
1677
  if (!result.ok) return result;
1468
1678
  const s = skipped.parse(input, result.span.end, ctx);
1469
1679
  if (!s.ok) return result;
1470
- return { ...result, span: { start: result.span.start, end: s.span.end } };
1680
+ return { ok: true, value: result.value, span: { start: result.span.start, end: s.span.end } };
1471
1681
  }
1472
1682
  };
1473
1683
  }
@@ -1491,7 +1701,7 @@ function label(name, combinator) {
1491
1701
  _def: { tag: "label", label: name, parser: combinator },
1492
1702
  parse(input, pos, ctx) {
1493
1703
  const result = combinator.parse(input, pos, ctx);
1494
- if (!result.ok) return { ...result, expected: [name] };
1704
+ if (!result.ok) return { ok: false, expected: [name], span: result.span };
1495
1705
  return result;
1496
1706
  }
1497
1707
  };
@@ -1682,9 +1892,9 @@ function expect(combinator, label2) {
1682
1892
 
1683
1893
  // src/compiler/scannable-run.ts
1684
1894
  var BACKSLASH = 92;
1685
- var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1895
+ var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1686
1896
  var META = new Set("()[]{}*+?|^$.".split(""));
1687
- var SPACE_RANGES = [
1897
+ var SPACE_RANGES2 = [
1688
1898
  [9, 13],
1689
1899
  [32, 32],
1690
1900
  [160, 160],
@@ -1697,9 +1907,9 @@ var SPACE_RANGES = [
1697
1907
  [12288, 12288],
1698
1908
  [65279, 65279]
1699
1909
  ];
1700
- function shorthandRanges(ch) {
1910
+ function shorthandRanges2(ch) {
1701
1911
  if (ch === "d") return [[48, 57]];
1702
- if (ch === "s") return SPACE_RANGES;
1912
+ if (ch === "s") return SPACE_RANGES2;
1703
1913
  return [[48, 57], [65, 90], [97, 122], [95, 95]];
1704
1914
  }
1705
1915
  function readUnicodeEscape(body, i) {
@@ -1723,8 +1933,8 @@ function parseClassRanges(body) {
1723
1933
  const e = body[i + 1];
1724
1934
  if (e === void 0) return null;
1725
1935
  i += 2;
1726
- if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
1727
- if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
1936
+ if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
1937
+ if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
1728
1938
  if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1729
1939
  return { cp: e.codePointAt(0) };
1730
1940
  }
@@ -1750,9 +1960,9 @@ function parseClassRanges(body) {
1750
1960
  return ranges.length ? ranges : null;
1751
1961
  }
1752
1962
  function classToRanges(cls) {
1753
- if (cls === "\\d") return shorthandRanges("d");
1754
- if (cls === "\\w") return shorthandRanges("w");
1755
- if (cls === "\\s") return shorthandRanges("s");
1963
+ if (cls === "\\d") return shorthandRanges2("d");
1964
+ if (cls === "\\w") return shorthandRanges2("w");
1965
+ if (cls === "\\s") return shorthandRanges2("s");
1756
1966
  const body = cls.slice(1, -1);
1757
1967
  if (body.startsWith("^")) return null;
1758
1968
  return parseClassRanges(body);
@@ -1770,7 +1980,7 @@ function literalCodePoints(frag) {
1770
1980
  if (ch === "\\") {
1771
1981
  const e = frag[i + 1];
1772
1982
  if (e === void 0) return null;
1773
- out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
1983
+ out.push(e in CLASS_ESCAPES2 ? CLASS_ESCAPES2[e] : e.codePointAt(0));
1774
1984
  i += 2;
1775
1985
  continue;
1776
1986
  }
@@ -1863,7 +2073,7 @@ function parseSeqParts(source) {
1863
2073
  if (e === "d" || e === "w" || e === "s") {
1864
2074
  flush();
1865
2075
  i += 2;
1866
- i += runFrom(shorthandRanges(e), false, source[i]);
2076
+ i += runFrom(shorthandRanges2(e), false, source[i]);
1867
2077
  continue;
1868
2078
  }
1869
2079
  const uni = readUnicodeEscape(source, i);
@@ -1872,8 +2082,8 @@ function parseSeqParts(source) {
1872
2082
  cp2 = uni.cp;
1873
2083
  i = uni.next;
1874
2084
  } else if (e === void 0) return null;
1875
- else if (e in CLASS_ESCAPES) {
1876
- cp2 = CLASS_ESCAPES[e];
2085
+ else if (e in CLASS_ESCAPES2) {
2086
+ cp2 = CLASS_ESCAPES2[e];
1877
2087
  i += 2;
1878
2088
  } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1879
2089
  else {
@@ -1980,7 +2190,7 @@ function rangesSubset(sub, sup) {
1980
2190
  }
1981
2191
  function parseClassOperand(body) {
1982
2192
  if (body === "\\d" || body === "\\w" || body === "\\s") {
1983
- return { ranges: shorthandRanges(body[1]), negated: false };
2193
+ return { ranges: shorthandRanges2(body[1]), negated: false };
1984
2194
  }
1985
2195
  if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
1986
2196
  let inner = body.slice(1, -1);
@@ -2413,7 +2623,7 @@ function parseScanShapeCore(source) {
2413
2623
  }
2414
2624
  m = /^\\([dws])([+*])$/.exec(source);
2415
2625
  if (m) {
2416
- return { kind: "chars", ranges: shorthandRanges(m[1]), minOne: m[2] === "+" };
2626
+ return { kind: "chars", ranges: shorthandRanges2(m[1]), minOne: m[2] === "+" };
2417
2627
  }
2418
2628
  m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
2419
2629
  if (m) {