parseman 0.26.0 → 0.26.1

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.
@@ -877,12 +877,159 @@ function keywords(words, opts = {}) {
877
877
  };
878
878
  }
879
879
 
880
+ // src/recovery/scan.ts
881
+ function probeAt(sentinel, input, pos, ctx) {
882
+ const s = {
883
+ _probe: ctx._probe,
884
+ _errors: ctx._errors,
885
+ _cstLeaves: ctx._cstLeaves,
886
+ _cstChildren: ctx._cstChildren,
887
+ _cstRawChildren: ctx._cstRawChildren,
888
+ _cstTriviaLog: ctx._cstTriviaLog,
889
+ _triviaLog: ctx._triviaLog,
890
+ _fields: ctx._fields,
891
+ _cstBuf: ctx._cstBuf,
892
+ _tolerant: ctx._tolerant,
893
+ _sync: ctx._sync
894
+ };
895
+ ctx._probe = void 0;
896
+ ctx._errors = void 0;
897
+ ctx._cstLeaves = void 0;
898
+ ctx._cstChildren = void 0;
899
+ ctx._cstRawChildren = void 0;
900
+ ctx._cstTriviaLog = void 0;
901
+ ctx._triviaLog = void 0;
902
+ ctx._fields = void 0;
903
+ ctx._cstBuf = void 0;
904
+ ctx._tolerant = void 0;
905
+ ctx._sync = void 0;
906
+ try {
907
+ return sentinel.parse(input, pos, ctx).ok;
908
+ } finally {
909
+ ctx._probe = s._probe;
910
+ ctx._errors = s._errors;
911
+ ctx._cstLeaves = s._cstLeaves;
912
+ ctx._cstChildren = s._cstChildren;
913
+ ctx._cstRawChildren = s._cstRawChildren;
914
+ ctx._cstTriviaLog = s._cstTriviaLog;
915
+ ctx._triviaLog = s._triviaLog;
916
+ ctx._fields = s._fields;
917
+ ctx._cstBuf = s._cstBuf;
918
+ ctx._tolerant = s._tolerant;
919
+ ctx._sync = s._sync;
920
+ }
921
+ }
922
+ function orSentinel(a, b) {
923
+ if (b === void 0) return a;
924
+ return {
925
+ _tag: "orSentinel",
926
+ _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
927
+ _def: { tag: "unknown" },
928
+ parse(input, pos, ctx) {
929
+ const ra = a.parse(input, pos, ctx);
930
+ if (ra.ok) return ra;
931
+ return b.parse(input, pos, ctx);
932
+ }
933
+ };
934
+ }
935
+ function firstSetSentinel(fs2) {
936
+ if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
937
+ const ranges = fs2.ranges;
938
+ return {
939
+ _tag: "firstSetSentinel",
940
+ _meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
941
+ _def: { tag: "unknown" },
942
+ parse(input, pos) {
943
+ const code = pos < input.length ? input.codePointAt(pos) : void 0;
944
+ if (code !== void 0) {
945
+ for (const r of ranges) {
946
+ if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
947
+ }
948
+ }
949
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
950
+ }
951
+ };
952
+ }
953
+ function recoverScan(input, from, ctx, sync, expected) {
954
+ let scanPos = from;
955
+ while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
956
+ const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
957
+ ctx._errors?.push(error);
958
+ return { error, end: scanPos };
959
+ }
960
+ function matchesAt(sentinel, input, pos, ctx) {
961
+ return probeAt(sentinel, input, pos, ctx);
962
+ }
963
+ function captureError(ctx, error) {
964
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
965
+ }
966
+
967
+ // src/combinators/expect.ts
968
+ function deriveExpected(c) {
969
+ const def = c._def;
970
+ switch (def.tag) {
971
+ case "literal":
972
+ return [JSON.stringify(def.value)];
973
+ case "regex":
974
+ return [`/${def.source}/`];
975
+ case "keywords":
976
+ return def.words.map((w) => JSON.stringify(w));
977
+ case "label":
978
+ return [def.label];
979
+ case "choice":
980
+ return def.parsers.flatMap(deriveExpected);
981
+ case "sequence":
982
+ return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
983
+ case "node":
984
+ case "grammar":
985
+ case "trivia":
986
+ case "token":
987
+ case "optional":
988
+ case "many":
989
+ case "oneOrMore":
990
+ case "transform":
991
+ case "not":
992
+ return deriveExpected(def.parser);
993
+ case "lazy": {
994
+ const name = c._ruleName;
995
+ try {
996
+ return deriveExpected(def.thunk());
997
+ } catch {
998
+ return name ? [name] : [];
999
+ }
1000
+ }
1001
+ default:
1002
+ return [];
1003
+ }
1004
+ }
1005
+ function expect(combinator, label2) {
1006
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1007
+ const meta = {
1008
+ firstSet: combinator._meta.firstSet,
1009
+ canMatchNewline: combinator._meta.canMatchNewline,
1010
+ isTrivia: false
1011
+ };
1012
+ return {
1013
+ _tag: "expect",
1014
+ _meta: meta,
1015
+ _def: { tag: "expect", parser: combinator, label: label2, expected },
1016
+ parse(input, pos, ctx) {
1017
+ const result = combinator.parse(input, pos, ctx);
1018
+ if (result.ok) return result;
1019
+ const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
1020
+ ctx._errors?.push(error);
1021
+ if (ctx._tolerant) captureError(ctx, error);
1022
+ return { ok: true, value: error, span: { start: pos, end: pos } };
1023
+ }
1024
+ };
1025
+ }
1026
+
880
1027
  // src/combinators/choice.ts
