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.
package/dist/index.js CHANGED
@@ -836,12 +836,163 @@ function keywords(words, opts = {}) {
836
836
  };
837
837
  }
838
838
 
839
+ // src/recovery/scan.ts
840
+ function probeAt(sentinel, input, pos, ctx) {
841
+ const s = {
842
+ _probe: ctx._probe,
843
+ _errors: ctx._errors,
844
+ _cstLeaves: ctx._cstLeaves,
845
+ _cstChildren: ctx._cstChildren,
846
+ _cstRawChildren: ctx._cstRawChildren,
847
+ _cstTriviaLog: ctx._cstTriviaLog,
848
+ _triviaLog: ctx._triviaLog,
849
+ _fields: ctx._fields,
850
+ _cstBuf: ctx._cstBuf,
851
+ _tolerant: ctx._tolerant,
852
+ _sync: ctx._sync
853
+ };
854
+ ctx._probe = void 0;
855
+ ctx._errors = void 0;
856
+ ctx._cstLeaves = void 0;
857
+ ctx._cstChildren = void 0;
858
+ ctx._cstRawChildren = void 0;
859
+ ctx._cstTriviaLog = void 0;
860
+ ctx._triviaLog = void 0;
861
+ ctx._fields = void 0;
862
+ ctx._cstBuf = void 0;
863
+ ctx._tolerant = void 0;
864
+ ctx._sync = void 0;
865
+ try {
866
+ return sentinel.parse(input, pos, ctx).ok;
867
+ } finally {
868
+ ctx._probe = s._probe;
869
+ ctx._errors = s._errors;
870
+ ctx._cstLeaves = s._cstLeaves;
871
+ ctx._cstChildren = s._cstChildren;
872
+ ctx._cstRawChildren = s._cstRawChildren;
873
+ ctx._cstTriviaLog = s._cstTriviaLog;
874
+ ctx._triviaLog = s._triviaLog;
875
+ ctx._fields = s._fields;
876
+ ctx._cstBuf = s._cstBuf;
877
+ ctx._tolerant = s._tolerant;
878
+ ctx._sync = s._sync;
879
+ }
880
+ }
881
+ function orSentinel(a, b) {
882
+ if (b === void 0) return a;
883
+ return {
884
+ _tag: "orSentinel",
885
+ _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
886
+ _def: { tag: "unknown" },
887
+ parse(input, pos, ctx) {
888
+ const ra = a.parse(input, pos, ctx);
889
+ if (ra.ok) return ra;
890
+ return b.parse(input, pos, ctx);
891
+ }
892
+ };
893
+ }
894
+ function firstSetSentinel(fs) {
895
+ if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
896
+ const ranges = fs.ranges;
897
+ return {
898
+ _tag: "firstSetSentinel",
899
+ _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
900
+ _def: { tag: "unknown" },
901
+ parse(input, pos) {
902
+ const code = pos < input.length ? input.codePointAt(pos) : void 0;
903
+ if (code !== void 0) {
904
+ for (const r of ranges) {
905
+ if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
906
+ }
907
+ }
908
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
909
+ }
910
+ };
911
+ }
912
+ function recoverScan(input, from, ctx, sync, expected) {
913
+ let scanPos = from;
914
+ while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
915
+ const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
916
+ ctx._errors?.push(error);
917
+ return { error, end: scanPos };
918
+ }
919
+ function matchesAt(sentinel, input, pos, ctx) {
920
+ return probeAt(sentinel, input, pos, ctx);
921
+ }
922
+ function captureError(ctx, error) {
923
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
924
+ }
925
+ var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
926
+
927
+ // src/combinators/expect.ts
928
+ function deriveExpected(c) {
929
+ const def = c._def;
930
+ switch (def.tag) {
931
+ case "literal":
932
+ return [JSON.stringify(def.value)];
933
+ case "regex":
934
+ return [`/${def.source}/`];
935
+ case "keywords":
936
+ return def.words.map((w) => JSON.stringify(w));
937
+ case "label":
938
+ return [def.label];
939
+ case "choice":
940
+ return def.parsers.flatMap(deriveExpected);
941
+ case "sequence":
942
+ return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
943
+ case "node":
944
+ case "grammar":
945
+ case "trivia":
946
+ case "token":
947
+ case "optional":
948
+ case "many":
949
+ case "oneOrMore":
950
+ case "transform":
951
+ case "not":
952
+ return deriveExpected(def.parser);
953
+ case "lazy": {
954
+ const name = c._ruleName;
955
+ try {
956
+ return deriveExpected(def.thunk());
957
+ } catch {
958
+ return name ? [name] : [];
959
+ }
960
+ }
961
+ default:
962
+ return [];
963
+ }
964
+ }
965
+ function expect(combinator, label2) {
966
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
967
+ const meta = {
968
+ firstSet: combinator._meta.firstSet,
969
+ canMatchNewline: combinator._meta.canMatchNewline,
970
+ isTrivia: false
971
+ };
972
+ return {
973
+ _tag: "expect",
974
+ _meta: meta,
975
+ _def: { tag: "expect", parser: combinator, label: label2, expected },
976
+ parse(input, pos, ctx) {
977
+ const result = combinator.parse(input, pos, ctx);
978
+ if (result.ok) return result;
979
+ const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
980
+ ctx._errors?.push(error);
981
+ if (ctx._tolerant) captureError(ctx, error);
982
+ return { ok: true, value: error, span: { start: pos, end: pos } };
983
+ }
984
+ };
985
+ }
986
+ function isParseError(value) {
987
+ return typeof value === "object" && value !== null && value._tag === "parseError";
988
+ }
989
+
839
990
  // src/combinators/choice.ts
