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.
package/dist/index.js CHANGED
@@ -349,13 +349,12 @@ function literal(value, opts = {}) {
349
349
  if (end > input.length) {
350
350
  return failAt(ctx, [JSON.stringify(value)], pos);
351
351
  }
352
- const slice = input.slice(pos, end);
353
- const matched = caseInsensitive ? asciiFoldEq(slice, value) : slice === value;
354
- if (matched) {
352
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
353
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
355
354
  const span = { start: pos, end };
356
- const leaf = { _tag: "leaf", value: slice, span };
355
+ const leaf = { _tag: "leaf", value: matchedValue, span };
357
356
  if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
358
- return { ok: true, value: slice, span };
357
+ return { ok: true, value: matchedValue, span };
359
358
  }
360
359
  return failAt(ctx, [JSON.stringify(value)], pos);
361
360
  }
@@ -368,10 +367,102 @@ function registerRegexAnalyzer(analyzer) {
368
367
  firstSetAnalyzer = analyzer;
369
368
  }
370
369
  var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
370
+ var SCAN_BAIL_AT = 64;
371
+ var SPACE_RANGES = [
372
+ [9, 13],
373
+ [32, 32],
374
+ [160, 160],
375
+ [5760, 5760],
376
+ [8192, 8202],
377
+ [8232, 8233],
378
+ [8239, 8239],
379
+ [8287, 8287],
380
+ [12288, 12288],
381
+ [65279, 65279]
382
+ ];
383
+ var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
384
+ function shorthandRanges(ch) {
385
+ if (ch === "d") return [[48, 57]];
386
+ if (ch === "s") return SPACE_RANGES;
387
+ return [[48, 57], [65, 90], [97, 122], [95, 95]];
388
+ }
389
+ function inRanges(cp, ranges) {
390
+ for (let i = 0; i < ranges.length; i++) {
391
+ const [lo, hi] = ranges[i];
392
+ if (cp >= lo && cp <= hi) return true;
393
+ }
394
+ return false;
395
+ }
396
+ function readClassRanges(body) {
397
+ if (body.startsWith("^")) return null;
398
+ const ranges = [];
399
+ let i = 0;
400
+ const readAtom = () => {
401
+ const ch = body[i];
402
+ if (ch === void 0) return null;
403
+ if (ch === "\\") {
404
+ const esc = body[i + 1];
405
+ if (esc === void 0) return null;
406
+ i += 2;
407
+ if (esc === "d" || esc === "w" || esc === "s") return { ranges: shorthandRanges(esc) };
408
+ if (esc in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[esc] };
409
+ if (esc >= "a" && esc <= "z" || esc >= "A" && esc <= "Z") return null;
410
+ return { cp: esc.charCodeAt(0) };
411
+ }
412
+ i++;
413
+ return { cp: ch.charCodeAt(0) };
414
+ };
415
+ while (i < body.length) {
416
+ const lo = readAtom();
417
+ if (!lo) return null;
418
+ if ("ranges" in lo) {
419
+ ranges.push(...lo.ranges);
420
+ continue;
421
+ }
422
+ if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
423
+ i++;
424
+ const hi = readAtom();
425
+ if (!hi || "ranges" in hi) return null;
426
+ ranges.push([lo.cp, hi.cp]);
427
+ } else {
428
+ ranges.push([lo.cp, lo.cp]);
429
+ }
430
+ }
431
+ return ranges.length ? ranges : null;
432
+ }
433
+ function shortScanner(source, flags) {
434
+ if (/[imsuvy]/.test(flags)) return null;
435
+ let ranges = null;
436
+ let quant = "";
437
+ if (source[0] === "[") {
438
+ let end = 1;
439
+ while (end < source.length && source[end] !== "]") {
440
+ if (source[end] === "\\") end += 2;
441
+ else end++;
442
+ }
443
+ if (source[end] !== "]") return null;
444
+ ranges = readClassRanges(source.slice(1, end));
445
+ quant = source.slice(end + 1);
446
+ } else if (source[0] === "\\" && (source[1] === "d" || source[1] === "w" || source[1] === "s")) {
447
+ ranges = shorthandRanges(source[1]);
448
+ quant = source.slice(2);
449
+ }
450
+ if (!ranges || quant !== "+" && quant !== "*") return null;
451
+ const minOne = quant === "+";
452
+ return (input, pos) => {
453
+ let end = pos;
454
+ while (end < input.length && inRanges(input.charCodeAt(end), ranges)) {
455
+ end++;
456
+ if (end - pos >= SCAN_BAIL_AT) return void 0;
457
+ }
458
+ return minOne && end === pos ? null : end;
459
+ };
460
+ }
371
461
  function regex(pattern, flags = "") {
372
462
  const source = typeof pattern === "string" ? pattern : pattern.source;
373
463
  const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
374
464
  const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
465
+ const scan = shortScanner(source, resolvedFlags);
375
466
  const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
376
467
  const meta = { firstSet, canMatchNewline, isTrivia: false };
377
468
  return {
@@ -379,6 +470,15 @@ function regex(pattern, flags = "") {
379
470
  _meta: meta,
380
471
  _def: { tag: "regex", source, flags: resolvedFlags },
381
472
  parse(input, pos, ctx) {
473
+ const scanEnd = scan?.(input, pos);
474
+ if (scanEnd !== void 0) {
475
+ if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
476
+ const value = input.slice(pos, scanEnd);
477
+ const span2 = { start: pos, end: scanEnd };
478
+ const leaf2 = { _tag: "leaf", value, span: span2 };
479
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf2);
480
+ return { ok: true, value, span: span2 };
481
+ }
382
482
  anchored.lastIndex = pos;
383
483
  const m = anchored.exec(input);
384
484
  if (m === null) {
@@ -562,13 +662,10 @@ function choice(...args) {
562
662
  };
563
663
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
564
664
  const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
565
- let greedyRe = null;
566
665
  let greedyLitMap = null;
567
666
  let sortedParsers = null;
667
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
568
668
  if (strategy?.tag === "greedyClassify") {
569
- const regexDef = getCoreRegexDef(parsers[strategy.superIndex]);
570
- const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
571
- greedyRe = new RegExp(regexDef.source, flags);
572
669
  greedyLitMap = /* @__PURE__ */ new Map();
573
670
  for (let i = 0; i < parsers.length; i++) {
574
671
  if (i === strategy.superIndex) continue;
@@ -593,14 +690,21 @@ function choice(...args) {
593
690
  const expected = [];
594
691
  if (disjoint && pos < input.length) {
595
692
  const code = input.codePointAt(pos);
596
- for (const parser2 of parsers) {
597
- if (inFirstSet(code, parser2._meta.firstSet)) {
598
- const result = parser2.parse(input, pos, ctx);
599
- if (result.ok) return result;
600
- expected.push(...result.expected);
601
- return { ok: false, expected, span: { start: pos, end: pos } };
693
+ let parser2 = code < 128 ? asciiDispatch?.[code] ?? null : null;
694
+ if (!parser2) {
695
+ for (const p of parsers) {
696
+ if (inFirstSet(code, p._meta.firstSet)) {
697
+ parser2 = p;
698
+ break;
699
+ }
602
700
  }
603
701
  }
702
+ if (parser2) {
703
+ const result = parser2.parse(input, pos, ctx);
704
+ if (result.ok) return result;
705
+ expected.push(...result.expected);
706
+ return { ok: false, expected, span: { start: pos, end: pos } };
707
+ }
604
708
  return {
605
709
  ok: false,
606
710
  expected: parsers.flatMap((p) => {
@@ -776,6 +880,19 @@ function areDisjoint(sets) {
776
880
  if (intersects(sets[i], sets[j])) return false;
777
881
  return true;
778
882
  }
883
+ function buildAsciiDispatch(parsers) {
884
+ const table = Array(128).fill(null);
885
+ for (const parser2 of parsers) {
886
+ const fs = parser2._meta.firstSet;
887
+ if (fs.kind !== "ranges") continue;
888
+ for (const { lo, hi } of fs.ranges) {
889
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
890
+ table[code] = parser2;
891
+ }
892
+ }
893
+ }
894
+ return table;
895
+ }
779
896
 
780
897
  // src/cst/trivia-kinds.ts
781
898
  function unwrapTrivia(p) {
@@ -897,6 +1014,7 @@ function recordTriviaChunks(ctx, chunks) {
897
1014
  // src/combinators/trivia-skip.ts
898
1015
  var NOOP_COMMIT = () => {
899
1016
  };
1017
+ var fastTriviaCache = /* @__PURE__ */ new WeakMap();
900
1018
  function needsDeferredTriviaCommit(ctx) {
901
1019
  return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
902
1020
  }
@@ -923,6 +1041,8 @@ function scanWithLabels(input, cur, ctx) {
923
1041
  function advanceTrivia(input, cur, ctx) {
924
1042
  const triviaP = ctx.trivia;
925
1043
  if (!triviaP) return cur;
1044
+ const fast = fastTriviaScanner(triviaP);
1045
+ if (fast) return fast(input, cur);
926
1046
  if (ctx.triviaKindLabels) {
927
1047
  const scan = scanWithLabels(input, cur, ctx);
928
1048
  return scan.end;
@@ -935,6 +1055,10 @@ function scanTrivia(input, cur, ctx) {
935
1055
  if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
936
1056
  const log = ctx._triviaLog;
937
1057
  const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1058
+ const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1059
+ if (fast && log === void 0 && !captureTl) {
1060
+ return { end: fast(input, cur), commit: NOOP_COMMIT };
1061
+ }
938
1062
  if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
939
1063
  return scanWithLabels(input, cur, ctx);
940
1064
  }
@@ -956,6 +1080,79 @@ function scanTrivia(input, cur, ctx) {
956
1080
  const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
957
1081
  return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
958
1082
  }
1083
+ function fastTriviaScanner(trivia2) {
1084
+ const cached = fastTriviaCache.get(trivia2);
1085
+ if (cached !== void 0) return cached;
1086
+ const scanner = buildFastTriviaScanner(trivia2);
1087
+ fastTriviaCache.set(trivia2, scanner);
1088
+ return scanner;
1089
+ }
1090
+ function buildFastTriviaScanner(trivia2) {
1091
+ const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1092
+ const direct = regexTriviaScanner(core);
1093
+ if (direct) return direct;
1094
+ const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1095
+ if (!repeat) return null;
1096
+ const one = regexTriviaScanner(repeat);
1097
+ if (one) return loopScanner([one]);
1098
+ if (repeat._def.tag !== "choice") return null;
1099
+ const arms = repeat._def.parsers.map(regexTriviaScanner);
1100
+ if (arms.some((s) => s === null)) return null;
1101
+ return loopScanner(arms);
1102
+ }
1103
+ function loopScanner(arms) {
1104
+ return (input, cur) => {
1105
+ let pos = cur;
1106
+ scan: while (pos < input.length) {
1107
+ for (const arm of arms) {
1108
+ const end = arm(input, pos);
1109
+ if (end > pos) {
1110
+ pos = end;
1111
+ continue scan;
1112
+ }
1113
+ }
1114
+ break;
1115
+ }
1116
+ return pos;
1117
+ };
1118
+ }
1119
+ function regexTriviaScanner(parser2) {
1120
+ if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1121
+ const ws = whitespaceSource(parser2._def.source);
1122
+ if (ws) return ws;
1123
+ return blockCommentSource(parser2._def.source) ? scanBlockComment : null;
1124
+ }
1125
+ function whitespaceSource(source) {
1126
+ const m = /^\[([ \\tnrf]+)\][*+]$/.exec(source);
1127
+ if (!m) return null;
1128
+ const chars = /* @__PURE__ */ new Set();
1129
+ for (let i = 0; i < m[1].length; i++) {
1130
+ const ch = m[1][i];
1131
+ if (ch !== "\\") {
1132
+ chars.add(ch.charCodeAt(0));
1133
+ continue;
1134
+ }
1135
+ const esc = m[1][++i];
1136
+ if (esc === "t") chars.add(9);
1137
+ else if (esc === "n") chars.add(10);
1138
+ else if (esc === "r") chars.add(13);
1139
+ else if (esc === "f") chars.add(12);
1140
+ else return null;
1141
+ }
1142
+ return (input, cur) => {
1143
+ let pos = cur;
1144
+ while (pos < input.length && chars.has(input.charCodeAt(pos))) pos++;
1145
+ return pos;
1146
+ };
1147
+ }
1148
+ function blockCommentSource(source) {
1149
+ return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
1150
+ }
1151
+ function scanBlockComment(input, cur) {
1152
+ if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
1153
+ const close = input.indexOf("*/", cur + 2);
1154
+ return close === -1 ? cur : close + 2;
1155
+ }
959
1156
 
960
1157
  // src/combinators/sequence.ts
961
1158
  function sequence(...parsers) {
@@ -1094,11 +1291,15 @@ function optional(combinator) {
1094
1291
  canMatchNewline: combinator._meta.canMatchNewline,
1095
1292
  isTrivia: false
1096
1293
  };
1294
+ const firstSetSkippable = !matchesEmpty(combinator);
1097
1295
  return {
1098
1296
  _tag: "optional",
1099
1297
  _meta: meta,
1100
1298
  _def: { tag: "optional", parser: combinator },
1101
1299
  parse(input, pos, ctx) {
1300
+ if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
1301
+ return { ok: true, value: null, span: { start: pos, end: pos } };
1302
+ }
1102
1303
  const mark = saveTriviaMark(ctx);
1103
1304
  const result = combinator.parse(input, pos, ctx);
1104
1305
  if (result.ok) return result;
@@ -1107,6 +1308,15 @@ function optional(combinator) {
1107
1308
  }
1108
1309
  };
1109
1310
  }
1311
+ function startsFirstSet(combinator, input, pos) {
1312
+ const fs = combinator._meta.firstSet;
1313
+ if (fs.kind === "any") return true;
1314
+ if (fs.kind === "empty") return false;
1315
+ const code = input.codePointAt(pos);
1316
+ if (code === void 0) return false;
1317
+ for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
1318
+ return false;
1319
+ }
1110
1320
  function sepBy(combinator, separator) {
1111
1321
  const meta = {
1112
1322
  firstSet: combinator._meta.firstSet,
@@ -1414,7 +1624,7 @@ function transform(combinator, fn) {
1414
1624
  parse(input, pos, ctx) {
1415
1625
  const result = combinator.parse(input, pos, ctx);
1416
1626
  if (!result.ok) return result;
1417
- return { ...result, value: fn(result.value, result.span) };
1627
+ return { ok: true, value: fn(result.value, result.span), span: result.span };
1418
1628
  }
1419
1629
  };
1420
1630
  }
@@ -1428,7 +1638,7 @@ function skip(main, skipped) {
1428
1638
  if (!result.ok) return result;
1429
1639
  const s = skipped.parse(input, result.span.end, ctx);
1430
1640
  if (!s.ok) return result;
1431
- return { ...result, span: { start: result.span.start, end: s.span.end } };
1641
+ return { ok: true, value: result.value, span: { start: result.span.start, end: s.span.end } };
1432
1642
  }
1433
1643
  };
1434
1644
  }
@@ -1452,7 +1662,7 @@ function label(name, combinator) {
1452
1662
  _def: { tag: "label", label: name, parser: combinator },
1453
1663
  parse(input, pos, ctx) {
1454
1664
  const result = combinator.parse(input, pos, ctx);
1455
- if (!result.ok) return { ...result, expected: [name] };
1665
+ if (!result.ok) return { ok: false, expected: [name], span: result.span };
1456
1666
  return result;
1457
1667
  }
1458
1668
  };
@@ -1666,9 +1876,9 @@ function expect(combinator, label2) {
1666
1876
 
1667
1877
  // src/compiler/scannable-run.ts
1668
1878
  var BACKSLASH = 92;
1669
- var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1879
+ var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1670
1880
  var META = new Set("()[]{}*+?|^$.".split(""));
1671
- var SPACE_RANGES = [
1881
+ var SPACE_RANGES2 = [
1672
1882
  [9, 13],
1673
1883
  [32, 32],
1674
1884
  [160, 160],
@@ -1681,9 +1891,9 @@ var SPACE_RANGES = [
1681
1891
  [12288, 12288],
1682
1892
  [65279, 65279]
1683
1893
  ];
1684
- function shorthandRanges(ch) {
1894
+ function shorthandRanges2(ch) {
1685
1895
  if (ch === "d") return [[48, 57]];
1686
- if (ch === "s") return SPACE_RANGES;
1896
+ if (ch === "s") return SPACE_RANGES2;
1687
1897
  return [[48, 57], [65, 90], [97, 122], [95, 95]];
1688
1898
  }
1689
1899
  function readUnicodeEscape(body, i) {
@@ -1707,8 +1917,8 @@ function parseClassRanges(body) {
1707
1917
  const e = body[i + 1];
1708
1918
  if (e === void 0) return null;
1709
1919
  i += 2;
1710
- if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
1711
- if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
1920
+ if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
1921
+ if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
1712
1922
  if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1713
1923
  return { cp: e.codePointAt(0) };
1714
1924
  }
@@ -1734,9 +1944,9 @@ function parseClassRanges(body) {
1734
1944
  return ranges.length ? ranges : null;
1735
1945
  }
1736
1946
  function classToRanges(cls) {
1737
- if (cls === "\\d") return shorthandRanges("d");
1738
- if (cls === "\\w") return shorthandRanges("w");
1739
- if (cls === "\\s") return shorthandRanges("s");
1947
+ if (cls === "\\d") return shorthandRanges2("d");
1948
+ if (cls === "\\w") return shorthandRanges2("w");
1949
+ if (cls === "\\s") return shorthandRanges2("s");
1740
1950
  const body = cls.slice(1, -1);
1741
1951
  if (body.startsWith("^")) return null;
1742
1952
  return parseClassRanges(body);
@@ -1754,7 +1964,7 @@ function literalCodePoints(frag) {
1754
1964
  if (ch === "\\") {
1755
1965
  const e = frag[i + 1];
1756
1966
  if (e === void 0) return null;
1757
- out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
1967
+ out.push(e in CLASS_ESCAPES2 ? CLASS_ESCAPES2[e] : e.codePointAt(0));
1758
1968
  i += 2;
1759
1969
  continue;
1760
1970
  }
@@ -1847,7 +2057,7 @@ function parseSeqParts(source) {
1847
2057
  if (e === "d" || e === "w" || e === "s") {
1848
2058
  flush();
1849
2059
  i += 2;
1850
- i += runFrom(shorthandRanges(e), false, source[i]);
2060
+ i += runFrom(shorthandRanges2(e), false, source[i]);
1851
2061
  continue;
1852
2062
  }
1853
2063
  const uni = readUnicodeEscape(source, i);
@@ -1856,8 +2066,8 @@ function parseSeqParts(source) {
1856
2066
  cp2 = uni.cp;
1857
2067
  i = uni.next;
1858
2068
  } else if (e === void 0) return null;
1859
- else if (e in CLASS_ESCAPES) {
1860
- cp2 = CLASS_ESCAPES[e];
2069
+ else if (e in CLASS_ESCAPES2) {
2070
+ cp2 = CLASS_ESCAPES2[e];
1861
2071
  i += 2;
1862
2072
  } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1863
2073
  else {
@@ -1964,7 +2174,7 @@ function rangesSubset(sub, sup) {
1964
2174
  }
1965
2175
  function parseClassOperand(body) {
1966
2176
  if (body === "\\d" || body === "\\w" || body === "\\s") {
1967
- return { ranges: shorthandRanges(body[1]), negated: false };
2177
+ return { ranges: shorthandRanges2(body[1]), negated: false };
1968
2178
  }
1969
2179
  if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
1970
2180
  let inner = body.slice(1, -1);
@@ -2397,7 +2607,7 @@ function parseScanShapeCore(source) {
2397
2607
  }
2398
2608
  m = /^\\([dws])([+*])$/.exec(source);
2399
2609
  if (m) {
2400
- return { kind: "chars", ranges: shorthandRanges(m[1]), minOne: m[2] === "+" };
2610
+ return { kind: "chars", ranges: shorthandRanges2(m[1]), minOne: m[2] === "+" };
2401
2611
  }
2402
2612
  m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
2403
2613
  if (m) {