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.
package/dist/index.cjs CHANGED
@@ -45,6 +45,7 @@ __export(index_exports, {
45
45
  makeFunctionalDoc: () => makeFunctionalDoc,
46
46
  makeWord: () => makeWord,
47
47
  many: () => many,
48
+ noTrivia: () => noTrivia,
48
49
  node: () => node,
49
50
  not: () => not,
50
51
  offsetToLineCol: () => offsetToLineCol,
@@ -1052,8 +1053,10 @@ function optional(combinator) {
1052
1053
  _meta: meta,
1053
1054
  _def: { tag: "optional", parser: combinator },
1054
1055
  parse(input, pos, ctx) {
1056
+ const mark = saveTriviaMark(ctx);
1055
1057
  const result = combinator.parse(input, pos, ctx);
1056
1058
  if (result.ok) return result;
1059
+ rollbackTrivia(ctx, mark);
1057
1060
  return { ok: true, value: null, span: { start: pos, end: pos } };
1058
1061
  }
1059
1062
  };
@@ -1074,7 +1077,7 @@ function sepBy(combinator, separator) {
1074
1077
  const values = [first.value];
1075
1078
  let cur = first.span.end;
1076
1079
  while (cur < input.length) {
1077
- let mark = saveTriviaMark(ctx);
1080
+ const loopMark = saveTriviaMark(ctx);
1078
1081
  let sepPos = cur;
1079
1082
  if (ctx.trivia) {
1080
1083
  if (needsDeferredTriviaCommit(ctx)) {
@@ -1087,10 +1090,9 @@ function sepBy(combinator, separator) {
1087
1090
  }
1088
1091
  const sep = separator.parse(input, sepPos, ctx);
1089
1092
  if (!sep.ok) {
1090
- rollbackTrivia(ctx, mark);
1093
+ rollbackTrivia(ctx, loopMark);
1091
1094
  break;
1092
1095
  }
1093
- mark = saveTriviaMark(ctx);
1094
1096
  let nextPos = sep.span.end;
1095
1097
  if (ctx.trivia) {
1096
1098
  if (needsDeferredTriviaCommit(ctx)) {
@@ -1103,7 +1105,7 @@ function sepBy(combinator, separator) {
1103
1105
  }
1104
1106
  const next = combinator.parse(input, nextPos, ctx);
1105
1107
  if (!next.ok) {
1106
- rollbackTrivia(ctx, mark);
1108
+ rollbackTrivia(ctx, loopMark);
1107
1109
  break;
1108
1110
  }
1109
1111
  values.push(next.value);
@@ -1306,13 +1308,15 @@ function annotateSpan(span, index) {
1306
1308
 
1307
1309
  // src/combinators/grammar.ts
1308
1310
  function parser(opts, root) {
1311
+ const clearTrivia = opts.trivia === null;
1309
1312
  return {
1310
1313
  _tag: "grammar",
1311
1314
  _meta: root._meta,
1312
1315
  _def: {
1313
1316
  tag: "grammar",
1314
1317
  parser: root,
1315
- triviaParser: opts.trivia,
1318
+ triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
1319
+ clearTrivia,
1316
1320
  trackLines: opts.trackLines ?? false
1317
1321
  },
1318
1322
  parse(input, pos, _ctx) {
@@ -1320,7 +1324,11 @@ function parser(opts, root) {
1320
1324
  const ctx = {
1321
1325
  ..._ctx,
1322
1326
  trackLines,
1323
- ...opts.trivia !== void 0 ? {
1327
+ // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
1328
+ ...clearTrivia ? {
1329
+ trivia: void 0,
1330
+ triviaKindLabels: void 0
1331
+ } : opts.trivia != null ? {
1324
1332
  trivia: opts.trivia,
1325
1333
  ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
1326
1334
  } : {},
@@ -1335,6 +1343,9 @@ function parser(opts, root) {
1335
1343
  }
1336
1344
  };
1337
1345
  }
1346
+ function noTrivia(root) {
1347
+ return parser({ trivia: null }, root);
1348
+ }
1338
1349
  function parse(combinator, input, opts = {}) {
1339
1350
  const trackLines = opts.trackLines ?? false;
1340
1351
  const _errors = opts.recover ? [] : void 0;
@@ -1673,6 +1684,41 @@ function v(ctx, prefix = "_v") {
1673
1684
  function ind(ctx) {
1674
1685
  return " ".repeat(ctx.indent);
1675
1686
  }
1687
+ function reindentStmts(stmts, targetLevels) {
1688
+ const nonEmpty = stmts.filter((s) => s.trim().length > 0);
1689
+ if (nonEmpty.length === 0) return stmts;
1690
+ const minLeading = Math.min(...nonEmpty.map((s) => s.length - s.trimStart().length));
1691
+ const targetPrefix = " ".repeat(targetLevels);
1692
+ return stmts.map((s) => s.trim().length === 0 ? "" : targetPrefix + s.slice(minLeading));
1693
+ }
1694
+ function failReturn(expected, posExpr) {
1695
+ return `return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
1696
+ }
1697
+ function failReturnArr(expectedArr, posExpr) {
1698
+ return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
1699
+ }
1700
+ function failBody(ctx, expected, posExpr) {
1701
+ if (ctx.failLabel) return `break ${ctx.failLabel}`;
1702
+ return failReturn(expected, posExpr);
1703
+ }
1704
+ function failArrBody(ctx, expectedArr, posExpr) {
1705
+ if (ctx.failLabel) return `break ${ctx.failLabel}`;
1706
+ return failReturnArr(expectedArr, posExpr);
1707
+ }
1708
+ function emitIfFail(ctx, cond, body) {
1709
+ return [
1710
+ `${ind(ctx)}if (${cond}) {`,
1711
+ `${ind(ctx)} ${body}`,
1712
+ `${ind(ctx)}}`
1713
+ ];
1714
+ }
1715
+ function emitElseFail(ctx, body) {
1716
+ return [
1717
+ `${ind(ctx)}else {`,
1718
+ `${ind(ctx)} ${body}`,
1719
+ `${ind(ctx)}}`
1720
+ ];
1721
+ }
1676
1722
  var NAMED_FN_FAIL = "_pfFail";
1677
1723
  var NAMED_FN_END = "_pfEnd";
1678
1724
  function namedFnPrelude() {
@@ -1683,8 +1729,10 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
1683
1729
  `function ${fnName}(input, _pos, _ctx) {`,
1684
1730
  ` let _pfok = false, _pfv, _pfe = _pos`,
1685
1731
  ` _pfail: {`,
1686
- ...bodyStmts,
1687
- ` _pfv = ${valueVar}; _pfe = ${endVar}; _pfok = true`,
1732
+ ...reindentStmts(bodyStmts, 2),
1733
+ ` _pfv = ${valueVar}`,
1734
+ ` _pfe = ${endVar}`,
1735
+ ` _pfok = true`,
1688
1736
  ` }`,
1689
1737
  ` if (!_pfok) return ${NAMED_FN_FAIL}`,
1690
1738
  ` ${NAMED_FN_END} = _pfe`,
@@ -1698,7 +1746,7 @@ function emitNamedFnCall(ctx, fnName, pos, failExpected) {
1698
1746
  return {
1699
1747
  stmts: [
1700
1748
  `${ind(ctx)}const ${vv} = ${fnName}(input, ${pos}, _ctx)`,
1701
- `${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, failExpected, pos).trim()}`,
1749
+ ...emitIfFail(ctx, `${vv} === ${NAMED_FN_FAIL}`, failBody(ctx, failExpected, pos)),
1702
1750
  `${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
1703
1751
  ],
1704
1752
  valueVar: vv,
@@ -1781,7 +1829,7 @@ function ensureTriviaFn(ctx) {
1781
1829
  `function ${fnName}(input, _pos, _ctx, _cap) {`,
1782
1830
  ` let _e = _pos`,
1783
1831
  ` _triv: {`,
1784
- ...r.stmts,
1832
+ ...reindentStmts(r.stmts, 2),
1785
1833
  ` _e = ${r.endVar}`,
1786
1834
  ` }`,
1787
1835
  ` if (_cap && _e > _pos) {`,
@@ -1796,14 +1844,6 @@ function ensureTriviaFn(ctx) {
1796
1844
  function ensureTriviaCaptureFn(ctx) {
1797
1845
  return ensureTriviaFn(ctx);
1798
1846
  }
1799
- function failStmt(ctx, expected, posExpr) {
1800
- if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
1801
- return `${ind(ctx)}return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
1802
- }
1803
- function failArr(ctx, expectedArr, posExpr) {
1804
- if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
1805
- return `${ind(ctx)}return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
1806
- }
1807
1847
  function firstSetCond(codeVar, fs) {
1808
1848
  if (fs.kind === "any") return "true";
1809
1849
  if (fs.kind === "empty") return "false";
@@ -1819,19 +1859,32 @@ function emitFallible(inner, ctx, pos) {
1819
1859
  const savedLabel = ctx.failLabel;
1820
1860
  const savedIndent = ctx.indent;
1821
1861
  ctx.failLabel = lbl;
1822
- ctx.indent = 0;
1862
+ ctx.indent = savedIndent + 1;
1823
1863
  const r = emit(inner, ctx, pos);
1824
1864
  ctx.failLabel = savedLabel;
1825
1865
  ctx.indent = savedIndent;
1826
1866
  const ind0 = ind(ctx);
1867
+ const mL = ctx.capturing ? v(ctx, "_fcl") : null;
1868
+ const mR = ctx.capturing ? v(ctx, "_fcr") : null;
1869
+ const mTl = ctx.capturing ? v(ctx, "_fctl") : null;
1870
+ const mLg = ctx.capturing ? v(ctx, "_fclg") : null;
1827
1871
  const stmts = [
1828
1872
  `${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
1873
+ ...mL ? [
1874
+ `${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
1875
+ `${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
1876
+ `${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
1877
+ `${ind0}const ${mLg} = _ctx._triviaLog?.length ?? 0`
1878
+ ] : [],
1829
1879
  `${ind0}${lbl}: {`,
1830
1880
  ...r.stmts,
1831
1881
  `${ind0} ${valV} = ${r.valueVar}`,
1832
1882
  `${ind0} ${endV} = ${r.endVar}`,
1833
1883
  `${ind0} ${okV} = true`,
1834
- `${ind0}}`
1884
+ `${ind0}}`,
1885
+ ...mL ? [
1886
+ `${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} }`
1887
+ ] : []
1835
1888
  ];
1836
1889
  return { stmts, okVar: okV, valVar: valV, endVar: endV };
1837
1890
  }
@@ -1844,9 +1897,9 @@ function emitLit(def, ctx, pos) {
1844
1897
  if (caseInsensitive) {
1845
1898
  ctx.needsCollator = true;
1846
1899
  stmts.push(
1847
- `${ind(ctx)}if (${pos} + ${len} > input.length) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1900
+ ...emitIfFail(ctx, `${pos} + ${len} > input.length`, failBody(ctx, expectedStr, pos)),
1848
1901
  `${ind(ctx)}const ${vv}_s = input.slice(${pos}, ${pos} + ${len})`,
1849
- `${ind(ctx)}if (_collator.compare(${vv}_s, ${JSON.stringify(value)}) !== 0) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1902
+ ...emitIfFail(ctx, `_collator.compare(${vv}_s, ${JSON.stringify(value)}) !== 0`, failBody(ctx, expectedStr, pos)),
1850
1903
  `${ind(ctx)}const ${vv} = ${vv}_s`
1851
1904
  );
1852
1905
  } else if (len === 0) {
@@ -1854,7 +1907,7 @@ function emitLit(def, ctx, pos) {
1854
1907
  } else if (len === 1) {
1855
1908
  const code = value.codePointAt(0);
1856
1909
  stmts.push(
1857
- `${ind(ctx)}if (${pos} >= input.length || input.charCodeAt(${pos}) !== ${code}) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1910
+ ...emitIfFail(ctx, `${pos} >= input.length || input.charCodeAt(${pos}) !== ${code}`, failBody(ctx, expectedStr, pos)),
1858
1911
  `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
1859
1912
  );
1860
1913
  } else if (len <= 4) {
@@ -1863,12 +1916,12 @@ function emitLit(def, ctx, pos) {
1863
1916
  (_, i) => `input.charCodeAt(${pos}${i > 0 ? ` + ${i}` : ""}) !== ${value.codePointAt(i)}`
1864
1917
  ).join(" || ");
1865
1918
  stmts.push(
1866
- `${ind(ctx)}if (${pos} + ${len} > input.length || ${checks}) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1919
+ ...emitIfFail(ctx, `${pos} + ${len} > input.length || ${checks}`, failBody(ctx, expectedStr, pos)),
1867
1920
  `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
1868
1921
  );
1869
1922
  } else {
1870
1923
  stmts.push(
1871
- `${ind(ctx)}if (!input.startsWith(${JSON.stringify(value)}, ${pos})) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1924
+ ...emitIfFail(ctx, `!input.startsWith(${JSON.stringify(value)}, ${pos})`, failBody(ctx, expectedStr, pos)),
1872
1925
  `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
1873
1926
  );
1874
1927
  }
@@ -1896,7 +1949,7 @@ function emitKeywords(def, ctx, pos) {
1896
1949
  const stmts = [
1897
1950
  `${ind(ctx)}${rName}.lastIndex = ${pos}`,
1898
1951
  `${ind(ctx)}const ${mv} = ${rName}.exec(input)`,
1899
- `${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, '"keyword"', pos).trim()}`,
1952
+ ...emitIfFail(ctx, `${mv} === null`, failBody(ctx, '"keyword"', pos)),
1900
1953
  `${ind(ctx)}const ${vv} = ${mv}[0]`
1901
1954
  ];
1902
1955
  const endVar = `${pos} + ${vv}.length`;
@@ -1918,7 +1971,7 @@ function emitRegex(def, ctx, pos) {
1918
1971
  const stmts = [
1919
1972
  `${ind(ctx)}${rName}.lastIndex = ${pos}`,
1920
1973
  `${ind(ctx)}const ${mv} = ${rName}.exec(input)`,
1921
- `${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
1974
+ ...emitIfFail(ctx, `${mv} === null`, failBody(ctx, expectedStr, pos)),
1922
1975
  `${ind(ctx)}const ${vv} = ${mv}[0]`
1923
1976
  ];
1924
1977
  const endVar = `${pos} + ${vv}.length`;
@@ -1999,11 +2052,12 @@ function emitChoice(def, ctx, pos) {
1999
2052
  ctx.indent++;
2000
2053
  const r = emit(p, ctx, pos);
2001
2054
  stmts.push(...r.stmts);
2002
- stmts.push(`${ind(ctx)}${valV} = ${r.valueVar}; ${endV} = ${r.endVar}`);
2055
+ stmts.push(`${ind(ctx)}${valV} = ${r.valueVar}`);
2056
+ stmts.push(`${ind(ctx)}${endV} = ${r.endVar}`);
2003
2057
  ctx.indent--;
2004
2058
  stmts.push(`${ind(ctx)}}`);
2005
2059
  }
2006
- stmts.push(`${ind(ctx)}else ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
2060
+ stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
2007
2061
  return { stmts, valueVar: valV, endVar: endV };
2008
2062
  }
2009
2063
  return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
@@ -2026,7 +2080,7 @@ function emitGreedyClassify(def, superIndex, allExpected, ctx, pos) {
2026
2080
  const stmts = [
2027
2081
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
2028
2082
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
2029
- `${ind(ctx)}if (${matchV} === null) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`,
2083
+ ...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, allExpected, pos)),
2030
2084
  `${ind(ctx)}const ${wordV} = ${matchV}[0]`,
2031
2085
  `${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
2032
2086
  `${ind(ctx)}let ${valV}`
@@ -2075,12 +2129,13 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
2075
2129
  stmts.push(
2076
2130
  ...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
2077
2131
  ...tR.stmts,
2078
- `${ind(ctx)}${valV} = ${tR.valueVar}; ${endV} = ${litEnd}`
2132
+ `${ind(ctx)}${valV} = ${tR.valueVar}`,
2133
+ `${ind(ctx)}${endV} = ${litEnd}`
2079
2134
  );
2080
2135
  ctx.indent--;
2081
2136
  stmts.push(`${ind(ctx)}}`);
2082
2137
  }
2083
- stmts.push(`${ind(ctx)}else ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
2138
+ stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
2084
2139
  return { stmts, valueVar: valV, endVar: endV };
2085
2140
  }
2086
2141
  function emitFirstMatch(def, allExpected, ctx, pos) {
@@ -2126,17 +2181,26 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
2126
2181
  const rejectCond = autoNot.map(
2127
2182
  (check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${endVar})`
2128
2183
  ).join(" || ");
2129
- stmts.push(
2130
- `${ind0} if (${okVar}) { const ${anCode} = ${endVar} < input.length ? input.charCodeAt(${endVar}) : -1; if (!(${rejectCond})) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true } }`
2131
- );
2184
+ stmts.push(`${ind0} if (${okVar}) {`);
2185
+ stmts.push(`${ind0} const ${anCode} = ${endVar} < input.length ? input.charCodeAt(${endVar}) : -1`);
2186
+ stmts.push(`${ind0} if (!(${rejectCond})) {`);
2187
+ stmts.push(`${ind0} ${resValV} = ${valVar}`);
2188
+ stmts.push(`${ind0} ${resEndV} = ${endVar}`);
2189
+ stmts.push(`${ind0} ${resOkV} = true`);
2190
+ stmts.push(`${ind0} }`);
2191
+ stmts.push(`${ind0} }`);
2132
2192
  if (rollback) stmts.push(`${ind0} if (!${resOkV}) { ${rollback} }`);
2133
2193
  } else {
2134
- stmts.push(`${ind0} if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
2194
+ stmts.push(`${ind0} if (${okVar}) {`);
2195
+ stmts.push(`${ind0} ${resValV} = ${valVar}`);
2196
+ stmts.push(`${ind0} ${resEndV} = ${endVar}`);
2197
+ stmts.push(`${ind0} ${resOkV} = true`);
2198
+ stmts.push(`${ind0} }`);
2135
2199
  if (rollback) stmts.push(`${ind0} else { ${rollback} }`);
2136
2200
  }
2137
2201
  stmts.push(`${ind0}}`);
2138
2202
  }
2139
- stmts.push(`${ind0}if (!${resOkV}) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
2203
+ stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, allExpected, pos)));
2140
2204
  return { stmts, valueVar: resValV, endVar: resEndV };
2141
2205
  }
2142
2206
  function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
@@ -2261,32 +2325,26 @@ function emitSepBy(_p, def, ctx, pos) {
2261
2325
  const markV = v(ctx, "_mk");
2262
2326
  const markTl = v(ctx, "_mktl");
2263
2327
  const markLog = v(ctx, "_mklg");
2328
+ const markLv = v(ctx, "_mklv");
2264
2329
  const spV = v(ctx, "_sp");
2265
2330
  stmts.push(
2266
2331
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
2267
2332
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
2268
2333
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
2334
+ `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
2269
2335
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
2270
2336
  );
2271
2337
  sepAtPos = spV;
2272
- const sepRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; `;
2338
+ 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}; `;
2273
2339
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
2274
- stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sepRollback}break }`);
2275
- const mark2V = v(ctx, "_mk2");
2276
- const mark2Tl = v(ctx, "_mktl2");
2277
- const mark2Log = v(ctx, "_mklg2");
2340
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}break }`);
2278
2341
  const npV = v(ctx, "_np");
2279
- stmts.push(
2280
- `${ind(ctx)}const ${mark2V} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
2281
- `${ind(ctx)}const ${mark2Tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
2282
- `${ind(ctx)}const ${mark2Log} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
2283
- `${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`
2284
- );
2285
- const nextRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mark2V}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mark2Tl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mark2Log}; `;
2342
+ stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
2286
2343
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV);
2287
2344
  stmts.push(
2288
2345
  ...nextStmts,
2289
- `${ind(ctx)}if (!${nextOk}) { ${nextRollback}break }`,
2346
+ // item failed → unwind the separator too, back to the end of the last item
2347
+ `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
2290
2348
  `${ind(ctx)}${arrV}.push(${nextVal})`,
2291
2349
  `${ind(ctx)}${curV} = ${nextEnd}`
2292
2350
  );
@@ -2308,12 +2366,21 @@ function emitSepBy(_p, def, ctx, pos) {
2308
2366
  );
2309
2367
  }
2310
2368
  } else {
2369
+ const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
2370
+ const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
2371
+ if (markLv) {
2372
+ stmts.push(
2373
+ `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
2374
+ `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
2375
+ );
2376
+ }
2311
2377
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
2312
2378
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) break`);
2379
+ const nextRb = markLv ? `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markRw}; ` : "";
2313
2380
  const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd);
2314
2381
  stmts.push(
2315
2382
  ...nextStmts,
2316
- `${ind(ctx)}if (!${nextOk}) break`,
2383
+ `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`,
2317
2384
  `${ind(ctx)}${arrV}.push(${nextVal})`,
2318
2385
  `${ind(ctx)}${curV} = ${nextEnd}`
2319
2386
  );
@@ -2357,12 +2424,12 @@ function emitScanTo(def, ctx, pos) {
2357
2424
  if (!def.orEOF) {
2358
2425
  const sentDef = def.sentinel._def;
2359
2426
  const expectedStr = sentDef.tag === "literal" ? JSON.stringify([JSON.stringify(sentDef.value)]) : `["sentinel"]`;
2360
- stmts.push(`${ind(ctx)}if (!${foundV}) ${failArr({ ...ctx, indent: 0 }, expectedStr, pos)}`);
2427
+ stmts.push(...emitIfFail(ctx, `!${foundV}`, failArrBody(ctx, expectedStr, pos)));
2361
2428
  }
2362
2429
  const valV = v(ctx);
2363
2430
  stmts.push(`${ind(ctx)}const ${valV} = input.slice(${pos}, ${curV})`);
2364
2431
  if (ctx.capturing) {
2365
- const cap = emitLeafCapture(ctx, valV, pos, curV).map((s) => " " + s);
2432
+ const cap = reindentStmts(emitLeafCapture(ctx, valV, pos, curV), ctx.indent + 1);
2366
2433
  stmts.push(`${ind(ctx)}if (${curV} > ${pos}) {`, ...cap, `${ind(ctx)}}`);
2367
2434
  }
2368
2435
  return { stmts, valueVar: valV, endVar: curV };
@@ -2372,7 +2439,7 @@ function emitNot(def, ctx, pos) {
2372
2439
  return {
2373
2440
  stmts: [
2374
2441
  ...stmts,
2375
- `${ind(ctx)}if (${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"not"', pos).trim()}`
2442
+ ...emitIfFail(ctx, okVar, failBody(ctx, '"not"', pos))
2376
2443
  ],
2377
2444
  valueVar: "null",
2378
2445
  endVar: pos
@@ -2399,7 +2466,7 @@ function emitNode(def, ctx, pos) {
2399
2466
  const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
2400
2467
  stmts.push(...innerStmts);
2401
2468
  stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}`);
2402
- stmts.push(`${i}if (!${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"node"', pos).trim()}`);
2469
+ stmts.push(...emitIfFail(ctx, `!${okVar}`, failBody(ctx, '"node"', pos)));
2403
2470
  const stV = v(ctx, "_nst");
2404
2471
  stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
2405
2472
  const ndV = v(ctx, "_nd");
@@ -2419,7 +2486,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
2419
2486
  const ev = v(ctx, "_rte");
2420
2487
  const stmts = [
2421
2488
  `${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
2422
- `${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"runtime"', pos).trim()}`,
2489
+ ...emitIfFail(ctx, `!${rv}.ok`, failBody(ctx, '"runtime"', pos)),
2423
2490
  `${ind(ctx)}const ${vv} = ${rv}.value`,
2424
2491
  `${ind(ctx)}const ${ev} = ${rv}.span.end`
2425
2492
  ];
@@ -2453,16 +2520,14 @@ function emitRecover(def, ctx, pos) {
2453
2520
  const ind0 = ind(ctx);
2454
2521
  const scanV = v(ctx, "_sc");
2455
2522
  const errV = v(ctx, "_err");
2456
- const savedIndent = ctx.indent;
2457
- ctx.indent += 2;
2523
+ const whileBodyLevels = ctx.indent + 2;
2458
2524
  const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, ctx, scanV);
2459
- ctx.indent = savedIndent;
2460
2525
  const stmts = [
2461
2526
  ...innerStmts,
2462
2527
  `${ind0}if (!${okVar}) {`,
2463
2528
  `${ind0} let ${scanV} = ${pos}`,
2464
2529
  `${ind0} while (${scanV} < input.length) {`,
2465
- ...sentStmts,
2530
+ ...reindentStmts(sentStmts, whileBodyLevels),
2466
2531
  `${ind0} if (${sentOk}) break`,
2467
2532
  `${ind0} ${scanV}++`,
2468
2533
  `${ind0} }`,
@@ -2544,7 +2609,7 @@ function emit(p, ctx, pos) {
2544
2609
  // try skipped; if fails, keep main end
2545
2610
  `${ind(ctx)}let ${endV} = ${mainR.endVar}`,
2546
2611
  `${ind(ctx)}try {`,
2547
- ...skipR.stmts.map((s) => " " + s),
2612
+ ...reindentStmts(skipR.stmts, ctx.indent + 1),
2548
2613
  `${ind(ctx)} ${endV} = ${skipR.endVar}`,
2549
2614
  `${ind(ctx)}} catch {}`
2550
2615
  ],
@@ -2561,7 +2626,10 @@ function emit(p, ctx, pos) {
2561
2626
  case "grammar": {
2562
2627
  const savedTrivia = ctx.activeTrivia;
2563
2628
  const savedKindLabels = ctx.triviaKindLabels;
2564
- if (def.triviaParser) {
2629
+ if (def.clearTrivia) {
2630
+ ctx.activeTrivia = void 0;
2631
+ ctx.triviaKindLabels = void 0;
2632
+ } else if (def.triviaParser) {
2565
2633
  ctx.activeTrivia = def.triviaParser;
2566
2634
  if (def.triviaParser._meta.triviaKindLabels) {
2567
2635
  ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
@@ -2586,7 +2654,7 @@ function emit(p, ctx, pos) {
2586
2654
  const vv = v(ctx);
2587
2655
  return {
2588
2656
  stmts: [
2589
- `${ind(ctx)}if (!_mf[${fnIdx}](_ctx.state)) ${failStmt({ ...ctx, indent: 0 }, '"gate"', pos).trim()}`,
2657
+ ...emitIfFail(ctx, `!_mf[${fnIdx}](_ctx.state)`, failBody(ctx, '"gate"', pos)),
2590
2658
  `${ind(ctx)}const ${vv} = null`
2591
2659
  ],
2592
2660
  valueVar: vv,
@@ -2618,7 +2686,7 @@ function emit(p, ctx, pos) {
2618
2686
  stmts: [
2619
2687
  `${ind(ctx)}const ${rv} = { ..._ctx, state: _mf[${evIdx}]() }`,
2620
2688
  `${ind(ctx)}const ${vv} = ${fn}(input, ${pos}, ${rv})`,
2621
- `${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, '"withCtx"', pos).trim()}`,
2689
+ ...emitIfFail(ctx, `${vv} === ${NAMED_FN_FAIL}`, failBody(ctx, '"withCtx"', pos)),
2622
2690
  `${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
2623
2691
  ],
2624
2692
  valueVar: vv,
@@ -2695,7 +2763,7 @@ function compile(combinator, mapFnSources) {
2695
2763
  ...ctx.regexDecls,
2696
2764
  "",
2697
2765
  ...namedPrelude,
2698
- ...ctx.namedFnDecls,
2766
+ ctx.namedFnDecls.join("\n\n"),
2699
2767
  `${collatorDecl}function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
2700
2768
  ` let pos = _pos`,
2701
2769
  ...r.stmts,
@@ -2706,7 +2774,7 @@ function compile(combinator, mapFnSources) {
2706
2774
  ...ctx.regexDecls,
2707
2775
  collatorDecl,
2708
2776
  ...namedPrelude,
2709
- ...ctx.namedFnDecls,
2777
+ ...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
2710
2778
  `let pos = _pos`,
2711
2779
  ...r.stmts,
2712
2780
  `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
@@ -2741,7 +2809,7 @@ function compile(combinator, mapFnSources) {
2741
2809
  function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
2742
2810
  const bodyLines = [
2743
2811
  ` let pos = _pos`,
2744
- ...r.stmts.map((s) => ` ${s}`),
2812
+ ...r.stmts,
2745
2813
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
2746
2814
  ];
2747
2815
  const innerFn = [
@@ -2754,17 +2822,23 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
2754
2822
  const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl;
2755
2823
  if (!needsWrapper) return innerFn;
2756
2824
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
2757
- return [
2758
- `/* @__PURE__ */ (() => {`,
2825
+ const hoistedDecls = [
2759
2826
  ...ctx.regexDecls.map((d) => ` ${d}`),
2760
2827
  collatorDecl ? ` ${collatorDecl.trim()}` : "",
2761
2828
  mfDecl,
2762
2829
  buildDecl,
2763
2830
  ...namedPrelude.map((l) => ` ${l}`),
2764
- ...ctx.namedFnDecls.flatMap((f) => f.split("\n").map((l) => ` ${l}`)),
2831
+ ...ctx.namedFnDecls.flatMap((decl, i) => {
2832
+ const lines = decl.split("\n").map((l) => ` ${l}`);
2833
+ return i > 0 ? ["", ...lines] : lines;
2834
+ })
2835
+ ].filter(Boolean);
2836
+ return [
2837
+ `/* @__PURE__ */ (() => {`,
2838
+ ...hoistedDecls,
2765
2839
  ` return ${innerFn}`,
2766
2840
  `})()`
2767
- ].filter(Boolean).join("\n");
2841
+ ].join("\n");
2768
2842
  }
2769
2843
 
2770
2844
  // src/combinators/guard.ts