840
991
  function choice(...args) {
841
992
  const parsers = args.map((a) => "gate" in a ? a.combinator : a);
842
993
  const gates = args.map((a) => "gate" in a ? a.gate : null);
843
994
  const hasGates = gates.some((g) => g !== null);
844
- const disjoint = !hasGates && areDisjoint(parsers.map((p) => p._meta.firstSet));
995
+ const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
845
996
  let combined = { kind: "empty" };
846
997
  for (const p of parsers) combined = union(combined, p._meta.firstSet);
847
998
  const meta = {
@@ -880,17 +1031,21 @@ function choice(...args) {
880
1031
  const expected = [];
881
1032
  if (disjoint && pos < input.length) {
882
1033
  const code = input.codePointAt(pos);
883
- let parser2 = code < 128 ? asciiDispatch?.[code] ?? null : null;
884
- if (!parser2) {
885
- for (const p of parsers) {
886
- if (inFirstSet(code, p._meta.firstSet)) {
887
- parser2 = p;
1034
+ let idx = code < 128 ? asciiDispatch[code] : -1;
1035
+ if (idx < 0) {
1036
+ for (let i = 0; i < parsers.length; i++) {
1037
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
1038
+ idx = i;
888
1039
  break;
889
1040
  }
890
1041
  }
891
1042
  }
892
- if (parser2) {
893
- const result = parser2.parse(input, pos, ctx);
1043
+ if (idx >= 0) {
1044
+ const gate = gates[idx];
1045
+ if (gate && !gate(ctx.state)) {
1046
+ return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
1047
+ }
1048
+ const result = parsers[idx].parse(input, pos, ctx);
894
1049
  if (result.ok) return result;
895
1050
  expected.push(...result.expected);
896
1051
  return { ok: false, expected, span: { start: pos, end: pos } };
@@ -1071,13 +1226,13 @@ function areDisjoint(sets) {
1071
1226
  return true;
1072
1227
  }
1073
1228
  function buildAsciiDispatch(parsers) {
1074
- const table = Array(128).fill(null);
1075
- for (const parser2 of parsers) {
1076
- const fs = parser2._meta.firstSet;
1229
+ const table = Array(128).fill(-1);
1230
+ for (let i = 0; i < parsers.length; i++) {
1231
+ const fs = parsers[i]._meta.firstSet;
1077
1232
  if (fs.kind !== "ranges") continue;
1078
1233
  for (const { lo, hi } of fs.ranges) {
1079
1234
  for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1080
- table[code] = parser2;
1235
+ table[code] = i;
1081
1236
  }
1082
1237
  }
1083
1238
  }
@@ -1459,94 +1614,6 @@ function scanBlockComment(input, cur) {
1459
1614
  return close === -1 ? cur : close + 2;
1460
1615
  }
1461
1616
 
1462
- // src/recovery/scan.ts
1463
- function probeAt(sentinel, input, pos, ctx) {
1464
- const s = {
1465
- _probe: ctx._probe,
1466
- _errors: ctx._errors,
1467
- _cstLeaves: ctx._cstLeaves,
1468
- _cstChildren: ctx._cstChildren,
1469
- _cstRawChildren: ctx._cstRawChildren,
1470
- _cstTriviaLog: ctx._cstTriviaLog,
1471
- _triviaLog: ctx._triviaLog,
1472
- _fields: ctx._fields,
1473
- _cstBuf: ctx._cstBuf,
1474
- _tolerant: ctx._tolerant,
1475
- _sync: ctx._sync
1476
- };
1477
- ctx._probe = void 0;
1478
- ctx._errors = void 0;
1479
- ctx._cstLeaves = void 0;
1480
- ctx._cstChildren = void 0;
1481
- ctx._cstRawChildren = void 0;
1482
- ctx._cstTriviaLog = void 0;
1483
- ctx._triviaLog = void 0;
1484
- ctx._fields = void 0;
1485
- ctx._cstBuf = void 0;
1486
- ctx._tolerant = void 0;
1487
- ctx._sync = void 0;
1488
- try {
1489
- return sentinel.parse(input, pos, ctx).ok;
1490
- } finally {
1491
- ctx._probe = s._probe;
1492
- ctx._errors = s._errors;
1493
- ctx._cstLeaves = s._cstLeaves;
1494
- ctx._cstChildren = s._cstChildren;
1495
- ctx._cstRawChildren = s._cstRawChildren;
1496
- ctx._cstTriviaLog = s._cstTriviaLog;
1497
- ctx._triviaLog = s._triviaLog;
1498
- ctx._fields = s._fields;
1499
- ctx._cstBuf = s._cstBuf;
1500
- ctx._tolerant = s._tolerant;
1501
- ctx._sync = s._sync;
1502
- }
1503
- }
1504
- function orSentinel(a, b) {
1505
- if (b === void 0) return a;
1506
- return {
1507
- _tag: "orSentinel",
1508
- _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
1509
- _def: { tag: "unknown" },
1510
- parse(input, pos, ctx) {
1511
- const ra = a.parse(input, pos, ctx);
1512
- if (ra.ok) return ra;
1513
- return b.parse(input, pos, ctx);
1514
- }
1515
- };
1516
- }
1517
- function firstSetSentinel(fs) {
1518
- if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
1519
- const ranges = fs.ranges;
1520
- return {
1521
- _tag: "firstSetSentinel",
1522
- _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
1523
- _def: { tag: "unknown" },
1524
- parse(input, pos) {
1525
- const code = pos < input.length ? input.codePointAt(pos) : void 0;
1526
- if (code !== void 0) {
1527
- for (const r of ranges) {
1528
- if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
1529
- }
1530
- }
1531
- return { ok: false, expected: [], span: { start: pos, end: pos } };
1532
- }
1533
- };
1534
- }
1535
- function recoverScan(input, from, ctx, sync, expected) {
1536
- let scanPos = from;
1537
- while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
1538
- const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
1539
- ctx._errors?.push(error);
1540
- return { error, end: scanPos };
1541
- }
1542
- function matchesAt(sentinel, input, pos, ctx) {
1543
- return probeAt(sentinel, input, pos, ctx);
1544
- }
1545
- function captureError(ctx, error) {
1546
- if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
1547
- }
1548
- var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
1549
-
1550
1617
  // src/combinators/sequence.ts
1551
1618
  function sequence(...parsers) {
1552
1619
  const meta = {
@@ -1648,69 +1715,6 @@ function sequence(...parsers) {
1648
1715
  };
1649
1716
  }
1650
1717
 
1651
- // src/combinators/expect.ts
1652
- function deriveExpected(c) {
1653
- const def = c._def;
1654
- switch (def.tag) {
1655
- case "literal":
1656
- return [JSON.stringify(def.value)];
1657
- case "regex":
1658
- return [`/${def.source}/`];
1659
- case "keywords":
1660
- return def.words.map((w) => JSON.stringify(w));
1661
- case "label":
1662
- return [def.label];
1663
- case "choice":
1664
- return def.parsers.flatMap(deriveExpected);
1665
- case "sequence":
1666
- return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
1667
- case "node":
1668
- case "grammar":
1669
- case "trivia":
1670
- case "token":
1671
- case "optional":
1672
- case "many":
1673
- case "oneOrMore":
1674
- case "transform":
1675
- case "not":
1676
- return deriveExpected(def.parser);
1677
- case "lazy": {
1678
- const name = c._ruleName;
1679
- try {
1680
- return deriveExpected(def.thunk());
1681
- } catch {
1682
- return name ? [name] : [];
1683
- }
1684
- }
1685
- default:
1686
- return [];
1687
- }
1688
- }
1689
- function expect(combinator, label2) {
1690
- const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1691
- const meta = {
1692
- firstSet: combinator._meta.firstSet,
1693
- canMatchNewline: combinator._meta.canMatchNewline,
1694
- isTrivia: false
1695
- };
1696
- return {
1697
- _tag: "expect",
1698
- _meta: meta,
1699
- _def: { tag: "expect", parser: combinator, label: label2, expected },
1700
- parse(input, pos, ctx) {
1701
- const result = combinator.parse(input, pos, ctx);
1702
- if (result.ok) return result;
1703
- const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
1704
- ctx._errors?.push(error);
1705
- if (ctx._tolerant) captureError(ctx, error);
1706
- return { ok: true, value: error, span: { start: pos, end: pos } };
1707
- }
1708
- };
1709
- }
1710
- function isParseError(value) {
1711
- return typeof value === "object" && value !== null && value._tag === "parseError";
1712
- }
1713
-
1714
1718
  // src/combinators/repeat.ts
1715
1719
  function repItem(combinator, input, cur, ctx) {
1716
1720
  const mark = saveTriviaMark(ctx);
@@ -4541,6 +4545,21 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
4541
4545
  `${ind(ctx)}${endV} = ${endVar}`
4542
4546
  ];
4543
4547
  }
4548
+ function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
4549
+ const p = def.parsers[i];
4550
+ const gate = def.gates[i];
4551
+ if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
4552
+ const gateIdx = ctx.mapFns.length;
4553
+ ctx.mapFns.push(gate);
4554
+ ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
4555
+ const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
4556
+ const stmts = [`${ind(ctx)}if (${gateCond}) {`];
4557
+ ctx.indent++;
4558
+ stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
4559
+ ctx.indent--;
4560
+ stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
4561
+ return stmts;
4562
+ }
4544
4563
  function emitChoice(def, ctx, pos) {
4545
4564
  const allExpected = deriveExpectedArr(def.parsers);
4546
4565
  if (def.disjoint) {
@@ -4556,12 +4575,11 @@ function emitChoice(def, ctx, pos) {
4556
4575
  stmts.push(`${ind(ctx)}switch (${codeV}) {`);
4557
4576
  ctx.indent++;
4558
4577
  for (let i = 0; i < def.parsers.length; i++) {
4559
- const p = def.parsers[i];
4560
4578
  for (const cp of plan.cases[i]) stmts.push(`${ind(ctx)}case ${cp}:`);
4561
4579
  stmts.push(`${ind(ctx)}{`);
4562
4580
  ctx.indent++;
4563
4581
  stmts.push(
4564
- ...emitDisjointArm(p, ctx, pos, valV, endV),
4582
+ ...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
4565
4583
  `${ind(ctx)}break`
4566
4584
  );
4567
4585
  ctx.indent--;
@@ -4573,13 +4591,14 @@ function emitChoice(def, ctx, pos) {
4573
4591
  return { stmts, valueVar: valV, endVar: endV };
4574
4592
  }
4575
4593
  let first = true;
4576
- for (const p of def.parsers) {
4594
+ for (let i = 0; i < def.parsers.length; i++) {
4595
+ const p = def.parsers[i];
4577
4596
  const cond = firstSetCond(codeV, p._meta.firstSet);
4578
4597
  const kw = first ? "if" : "else if";
4579
4598
  first = false;
4580
4599
  stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
4581
4600
  ctx.indent++;
4582
- stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
4601
+ stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
4583
4602
  ctx.indent--;
4584
4603
  stmts.push(`${ind(ctx)}}`);
4585
4604
  }