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.
@@ -386,13 +386,12 @@ function literal(value, opts = {}) {
386
386
  if (end > input.length) {
387
387
  return failAt(ctx, [JSON.stringify(value)], pos);
388
388
  }
389
- const slice = input.slice(pos, end);
390
- const matched = caseInsensitive ? asciiFoldEq(slice, value) : slice === value;
391
- if (matched) {
389
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
390
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
392
391
  const span = { start: pos, end };
393
- const leaf = { _tag: "leaf", value: slice, span };
392
+ const leaf = { _tag: "leaf", value: matchedValue, span };
394
393
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
395
- return { ok: true, value: slice, span };
394
+ return { ok: true, value: matchedValue, span };
396
395
  }
397
396
  return failAt(ctx, [JSON.stringify(value)], pos);
398
397
  }
@@ -405,10 +404,102 @@ function registerRegexAnalyzer(analyzer) {
405
404
  firstSetAnalyzer = analyzer;
406
405
  }
407
406
  var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
407
+ var SCAN_BAIL_AT = 64;
408
+ var SPACE_RANGES = [
409
+ [9, 13],
410
+ [32, 32],
411
+ [160, 160],
412
+ [5760, 5760],
413
+ [8192, 8202],
414
+ [8232, 8233],
415
+ [8239, 8239],
416
+ [8287, 8287],
417
+ [12288, 12288],
418
+ [65279, 65279]
419
+ ];
420
+ var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
421
+ function shorthandRanges(ch) {
422
+ if (ch === "d") return [[48, 57]];
423
+ if (ch === "s") return SPACE_RANGES;
424
+ return [[48, 57], [65, 90], [97, 122], [95, 95]];
425
+ }
426
+ function inRanges(cp, ranges) {
427
+ for (let i = 0; i < ranges.length; i++) {
428
+ const [lo, hi] = ranges[i];
429
+ if (cp >= lo && cp <= hi) return true;
430
+ }
431
+ return false;
432
+ }
433
+ function readClassRanges(body) {
434
+ if (body.startsWith("^")) return null;
435
+ const ranges = [];
436
+ let i = 0;
437
+ const readAtom = () => {
438
+ const ch = body[i];
439
+ if (ch === void 0) return null;
440
+ if (ch === "\\") {
441
+ const esc = body[i + 1];
442
+ if (esc === void 0) return null;
443
+ i += 2;
444
+ if (esc === "d" || esc === "w" || esc === "s") return { ranges: shorthandRanges(esc) };
445
+ if (esc in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[esc] };
446
+ if (esc >= "a" && esc <= "z" || esc >= "A" && esc <= "Z") return null;
447
+ return { cp: esc.charCodeAt(0) };
448
+ }
449
+ i++;
450
+ return { cp: ch.charCodeAt(0) };
451
+ };
452
+ while (i < body.length) {
453
+ const lo = readAtom();
454
+ if (!lo) return null;
455
+ if ("ranges" in lo) {
456
+ ranges.push(...lo.ranges);
457
+ continue;
458
+ }
459
+ if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
460
+ i++;
461
+ const hi = readAtom();
462
+ if (!hi || "ranges" in hi) return null;
463
+ ranges.push([lo.cp, hi.cp]);
464
+ } else {
465
+ ranges.push([lo.cp, lo.cp]);
466
+ }
467
+ }
468
+ return ranges.length ? ranges : null;
469
+ }
470
+ function shortScanner(source, flags) {
471
+ if (/[imsuvy]/.test(flags)) return null;
472
+ let ranges = null;
473
+ let quant = "";
474
+ if (source[0] === "[") {
475
+ let end = 1;
476
+ while (end < source.length && source[end] !== "]") {
477
+ if (source[end] === "\\") end += 2;
478
+ else end++;
479
+ }
480
+ if (source[end] !== "]") return null;
481
+ ranges = readClassRanges(source.slice(1, end));
482
+ quant = source.slice(end + 1);
483
+ } else if (source[0] === "\\" && (source[1] === "d" || source[1] === "w" || source[1] === "s")) {
484
+ ranges = shorthandRanges(source[1]);
485
+ quant = source.slice(2);
486
+ }
487
+ if (!ranges || quant !== "+" && quant !== "*") return null;
488
+ const minOne = quant === "+";
489
+ return (input, pos) => {
490
+ let end = pos;
491
+ while (end < input.length && inRanges(input.charCodeAt(end), ranges)) {
492
+ end++;
493
+ if (end - pos >= SCAN_BAIL_AT) return void 0;
494
+ }
495
+ return minOne && end === pos ? null : end;
496
+ };
497
+ }
408
498
  function regex(pattern, flags = "") {
409
499
  const source = typeof pattern === "string" ? pattern : pattern.source;
410
500
  const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
411
501
  const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
502
+ const scan = shortScanner(source, resolvedFlags);
412
503
  const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
413
504
  const meta = { firstSet, canMatchNewline, isTrivia: false };
414
505
  return {
@@ -416,6 +507,15 @@ function regex(pattern, flags = "") {
416
507
  _meta: meta,
417
508
  _def: { tag: "regex", source, flags: resolvedFlags },
418
509
  parse(input, pos, ctx) {
510
+ const scanEnd = scan?.(input, pos);
511
+ if (scanEnd !== void 0) {
512
+ if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
513
+ const value = input.slice(pos, scanEnd);
514
+ const span2 = { start: pos, end: scanEnd };
515
+ const leaf2 = { _tag: "leaf", value, span: span2 };
516
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf2);
517
+ return { ok: true, value, span: span2 };
518
+ }
419
519
  anchored.lastIndex = pos;
420
520
  const m = anchored.exec(input);
421
521
  if (m === null) {
@@ -596,13 +696,10 @@ function choice(...args) {
596
696
  };
597
697
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
598
698
  const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
599
- let greedyRe = null;
600
699
  let greedyLitMap = null;
601
700
  let sortedParsers = null;
701
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
602
702
  if (strategy?.tag === "greedyClassify") {
603
- const regexDef = getCoreRegexDef(parsers[strategy.superIndex]);
604
- const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
605
- greedyRe = new RegExp(regexDef.source, flags);
606
703
  greedyLitMap = /* @__PURE__ */ new Map();
607
704
  for (let i = 0; i < parsers.length; i++) {
608
705
  if (i === strategy.superIndex) continue;
@@ -627,14 +724,21 @@ function choice(...args) {
627
724
  const expected = [];
628
725
  if (disjoint && pos < input.length) {
629
726
  const code = input.codePointAt(pos);
630
- for (const parser2 of parsers) {
631
- if (inFirstSet(code, parser2._meta.firstSet)) {
632
- const result = parser2.parse(input, pos, ctx);
633
- if (result.ok) return result;
634
- expected.push(...result.expected);
635
- return { ok: false, expected, span: { start: pos, end: pos } };
727
+ let parser2 = code < 128 ? asciiDispatch?.[code] ?? null : null;
728
+ if (!parser2) {
729
+ for (const p of parsers) {
730
+ if (inFirstSet(code, p._meta.firstSet)) {
731
+ parser2 = p;
732
+ break;
733
+ }
636
734
  }
637
735
  }
736
+ if (parser2) {
737
+ const result = parser2.parse(input, pos, ctx);
738
+ if (result.ok) return result;
739
+ expected.push(...result.expected);
740
+ return { ok: false, expected, span: { start: pos, end: pos } };
741
+ }
638
742
  return {
639
743
  ok: false,
640
744
  expected: parsers.flatMap((p) => {
@@ -810,6 +914,19 @@ function areDisjoint(sets) {
810
914
  if (intersects(sets[i], sets[j])) return false;
811
915
  return true;
812
916
  }
917
+ function buildAsciiDispatch(parsers) {
918
+ const table = Array(128).fill(null);
919
+ for (const parser2 of parsers) {
920
+ const fs2 = parser2._meta.firstSet;
921
+ if (fs2.kind !== "ranges") continue;
922
+ for (const { lo, hi } of fs2.ranges) {
923
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
924
+ table[code] = parser2;
925
+ }
926
+ }
927
+ }
928
+ return table;
929
+ }
813
930
 
814
931
  // src/cst/trivia-kinds.ts
815
932
  function unwrapTrivia(p) {
@@ -931,6 +1048,7 @@ function recordTriviaChunks(ctx, chunks) {
931
1048
  // src/combinators/trivia-skip.ts
932
1049
  var NOOP_COMMIT = () => {
933
1050
  };
1051
+ var fastTriviaCache = /* @__PURE__ */ new WeakMap();
934
1052
  function needsDeferredTriviaCommit(ctx) {
935
1053
  return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
936
1054
  }
@@ -957,6 +1075,8 @@ function scanWithLabels(input, cur, ctx) {
957
1075
  function advanceTrivia(input, cur, ctx) {
958
1076
  const triviaP = ctx.trivia;
959
1077
  if (!triviaP) return cur;
1078
+ const fast = fastTriviaScanner(triviaP);
1079
+ if (fast) return fast(input, cur);
960
1080
  if (ctx.triviaKindLabels) {
961
1081
  const scan = scanWithLabels(input, cur, ctx);
962
1082
  return scan.end;
@@ -969,6 +1089,10 @@ function scanTrivia(input, cur, ctx) {
969
1089
  if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
970
1090
  const log = ctx._triviaLog;
971
1091
  const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1092
+ const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1093
+ if (fast && log === void 0 && !captureTl) {
1094
+ return { end: fast(input, cur), commit: NOOP_COMMIT };
1095
+ }
972
1096
  if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
973
1097
  return scanWithLabels(input, cur, ctx);
974
1098
  }
@@ -990,6 +1114,79 @@ function scanTrivia(input, cur, ctx) {
990
1114
  const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
991
1115
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
992
1116
  }
1117
+ function fastTriviaScanner(trivia2) {
1118
+ const cached = fastTriviaCache.get(trivia2);
1119
+ if (cached !== void 0) return cached;
1120
+ const scanner = buildFastTriviaScanner(trivia2);
1121
+ fastTriviaCache.set(trivia2, scanner);
1122
+ return scanner;
1123
+ }
1124
+ function buildFastTriviaScanner(trivia2) {
1125
+ const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1126
+ const direct = regexTriviaScanner(core);
1127
+ if (direct) return direct;
1128
+ const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1129
+ if (!repeat) return null;
1130
+ const one = regexTriviaScanner(repeat);
1131
+ if (one) return loopScanner([one]);
1132
+ if (repeat._def.tag !== "choice") return null;
1133
+ const arms = repeat._def.parsers.map(regexTriviaScanner);
1134
+ if (arms.some((s) => s === null)) return null;
1135
+ return loopScanner(arms);
1136
+ }
1137
+ function loopScanner(arms) {
1138
+ return (input, cur) => {
1139
+ let pos = cur;
1140
+ scan: while (pos < input.length) {
1141
+ for (const arm of arms) {
1142
+ const end = arm(input, pos);
1143
+ if (end > pos) {
1144
+ pos = end;
1145
+ continue scan;
1146
+ }
1147
+ }
1148
+ break;
1149
+ }
1150
+ return pos;
1151
+ };
1152
+ }
1153
+ function regexTriviaScanner(parser2) {
1154
+ if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1155
+ const ws = whitespaceSource(parser2._def.source);
1156
+ if (ws) return ws;
1157
+ return blockCommentSource(parser2._def.source) ? scanBlockComment : null;
1158
+ }
1159
+ function whitespaceSource(source) {
1160
+ const m = /^\[([ \\tnrf]+)\][*+]$/.exec(source);
1161
+ if (!m) return null;
1162
+ const chars = /* @__PURE__ */ new Set();
1163
+ for (let i = 0; i < m[1].length; i++) {
1164
+ const ch = m[1][i];
1165
+ if (ch !== "\\") {
1166
+ chars.add(ch.charCodeAt(0));
1167
+ continue;
1168
+ }
1169
+ const esc = m[1][++i];
1170
+ if (esc === "t") chars.add(9);
1171
+ else if (esc === "n") chars.add(10);
1172
+ else if (esc === "r") chars.add(13);
1173
+ else if (esc === "f") chars.add(12);
1174
+ else return null;
1175
+ }
1176
+ return (input, cur) => {
1177
+ let pos = cur;
1178
+ while (pos < input.length && chars.has(input.charCodeAt(pos))) pos++;
1179
+ return pos;
1180
+ };
1181
+ }
1182
+ function blockCommentSource(source) {
1183
+ return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
1184
+ }
1185
+ function scanBlockComment(input, cur) {
1186
+ if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
1187
+ const close = input.indexOf("*/", cur + 2);
1188
+ return close === -1 ? cur : close + 2;
1189
+ }
993
1190
 
994
1191
  // src/combinators/sequence.ts
995
1192
  function sequence(...parsers) {
@@ -1128,11 +1325,15 @@ function optional(combinator) {
1128
1325
  canMatchNewline: combinator._meta.canMatchNewline,
1129
1326
  isTrivia: false
1130
1327
  };
1328
+ const firstSetSkippable = !matchesEmpty(combinator);
1131
1329
  return {
1132
1330
  _tag: "optional",
1133
1331
  _meta: meta,
1134
1332
  _def: { tag: "optional", parser: combinator },
1135
1333
  parse(input, pos, ctx) {
1334
+ if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
1335
+ return { ok: true, value: null, span: { start: pos, end: pos } };
1336
+ }
1136
1337
  const mark = saveTriviaMark(ctx);
1137
1338
  const result = combinator.parse(input, pos, ctx);
1138
1339
  if (result.ok) return result;
@@ -1141,6 +1342,15 @@ function optional(combinator) {
1141
1342
  }
1142
1343
  };
1143
1344
  }
1345
+ function startsFirstSet(combinator, input, pos) {
1346
+ const fs2 = combinator._meta.firstSet;
1347
+ if (fs2.kind === "any") return true;
1348
+ if (fs2.kind === "empty") return false;
1349
+ const code = input.codePointAt(pos);
1350
+ if (code === void 0) return false;
1351
+ for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
1352
+ return false;
1353
+ }
1144
1354
  function sepBy(combinator, separator) {
1145
1355
  const meta = {
1146
1356
  firstSet: combinator._meta.firstSet,
@@ -1418,7 +1628,7 @@ function transform(combinator, fn) {
1418
1628
  parse(input, pos, ctx) {
1419
1629
  const result = combinator.parse(input, pos, ctx);
1420
1630
  if (!result.ok) return result;
1421
- return { ...result, value: fn(result.value, result.span) };
1631
+ return { ok: true, value: fn(result.value, result.span), span: result.span };
1422
1632
  }
1423
1633
  };
1424
1634
  }
@@ -1432,7 +1642,7 @@ function skip(main, skipped) {
1432
1642
  if (!result.ok) return result;
1433
1643
  const s = skipped.parse(input, result.span.end, ctx);
1434
1644
  if (!s.ok) return result;
1435
- return { ...result, span: { start: result.span.start, end: s.span.end } };
1645
+ return { ok: true, value: result.value, span: { start: result.span.start, end: s.span.end } };
1436
1646
  }
1437
1647
  };
1438
1648
  }
@@ -1456,7 +1666,7 @@ function label(name, combinator) {
1456
1666
  _def: { tag: "label", label: name, parser: combinator },
1457
1667
  parse(input, pos, ctx) {
1458
1668
  const result = combinator.parse(input, pos, ctx);
1459
- if (!result.ok) return { ...result, expected: [name] };
1669
+ if (!result.ok) return { ok: false, expected: [name], span: result.span };
1460
1670
  return result;
1461
1671
  }
1462
1672
  };
@@ -1647,9 +1857,9 @@ function expect(combinator, label2) {
1647
1857
 
1648
1858
  // src/compiler/scannable-run.ts
1649
1859
  var BACKSLASH = 92;
1650
- var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1860
+ var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1651
1861
  var META = new Set("()[]{}*+?|^$.".split(""));
1652
- var SPACE_RANGES = [
1862
+ var SPACE_RANGES2 = [
1653
1863
  [9, 13],
1654
1864
  [32, 32],
1655
1865
  [160, 160],
@@ -1662,9 +1872,9 @@ var SPACE_RANGES = [
1662
1872
  [12288, 12288],
1663
1873
  [65279, 65279]
1664
1874
  ];
1665
- function shorthandRanges(ch) {
1875
+ function shorthandRanges2(ch) {
1666
1876
  if (ch === "d") return [[48, 57]];
1667
- if (ch === "s") return SPACE_RANGES;
1877
+ if (ch === "s") return SPACE_RANGES2;
1668
1878
  return [[48, 57], [65, 90], [97, 122], [95, 95]];
1669
1879
  }
1670
1880
  function readUnicodeEscape(body, i) {
@@ -1688,8 +1898,8 @@ function parseClassRanges(body) {
1688
1898
  const e = body[i + 1];
1689
1899
  if (e === void 0) return null;
1690
1900
  i += 2;
1691
- if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
1692
- if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
1901
+ if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
1902
+ if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
1693
1903
  if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1694
1904
  return { cp: e.codePointAt(0) };
1695
1905
  }
@@ -1715,9 +1925,9 @@ function parseClassRanges(body) {
1715
1925
  return ranges.length ? ranges : null;
1716
1926
  }
1717
1927
  function classToRanges(cls) {
1718
- if (cls === "\\d") return shorthandRanges("d");
1719
- if (cls === "\\w") return shorthandRanges("w");
1720
- if (cls === "\\s") return shorthandRanges("s");
1928
+ if (cls === "\\d") return shorthandRanges2("d");
1929
+ if (cls === "\\w") return shorthandRanges2("w");
1930
+ if (cls === "\\s") return shorthandRanges2("s");
1721
1931
  const body = cls.slice(1, -1);
1722
1932
  if (body.startsWith("^")) return null;
1723
1933
  return parseClassRanges(body);
@@ -1735,7 +1945,7 @@ function literalCodePoints(frag) {
1735
1945
  if (ch === "\\") {
1736
1946
  const e = frag[i + 1];
1737
1947
  if (e === void 0) return null;
1738
- out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
1948
+ out.push(e in CLASS_ESCAPES2 ? CLASS_ESCAPES2[e] : e.codePointAt(0));
1739
1949
  i += 2;
1740
1950
  continue;
1741
1951
  }
@@ -1828,7 +2038,7 @@ function parseSeqParts(source) {
1828
2038
  if (e === "d" || e === "w" || e === "s") {
1829
2039
  flush();
1830
2040
  i += 2;
1831
- i += runFrom(shorthandRanges(e), false, source[i]);
2041
+ i += runFrom(shorthandRanges2(e), false, source[i]);
1832
2042
  continue;
1833
2043
  }
1834
2044
  const uni = readUnicodeEscape(source, i);
@@ -1837,8 +2047,8 @@ function parseSeqParts(source) {
1837
2047
  cp2 = uni.cp;
1838
2048
  i = uni.next;
1839
2049
  } else if (e === void 0) return null;
1840
- else if (e in CLASS_ESCAPES) {
1841
- cp2 = CLASS_ESCAPES[e];
2050
+ else if (e in CLASS_ESCAPES2) {
2051
+ cp2 = CLASS_ESCAPES2[e];
1842
2052
  i += 2;
1843
2053
  } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1844
2054
  else {
@@ -1945,7 +2155,7 @@ function rangesSubset(sub, sup) {
1945
2155
  }
1946
2156
  function parseClassOperand(body) {
1947
2157
  if (body === "\\d" || body === "\\w" || body === "\\s") {
1948
- return { ranges: shorthandRanges(body[1]), negated: false };
2158
+ return { ranges: shorthandRanges2(body[1]), negated: false };
1949
2159
  }
1950
2160
  if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
1951
2161
  let inner = body.slice(1, -1);
@@ -2378,7 +2588,7 @@ function parseScanShapeCore(source) {
2378
2588
  }
2379
2589
  m = /^\\([dws])([+*])$/.exec(source);
2380
2590
  if (m) {
2381
- return { kind: "chars", ranges: shorthandRanges(m[1]), minOne: m[2] === "+" };
2591
+ return { kind: "chars", ranges: shorthandRanges2(m[1]), minOne: m[2] === "+" };
2382
2592
  }
2383
2593
  m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
2384
2594
  if (m) {