881
1028
  function choice(...args) {
882
1029
  const parsers = args.map((a) => "gate" in a ? a.combinator : a);
883
1030
  const gates = args.map((a) => "gate" in a ? a.gate : null);
884
1031
  const hasGates = gates.some((g) => g !== null);
885
- const disjoint = !hasGates && areDisjoint(parsers.map((p) => p._meta.firstSet));
1032
+ const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
886
1033
  let combined = { kind: "empty" };
887
1034
  for (const p of parsers) combined = union(combined, p._meta.firstSet);
888
1035
  const meta = {
@@ -921,17 +1068,21 @@ function choice(...args) {
921
1068
  const expected = [];
922
1069
  if (disjoint && pos < input.length) {
923
1070
  const code = input.codePointAt(pos);
924
- let parser2 = code < 128 ? asciiDispatch?.[code] ?? null : null;
925
- if (!parser2) {
926
- for (const p of parsers) {
927
- if (inFirstSet(code, p._meta.firstSet)) {
928
- parser2 = p;
1071
+ let idx = code < 128 ? asciiDispatch[code] : -1;
1072
+ if (idx < 0) {
1073
+ for (let i = 0; i < parsers.length; i++) {
1074
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1075
+ idx = i;
929
1076
  break;
930
1077
  }
931
1078
  }
932
1079
  }
933
- if (parser2) {
934
- const result = parser2.parse(input, pos, ctx);
1080
+ if (idx >= 0) {
1081
+ const gate = gates[idx];
1082
+ if (gate && !gate(ctx.state)) {
1083
+ return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
1084
+ }
1085
+ const result = parsers[idx].parse(input, pos, ctx);
935
1086
  if (result.ok) return result;
936
1087
  expected.push(...result.expected);
937
1088
  return { ok: false, expected, span: { start: pos, end: pos } };
@@ -1112,13 +1263,13 @@ function areDisjoint(sets) {
1112
1263
  return true;
1113
1264
  }
1114
1265
  function buildAsciiDispatch(parsers) {
1115
- const table = Array(128).fill(null);
1116
- for (const parser2 of parsers) {
1117
- const fs2 = parser2._meta.firstSet;
1266
+ const table = Array(128).fill(-1);
1267
+ for (let i = 0; i < parsers.length; i++) {
1268
+ const fs2 = parsers[i]._meta.firstSet;
1118
1269
  if (fs2.kind !== "ranges") continue;
1119
1270
  for (const { lo, hi } of fs2.ranges) {
1120
1271
  for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1121
- table[code] = parser2;
1272
+ table[code] = i;
1122
1273
  }
1123
1274
  }
1124
1275
  }
@@ -1500,93 +1651,6 @@ function scanBlockComment(input, cur) {
1500
1651
  return close === -1 ? cur : close + 2;
1501
1652
  }
1502
1653
 
1503
- // src/recovery/scan.ts
1504
- function probeAt(sentinel, input, pos, ctx) {
1505
- const s = {
1506
- _probe: ctx._probe,
1507
- _errors: ctx._errors,
1508
- _cstLeaves: ctx._cstLeaves,
1509
- _cstChildren: ctx._cstChildren,
1510
- _cstRawChildren: ctx._cstRawChildren,
1511
- _cstTriviaLog: ctx._cstTriviaLog,
1512
- _triviaLog: ctx._triviaLog,
1513
- _fields: ctx._fields,
1514
- _cstBuf: ctx._cstBuf,
1515
- _tolerant: ctx._tolerant,
1516
- _sync: ctx._sync
1517
- };
1518
- ctx._probe = void 0;
1519
- ctx._errors = void 0;
1520
- ctx._cstLeaves = void 0;
1521
- ctx._cstChildren = void 0;
1522
- ctx._cstRawChildren = void 0;
1523
- ctx._cstTriviaLog = void 0;
1524
- ctx._triviaLog = void 0;
1525
- ctx._fields = void 0;
1526
- ctx._cstBuf = void 0;
1527
- ctx._tolerant = void 0;
1528
- ctx._sync = void 0;
1529
- try {
1530
- return sentinel.parse(input, pos, ctx).ok;
1531
- } finally {
1532
- ctx._probe = s._probe;
1533
- ctx._errors = s._errors;
1534
- ctx._cstLeaves = s._cstLeaves;
1535
- ctx._cstChildren = s._cstChildren;
1536
- ctx._cstRawChildren = s._cstRawChildren;
1537
- ctx._cstTriviaLog = s._cstTriviaLog;
1538
- ctx._triviaLog = s._triviaLog;
1539
- ctx._fields = s._fields;
1540
- ctx._cstBuf = s._cstBuf;
1541
- ctx._tolerant = s._tolerant;
1542
- ctx._sync = s._sync;
1543
- }
1544
- }
1545
- function orSentinel(a, b) {
1546
- if (b === void 0) return a;
1547
- return {
1548
- _tag: "orSentinel",
1549
- _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1550
- _def: { tag: "unknown" },
1551
- parse(input, pos, ctx) {
1552
- const ra = a.parse(input, pos, ctx);
1553
- if (ra.ok) return ra;
1554
- return b.parse(input, pos, ctx);
1555
- }
1556
- };
1557
- }
1558
- function firstSetSentinel(fs2) {
1559
- if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
1560
- const ranges = fs2.ranges;
1561
- return {
1562
- _tag: "firstSetSentinel",
1563
- _meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
1564
- _def: { tag: "unknown" },
1565
- parse(input, pos) {
1566
- const code = pos < input.length ? input.codePointAt(pos) : void 0;
1567
- if (code !== void 0) {
1568
- for (const r of ranges) {
1569
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1570
- }
1571
- }
1572
- return { ok: false, expected: [], span: { start: pos, end: pos } };
1573
- }
1574
- };
1575
- }
1576
- function recoverScan(input, from, ctx, sync, expected) {
1577
- let scanPos = from;
1578
- while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1579
- const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
1580
- ctx._errors?.push(error);
1581
- return { error, end: scanPos };
1582
- }
1583
- function matchesAt(sentinel, input, pos, ctx) {
1584
- return probeAt(sentinel, input, pos, ctx);
1585
- }
1586
- function captureError(ctx, error) {
1587
- if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1588
- }
1589
-
1590
1654
  // src/combinators/sequence.ts
1591
1655
  function sequence(...parsers) {
1592
1656
  const meta = {
@@ -1688,66 +1752,6 @@ function sequence(...parsers) {
1688
1752
  };
1689
1753
  }
1690
1754
 
1691
- // src/combinators/expect.ts
1692
- function deriveExpected(c) {
1693
- const def = c._def;
1694
- switch (def.tag) {
1695
- case "literal":
1696
- return [JSON.stringify(def.value)];
1697
- case "regex":
1698
- return [`/${def.source}/`];
1699
- case "keywords":
1700
- return def.words.map((w) => JSON.stringify(w));
1701
- case "label":
1702
- return [def.label];
1703
- case "choice":
1704
- return def.parsers.flatMap(deriveExpected);
1705
- case "sequence":
1706
- return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
1707
- case "node":
1708
- case "grammar":
1709
- case "trivia":
1710
- case "token":
1711
- case "optional":
1712
- case "many":
1713
- case "oneOrMore":
1714
- case "transform":
1715
- case "not":
1716
- return deriveExpected(def.parser);
1717
- case "lazy": {
1718
- const name = c._ruleName;
1719
- try {
1720
- return deriveExpected(def.thunk());
1721
- } catch {
1722
- return name ? [name] : [];
1723
- }
1724
- }
1725
- default:
1726
- return [];
1727
- }
1728
- }
1729
- function expect(combinator, label2) {
1730
- const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1731
- const meta = {
1732
- firstSet: combinator._meta.firstSet,
1733
- canMatchNewline: combinator._meta.canMatchNewline,
1734
- isTrivia: false
1735
- };
1736
- return {
1737
- _tag: "expect",
1738
- _meta: meta,
1739
- _def: { tag: "expect", parser: combinator, label: label2, expected },
1740
- parse(input, pos, ctx) {
1741
- const result = combinator.parse(input, pos, ctx);
1742
- if (result.ok) return result;
1743
- const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
1744
- ctx._errors?.push(error);
1745
- if (ctx._tolerant) captureError(ctx, error);
1746
- return { ok: true, value: error, span: { start: pos, end: pos } };
1747
- }
1748
- };
1749
- }
1750
-
1751
1755
  // src/combinators/repeat.ts
1752
1756
  function repItem(combinator, input, cur, ctx) {
1753
1757
  const mark = saveTriviaMark(ctx);
@@ -4524,6 +4528,21 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
4524
4528
  `${ind(ctx)}${endV} = ${endVar}`
4525
4529
  ];
4526
4530
  }
4531
+ function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
4532
+ const p = def.parsers[i];
4533
+ const gate = def.gates[i];
4534
+ if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
4535
+ const gateIdx = ctx.mapFns.length;
4536
+ ctx.mapFns.push(gate);
4537
+ ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
4538
+ const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
4539
+ const stmts = [`${ind(ctx)}if (${gateCond}) {`];
4540
+ ctx.indent++;
4541
+ stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
4542
+ ctx.indent--;
4543
+ stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
4544
+ return stmts;
4545
+ }
4527
4546
  function emitChoice(def, ctx, pos) {
4528
4547
  const allExpected = deriveExpectedArr(def.parsers);
4529
4548
  if (def.disjoint) {
@@ -4539,12 +4558,11 @@ function emitChoice(def, ctx, pos) {
4539
4558
  stmts.push(`${ind(ctx)}switch (${codeV}) {`);
4540
4559
  ctx.indent++;
4541
4560
  for (let i = 0; i < def.parsers.length; i++) {
4542
- const p = def.parsers[i];
4543
4561
  for (const cp of plan.cases[i]) stmts.push(`${ind(ctx)}case ${cp}:`);
4544
4562
  stmts.push(`${ind(ctx)}{`);
4545
4563
  ctx.indent++;
4546
4564
  stmts.push(
4547
- ...emitDisjointArm(p, ctx, pos, valV, endV),
4565
+ ...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
4548
4566
  `${ind(ctx)}break`
4549
4567
  );
4550
4568
  ctx.indent--;
@@ -4556,13 +4574,14 @@ function emitChoice(def, ctx, pos) {
4556
4574
  return { stmts, valueVar: valV, endVar: endV };
4557
4575
  }
4558
4576
  let first = true;
4559
- for (const p of def.parsers) {
4577
+ for (let i = 0; i < def.parsers.length; i++) {
4578
+ const p = def.parsers[i];
4560
4579
  const cond = firstSetCond(codeV, p._meta.firstSet);
4561
4580
  const kw = first ? "if" : "else if";
4562
4581
  first = false;
4563
4582
  stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
4564
4583
  ctx.indent++;
4565
- stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
4584
+ stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
4566
4585
  ctx.indent--;
4567
4586
  stmts.push(`${ind(ctx)}}`);
4568
4587
  }