parseman 0.6.2 → 0.7.0

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.
@@ -1014,8 +1014,10 @@ function optional(combinator) {
1014
1014
  _meta: meta,
1015
1015
  _def: { tag: "optional", parser: combinator },
1016
1016
  parse(input, pos, ctx) {
1017
+ const mark = saveTriviaMark(ctx);
1017
1018
  const result = combinator.parse(input, pos, ctx);
1018
1019
  if (result.ok) return result;
1020
+ rollbackTrivia(ctx, mark);
1019
1021
  return { ok: true, value: null, span: { start: pos, end: pos } };
1020
1022
  }
1021
1023
  };
@@ -1036,7 +1038,7 @@ function sepBy(combinator, separator) {
1036
1038
  const values = [first.value];
1037
1039
  let cur = first.span.end;
1038
1040
  while (cur < input.length) {
1039
- let mark = saveTriviaMark(ctx);
1041
+ const loopMark = saveTriviaMark(ctx);
1040
1042
  let sepPos = cur;
1041
1043
  if (ctx.trivia) {
1042
1044
  if (needsDeferredTriviaCommit(ctx)) {
@@ -1049,10 +1051,9 @@ function sepBy(combinator, separator) {
1049
1051
  }
1050
1052
  const sep = separator.parse(input, sepPos, ctx);
1051
1053
  if (!sep.ok) {
1052
- rollbackTrivia(ctx, mark);
1054
+ rollbackTrivia(ctx, loopMark);
1053
1055
  break;
1054
1056
  }
1055
- mark = saveTriviaMark(ctx);
1056
1057
  let nextPos = sep.span.end;
1057
1058
  if (ctx.trivia) {
1058
1059
  if (needsDeferredTriviaCommit(ctx)) {
@@ -1065,7 +1066,7 @@ function sepBy(combinator, separator) {
1065
1066
  }
1066
1067
  const next = combinator.parse(input, nextPos, ctx);
1067
1068
  if (!next.ok) {
1068
- rollbackTrivia(ctx, mark);
1069
+ rollbackTrivia(ctx, loopMark);
1069
1070
  break;
1070
1071
  }
1071
1072
  values.push(next.value);
@@ -1194,13 +1195,15 @@ function annotateSpan(span, index) {
1194
1195
 
1195
1196
  // src/combinators/grammar.ts
1196
1197
  function parser(opts, root) {
1198
+ const clearTrivia = opts.trivia === null;
1197
1199
  return {
1198
1200
  _tag: "grammar",
1199
1201
  _meta: root._meta,
1200
1202
  _def: {
1201
1203
  tag: "grammar",
1202
1204
  parser: root,
1203
- triviaParser: opts.trivia,
1205
+ triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
1206
+ clearTrivia,
1204
1207
  trackLines: opts.trackLines ?? false
1205
1208
  },
1206
1209
  parse(input, pos, _ctx) {
@@ -1208,7 +1211,11 @@ function parser(opts, root) {
1208
1211
  const ctx = {
1209
1212
  ..._ctx,
1210
1213
  trackLines,
1211
- ...opts.trivia !== void 0 ? {
1214
+ // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
1215
+ ...clearTrivia ? {
1216
+ trivia: void 0,
1217
+ triviaKindLabels: void 0
1218
+ } : opts.trivia != null ? {
1212
1219
  trivia: opts.trivia,
1213
1220
  ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
1214
1221
  } : {},
@@ -1223,6 +1230,9 @@ function parser(opts, root) {
1223
1230
  }
1224
1231
  };
1225
1232
  }
1233
+ function noTrivia(root) {
1234
+ return parser({ trivia: null }, root);
1235
+ }
1226
1236
 
1227
1237
  // src/compiler/trivia-fast-path.ts
1228
1238
  var BLOCK_COMMENT = String.raw`\/\*(?:[^*]|\*(?!\/))*\*\/`;
@@ -1545,6 +1555,41 @@ function v(ctx, prefix = "_v") {
1545
1555
  function ind(ctx) {
1546
1556
  return " ".repeat(ctx.indent);
1547
1557
  }
1558
+ function reindentStmts(stmts, targetLevels) {
1559
+ const nonEmpty = stmts.filter((s) => s.trim().length > 0);
1560
+ if (nonEmpty.length === 0) return stmts;
1561
+ const minLeading = Math.min(...nonEmpty.map((s) => s.length - s.trimStart().length));
1562
+ const targetPrefix = " ".repeat(targetLevels);
1563
+ return stmts.map((s) => s.trim().length === 0 ? "" : targetPrefix + s.slice(minLeading));
1564
+ }
1565
+ function failReturn(expected, posExpr) {
1566
+ return `return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
1567
+ }
1568
+ function failReturnArr(expectedArr, posExpr) {
1569
+ return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
1570
+ }
1571
+ function failBody(ctx, expected, posExpr) {
1572
+ if (ctx.failLabel) return `break ${ctx.failLabel}`;
1573
+ return failReturn(expected, posExpr);
1574
+ }
1575
+ function failArrBody(ctx, expectedArr, posExpr) {
1576
+ if (ctx.failLabel) return `break ${ctx.failLabel}`;
1577
+ return failReturnArr(expectedArr, posExpr);
1578
+ }
1579
+ function emitIfFail(ctx, cond, body) {
1580
+ return [
1581
+ `${ind(ctx)}if (${cond}) {`,
1582
+ `${ind(ctx)} ${body}`,
1583
+ `${ind(ctx)}}`
1584
+ ];
1585
+ }
1586
+ function emitElseFail(ctx, body) {
1587
+ return [
1588
+ `${ind(ctx)}else {`,
1589
+ `${ind(ctx)} ${body}`,
1590
+ `${ind(ctx)}}`
1591
+ ];
1592
+ }
1548
1593
  var NAMED_FN_FAIL = "_pfFail";
1549
1594
  var NAMED_FN_END = "_pfEnd";
1550
1595
  function namedFnPrelude() {
@@ -1555,8 +1600,10 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
1555
1600
  `function ${fnName}(input, _pos, _ctx) {`,
1556
1601
  ` let _pfok = false, _pfv, _pfe = _pos`,
1557
1602
  ` _pfail: {`,
1558
- ...bodyStmts,
1559
- ` _pfv = ${valueVar}; _pfe = ${endVar}; _pfok = true`,
1603
+ ...reindentStmts(bodyStmts, 2),
1604
+ ` _pfv = ${valueVar}`,
1605
+ ` _pfe = ${endVar}`,
1606
+ ` _pfok = true`,
1560
1607
  ` }`,
1561
1608
  ` if (!_pfok) return ${NAMED_FN_FAIL}`,
1562
1609
  ` ${NAMED_FN_END} = _pfe`,
@@ -1570,7 +1617,7 @@ function emitNamedFnCall(ctx, fnName, pos, failExpected) {
1570
1617
  return {
1571
1618
  stmts: [
1572
1619
  `${ind(ctx)}const ${vv} = ${fnName}(input, ${pos}, _ctx)`,
1573
- `${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, failExpected, pos).trim()}`,
1620
+ ...emitIfFail(ctx, `${vv} === ${NAMED_FN_FAIL}`, failBody(ctx, failExpected, pos)),
1574
1621
  `${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
1575
1622
  ],
1576
1623
  valueVar: vv,
@@ -1653,7 +1700,7 @@ function ensureTriviaFn(ctx) {
1653
1700
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
1654
1701
  ` let _e = _pos`,
1655
1702
  ` _triv: {`,
1656
- ...r.stmts,
1703
+ ...reindentStmts(r.stmts, 2),
1657
1704
  ` _e = ${r.endVar}`,
1658
1705
  ` }`,
1659
1706
  ` if (_cap && _e > _pos) {`,
@@ -1668,14 +1715,6 @@ function ensureTriviaFn(ctx) {
1668
1715
  function ensureTriviaCaptureFn(ctx) {
1669
1716
  return ensureTriviaFn(ctx);
1670
1717
  }
1671
- function failStmt(ctx, expected, posExpr) {
1672
- if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
1673
- return `${ind(ctx)}return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
1674
- }
1675
- function failArr(ctx, expectedArr, posExpr) {
1676
- if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
1677
- return `${ind(ctx)}return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
1678
- }
1679
1718
  function firstSetCond(codeVar, fs) {
1680
1719
  if (fs.kind === "any") return "true";
1681
1720
  if (fs.kind === "empty") return "false";
@@ -1691,19 +1730,32 @@ function emitFallible(inner, ctx, pos) {
1691
1730
  const savedLabel = ctx.failLabel;
1692
1731
  const savedIndent = ctx.indent;
1693
1732
  ctx.failLabel = lbl;
1694
- ctx.indent = 0;
1733
+ ctx.indent = savedIndent + 1;
1695
1734
  const r = emit(inner, ctx, pos);
1696
1735
  ctx.failLabel = savedLabel;
1697
1736
  ctx.indent = savedIndent;
1698
1737
  const ind0 = ind(ctx);
1738
+ const mL = ctx.capturing ? v(ctx, "_fcl") : null;
1739
+ const mR = ctx.capturing ? v(ctx, "_fcr") : null;
1740
+ const mTl = ctx.capturing ? v(ctx, "_fctl") : null;
1741
+ const mLg = ctx.capturing ? v(ctx, "_fclg") : null;
1699
1742
  const stmts = [
1700
1743
  `${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
1744
+ ...mL ? [
1745
+ `${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
1746
+ `${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
1747
+ `${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
1748
+ `${ind0}const ${mLg} = _ctx._triviaLog?.length ?? 0`
1749
+ ] : [],
1701
1750
  `${ind0}${lbl}: {`,
1702
1751
  ...r.stmts,
1703
1752
  `${ind0} ${valV} = ${r.valueVar}`,
1704
1753
  `${ind0} ${endV} = ${r.endVar}`,
1705
1754
  `${ind0} ${okV} = true`,
1706
- `${ind0}}`
1755
+ `${ind0}}`,
1756
+ ...mL ? [
1757
+ `${ind0}if (!${okV}) { if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg} }`
1758
+ ] : []
1707
1759
  ];
1708
1760
  return { stmts, okVar: okV, valVar: valV, endVar: endV };
1709
1761
  }
@@ -1716,9 +1768,9 @@ function emitLit(def, ctx, pos) {
1716
1768
  if (caseInsensitive) {
1717
1769
  ctx.needsCollator = true;
1718
1770
  stmts.push(
1719
- `${ind(ctx)}if (${pos} + ${len} > input.length) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1771
+ ...emitIfFail(ctx, `${pos} + ${len} > input.length`, failBody(ctx, expectedStr, pos)),
1720
1772
  `${ind(ctx)}const ${vv}_s = input.slice(${pos}, ${pos} + ${len})`,
1721
- `${ind(ctx)}if (_collator.compare(${vv}_s, ${JSON.stringify(value)}) !== 0) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1773
+ ...emitIfFail(ctx, `_collator.compare(${vv}_s, ${JSON.stringify(value)}) !== 0`, failBody(ctx, expectedStr, pos)),
1722
1774
  `${ind(ctx)}const ${vv} = ${vv}_s`
1723
1775
  );
1724
1776
  } else if (len === 0) {
@@ -1726,7 +1778,7 @@ function emitLit(def, ctx, pos) {
1726
1778
  } else if (len === 1) {
1727
1779
  const code = value.codePointAt(0);
1728
1780
  stmts.push(
1729
- `${ind(ctx)}if (${pos} >= input.length || input.charCodeAt(${pos}) !== ${code}) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1781
+ ...emitIfFail(ctx, `${pos} >= input.length || input.charCodeAt(${pos}) !== ${code}`, failBody(ctx, expectedStr, pos)),
1730
1782
  `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
1731
1783
  );
1732
1784
  } else if (len <= 4) {
@@ -1735,12 +1787,12 @@ function emitLit(def, ctx, pos) {
1735
1787
  (_, i) => `input.charCodeAt(${pos}${i > 0 ? ` + ${i}` : ""}) !== ${value.codePointAt(i)}`
1736
1788
  ).join(" || ");
1737
1789
  stmts.push(
1738
- `${ind(ctx)}if (${pos} + ${len} > input.length || ${checks}) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1790
+ ...emitIfFail(ctx, `${pos} + ${len} > input.length || ${checks}`, failBody(ctx, expectedStr, pos)),
1739
1791
  `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
1740
1792
  );
1741
1793
  } else {
1742
1794
  stmts.push(
1743
- `${ind(ctx)}if (!input.startsWith(${JSON.stringify(value)}, ${pos})) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1795
+ ...emitIfFail(ctx, `!input.startsWith(${JSON.stringify(value)}, ${pos})`, failBody(ctx, expectedStr, pos)),
1744
1796
  `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
1745
1797
  );
1746
1798
  }
@@ -1768,7 +1820,7 @@ function emitKeywords(def, ctx, pos) {
1768
1820
  const stmts = [
1769
1821
  `${ind(ctx)}${rName}.lastIndex = ${pos}`,
1770
1822
  `${ind(ctx)}const ${mv} = ${rName}.exec(input)`,
1771
- `${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, '"keyword"', pos).trim()}`,
1823
+ ...emitIfFail(ctx, `${mv} === null`, failBody(ctx, '"keyword"', pos)),
1772
1824
  `${ind(ctx)}const ${vv} = ${mv}[0]`
1773
1825
  ];
1774
1826
  const endVar = `${pos} + ${vv}.length`;
@@ -1790,7 +1842,7 @@ function emitRegex(def, ctx, pos) {
1790
1842
  const stmts = [
1791
1843
  `${ind(ctx)}${rName}.lastIndex = ${pos}`,
1792
1844
  `${ind(ctx)}const ${mv} = ${rName}.exec(input)`,
1793
- `${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1845
+ ...emitIfFail(ctx, `${mv} === null`, failBody(ctx, expectedStr, pos)),
1794
1846
  `${ind(ctx)}const ${vv} = ${mv}[0]`
1795
1847
  ];
1796
1848
  const endVar = `${pos} + ${vv}.length`;
@@ -1871,11 +1923,12 @@ function emitChoice(def, ctx, pos) {
1871
1923
  ctx.indent++;
1872
1924
  const r = emit(p, ctx, pos);
1873
1925
  stmts.push(...r.stmts);
1874
- stmts.push(`${ind(ctx)}${valV} = ${r.valueVar}; ${endV} = ${r.endVar}`);
1926
+ stmts.push(`${ind(ctx)}${valV} = ${r.valueVar}`);
1927
+ stmts.push(`${ind(ctx)}${endV} = ${r.endVar}`);
1875
1928
  ctx.indent--;
1876
1929
  stmts.push(`${ind(ctx)}}`);
1877
1930
  }
1878
- stmts.push(`${ind(ctx)}else ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
1931
+ stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
1879
1932
  return { stmts, valueVar: valV, endVar: endV };
1880
1933
  }
1881
1934
  return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
@@ -1898,7 +1951,7 @@ function emitGreedyClassify(def, superIndex, allExpected, ctx, pos) {
1898
1951
  const stmts = [
1899
1952
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
1900
1953
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
1901
- `${ind(ctx)}if (${matchV} === null) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`,
1954
+ ...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, allExpected, pos)),
1902
1955
  `${ind(ctx)}const ${wordV} = ${matchV}[0]`,
1903
1956
  `${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
1904
1957
  `${ind(ctx)}let ${valV}`
@@ -1947,12 +2000,13 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
1947
2000
  stmts.push(
1948
2001
  ...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
1949
2002
  ...tR.stmts,
1950
- `${ind(ctx)}${valV} = ${tR.valueVar}; ${endV} = ${litEnd}`
2003
+ `${ind(ctx)}${valV} = ${tR.valueVar}`,
2004
+ `${ind(ctx)}${endV} = ${litEnd}`
1951
2005
  );
1952
2006
  ctx.indent--;
1953
2007
  stmts.push(`${ind(ctx)}}`);
1954
2008
  }
1955
- stmts.push(`${ind(ctx)}else ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
2009
+ stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
1956
2010
  return { stmts, valueVar: valV, endVar: endV };
1957
2011
  }
1958
2012
  function emitFirstMatch(def, allExpected, ctx, pos) {
@@ -1998,17 +2052,26 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
1998
2052
  const rejectCond = autoNot.map(
1999
2053
  (check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${endVar})`
2000
2054
  ).join(" || ");
2001
- stmts.push(
2002
- `${ind0} if (${okVar}) { const ${anCode} = ${endVar} < input.length ? input.charCodeAt(${endVar}) : -1; if (!(${rejectCond})) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true } }`
2003
- );
2055
+ stmts.push(`${ind0} if (${okVar}) {`);
2056
+ stmts.push(`${ind0} const ${anCode} = ${endVar} < input.length ? input.charCodeAt(${endVar}) : -1`);
2057
+ stmts.push(`${ind0} if (!(${rejectCond})) {`);
2058
+ stmts.push(`${ind0} ${resValV} = ${valVar}`);
2059
+ stmts.push(`${ind0} ${resEndV} = ${endVar}`);
2060
+ stmts.push(`${ind0} ${resOkV} = true`);
2061
+ stmts.push(`${ind0} }`);
2062
+ stmts.push(`${ind0} }`);
2004
2063
  if (rollback) stmts.push(`${ind0} if (!${resOkV}) { ${rollback} }`);
2005
2064
  } else {
2006
- stmts.push(`${ind0} if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
2065
+ stmts.push(`${ind0} if (${okVar}) {`);
2066
+ stmts.push(`${ind0} ${resValV} = ${valVar}`);
2067
+ stmts.push(`${ind0} ${resEndV} = ${endVar}`);
2068
+ stmts.push(`${ind0} ${resOkV} = true`);
2069
+ stmts.push(`${ind0} }`);
2007
2070
  if (rollback) stmts.push(`${ind0} else { ${rollback} }`);
2008
2071
  }
2009
2072
  stmts.push(`${ind0}}`);
2010
2073
  }
2011
- stmts.push(`${ind0}if (!${resOkV}) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
2074
+ stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, allExpected, pos)));
2012
2075
  return { stmts, valueVar: resValV, endVar: resEndV };
2013
2076
  }
2014
2077
  function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
@@ -2133,32 +2196,26 @@ function emitSepBy(_p, def, ctx, pos) {
2133
2196
  const markV = v(ctx, "_mk");
2134
2197
  const markTl = v(ctx, "_mktl");
2135
2198
  const markLog = v(ctx, "_mklg");
2199
+ const markLv = v(ctx, "_mklv");
2136
2200
  const spV = v(ctx, "_sp");
2137
2201
  stmts.push(
2138
2202
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
2139
2203
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
2140
2204
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
2205
+ `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
2141
2206
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
2142
2207
  );
2143
2208
  sepAtPos = spV;
2144
- const sepRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; `;
2209
+ const rollbackToSep = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; `;
2145
2210
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
2146
- stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sepRollback}break }`);
2147
- const mark2V = v(ctx, "_mk2");
2148
- const mark2Tl = v(ctx, "_mktl2");
2149
- const mark2Log = v(ctx, "_mklg2");
2211
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}break }`);
2150
2212
  const npV = v(ctx, "_np");
2151
- stmts.push(
2152
- `${ind(ctx)}const ${mark2V} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
2153
- `${ind(ctx)}const ${mark2Tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
2154
- `${ind(ctx)}const ${mark2Log} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
2155
- `${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`
2156
- );
2157
- const nextRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mark2V}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mark2Tl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mark2Log}; `;
2213
+ stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
2158
2214
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV);
2159
2215
  stmts.push(
2160
2216
  ...nextStmts,
2161
- `${ind(ctx)}if (!${nextOk}) { ${nextRollback}break }`,
2217
+ // item failed → unwind the separator too, back to the end of the last item
2218
+ `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
2162
2219
  `${ind(ctx)}${arrV}.push(${nextVal})`,
2163
2220
  `${ind(ctx)}${curV} = ${nextEnd}`
2164
2221
  );
@@ -2180,12 +2237,21 @@ function emitSepBy(_p, def, ctx, pos) {
2180
2237
  );
2181
2238
  }
2182
2239
  } else {
2240
+ const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
2241
+ const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
2242
+ if (markLv) {
2243
+ stmts.push(
2244
+ `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
2245
+ `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
2246
+ );
2247
+ }
2183
2248
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
2184
2249
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) break`);
2250
+ const nextRb = markLv ? `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markRw}; ` : "";
2185
2251
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd);
2186
2252
  stmts.push(
2187
2253
  ...nextStmts,
2188
- `${ind(ctx)}if (!${nextOk}) break`,
2254
+ `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`,
2189
2255
  `${ind(ctx)}${arrV}.push(${nextVal})`,
2190
2256
  `${ind(ctx)}${curV} = ${nextEnd}`
2191
2257
  );
@@ -2229,12 +2295,12 @@ function emitScanTo(def, ctx, pos) {
2229
2295
  if (!def.orEOF) {
2230
2296
  const sentDef = def.sentinel._def;
2231
2297
  const expectedStr = sentDef.tag === "literal" ? JSON.stringify([JSON.stringify(sentDef.value)]) : `["sentinel"]`;
2232
- stmts.push(`${ind(ctx)}if (!${foundV}) ${failArr({ ...ctx, indent: 0 }, expectedStr, pos)}`);
2298
+ stmts.push(...emitIfFail(ctx, `!${foundV}`, failArrBody(ctx, expectedStr, pos)));
2233
2299
  }
2234
2300
  const valV = v(ctx);
2235
2301
  stmts.push(`${ind(ctx)}const ${valV} = input.slice(${pos}, ${curV})`);
2236
2302
  if (ctx.capturing) {
2237
- const cap = emitLeafCapture(ctx, valV, pos, curV).map((s) => " " + s);
2303
+ const cap = reindentStmts(emitLeafCapture(ctx, valV, pos, curV), ctx.indent + 1);
2238
2304
  stmts.push(`${ind(ctx)}if (${curV} > ${pos}) {`, ...cap, `${ind(ctx)}}`);
2239
2305
  }
2240
2306
  return { stmts, valueVar: valV, endVar: curV };
@@ -2244,7 +2310,7 @@ function emitNot(def, ctx, pos) {
2244
2310
  return {
2245
2311
  stmts: [
2246
2312
  ...stmts,
2247
- `${ind(ctx)}if (${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"not"', pos).trim()}`
2313
+ ...emitIfFail(ctx, okVar, failBody(ctx, '"not"', pos))
2248
2314
  ],
2249
2315
  valueVar: "null",
2250
2316
  endVar: pos
@@ -2271,7 +2337,7 @@ function emitNode(def, ctx, pos) {
2271
2337
  const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
2272
2338
  stmts.push(...innerStmts);
2273
2339
  stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}`);
2274
- stmts.push(`${i}if (!${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"node"', pos).trim()}`);
2340
+ stmts.push(...emitIfFail(ctx, `!${okVar}`, failBody(ctx, '"node"', pos)));
2275
2341
  const stV = v(ctx, "_nst");
2276
2342
  stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
2277
2343
  const ndV = v(ctx, "_nd");
@@ -2291,7 +2357,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
2291
2357
  const ev = v(ctx, "_rte");
2292
2358
  const stmts = [
2293
2359
  `${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
2294
- `${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"runtime"', pos).trim()}`,
2360
+ ...emitIfFail(ctx, `!${rv}.ok`, failBody(ctx, '"runtime"', pos)),
2295
2361
  `${ind(ctx)}const ${vv} = ${rv}.value`,
2296
2362
  `${ind(ctx)}const ${ev} = ${rv}.span.end`
2297
2363
  ];
@@ -2325,16 +2391,14 @@ function emitRecover(def, ctx, pos) {
2325
2391
  const ind0 = ind(ctx);
2326
2392
  const scanV = v(ctx, "_sc");
2327
2393
  const errV = v(ctx, "_err");
2328
- const savedIndent = ctx.indent;
2329
- ctx.indent += 2;
2394
+ const whileBodyLevels = ctx.indent + 2;
2330
2395
  const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, ctx, scanV);
2331
- ctx.indent = savedIndent;
2332
2396
  const stmts = [
2333
2397
  ...innerStmts,
2334
2398
  `${ind0}if (!${okVar}) {`,
2335
2399
  `${ind0} let ${scanV} = ${pos}`,
2336
2400
  `${ind0} while (${scanV} < input.length) {`,
2337
- ...sentStmts,
2401
+ ...reindentStmts(sentStmts, whileBodyLevels),
2338
2402
  `${ind0} if (${sentOk}) break`,
2339
2403
  `${ind0} ${scanV}++`,
2340
2404
  `${ind0} }`,
@@ -2416,7 +2480,7 @@ function emit(p, ctx, pos) {
2416
2480
  // try skipped; if fails, keep main end
2417
2481
  `${ind(ctx)}let ${endV} = ${mainR.endVar}`,
2418
2482
  `${ind(ctx)}try {`,
2419
- ...skipR.stmts.map((s) => " " + s),
2483
+ ...reindentStmts(skipR.stmts, ctx.indent + 1),
2420
2484
  `${ind(ctx)} ${endV} = ${skipR.endVar}`,
2421
2485
  `${ind(ctx)}} catch {}`
2422
2486
  ],
@@ -2433,7 +2497,10 @@ function emit(p, ctx, pos) {
2433
2497
  case "grammar": {
2434
2498
  const savedTrivia = ctx.activeTrivia;
2435
2499
  const savedKindLabels = ctx.triviaKindLabels;
2436
- if (def.triviaParser) {
2500
+ if (def.clearTrivia) {
2501
+ ctx.activeTrivia = void 0;
2502
+ ctx.triviaKindLabels = void 0;
2503
+ } else if (def.triviaParser) {
2437
2504
  ctx.activeTrivia = def.triviaParser;
2438
2505
  if (def.triviaParser._meta.triviaKindLabels) {
2439
2506
  ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
@@ -2458,7 +2525,7 @@ function emit(p, ctx, pos) {
2458
2525
  const vv = v(ctx);
2459
2526
  return {
2460
2527
  stmts: [
2461
- `${ind(ctx)}if (!_mf[${fnIdx}](_ctx.state)) ${failStmt({ ...ctx, indent: 0 }, '"gate"', pos).trim()}`,
2528
+ ...emitIfFail(ctx, `!_mf[${fnIdx}](_ctx.state)`, failBody(ctx, '"gate"', pos)),
2462
2529
  `${ind(ctx)}const ${vv} = null`
2463
2530
  ],
2464
2531
  valueVar: vv,
@@ -2490,7 +2557,7 @@ function emit(p, ctx, pos) {
2490
2557
  stmts: [
2491
2558
  `${ind(ctx)}const ${rv} = { ..._ctx, state: _mf[${evIdx}]() }`,
2492
2559
  `${ind(ctx)}const ${vv} = ${fn}(input, ${pos}, ${rv})`,
2493
- `${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, '"withCtx"', pos).trim()}`,
2560
+ ...emitIfFail(ctx, `${vv} === ${NAMED_FN_FAIL}`, failBody(ctx, '"withCtx"', pos)),
2494
2561
  `${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
2495
2562
  ],
2496
2563
  valueVar: vv,
@@ -2567,7 +2634,7 @@ function compile(combinator, mapFnSources) {
2567
2634
  ...ctx.regexDecls,
2568
2635
  "",
2569
2636
  ...namedPrelude,
2570
- ...ctx.namedFnDecls,
2637
+ ctx.namedFnDecls.join("\n\n"),
2571
2638
  `${collatorDecl}function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
2572
2639
  ` let pos = _pos`,
2573
2640
  ...r.stmts,
@@ -2578,7 +2645,7 @@ function compile(combinator, mapFnSources) {
2578
2645
  ...ctx.regexDecls,
2579
2646
  collatorDecl,
2580
2647
  ...namedPrelude,
2581
- ...ctx.namedFnDecls,
2648
+ ...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
2582
2649
  `let pos = _pos`,
2583
2650
  ...r.stmts,
2584
2651
  `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
@@ -2613,7 +2680,7 @@ function compile(combinator, mapFnSources) {
2613
2680
  function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
2614
2681
  const bodyLines = [
2615
2682
  ` let pos = _pos`,
2616
- ...r.stmts.map((s) => ` ${s}`),
2683
+ ...r.stmts,
2617
2684
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
2618
2685
  ];
2619
2686
  const innerFn = [
@@ -2626,17 +2693,23 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
2626
2693
  const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl;
2627
2694
  if (!needsWrapper) return innerFn;
2628
2695
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
2629
- return [
2630
- `/* @__PURE__ */ (() => {`,
2696
+ const hoistedDecls = [
2631
2697
  ...ctx.regexDecls.map((d) => ` ${d}`),
2632
2698
  collatorDecl ? ` ${collatorDecl.trim()}` : "",
2633
2699
  mfDecl,
2634
2700
  buildDecl,
2635
2701
  ...namedPrelude.map((l) => ` ${l}`),
2636
- ...ctx.namedFnDecls.flatMap((f) => f.split("\n").map((l) => ` ${l}`)),
2702
+ ...ctx.namedFnDecls.flatMap((decl, i) => {
2703
+ const lines = decl.split("\n").map((l) => ` ${l}`);
2704
+ return i > 0 ? ["", ...lines] : lines;
2705
+ })
2706
+ ].filter(Boolean);
2707
+ return [
2708
+ `/* @__PURE__ */ (() => {`,
2709
+ ...hoistedDecls,
2637
2710
  ` return ${innerFn}`,
2638
2711
  `})()`
2639
- ].filter(Boolean).join("\n");
2712
+ ].join("\n");
2640
2713
  }
2641
2714
 
2642
2715
  // src/combinators/scanTo.ts
@@ -2714,7 +2787,8 @@ var SUPPORTED = {
2714
2787
  optional: (...a) => optional(a[0]),
2715
2788
  sepBy: (...a) => sepBy(a[0], a[1]),
2716
2789
  trivia: (...a) => trivia(a[0]),
2717
- label: (...a) => label(a[0], a[1])
2790
+ label: (...a) => label(a[0], a[1]),
2791
+ noTrivia: (...a) => noTrivia(a[0])
2718
2792
  };
2719
2793
  function isScopeEntry(v2) {
2720
2794
  return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
@@ -3170,7 +3244,9 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
3170
3244
  replacements.push({
3171
3245
  start: init.start,
3172
3246
  end: init.end,
3173
- replacement: `{ ${compiledRules.entries.map(([k, expr]) => `${k}: ${expr}`).join(", ")} }`
3247
+ replacement: `{
3248
+ ${compiledRules.entries.map(([k, expr]) => ` ${k}: ${expr}`).join(",\n")}
3249
+ }`
3174
3250
  });
3175
3251
  continue;
3176
3252
  }