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
package/dist/plugin/index.js
CHANGED
|
@@ -1722,6 +1722,119 @@ function firstSetCond(codeVar, fs) {
|
|
|
1722
1722
|
(r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
|
|
1723
1723
|
).join(" || ");
|
|
1724
1724
|
}
|
|
1725
|
+
function captureRestoreBody(mL, mR, mTl, mLg) {
|
|
1726
|
+
const base = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}`;
|
|
1727
|
+
return mLg ? `${base}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg}` : base;
|
|
1728
|
+
}
|
|
1729
|
+
function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
1730
|
+
if (seen.has(p)) return false;
|
|
1731
|
+
seen.add(p);
|
|
1732
|
+
const d = p._def;
|
|
1733
|
+
switch (d.tag) {
|
|
1734
|
+
// Atomic / non-capturing-then-failing: a failure happens before any push.
|
|
1735
|
+
case "literal":
|
|
1736
|
+
case "regex":
|
|
1737
|
+
case "keywords":
|
|
1738
|
+
case "guard":
|
|
1739
|
+
case "not":
|
|
1740
|
+
case "trivia":
|
|
1741
|
+
case "scanTo":
|
|
1742
|
+
case "unknown":
|
|
1743
|
+
return false;
|
|
1744
|
+
// node() captures into its own private buffers and rolls them back on
|
|
1745
|
+
// failure (emitNode restores _ctx.* and never pushes on the !ok path).
|
|
1746
|
+
case "node":
|
|
1747
|
+
return false;
|
|
1748
|
+
// choice/firstMatch already roll back each failed arm; on overall failure
|
|
1749
|
+
// nothing committed remains.
|
|
1750
|
+
case "choice":
|
|
1751
|
+
return false;
|
|
1752
|
+
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
1753
|
+
case "optional":
|
|
1754
|
+
case "many":
|
|
1755
|
+
case "oneOrMore":
|
|
1756
|
+
return false;
|
|
1757
|
+
// sepBy emits its own per-iteration rollback in emitSepBy.
|
|
1758
|
+
case "sepBy":
|
|
1759
|
+
return false;
|
|
1760
|
+
// A sequence is the real case: an earlier capturing term followed by a term
|
|
1761
|
+
// that can fail leaves the earlier captures buffered.
|
|
1762
|
+
case "sequence": {
|
|
1763
|
+
const parts = d.parsers;
|
|
1764
|
+
if (parts.length < 2) return parts.some((x) => mayLeavePartialCapture(x, seen));
|
|
1765
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1766
|
+
if (hasNodeDef(parts[i]) || capturesLeaf(parts[i])) return true;
|
|
1767
|
+
}
|
|
1768
|
+
return false;
|
|
1769
|
+
}
|
|
1770
|
+
// Delegating wrappers: defer to the wrapped parser.
|
|
1771
|
+
case "transform":
|
|
1772
|
+
case "label":
|
|
1773
|
+
case "expect":
|
|
1774
|
+
case "withCtx":
|
|
1775
|
+
case "grammar":
|
|
1776
|
+
return mayLeavePartialCapture(d.parser, seen);
|
|
1777
|
+
case "skip":
|
|
1778
|
+
return mayLeavePartialCapture(d.main, seen);
|
|
1779
|
+
case "recover":
|
|
1780
|
+
return mayLeavePartialCapture(d.parser, seen);
|
|
1781
|
+
case "lazy": {
|
|
1782
|
+
try {
|
|
1783
|
+
return mayLeavePartialCapture(d.thunk(), seen);
|
|
1784
|
+
} catch {
|
|
1785
|
+
return true;
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
// Unknown shapes: be safe and keep the rollback.
|
|
1789
|
+
default:
|
|
1790
|
+
return true;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
1794
|
+
if (seen.has(p)) return false;
|
|
1795
|
+
seen.add(p);
|
|
1796
|
+
const d = p._def;
|
|
1797
|
+
switch (d.tag) {
|
|
1798
|
+
case "literal":
|
|
1799
|
+
case "regex":
|
|
1800
|
+
case "keywords":
|
|
1801
|
+
case "node":
|
|
1802
|
+
return true;
|
|
1803
|
+
case "not":
|
|
1804
|
+
case "guard":
|
|
1805
|
+
case "trivia":
|
|
1806
|
+
case "unknown":
|
|
1807
|
+
return false;
|
|
1808
|
+
case "sequence":
|
|
1809
|
+
case "choice":
|
|
1810
|
+
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
1811
|
+
case "sepBy":
|
|
1812
|
+
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
1813
|
+
case "many":
|
|
1814
|
+
case "oneOrMore":
|
|
1815
|
+
case "optional":
|
|
1816
|
+
case "transform":
|
|
1817
|
+
case "label":
|
|
1818
|
+
case "expect":
|
|
1819
|
+
case "withCtx":
|
|
1820
|
+
case "grammar":
|
|
1821
|
+
case "recover":
|
|
1822
|
+
return capturesLeaf(d.parser, seen);
|
|
1823
|
+
case "skip":
|
|
1824
|
+
return capturesLeaf(d.main, seen);
|
|
1825
|
+
case "scanTo":
|
|
1826
|
+
return true;
|
|
1827
|
+
case "lazy": {
|
|
1828
|
+
try {
|
|
1829
|
+
return capturesLeaf(d.thunk(), seen);
|
|
1830
|
+
} catch {
|
|
1831
|
+
return true;
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
default:
|
|
1835
|
+
return true;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1725
1838
|
function emitFallible(inner, ctx, pos) {
|
|
1726
1839
|
const lbl = v(ctx, "_lbl");
|
|
1727
1840
|
const okV = `${lbl}ok`;
|
|
@@ -1735,26 +1848,23 @@ function emitFallible(inner, ctx, pos) {
|
|
|
1735
1848
|
ctx.failLabel = savedLabel;
|
|
1736
1849
|
ctx.indent = savedIndent;
|
|
1737
1850
|
const ind0 = ind(ctx);
|
|
1738
|
-
const
|
|
1739
|
-
const
|
|
1740
|
-
const
|
|
1741
|
-
const
|
|
1851
|
+
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
1852
|
+
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
1853
|
+
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
1854
|
+
const mTl = needsRollback ? v(ctx, "_fctl") : null;
|
|
1742
1855
|
const stmts = [
|
|
1743
1856
|
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
1744
1857
|
...mL ? [
|
|
1745
1858
|
`${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
|
|
1746
1859
|
`${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
|
|
1747
|
-
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0
|
|
1748
|
-
`${ind0}const ${mLg} = _ctx._triviaLog?.length ?? 0`
|
|
1860
|
+
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`
|
|
1749
1861
|
] : [],
|
|
1750
1862
|
`${ind0}${lbl}: {`,
|
|
1751
1863
|
...r.stmts,
|
|
1752
|
-
`${ind0} ${valV} = ${r.valueVar}`,
|
|
1753
|
-
`${ind0} ${endV} = ${r.endVar}`,
|
|
1754
|
-
`${ind0} ${okV} = true`,
|
|
1864
|
+
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
1755
1865
|
`${ind0}}`,
|
|
1756
1866
|
...mL ? [
|
|
1757
|
-
`${ind0}if (!${okV}) {
|
|
1867
|
+
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null)} }`
|
|
1758
1868
|
] : []
|
|
1759
1869
|
];
|
|
1760
1870
|
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
@@ -2028,11 +2138,13 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
|
2028
2138
|
gateCond = `_mf[${gateIdx}](_ctx.state)`;
|
|
2029
2139
|
}
|
|
2030
2140
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
2031
|
-
const
|
|
2032
|
-
const
|
|
2033
|
-
const
|
|
2034
|
-
const
|
|
2035
|
-
const
|
|
2141
|
+
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
2142
|
+
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
2143
|
+
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
2144
|
+
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
2145
|
+
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
2146
|
+
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
2147
|
+
const rollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog) : "";
|
|
2036
2148
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
2037
2149
|
ctx.indent++;
|
|
2038
2150
|
const ind1 = ind(ctx);
|
|
@@ -2062,11 +2174,7 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
|
2062
2174
|
stmts.push(`${ind0} }`);
|
|
2063
2175
|
if (rollback) stmts.push(`${ind0} if (!${resOkV}) { ${rollback} }`);
|
|
2064
2176
|
} else {
|
|
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} }`);
|
|
2177
|
+
stmts.push(`${ind0} if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
|
|
2070
2178
|
if (rollback) stmts.push(`${ind0} else { ${rollback} }`);
|
|
2071
2179
|
}
|
|
2072
2180
|
stmts.push(`${ind0}}`);
|
|
@@ -2411,6 +2519,22 @@ function emitRecover(def, ctx, pos) {
|
|
|
2411
2519
|
];
|
|
2412
2520
|
return { stmts, valueVar: valVar, endVar };
|
|
2413
2521
|
}
|
|
2522
|
+
function emitExpect(def, ctx, pos) {
|
|
2523
|
+
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
2524
|
+
const ind0 = ind(ctx);
|
|
2525
|
+
const errV = v(ctx, "_err");
|
|
2526
|
+
const stmts = [
|
|
2527
|
+
...innerStmts,
|
|
2528
|
+
`${ind0}if (!${okVar}) {`,
|
|
2529
|
+
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
2530
|
+
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
2531
|
+
`${ind0} ${valVar} = ${errV}`,
|
|
2532
|
+
`${ind0} ${endVar} = ${pos}`,
|
|
2533
|
+
`${ind0} ${okVar} = true`,
|
|
2534
|
+
`${ind0}}`
|
|
2535
|
+
];
|
|
2536
|
+
return { stmts, valueVar: valVar, endVar };
|
|
2537
|
+
}
|
|
2414
2538
|
function emit(p, ctx, pos) {
|
|
2415
2539
|
const def = p._def;
|
|
2416
2540
|
switch (def.tag) {
|
|
@@ -2519,6 +2643,8 @@ function emit(p, ctx, pos) {
|
|
|
2519
2643
|
return emitScanTo(def, ctx, pos);
|
|
2520
2644
|
case "recover":
|
|
2521
2645
|
return emitRecover(def, ctx, pos);
|
|
2646
|
+
case "expect":
|
|
2647
|
+
return emitExpect(def, ctx, pos);
|
|
2522
2648
|
case "guard": {
|
|
2523
2649
|
const fnIdx = ctx.mapFns.length;
|
|
2524
2650
|
ctx.mapFns.push(def.predicate);
|
|
@@ -2602,6 +2728,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2602
2728
|
return hasNodeDef(d.sentinel, seen) || d.skip.some((x) => hasNodeDef(x, seen));
|
|
2603
2729
|
case "recover":
|
|
2604
2730
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.sentinel, seen);
|
|
2731
|
+
case "expect":
|
|
2732
|
+
return hasNodeDef(d.parser, seen);
|
|
2605
2733
|
case "withCtx":
|
|
2606
2734
|
return hasNodeDef(d.parser, seen);
|
|
2607
2735
|
default:
|
|
@@ -2670,6 +2798,11 @@ function compile(combinator, mapFnSources) {
|
|
|
2670
2798
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
2671
2799
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
2672
2800
|
},
|
|
2801
|
+
// Note: collects recover()/expect() errors via _errors. Unlike interpreter
|
|
2802
|
+
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
2803
|
+
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
2804
|
+
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
2805
|
+
// (span.end < input.length) instead, which is mode-agnostic.
|
|
2673
2806
|
parseWithErrors(input, pos = 0) {
|
|
2674
2807
|
const errors = [];
|
|
2675
2808
|
const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
|
|
@@ -2712,6 +2845,58 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
2712
2845
|
].join("\n");
|
|
2713
2846
|
}
|
|
2714
2847
|
|
|
2848
|
+
// src/combinators/expect.ts
|
|
2849
|
+
function staticExpected(c) {
|
|
2850
|
+
const def = c._def;
|
|
2851
|
+
switch (def.tag) {
|
|
2852
|
+
case "literal":
|
|
2853
|
+
return [JSON.stringify(def.value)];
|
|
2854
|
+
case "regex":
|
|
2855
|
+
return [`/${def.source}/`];
|
|
2856
|
+
case "keywords":
|
|
2857
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
2858
|
+
case "label":
|
|
2859
|
+
return [def.label];
|
|
2860
|
+
case "choice":
|
|
2861
|
+
return def.parsers.flatMap(staticExpected);
|
|
2862
|
+
case "sequence":
|
|
2863
|
+
return def.parsers.length > 0 ? staticExpected(def.parsers[0]) : [];
|
|
2864
|
+
case "node":
|
|
2865
|
+
case "grammar":
|
|
2866
|
+
case "trivia":
|
|
2867
|
+
case "optional":
|
|
2868
|
+
case "many":
|
|
2869
|
+
case "oneOrMore":
|
|
2870
|
+
case "transform":
|
|
2871
|
+
case "not":
|
|
2872
|
+
return staticExpected(def.parser);
|
|
2873
|
+
case "lazy":
|
|
2874
|
+
return staticExpected(def.thunk());
|
|
2875
|
+
default:
|
|
2876
|
+
return [];
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
function expect(combinator, label2) {
|
|
2880
|
+
const expected = label2 !== void 0 ? [label2] : staticExpected(combinator);
|
|
2881
|
+
const meta = {
|
|
2882
|
+
firstSet: combinator._meta.firstSet,
|
|
2883
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2884
|
+
isTrivia: false
|
|
2885
|
+
};
|
|
2886
|
+
return {
|
|
2887
|
+
_tag: "expect",
|
|
2888
|
+
_meta: meta,
|
|
2889
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2890
|
+
parse(input, pos, ctx) {
|
|
2891
|
+
const result = combinator.parse(input, pos, ctx);
|
|
2892
|
+
if (result.ok) return result;
|
|
2893
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2894
|
+
ctx._errors?.push(error);
|
|
2895
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2896
|
+
}
|
|
2897
|
+
};
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2715
2900
|
// src/combinators/scanTo.ts
|
|
2716
2901
|
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
2717
2902
|
const meta = {
|
|
@@ -2725,7 +2910,11 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
2725
2910
|
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
2726
2911
|
parse(input, pos, ctx) {
|
|
2727
2912
|
let cur = pos;
|
|
2728
|
-
const probeCtx = {
|
|
2913
|
+
const probeCtx = {
|
|
2914
|
+
trackLines: ctx.trackLines,
|
|
2915
|
+
state: ctx.state,
|
|
2916
|
+
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
2917
|
+
};
|
|
2729
2918
|
const emit2 = (end) => {
|
|
2730
2919
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
2731
2920
|
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
@@ -2761,20 +2950,46 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
2761
2950
|
}
|
|
2762
2951
|
function balanced(open, close, options = {}) {
|
|
2763
2952
|
const self = ref();
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2953
|
+
const skips = options.skip ?? [];
|
|
2954
|
+
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
2955
|
+
let bounded = true;
|
|
2956
|
+
for (const sk of skips) {
|
|
2957
|
+
const cs = firstSetClassChars(sk);
|
|
2958
|
+
if (cs === null) {
|
|
2959
|
+
bounded = false;
|
|
2960
|
+
break;
|
|
2961
|
+
}
|
|
2962
|
+
for (const ch of cs) stop.add(ch);
|
|
2963
|
+
}
|
|
2964
|
+
const cls = [...stop].map(escapeClassChar).join("");
|
|
2965
|
+
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
2966
|
+
const inner = many(choice(self, ...skips, content));
|
|
2768
2967
|
const combi = transform(
|
|
2769
|
-
sequence(literal(open), inner, literal(close)),
|
|
2770
|
-
(
|
|
2968
|
+
sequence(literal(open), inner, expect(literal(close), close)),
|
|
2969
|
+
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
2970
|
+
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
2971
|
+
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
2771
2972
|
);
|
|
2772
2973
|
if (combi._def.tag === "transform") {
|
|
2773
|
-
combi._def.fnSrc =
|
|
2974
|
+
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
2774
2975
|
}
|
|
2775
2976
|
self.define(combi);
|
|
2776
2977
|
return combi;
|
|
2777
2978
|
}
|
|
2979
|
+
function firstSetClassChars(c) {
|
|
2980
|
+
const fs = c._meta.firstSet;
|
|
2981
|
+
if (fs.kind === "empty") return [];
|
|
2982
|
+
if (fs.kind !== "ranges") return null;
|
|
2983
|
+
const out = [];
|
|
2984
|
+
for (const { lo, hi } of fs.ranges) {
|
|
2985
|
+
if (hi - lo > 8) return null;
|
|
2986
|
+
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
2987
|
+
}
|
|
2988
|
+
return out;
|
|
2989
|
+
}
|
|
2990
|
+
function escapeClassChar(ch) {
|
|
2991
|
+
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
2992
|
+
}
|
|
2778
2993
|
|
|
2779
2994
|
// src/plugin/evaluator.ts
|
|
2780
2995
|
function isWordFactory(v2) {
|
|
@@ -2793,7 +3008,8 @@ var SUPPORTED = {
|
|
|
2793
3008
|
sepBy: (...a) => sepBy(a[0], a[1]),
|
|
2794
3009
|
trivia: (...a) => trivia(a[0]),
|
|
2795
3010
|
label: (...a) => label(a[0], a[1]),
|
|
2796
|
-
noTrivia: (...a) => noTrivia(a[0])
|
|
3011
|
+
noTrivia: (...a) => noTrivia(a[0]),
|
|
3012
|
+
expect: (...a) => expect(a[0], a[1])
|
|
2797
3013
|
};
|
|
2798
3014
|
function isScopeEntry(v2) {
|
|
2799
3015
|
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
@@ -2929,13 +3145,14 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
2929
3145
|
}
|
|
2930
3146
|
}
|
|
2931
3147
|
if (callee.name === "balanced") {
|
|
2932
|
-
const [openArg, closeArg] = node2.arguments;
|
|
3148
|
+
const [openArg, closeArg, optsArg] = node2.arguments;
|
|
2933
3149
|
if (!openArg || !closeArg || openArg.type === "SpreadElement" || closeArg.type === "SpreadElement") return null;
|
|
2934
3150
|
const open = anyValue(openArg, scope, code, []);
|
|
2935
3151
|
const close = anyValue(closeArg, scope, code, []);
|
|
2936
3152
|
if (typeof open !== "string" || typeof close !== "string") return null;
|
|
3153
|
+
const opts = optsArg && optsArg.type !== "SpreadElement" ? anyValue(optsArg, scope, code, []) : void 0;
|
|
2937
3154
|
try {
|
|
2938
|
-
return balanced(open, close);
|
|
3155
|
+
return balanced(open, close, opts);
|
|
2939
3156
|
} catch {
|
|
2940
3157
|
return null;
|
|
2941
3158
|
}
|