parseman 0.7.1 → 0.8.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/combinators/expect.d.ts +36 -0
- package/dist/combinators/expect.d.ts.map +1 -0
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/index.cjs +249 -30
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +249 -30
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +248 -31
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.js +248 -31
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/plugin/evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,UAAU,EAAE,IAAI,EAMjB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAa7C,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AACD,MAAM,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAM3C,KAAK,gBAAgB,GAAG;IAAE,GAAG,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/plugin/evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,UAAU,EAAE,IAAI,EAMjB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAa7C,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AACD,MAAM,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAM3C,KAAK,gBAAgB,GAAG;IAAE,GAAG,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;AAmThE,0EAA0E;AAC1E,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,KAAK,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,gBAAgB,GAAG,IAAI,CAUzB;AAED,6EAA6E;AAC7E,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,KAAK,EACZ,IAAI,CAAC,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAE5B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,UAAU,EACvB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EAAE,GACrB,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAuGzC;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAcnF"}
|
package/dist/plugin/index.cjs
CHANGED
|
@@ -1757,6 +1757,119 @@ function firstSetCond(codeVar, fs) {
|
|
|
1757
1757
|
(r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
|
|
1758
1758
|
).join(" || ");
|
|
1759
1759
|
}
|
|
1760
|
+
function captureRestoreBody(mL, mR, mTl, mLg) {
|
|
1761
|
+
const base = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}`;
|
|
1762
|
+
return mLg ? `${base}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg}` : base;
|
|
1763
|
+
}
|
|
1764
|
+
function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
1765
|
+
if (seen.has(p)) return false;
|
|
1766
|
+
seen.add(p);
|
|
1767
|
+
const d = p._def;
|
|
1768
|
+
switch (d.tag) {
|
|
1769
|
+
// Atomic / non-capturing-then-failing: a failure happens before any push.
|
|
1770
|
+
case "literal":
|
|
1771
|
+
case "regex":
|
|
1772
|
+
case "keywords":
|
|
1773
|
+
case "guard":
|
|
1774
|
+
case "not":
|
|
1775
|
+
case "trivia":
|
|
1776
|
+
case "scanTo":
|
|
1777
|
+
case "unknown":
|
|
1778
|
+
return false;
|
|
1779
|
+
// node() captures into its own private buffers and rolls them back on
|
|
1780
|
+
// failure (emitNode restores _ctx.* and never pushes on the !ok path).
|
|
1781
|
+
case "node":
|
|
1782
|
+
return false;
|
|
1783
|
+
// choice/firstMatch already roll back each failed arm; on overall failure
|
|
1784
|
+
// nothing committed remains.
|
|
1785
|
+
case "choice":
|
|
1786
|
+
return false;
|
|
1787
|
+
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
1788
|
+
case "optional":
|
|
1789
|
+
case "many":
|
|
1790
|
+
case "oneOrMore":
|
|
1791
|
+
return false;
|
|
1792
|
+
// sepBy emits its own per-iteration rollback in emitSepBy.
|
|
1793
|
+
case "sepBy":
|
|
1794
|
+
return false;
|
|
1795
|
+
// A sequence is the real case: an earlier capturing term followed by a term
|
|
1796
|
+
// that can fail leaves the earlier captures buffered.
|
|
1797
|
+
case "sequence": {
|
|
1798
|
+
const parts = d.parsers;
|
|
1799
|
+
if (parts.length < 2) return parts.some((x) => mayLeavePartialCapture(x, seen));
|
|
1800
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1801
|
+
if (hasNodeDef(parts[i]) || capturesLeaf(parts[i])) return true;
|
|
1802
|
+
}
|
|
1803
|
+
return false;
|
|
1804
|
+
}
|
|
1805
|
+
// Delegating wrappers: defer to the wrapped parser.
|
|
1806
|
+
case "transform":
|
|
1807
|
+
case "label":
|
|
1808
|
+
case "expect":
|
|
1809
|
+
case "withCtx":
|
|
1810
|
+
case "grammar":
|
|
1811
|
+
return mayLeavePartialCapture(d.parser, seen);
|
|
1812
|
+
case "skip":
|
|
1813
|
+
return mayLeavePartialCapture(d.main, seen);
|
|
1814
|
+
case "recover":
|
|
1815
|
+
return mayLeavePartialCapture(d.parser, seen);
|
|
1816
|
+
case "lazy": {
|
|
1817
|
+
try {
|
|
1818
|
+
return mayLeavePartialCapture(d.thunk(), seen);
|
|
1819
|
+
} catch {
|
|
1820
|
+
return true;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
// Unknown shapes: be safe and keep the rollback.
|
|
1824
|
+
default:
|
|
1825
|
+
return true;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
1829
|
+
if (seen.has(p)) return false;
|
|
1830
|
+
seen.add(p);
|
|
1831
|
+
const d = p._def;
|
|
1832
|
+
switch (d.tag) {
|
|
1833
|
+
case "literal":
|
|
1834
|
+
case "regex":
|
|
1835
|
+
case "keywords":
|
|
1836
|
+
case "node":
|
|
1837
|
+
return true;
|
|
1838
|
+
case "not":
|
|
1839
|
+
case "guard":
|
|
1840
|
+
case "trivia":
|
|
1841
|
+
case "unknown":
|
|
1842
|
+
return false;
|
|
1843
|
+
case "sequence":
|
|
1844
|
+
case "choice":
|
|
1845
|
+
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
1846
|
+
case "sepBy":
|
|
1847
|
+
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
1848
|
+
case "many":
|
|
1849
|
+
case "oneOrMore":
|
|
1850
|
+
case "optional":
|
|
1851
|
+
case "transform":
|
|
1852
|
+
case "label":
|
|
1853
|
+
case "expect":
|
|
1854
|
+
case "withCtx":
|
|
1855
|
+
case "grammar":
|
|
1856
|
+
case "recover":
|
|
1857
|
+
return capturesLeaf(d.parser, seen);
|
|
1858
|
+
case "skip":
|
|
1859
|
+
return capturesLeaf(d.main, seen);
|
|
1860
|
+
case "scanTo":
|
|
1861
|
+
return true;
|
|
1862
|
+
case "lazy": {
|
|
1863
|
+
try {
|
|
1864
|
+
return capturesLeaf(d.thunk(), seen);
|
|
1865
|
+
} catch {
|
|
1866
|
+
return true;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
default:
|
|
1870
|
+
return true;
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1760
1873
|
function emitFallible(inner, ctx, pos) {
|
|
1761
1874
|
const lbl = v(ctx, "_lbl");
|
|
1762
1875
|
const okV = `${lbl}ok`;
|
|
@@ -1770,26 +1883,23 @@ function emitFallible(inner, ctx, pos) {
|
|
|
1770
1883
|
ctx.failLabel = savedLabel;
|
|
1771
1884
|
ctx.indent = savedIndent;
|
|
1772
1885
|
const ind0 = ind(ctx);
|
|
1773
|
-
const
|
|
1774
|
-
const
|
|
1775
|
-
const
|
|
1776
|
-
const
|
|
1886
|
+
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
1887
|
+
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
1888
|
+
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
1889
|
+
const mTl = needsRollback ? v(ctx, "_fctl") : null;
|
|
1777
1890
|
const stmts = [
|
|
1778
1891
|
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
1779
1892
|
...mL ? [
|
|
1780
1893
|
`${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
|
|
1781
1894
|
`${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
|
|
1782
|
-
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0
|
|
1783
|
-
`${ind0}const ${mLg} = _ctx._triviaLog?.length ?? 0`
|
|
1895
|
+
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`
|
|
1784
1896
|
] : [],
|
|
1785
1897
|
`${ind0}${lbl}: {`,
|
|
1786
1898
|
...r.stmts,
|
|
1787
|
-
`${ind0} ${valV} = ${r.valueVar}`,
|
|
1788
|
-
`${ind0} ${endV} = ${r.endVar}`,
|
|
1789
|
-
`${ind0} ${okV} = true`,
|
|
1899
|
+
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
1790
1900
|
`${ind0}}`,
|
|
1791
1901
|
...mL ? [
|
|
1792
|
-
`${ind0}if (!${okV}) {
|
|
1902
|
+
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null)} }`
|
|
1793
1903
|
] : []
|
|
1794
1904
|
];
|
|
1795
1905
|
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
@@ -2063,11 +2173,13 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
|
2063
2173
|
gateCond = `_mf[${gateIdx}](_ctx.state)`;
|
|
2064
2174
|
}
|
|
2065
2175
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
2066
|
-
const
|
|
2067
|
-
const
|
|
2068
|
-
const
|
|
2069
|
-
const
|
|
2070
|
-
const
|
|
2176
|
+
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
2177
|
+
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
2178
|
+
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
2179
|
+
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
2180
|
+
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
2181
|
+
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
2182
|
+
const rollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog) : "";
|
|
2071
2183
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
2072
2184
|
ctx.indent++;
|
|
2073
2185
|
const ind1 = ind(ctx);
|
|
@@ -2097,11 +2209,7 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
|
2097
2209
|
stmts.push(`${ind0} }`);
|
|
2098
2210
|
if (rollback) stmts.push(`${ind0} if (!${resOkV}) { ${rollback} }`);
|
|
2099
2211
|
} else {
|
|
2100
|
-
stmts.push(`${ind0} if (${okVar}) {`);
|
|
2101
|
-
stmts.push(`${ind0} ${resValV} = ${valVar}`);
|
|
2102
|
-
stmts.push(`${ind0} ${resEndV} = ${endVar}`);
|
|
2103
|
-
stmts.push(`${ind0} ${resOkV} = true`);
|
|
2104
|
-
stmts.push(`${ind0} }`);
|
|
2212
|
+
stmts.push(`${ind0} if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
|
|
2105
2213
|
if (rollback) stmts.push(`${ind0} else { ${rollback} }`);
|
|
2106
2214
|
}
|
|
2107
2215
|
stmts.push(`${ind0}}`);
|
|
@@ -2446,6 +2554,22 @@ function emitRecover(def, ctx, pos) {
|
|
|
2446
2554
|
];
|
|
2447
2555
|
return { stmts, valueVar: valVar, endVar };
|
|
2448
2556
|
}
|
|
2557
|
+
function emitExpect(def, ctx, pos) {
|
|
2558
|
+
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
2559
|
+
const ind0 = ind(ctx);
|
|
2560
|
+
const errV = v(ctx, "_err");
|
|
2561
|
+
const stmts = [
|
|
2562
|
+
...innerStmts,
|
|
2563
|
+
`${ind0}if (!${okVar}) {`,
|
|
2564
|
+
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
2565
|
+
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
2566
|
+
`${ind0} ${valVar} = ${errV}`,
|
|
2567
|
+
`${ind0} ${endVar} = ${pos}`,
|
|
2568
|
+
`${ind0} ${okVar} = true`,
|
|
2569
|
+
`${ind0}}`
|
|
2570
|
+
];
|
|
2571
|
+
return { stmts, valueVar: valVar, endVar };
|
|
2572
|
+
}
|
|
2449
2573
|
function emit(p, ctx, pos) {
|
|
2450
2574
|
const def = p._def;
|
|
2451
2575
|
switch (def.tag) {
|
|
@@ -2554,6 +2678,8 @@ function emit(p, ctx, pos) {
|
|
|
2554
2678
|
return emitScanTo(def, ctx, pos);
|
|
2555
2679
|
case "recover":
|
|
2556
2680
|
return emitRecover(def, ctx, pos);
|
|
2681
|
+
case "expect":
|
|
2682
|
+
return emitExpect(def, ctx, pos);
|
|
2557
2683
|
case "guard": {
|
|
2558
2684
|
const fnIdx = ctx.mapFns.length;
|
|
2559
2685
|
ctx.mapFns.push(def.predicate);
|
|
@@ -2637,6 +2763,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2637
2763
|
return hasNodeDef(d.sentinel, seen) || d.skip.some((x) => hasNodeDef(x, seen));
|
|
2638
2764
|
case "recover":
|
|
2639
2765
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.sentinel, seen);
|
|
2766
|
+
case "expect":
|
|
2767
|
+
return hasNodeDef(d.parser, seen);
|
|
2640
2768
|
case "withCtx":
|
|
2641
2769
|
return hasNodeDef(d.parser, seen);
|
|
2642
2770
|
default:
|
|
@@ -2705,6 +2833,11 @@ function compile(combinator, mapFnSources) {
|
|
|
2705
2833
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
2706
2834
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
2707
2835
|
},
|
|
2836
|
+
// Note: collects recover()/expect() errors via _errors. Unlike interpreter
|
|
2837
|
+
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
2838
|
+
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
2839
|
+
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
2840
|
+
// (span.end < input.length) instead, which is mode-agnostic.
|
|
2708
2841
|
parseWithErrors(input, pos = 0) {
|
|
2709
2842
|
const errors = [];
|
|
2710
2843
|
const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
|
|
@@ -2747,6 +2880,58 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
2747
2880
|
].join("\n");
|
|
2748
2881
|
}
|
|
2749
2882
|
|
|
2883
|
+
// src/combinators/expect.ts
|
|
2884
|
+
function staticExpected(c) {
|
|
2885
|
+
const def = c._def;
|
|
2886
|
+
switch (def.tag) {
|
|
2887
|
+
case "literal":
|
|
2888
|
+
return [JSON.stringify(def.value)];
|
|
2889
|
+
case "regex":
|
|
2890
|
+
return [`/${def.source}/`];
|
|
2891
|
+
case "keywords":
|
|
2892
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
2893
|
+
case "label":
|
|
2894
|
+
return [def.label];
|
|
2895
|
+
case "choice":
|
|
2896
|
+
return def.parsers.flatMap(staticExpected);
|
|
2897
|
+
case "sequence":
|
|
2898
|
+
return def.parsers.length > 0 ? staticExpected(def.parsers[0]) : [];
|
|
2899
|
+
case "node":
|
|
2900
|
+
case "grammar":
|
|
2901
|
+
case "trivia":
|
|
2902
|
+
case "optional":
|
|
2903
|
+
case "many":
|
|
2904
|
+
case "oneOrMore":
|
|
2905
|
+
case "transform":
|
|
2906
|
+
case "not":
|
|
2907
|
+
return staticExpected(def.parser);
|
|
2908
|
+
case "lazy":
|
|
2909
|
+
return staticExpected(def.thunk());
|
|
2910
|
+
default:
|
|
2911
|
+
return [];
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
function expect(combinator, label2) {
|
|
2915
|
+
const expected = label2 !== void 0 ? [label2] : staticExpected(combinator);
|
|
2916
|
+
const meta = {
|
|
2917
|
+
firstSet: combinator._meta.firstSet,
|
|
2918
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2919
|
+
isTrivia: false
|
|
2920
|
+
};
|
|
2921
|
+
return {
|
|
2922
|
+
_tag: "expect",
|
|
2923
|
+
_meta: meta,
|
|
2924
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2925
|
+
parse(input, pos, ctx) {
|
|
2926
|
+
const result = combinator.parse(input, pos, ctx);
|
|
2927
|
+
if (result.ok) return result;
|
|
2928
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2929
|
+
ctx._errors?.push(error);
|
|
2930
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2931
|
+
}
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2750
2935
|
// src/combinators/scanTo.ts
|
|
2751
2936
|
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
2752
2937
|
const meta = {
|
|
@@ -2760,7 +2945,11 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
2760
2945
|
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
2761
2946
|
parse(input, pos, ctx) {
|
|
2762
2947
|
let cur = pos;
|
|
2763
|
-
const probeCtx = {
|
|
2948
|
+
const probeCtx = {
|
|
2949
|
+
trackLines: ctx.trackLines,
|
|
2950
|
+
state: ctx.state,
|
|
2951
|
+
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
2952
|
+
};
|
|
2764
2953
|
const emit2 = (end) => {
|
|
2765
2954
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
2766
2955
|
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
@@ -2796,20 +2985,46 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
2796
2985
|
}
|
|
2797
2986
|
function balanced(open, close, options = {}) {
|
|
2798
2987
|
const self = ref();
|
|
2799
|
-
const
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2988
|
+
const skips = options.skip ?? [];
|
|
2989
|
+
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
2990
|
+
let bounded = true;
|
|
2991
|
+
for (const sk of skips) {
|
|
2992
|
+
const cs = firstSetClassChars(sk);
|
|
2993
|
+
if (cs === null) {
|
|
2994
|
+
bounded = false;
|
|
2995
|
+
break;
|
|
2996
|
+
}
|
|
2997
|
+
for (const ch of cs) stop.add(ch);
|
|
2998
|
+
}
|
|
2999
|
+
const cls = [...stop].map(escapeClassChar).join("");
|
|
3000
|
+
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
3001
|
+
const inner = many(choice(self, ...skips, content));
|
|
2803
3002
|
const combi = transform(
|
|
2804
|
-
sequence(literal(open), inner, literal(close)),
|
|
2805
|
-
(
|
|
3003
|
+
sequence(literal(open), inner, expect(literal(close), close)),
|
|
3004
|
+
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
3005
|
+
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
3006
|
+
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
2806
3007
|
);
|
|
2807
3008
|
if (combi._def.tag === "transform") {
|
|
2808
|
-
combi._def.fnSrc =
|
|
3009
|
+
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
2809
3010
|
}
|
|
2810
3011
|
self.define(combi);
|
|
2811
3012
|
return combi;
|
|
2812
3013
|
}
|
|
3014
|
+
function firstSetClassChars(c) {
|
|
3015
|
+
const fs = c._meta.firstSet;
|
|
3016
|
+
if (fs.kind === "empty") return [];
|
|
3017
|
+
if (fs.kind !== "ranges") return null;
|
|
3018
|
+
const out = [];
|
|
3019
|
+
for (const { lo, hi } of fs.ranges) {
|
|
3020
|
+
if (hi - lo > 8) return null;
|
|
3021
|
+
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
3022
|
+
}
|
|
3023
|
+
return out;
|
|
3024
|
+
}
|
|
3025
|
+
function escapeClassChar(ch) {
|
|
3026
|
+
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
3027
|
+
}
|
|
2813
3028
|
|
|
2814
3029
|
// src/plugin/evaluator.ts
|
|
2815
3030
|
function isWordFactory(v2) {
|
|
@@ -2828,7 +3043,8 @@ var SUPPORTED = {
|
|
|
2828
3043
|
sepBy: (...a) => sepBy(a[0], a[1]),
|
|
2829
3044
|
trivia: (...a) => trivia(a[0]),
|
|
2830
3045
|
label: (...a) => label(a[0], a[1]),
|
|
2831
|
-
noTrivia: (...a) => noTrivia(a[0])
|
|
3046
|
+
noTrivia: (...a) => noTrivia(a[0]),
|
|
3047
|
+
expect: (...a) => expect(a[0], a[1])
|
|
2832
3048
|
};
|
|
2833
3049
|
function isScopeEntry(v2) {
|
|
2834
3050
|
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
@@ -2964,13 +3180,14 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
2964
3180
|
}
|
|
2965
3181
|
}
|
|
2966
3182
|
if (callee.name === "balanced") {
|
|
2967
|
-
const [openArg, closeArg] = node2.arguments;
|
|
3183
|
+
const [openArg, closeArg, optsArg] = node2.arguments;
|
|
2968
3184
|
if (!openArg || !closeArg || openArg.type === "SpreadElement" || closeArg.type === "SpreadElement") return null;
|
|
2969
3185
|
const open = anyValue(openArg, scope, code, []);
|
|
2970
3186
|
const close = anyValue(closeArg, scope, code, []);
|
|
2971
3187
|
if (typeof open !== "string" || typeof close !== "string") return null;
|
|
3188
|
+
const opts = optsArg && optsArg.type !== "SpreadElement" ? anyValue(optsArg, scope, code, []) : void 0;
|
|
2972
3189
|
try {
|
|
2973
|
-
return balanced(open, close);
|
|
3190
|
+
return balanced(open, close, opts);
|
|
2974
3191
|
} catch {
|
|
2975
3192
|
return null;
|
|
2976
3193
|
}
|