parseman 0.26.0 → 0.26.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.
@@ -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
  }
@@ -6306,6 +6325,34 @@ function evalRuleMapIR(ir) {
6306
6325
  n._def.buildSrc = src;
6307
6326
  return n;
6308
6327
  };
6328
+ const _gch = (items) => {
6329
+ const gateSrcs = [];
6330
+ const arms = items.map((it) => {
6331
+ if (Array.isArray(it)) {
6332
+ const [src, comb] = it;
6333
+ gateSrcs.push(src);
6334
+ let gate;
6335
+ try {
6336
+ gate = (0, eval)(`(${src})`);
6337
+ } catch {
6338
+ gate = () => {
6339
+ throw new Error("IR gate fn not materialized");
6340
+ };
6341
+ }
6342
+ return { gate, combinator: comb };
6343
+ }
6344
+ gateSrcs.push(null);
6345
+ return it;
6346
+ });
6347
+ const c = choice(...arms);
6348
+ const gates = c._def.gates;
6349
+ if (gates && gates.length !== gateSrcs.length) {
6350
+ throw new Error(`_gch: gateSrcs length ${gateSrcs.length} != choice gates length ${gates.length}`);
6351
+ }
6352
+ ;
6353
+ c._def.gateSrcs = gateSrcs;
6354
+ return c;
6355
+ };
6309
6356
  const fn = new Function(
6310
6357
  "rules",
6311
6358
  "ref",
@@ -6331,6 +6378,7 @@ function evalRuleMapIR(ir) {
6331
6378
  "expect",
6332
6379
  "_tf",
6333
6380
  "_nd",
6381
+ "_gch",
6334
6382
  `return (${ir})`
6335
6383
  );
6336
6384
  const map = fn(
@@ -6357,7 +6405,8 @@ function evalRuleMapIR(ir) {
6357
6405
  field,
6358
6406
  expect,
6359
6407
  _tf,
6360
- _nd
6408
+ _nd,
6409
+ _gch
6361
6410
  );
6362
6411
  return Object.entries(map);
6363
6412
  }
@@ -6469,8 +6518,16 @@ ${body}
6469
6518
  case "sequence":
6470
6519
  return `sequence(${def.parsers.map(kid).join(", ")})`;
6471
6520
  case "choice": {
6472
- if (def.gates.some((g) => g !== null)) throw new Unserializable("choice with a gate() has no source");
6473
- return `choice(${def.parsers.map(kid).join(", ")})`;
6521
+ const gates = def.gates;
6522
+ if (gates.every((g) => g === null)) return `choice(${def.parsers.map(kid).join(", ")})`;
6523
+ const gateSrcs = def.gateSrcs;
6524
+ const items = def.parsers.map((p, i) => {
6525
+ if (gates[i] === null) return kid(p);
6526
+ const src = gateSrcs?.[i];
6527
+ if (src == null) throw new Unserializable("choice gate() has no captured source");
6528
+ return `[${JSON.stringify(src)}, ${kid(p)}]`;
6529
+ });
6530
+ return `_gch([${items.join(", ")}])`;
6474
6531
  }
6475
6532
  case "many":
6476
6533
  return `many(${kid(def.parser)})`;
@@ -6651,6 +6708,48 @@ var { isFinite } = Number;
6651
6708
  registerRegexAnalyzer(firstSetFromRegex);
6652
6709
 
6653
6710
  // src/plugin/evaluator.ts
6711
+ function stripTsFromSource(node2, code) {
6712
+ const cuts = [];
6713
+ const walk2 = (n) => {
6714
+ if (!n || typeof n !== "object") return;
6715
+ const rec = n;
6716
+ if (typeof rec.type === "string" && rec.type.startsWith("TS") && typeof rec.start === "number" && typeof rec.end === "number") {
6717
+ const ex = rec.expression;
6718
+ if ((rec.type === "TSAsExpression" || rec.type === "TSSatisfiesExpression" || rec.type === "TSNonNullExpression" || rec.type === "TSInstantiationExpression") && ex && typeof ex.end === "number") {
6719
+ cuts.push([ex.end, rec.end]);
6720
+ walk2(rec.expression);
6721
+ return;
6722
+ }
6723
+ if (rec.type === "TSTypeAssertion" && ex && typeof ex.start === "number") {
6724
+ cuts.push([rec.start, ex.start]);
6725
+ walk2(rec.expression);
6726
+ return;
6727
+ }
6728
+ cuts.push([rec.start, rec.end]);
6729
+ return;
6730
+ }
6731
+ for (const key of Object.keys(rec)) {
6732
+ if (key === "type" || key === "start" || key === "end") continue;
6733
+ const v2 = rec[key];
6734
+ if (Array.isArray(v2)) {
6735
+ for (const item of v2) walk2(item);
6736
+ } else if (v2 && typeof v2 === "object") walk2(v2);
6737
+ }
6738
+ };
6739
+ walk2(node2);
6740
+ const start = node2.start;
6741
+ const end = node2.end;
6742
+ if (cuts.length === 0) return code.slice(start, end);
6743
+ cuts.sort((a, b) => a[0] - b[0]);
6744
+ let out = "";
6745
+ let cur = start;
6746
+ for (const [s, e] of cuts) {
6747
+ if (s < cur) continue;
6748
+ out += code.slice(cur, s);
6749
+ cur = e;
6750
+ }
6751
+ return out + code.slice(cur, end);
6752
+ }
6654
6753
  function isWordFactory(v2) {
6655
6754
  return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
6656
6755
  }
@@ -6926,7 +7025,7 @@ function exprToCombi(node2, scope, code, mfs) {
6926
7025
  if (isGatedArmExpr(argNode)) {
6927
7026
  const parts = gatedArmParts(argNode);
6928
7027
  if (!parts) return null;
6929
- const gateSrc = code.slice(parts.gate.start, parts.gate.end);
7028
+ const gateSrc = stripTsFromSource(parts.gate, code);
6930
7029
  mfs.push(gateSrc);
6931
7030
  const combi = anyValue(parts.combinator, scope, code, mfs);
6932
7031
  if (!isCombinator(combi)) return null;