parseman 0.25.0 → 0.26.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/completions.d.ts +14 -4
- package/dist/combinators/completions.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts +2 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts +5 -5
- package/dist/combinators/not.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts +3 -2
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +1 -0
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +9 -4
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/scannable-run.d.ts +2 -2
- package/dist/compiler/scannable-run.d.ts.map +1 -1
- package/dist/cst/capture-buffer.d.ts +1 -0
- package/dist/cst/capture-buffer.d.ts.map +1 -1
- package/dist/cst/types.d.ts +7 -7
- package/dist/cst/types.d.ts.map +1 -1
- package/dist/functional/doc.d.ts +37 -2
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/functional/run.d.ts +12 -1
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +505 -195
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +505 -195
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +776 -0
- package/dist/language-service/index.cjs.map +7 -0
- package/dist/language-service/index.d.ts +94 -0
- package/dist/language-service/index.d.ts.map +1 -0
- package/dist/language-service/index.js +753 -0
- package/dist/language-service/index.js.map +7 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +568 -129
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts +11 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +568 -129
- package/dist/plugin/index.js.map +4 -4
- package/dist/recovery/scan.d.ts +54 -0
- package/dist/recovery/scan.d.ts.map +1 -0
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.js.map +1 -1
- package/dist/types.d.ts +60 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/dist/combinators/recover-list.d.ts +0 -41
- package/dist/combinators/recover-list.d.ts.map +0 -1
- package/dist/combinators/recover.d.ts +0 -20
- package/dist/combinators/recover.d.ts.map +0 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -332,7 +332,13 @@ function saveCstMark(ctx) {
|
|
|
332
332
|
raw: cstRawLen(ctx),
|
|
333
333
|
tlog: cstTlLen(ctx),
|
|
334
334
|
leaves: cstLeavesLen(ctx),
|
|
335
|
-
fields: ctx._fields?.length ?? 0
|
|
335
|
+
fields: ctx._fields?.length ?? 0,
|
|
336
|
+
// Speculative rollback must truncate the flat recovery-error sink in lockstep
|
|
337
|
+
// with the CST leaves: a branch that recovered (pushing a ParseError to
|
|
338
|
+
// ctx._errors AND embedding it as a CST child via captureError) then failed
|
|
339
|
+
// must remove BOTH, or the flat error survives as a GHOST that a tree walk
|
|
340
|
+
// can't see (flat run().errors would disagree with the embedded set).
|
|
341
|
+
errors: ctx._errors?.length ?? 0
|
|
336
342
|
};
|
|
337
343
|
}
|
|
338
344
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -348,6 +354,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
348
354
|
if (len === 0) b[keySingle] = void 0;
|
|
349
355
|
}
|
|
350
356
|
function rollbackCstCapture(ctx, mark) {
|
|
357
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
351
358
|
const b = ctx._cstBuf;
|
|
352
359
|
if (b) {
|
|
353
360
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -1291,10 +1298,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1291
1298
|
}
|
|
1292
1299
|
function saveTriviaMark(ctx) {
|
|
1293
1300
|
const m = saveCstMark(ctx);
|
|
1294
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1301
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1295
1302
|
}
|
|
1296
1303
|
function rollbackTrivia(ctx, mark) {
|
|
1297
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1304
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1298
1305
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1299
1306
|
}
|
|
1300
1307
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1528,6 +1535,93 @@ function scanBlockComment(input, cur) {
|
|
|
1528
1535
|
return close === -1 ? cur : close + 2;
|
|
1529
1536
|
}
|
|
1530
1537
|
|
|
1538
|
+
// src/recovery/scan.ts
|
|
1539
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
1540
|
+
const s = {
|
|
1541
|
+
_probe: ctx._probe,
|
|
1542
|
+
_errors: ctx._errors,
|
|
1543
|
+
_cstLeaves: ctx._cstLeaves,
|
|
1544
|
+
_cstChildren: ctx._cstChildren,
|
|
1545
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
1546
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
1547
|
+
_triviaLog: ctx._triviaLog,
|
|
1548
|
+
_fields: ctx._fields,
|
|
1549
|
+
_cstBuf: ctx._cstBuf,
|
|
1550
|
+
_tolerant: ctx._tolerant,
|
|
1551
|
+
_sync: ctx._sync
|
|
1552
|
+
};
|
|
1553
|
+
ctx._probe = void 0;
|
|
1554
|
+
ctx._errors = void 0;
|
|
1555
|
+
ctx._cstLeaves = void 0;
|
|
1556
|
+
ctx._cstChildren = void 0;
|
|
1557
|
+
ctx._cstRawChildren = void 0;
|
|
1558
|
+
ctx._cstTriviaLog = void 0;
|
|
1559
|
+
ctx._triviaLog = void 0;
|
|
1560
|
+
ctx._fields = void 0;
|
|
1561
|
+
ctx._cstBuf = void 0;
|
|
1562
|
+
ctx._tolerant = void 0;
|
|
1563
|
+
ctx._sync = void 0;
|
|
1564
|
+
try {
|
|
1565
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
1566
|
+
} finally {
|
|
1567
|
+
ctx._probe = s._probe;
|
|
1568
|
+
ctx._errors = s._errors;
|
|
1569
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
1570
|
+
ctx._cstChildren = s._cstChildren;
|
|
1571
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
1572
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
1573
|
+
ctx._triviaLog = s._triviaLog;
|
|
1574
|
+
ctx._fields = s._fields;
|
|
1575
|
+
ctx._cstBuf = s._cstBuf;
|
|
1576
|
+
ctx._tolerant = s._tolerant;
|
|
1577
|
+
ctx._sync = s._sync;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
function orSentinel(a, b) {
|
|
1581
|
+
if (b === void 0) return a;
|
|
1582
|
+
return {
|
|
1583
|
+
_tag: "orSentinel",
|
|
1584
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
1585
|
+
_def: { tag: "unknown" },
|
|
1586
|
+
parse(input, pos, ctx) {
|
|
1587
|
+
const ra = a.parse(input, pos, ctx);
|
|
1588
|
+
if (ra.ok) return ra;
|
|
1589
|
+
return b.parse(input, pos, ctx);
|
|
1590
|
+
}
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
function firstSetSentinel(fs2) {
|
|
1594
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
1595
|
+
const ranges = fs2.ranges;
|
|
1596
|
+
return {
|
|
1597
|
+
_tag: "firstSetSentinel",
|
|
1598
|
+
_meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
|
|
1599
|
+
_def: { tag: "unknown" },
|
|
1600
|
+
parse(input, pos) {
|
|
1601
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
1602
|
+
if (code !== void 0) {
|
|
1603
|
+
for (const r of ranges) {
|
|
1604
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
1612
|
+
let scanPos = from;
|
|
1613
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
1614
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
1615
|
+
ctx._errors?.push(error);
|
|
1616
|
+
return { error, end: scanPos };
|
|
1617
|
+
}
|
|
1618
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
1619
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
1620
|
+
}
|
|
1621
|
+
function captureError(ctx, error) {
|
|
1622
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1531
1625
|
// src/combinators/sequence.ts
|
|
1532
1626
|
function sequence(...parsers) {
|
|
1533
1627
|
const meta = {
|
|
@@ -1538,11 +1632,59 @@ function sequence(...parsers) {
|
|
|
1538
1632
|
isTrivia: false
|
|
1539
1633
|
};
|
|
1540
1634
|
const def = { tag: "sequence", parsers };
|
|
1635
|
+
let followSentinels;
|
|
1636
|
+
function parseTolerant(input, pos, ctx) {
|
|
1637
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1638
|
+
const fs2 = parsers.slice(i + 1).reduce(
|
|
1639
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1640
|
+
{ kind: "empty" }
|
|
1641
|
+
);
|
|
1642
|
+
return firstSetSentinel(fs2);
|
|
1643
|
+
});
|
|
1644
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1645
|
+
let cur = pos;
|
|
1646
|
+
const inheritedSync = ctx._sync;
|
|
1647
|
+
try {
|
|
1648
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1649
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1650
|
+
if (ctx.trivia && i > 0) {
|
|
1651
|
+
const mark = saveTriviaMark(ctx);
|
|
1652
|
+
let scanEnd;
|
|
1653
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1654
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1655
|
+
scan.commit();
|
|
1656
|
+
scanEnd = scan.end;
|
|
1657
|
+
} else {
|
|
1658
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1659
|
+
}
|
|
1660
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1661
|
+
if (!result2.ok) return result2;
|
|
1662
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1663
|
+
else rollbackTrivia(ctx, mark);
|
|
1664
|
+
if (values !== void 0) values.push(result2.value);
|
|
1665
|
+
continue;
|
|
1666
|
+
}
|
|
1667
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1668
|
+
if (!result.ok) return result;
|
|
1669
|
+
if (values !== void 0) values.push(result.value);
|
|
1670
|
+
cur = result.span.end;
|
|
1671
|
+
}
|
|
1672
|
+
} finally {
|
|
1673
|
+
ctx._sync = inheritedSync;
|
|
1674
|
+
}
|
|
1675
|
+
return {
|
|
1676
|
+
ok: true,
|
|
1677
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1678
|
+
value: values ?? void 0,
|
|
1679
|
+
span: { start: pos, end: cur }
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1541
1682
|
return {
|
|
1542
1683
|
_tag: "sequence",
|
|
1543
1684
|
_meta: meta,
|
|
1544
1685
|
_def: def,
|
|
1545
1686
|
parse(input, pos, ctx) {
|
|
1687
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1546
1688
|
const values = def.valueUnused ? void 0 : [];
|
|
1547
1689
|
let cur = pos;
|
|
1548
1690
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1581,6 +1723,66 @@ function sequence(...parsers) {
|
|
|
1581
1723
|
};
|
|
1582
1724
|
}
|
|
1583
1725
|
|
|
1726
|
+
// src/combinators/expect.ts
|
|
1727
|
+
function deriveExpected(c) {
|
|
1728
|
+
const def = c._def;
|
|
1729
|
+
switch (def.tag) {
|
|
1730
|
+
case "literal":
|
|
1731
|
+
return [JSON.stringify(def.value)];
|
|
1732
|
+
case "regex":
|
|
1733
|
+
return [`/${def.source}/`];
|
|
1734
|
+
case "keywords":
|
|
1735
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1736
|
+
case "label":
|
|
1737
|
+
return [def.label];
|
|
1738
|
+
case "choice":
|
|
1739
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1740
|
+
case "sequence":
|
|
1741
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1742
|
+
case "node":
|
|
1743
|
+
case "grammar":
|
|
1744
|
+
case "trivia":
|
|
1745
|
+
case "token":
|
|
1746
|
+
case "optional":
|
|
1747
|
+
case "many":
|
|
1748
|
+
case "oneOrMore":
|
|
1749
|
+
case "transform":
|
|
1750
|
+
case "not":
|
|
1751
|
+
return deriveExpected(def.parser);
|
|
1752
|
+
case "lazy": {
|
|
1753
|
+
const name = c._ruleName;
|
|
1754
|
+
try {
|
|
1755
|
+
return deriveExpected(def.thunk());
|
|
1756
|
+
} catch {
|
|
1757
|
+
return name ? [name] : [];
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
default:
|
|
1761
|
+
return [];
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
function expect(combinator, label2) {
|
|
1765
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1766
|
+
const meta = {
|
|
1767
|
+
firstSet: combinator._meta.firstSet,
|
|
1768
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1769
|
+
isTrivia: false
|
|
1770
|
+
};
|
|
1771
|
+
return {
|
|
1772
|
+
_tag: "expect",
|
|
1773
|
+
_meta: meta,
|
|
1774
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1775
|
+
parse(input, pos, ctx) {
|
|
1776
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1777
|
+
if (result.ok) return result;
|
|
1778
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
1779
|
+
ctx._errors?.push(error);
|
|
1780
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1781
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1782
|
+
}
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1584
1786
|
// src/combinators/repeat.ts
|
|
1585
1787
|
function repItem(combinator, input, cur, ctx) {
|
|
1586
1788
|
const mark = saveTriviaMark(ctx);
|
|
@@ -1601,7 +1803,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1601
1803
|
const result = combinator.parse(input, pos, ctx);
|
|
1602
1804
|
if (!result.ok) {
|
|
1603
1805
|
rollbackTrivia(ctx, mark);
|
|
1604
|
-
return { fail: result };
|
|
1806
|
+
return { fail: result, failPos: pos };
|
|
1605
1807
|
}
|
|
1606
1808
|
if (result.span.end === pos) {
|
|
1607
1809
|
rollbackTrivia(ctx, mark);
|
|
@@ -1616,6 +1818,7 @@ function many(combinator) {
|
|
|
1616
1818
|
isTrivia: false
|
|
1617
1819
|
};
|
|
1618
1820
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1821
|
+
let expected;
|
|
1619
1822
|
return {
|
|
1620
1823
|
_tag: "many",
|
|
1621
1824
|
_meta: meta,
|
|
@@ -1625,7 +1828,18 @@ function many(combinator) {
|
|
|
1625
1828
|
let cur = pos;
|
|
1626
1829
|
while (cur < input.length) {
|
|
1627
1830
|
const item = repItem(combinator, input, cur, ctx);
|
|
1628
|
-
if (item === "stop"
|
|
1831
|
+
if (item === "stop") break;
|
|
1832
|
+
if ("fail" in item) {
|
|
1833
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1834
|
+
if (sync === void 0) break;
|
|
1835
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1836
|
+
expected ??= deriveExpected(combinator);
|
|
1837
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1838
|
+
if (values !== void 0) values.push(error);
|
|
1839
|
+
captureError(ctx, error);
|
|
1840
|
+
cur = end;
|
|
1841
|
+
continue;
|
|
1842
|
+
}
|
|
1629
1843
|
if (values !== void 0) values.push(item.value);
|
|
1630
1844
|
cur = item.end;
|
|
1631
1845
|
}
|
|
@@ -1640,6 +1854,7 @@ function oneOrMore(combinator) {
|
|
|
1640
1854
|
isTrivia: false
|
|
1641
1855
|
};
|
|
1642
1856
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1857
|
+
let expected;
|
|
1643
1858
|
return {
|
|
1644
1859
|
_tag: "oneOrMore",
|
|
1645
1860
|
_meta: meta,
|
|
@@ -1651,7 +1866,18 @@ function oneOrMore(combinator) {
|
|
|
1651
1866
|
let cur = first.span.end;
|
|
1652
1867
|
while (cur < input.length) {
|
|
1653
1868
|
const item = repItem(combinator, input, cur, ctx);
|
|
1654
|
-
if (item === "stop"
|
|
1869
|
+
if (item === "stop") break;
|
|
1870
|
+
if ("fail" in item) {
|
|
1871
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1872
|
+
if (sync === void 0) break;
|
|
1873
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1874
|
+
expected ??= deriveExpected(combinator);
|
|
1875
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1876
|
+
if (values !== void 0) values.push(error);
|
|
1877
|
+
captureError(ctx, error);
|
|
1878
|
+
cur = end;
|
|
1879
|
+
continue;
|
|
1880
|
+
}
|
|
1655
1881
|
if (values !== void 0) values.push(item.value);
|
|
1656
1882
|
cur = item.end;
|
|
1657
1883
|
}
|
|
@@ -1697,15 +1923,29 @@ function sepBy(combinator, separator) {
|
|
|
1697
1923
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1698
1924
|
isTrivia: false
|
|
1699
1925
|
};
|
|
1926
|
+
let expected;
|
|
1700
1927
|
return {
|
|
1701
1928
|
_tag: "sepBy",
|
|
1702
1929
|
_meta: meta,
|
|
1703
1930
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1704
1931
|
parse(input, pos, ctx) {
|
|
1705
1932
|
const first = combinator.parse(input, pos, ctx);
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1933
|
+
const values = [];
|
|
1934
|
+
let cur;
|
|
1935
|
+
if (first.ok) {
|
|
1936
|
+
values.push(first.value);
|
|
1937
|
+
cur = first.span.end;
|
|
1938
|
+
} else {
|
|
1939
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1940
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1941
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1942
|
+
}
|
|
1943
|
+
expected ??= deriveExpected(combinator);
|
|
1944
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1945
|
+
values.push(rec.error);
|
|
1946
|
+
captureError(ctx, rec.error);
|
|
1947
|
+
cur = rec.end;
|
|
1948
|
+
}
|
|
1709
1949
|
while (cur < input.length) {
|
|
1710
1950
|
const loopMark = saveTriviaMark(ctx);
|
|
1711
1951
|
let sepPos = cur;
|
|
@@ -1735,6 +1975,15 @@ function sepBy(combinator, separator) {
|
|
|
1735
1975
|
}
|
|
1736
1976
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1737
1977
|
if (!next.ok) {
|
|
1978
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1979
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
1980
|
+
expected ??= deriveExpected(combinator);
|
|
1981
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
1982
|
+
values.push(rec.error);
|
|
1983
|
+
captureError(ctx, rec.error);
|
|
1984
|
+
cur = rec.end;
|
|
1985
|
+
continue;
|
|
1986
|
+
}
|
|
1738
1987
|
rollbackTrivia(ctx, loopMark);
|
|
1739
1988
|
break;
|
|
1740
1989
|
}
|
|
@@ -1871,7 +2120,7 @@ function rules(a, b) {
|
|
|
1871
2120
|
cache[key] = parser2;
|
|
1872
2121
|
}
|
|
1873
2122
|
}
|
|
1874
|
-
if (options?.trivia
|
|
2123
|
+
if (options?.trivia != null) {
|
|
1875
2124
|
for (const key of Object.keys(definitions)) {
|
|
1876
2125
|
const rule = cache[key];
|
|
1877
2126
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1901,7 +2150,9 @@ function not(combinator) {
|
|
|
1901
2150
|
_meta: meta,
|
|
1902
2151
|
_def: { tag: "not", parser: combinator },
|
|
1903
2152
|
parse(input, pos, ctx) {
|
|
2153
|
+
const mark = saveCstMark(ctx);
|
|
1904
2154
|
const result = combinator.parse(input, pos, ctx);
|
|
2155
|
+
rollbackCstCapture(ctx, mark);
|
|
1905
2156
|
if (result.ok) {
|
|
1906
2157
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1907
2158
|
}
|
|
@@ -2015,7 +2266,7 @@ function unwrapChild(child) {
|
|
|
2015
2266
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
2016
2267
|
}
|
|
2017
2268
|
function isCstChild(value) {
|
|
2018
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2269
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
2019
2270
|
}
|
|
2020
2271
|
function missingInferredType() {
|
|
2021
2272
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2268,65 +2519,6 @@ function token(root) {
|
|
|
2268
2519
|
};
|
|
2269
2520
|
}
|
|
2270
2521
|
|
|
2271
|
-
// src/combinators/expect.ts
|
|
2272
|
-
function deriveExpected(c) {
|
|
2273
|
-
const def = c._def;
|
|
2274
|
-
switch (def.tag) {
|
|
2275
|
-
case "literal":
|
|
2276
|
-
return [JSON.stringify(def.value)];
|
|
2277
|
-
case "regex":
|
|
2278
|
-
return [`/${def.source}/`];
|
|
2279
|
-
case "keywords":
|
|
2280
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2281
|
-
case "label":
|
|
2282
|
-
return [def.label];
|
|
2283
|
-
case "choice":
|
|
2284
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2285
|
-
case "sequence":
|
|
2286
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2287
|
-
case "node":
|
|
2288
|
-
case "grammar":
|
|
2289
|
-
case "trivia":
|
|
2290
|
-
case "token":
|
|
2291
|
-
case "optional":
|
|
2292
|
-
case "many":
|
|
2293
|
-
case "oneOrMore":
|
|
2294
|
-
case "transform":
|
|
2295
|
-
case "not":
|
|
2296
|
-
return deriveExpected(def.parser);
|
|
2297
|
-
case "lazy": {
|
|
2298
|
-
const name = c._ruleName;
|
|
2299
|
-
try {
|
|
2300
|
-
return deriveExpected(def.thunk());
|
|
2301
|
-
} catch {
|
|
2302
|
-
return name ? [name] : [];
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
default:
|
|
2306
|
-
return [];
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2309
|
-
function expect(combinator, label2) {
|
|
2310
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2311
|
-
const meta = {
|
|
2312
|
-
firstSet: combinator._meta.firstSet,
|
|
2313
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2314
|
-
isTrivia: false
|
|
2315
|
-
};
|
|
2316
|
-
return {
|
|
2317
|
-
_tag: "expect",
|
|
2318
|
-
_meta: meta,
|
|
2319
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2320
|
-
parse(input, pos, ctx) {
|
|
2321
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2322
|
-
if (result.ok) return result;
|
|
2323
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2324
|
-
ctx._errors?.push(error);
|
|
2325
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2326
|
-
}
|
|
2327
|
-
};
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
2522
|
// src/compiler/scannable-run.ts
|
|
2331
2523
|
var BACKSLASH = 92;
|
|
2332
2524
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2398,20 +2590,39 @@ function parseSeqParts(source) {
|
|
|
2398
2590
|
lit = [];
|
|
2399
2591
|
}
|
|
2400
2592
|
};
|
|
2401
|
-
const
|
|
2593
|
+
const braceQuant = (at) => {
|
|
2594
|
+
const close = source.indexOf("}", at);
|
|
2595
|
+
if (close === -1) return null;
|
|
2596
|
+
const body = source.slice(at + 1, close);
|
|
2597
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2598
|
+
if (!m) return null;
|
|
2599
|
+
const min = Number(m[1]);
|
|
2600
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2601
|
+
if (max < 1 || min > max) return null;
|
|
2602
|
+
return { min, max, len: close - at + 1 };
|
|
2603
|
+
};
|
|
2604
|
+
const runFrom = (ranges, negated, at) => {
|
|
2605
|
+
const q = source[at];
|
|
2402
2606
|
if (q === "+") {
|
|
2403
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2607
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2404
2608
|
return 1;
|
|
2405
2609
|
}
|
|
2406
2610
|
if (q === "*") {
|
|
2407
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2611
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2408
2612
|
return 1;
|
|
2409
2613
|
}
|
|
2410
2614
|
if (q === "?") {
|
|
2411
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2615
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2412
2616
|
return 1;
|
|
2413
2617
|
}
|
|
2414
|
-
|
|
2618
|
+
if (q === "{") {
|
|
2619
|
+
const b = braceQuant(at);
|
|
2620
|
+
if (b) {
|
|
2621
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2622
|
+
return b.len;
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2415
2626
|
return 0;
|
|
2416
2627
|
};
|
|
2417
2628
|
let i = 0;
|
|
@@ -2436,7 +2647,7 @@ function parseSeqParts(source) {
|
|
|
2436
2647
|
if (!ranges) return null;
|
|
2437
2648
|
flush();
|
|
2438
2649
|
i = k + 1;
|
|
2439
|
-
i += runFrom(ranges, neg,
|
|
2650
|
+
i += runFrom(ranges, neg, i);
|
|
2440
2651
|
continue;
|
|
2441
2652
|
}
|
|
2442
2653
|
if (ch === "\\") {
|
|
@@ -2444,7 +2655,7 @@ function parseSeqParts(source) {
|
|
|
2444
2655
|
if (e === "d" || e === "w" || e === "s") {
|
|
2445
2656
|
flush();
|
|
2446
2657
|
i += 2;
|
|
2447
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2658
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2448
2659
|
continue;
|
|
2449
2660
|
}
|
|
2450
2661
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2533,7 +2744,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2533
2744
|
let hasMandatory = false;
|
|
2534
2745
|
for (let k = 0; k < parts.length; k++) {
|
|
2535
2746
|
const p = parts[k];
|
|
2536
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2747
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2537
2748
|
if (mandatory) hasMandatory = true;
|
|
2538
2749
|
if (p.part === "group") {
|
|
2539
2750
|
const exposure = groupPartExposure(p);
|
|
@@ -2544,9 +2755,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2544
2755
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2545
2756
|
}
|
|
2546
2757
|
}
|
|
2547
|
-
const
|
|
2548
|
-
|
|
2549
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2758
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2759
|
+
if (needsDisjoint) {
|
|
2550
2760
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2551
2761
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2552
2762
|
}
|
|
@@ -2603,8 +2813,8 @@ function fixedClassSeq(shape) {
|
|
|
2603
2813
|
if (p.part === "lit") {
|
|
2604
2814
|
if (p.optional) return null;
|
|
2605
2815
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2606
|
-
} else if (p.part === "run" &&
|
|
2607
|
-
out.push({ ranges: p.ranges, negated: p.negated });
|
|
2816
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2817
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2608
2818
|
} else {
|
|
2609
2819
|
return null;
|
|
2610
2820
|
}
|
|
@@ -2656,7 +2866,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2656
2866
|
const last = shape.parts[shape.parts.length - 1];
|
|
2657
2867
|
if (last.part === "lit") return null;
|
|
2658
2868
|
if (last.part === "run") {
|
|
2659
|
-
if (last.
|
|
2869
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2660
2870
|
return null;
|
|
2661
2871
|
}
|
|
2662
2872
|
return groupPartExposure(last);
|
|
@@ -2793,7 +3003,7 @@ function partFirstAccept(part) {
|
|
|
2793
3003
|
function seqFirstAccept(parts) {
|
|
2794
3004
|
const sets = [];
|
|
2795
3005
|
for (const p of parts) {
|
|
2796
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
3006
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2797
3007
|
sets.push(partFirstAccept(p));
|
|
2798
3008
|
if (mandatory) break;
|
|
2799
3009
|
}
|
|
@@ -3208,7 +3418,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3208
3418
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3209
3419
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3210
3420
|
}
|
|
3211
|
-
} else if (p.part === "run" &&
|
|
3421
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3422
|
+
const s = mint("_s");
|
|
3423
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3424
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3425
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3426
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3427
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3212
3428
|
if (p.min === 1) {
|
|
3213
3429
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3214
3430
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3218,8 +3434,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3218
3434
|
} else if (p.part === "run") {
|
|
3219
3435
|
const s = mint("_s");
|
|
3220
3436
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3221
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3222
|
-
if (p.min
|
|
3437
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3438
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3223
3439
|
} else {
|
|
3224
3440
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3225
3441
|
if (!p.unbounded) {
|
|
@@ -3686,21 +3902,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3686
3902
|
}
|
|
3687
3903
|
return name;
|
|
3688
3904
|
}
|
|
3905
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3906
|
+
if (!ctx.recovery) return "";
|
|
3907
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3908
|
+
const pb = v(ctx, "_pb");
|
|
3909
|
+
return `if (_ctx._probe !== undefined && ${posExpr} <= _ctx._probe.offset) { const ${pb} = _ctx._probe.best; if (${pb} === null || ${posExpr} > ${pb}.span.start) _ctx._probe.best = { ok: false, expected: [...${fx}], span: { start: ${posExpr}, end: ${posExpr} } }; else if (${posExpr} === ${pb}.span.start) _ctx._probe.best = { ok: false, expected: [...${pb}.expected, ...${fx}], span: { start: ${posExpr}, end: ${posExpr} } } } `;
|
|
3910
|
+
}
|
|
3689
3911
|
function failBody(ctx, expected, posExpr) {
|
|
3912
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3690
3913
|
if (ctx.failLabel) {
|
|
3691
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3692
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3914
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3915
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3693
3916
|
}
|
|
3694
|
-
return failReturn(expected, posExpr);
|
|
3917
|
+
return probe + failReturn(expected, posExpr);
|
|
3695
3918
|
}
|
|
3696
3919
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3920
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3697
3921
|
if (ctx.failLabel) {
|
|
3698
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3922
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3699
3923
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3700
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3924
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3701
3925
|
}
|
|
3702
|
-
if (!constant) return
|
|
3703
|
-
return failReturnArr(expectedArr, posExpr);
|
|
3926
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3927
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3704
3928
|
}
|
|
3705
3929
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3706
3930
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4200,6 +4424,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4200
4424
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4201
4425
|
return { stmts, valueVar: vv, endVar };
|
|
4202
4426
|
}
|
|
4427
|
+
function syncSentinelExpr(fs2) {
|
|
4428
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
4429
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs2.ranges)} })`;
|
|
4430
|
+
}
|
|
4203
4431
|
function emitSeqValues(def, ctx, pos) {
|
|
4204
4432
|
const startV = v(ctx, "_start");
|
|
4205
4433
|
const curV = v(ctx, "_cur");
|
|
@@ -4208,7 +4436,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4208
4436
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4209
4437
|
];
|
|
4210
4438
|
const valueVars = [];
|
|
4439
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4440
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4441
|
+
const publishSync = (i) => {
|
|
4442
|
+
if (!ctx.recovery) return "";
|
|
4443
|
+
const fs2 = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4444
|
+
const ref2 = syncSentinelExpr(fs2);
|
|
4445
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4446
|
+
};
|
|
4211
4447
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4448
|
+
const syncPub = publishSync(i);
|
|
4449
|
+
if (syncPub) stmts.push(syncPub);
|
|
4212
4450
|
if (i > 0 && ctx.activeTrivia) {
|
|
4213
4451
|
if (ctx.capturing) {
|
|
4214
4452
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4233,7 +4471,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4233
4471
|
continue;
|
|
4234
4472
|
} else {
|
|
4235
4473
|
const trivFn = ensureTriviaFn(ctx);
|
|
4236
|
-
|
|
4474
|
+
const scanEndV = v(ctx, "_sne");
|
|
4475
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4476
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4477
|
+
stmts.push(...r2.stmts);
|
|
4478
|
+
const endAfterV = v(ctx, "_sea");
|
|
4479
|
+
stmts.push(
|
|
4480
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4481
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4482
|
+
);
|
|
4483
|
+
valueVars.push(r2.valueVar);
|
|
4484
|
+
continue;
|
|
4237
4485
|
}
|
|
4238
4486
|
}
|
|
4239
4487
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4463,7 +4711,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4463
4711
|
if (gate) {
|
|
4464
4712
|
const gateIdx = ctx.mapFns.length;
|
|
4465
4713
|
ctx.mapFns.push(gate);
|
|
4466
|
-
ctx.mapFnSrcs.push(null);
|
|
4714
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4467
4715
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4468
4716
|
}
|
|
4469
4717
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4568,6 +4816,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4568
4816
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4569
4817
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4570
4818
|
];
|
|
4819
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4820
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4571
4821
|
if (def.min === 1) {
|
|
4572
4822
|
const firstR = emit(def.parser, ctx, curV);
|
|
4573
4823
|
stmts.push(...firstR.stmts);
|
|
@@ -4601,10 +4851,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4601
4851
|
}
|
|
4602
4852
|
}
|
|
4603
4853
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4604
|
-
stmts.push(
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4854
|
+
stmts.push(...iterStmts);
|
|
4855
|
+
if (ctx.recovery) {
|
|
4856
|
+
const rrV = v(ctx, "_rr");
|
|
4857
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4858
|
+
stmts.push(
|
|
4859
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4860
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4861
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4862
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4863
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4864
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4865
|
+
`${ind(ctx)} continue`,
|
|
4866
|
+
`${ind(ctx)} }`,
|
|
4867
|
+
`${ind(ctx)} break`,
|
|
4868
|
+
`${ind(ctx)}}`,
|
|
4869
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4870
|
+
);
|
|
4871
|
+
} else {
|
|
4872
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4873
|
+
}
|
|
4608
4874
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4609
4875
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4610
4876
|
ctx.indent--;
|
|
@@ -4626,20 +4892,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4626
4892
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4627
4893
|
const arrV = v(ctx, "_arr");
|
|
4628
4894
|
const curV = v(ctx, "_cur");
|
|
4895
|
+
const rec = !!ctx.recovery;
|
|
4896
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4897
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4898
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4899
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4629
4900
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4630
4901
|
const stmts = [
|
|
4631
4902
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4632
4903
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4633
|
-
...
|
|
4634
|
-
|
|
4904
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4905
|
+
...firstStmts
|
|
4635
4906
|
];
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
)
|
|
4642
|
-
|
|
4907
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4908
|
+
if (!rec) return [originalFail];
|
|
4909
|
+
const rr = v(ctx, "_rr");
|
|
4910
|
+
return [
|
|
4911
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
4912
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
4913
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
4914
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
4915
|
+
`${ind(ctx)} }`,
|
|
4916
|
+
`${ind(ctx)} ${rb}break`,
|
|
4917
|
+
`${ind(ctx)}}`
|
|
4918
|
+
];
|
|
4919
|
+
};
|
|
4920
|
+
if (rec) {
|
|
4921
|
+
const rr0 = v(ctx, "_rr0");
|
|
4922
|
+
const didV = v(ctx, "_did");
|
|
4923
|
+
stmts.push(
|
|
4924
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
4925
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
4926
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
4927
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
4928
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
4929
|
+
`${ind(ctx)}}`,
|
|
4930
|
+
`${ind(ctx)}if (${didV}) {`
|
|
4931
|
+
);
|
|
4932
|
+
ctx.indent++;
|
|
4933
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
4934
|
+
ctx.indent++;
|
|
4935
|
+
} else {
|
|
4936
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
4937
|
+
ctx.indent++;
|
|
4938
|
+
stmts.push(
|
|
4939
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
4940
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
4941
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
4942
|
+
);
|
|
4943
|
+
ctx.indent++;
|
|
4944
|
+
}
|
|
4643
4945
|
let sepAtPos = curV;
|
|
4644
4946
|
if (ctx.activeTrivia) {
|
|
4645
4947
|
if (ctx.capturing) {
|
|
@@ -4665,8 +4967,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4665
4967
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4666
4968
|
stmts.push(
|
|
4667
4969
|
...nextStmts,
|
|
4668
|
-
|
|
4669
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
4970
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4670
4971
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4671
4972
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4672
4973
|
);
|
|
@@ -4682,7 +4983,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4682
4983
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4683
4984
|
stmts.push(
|
|
4684
4985
|
...nextStmts,
|
|
4685
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
4986
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4686
4987
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4687
4988
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4688
4989
|
);
|
|
@@ -4702,7 +5003,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4702
5003
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4703
5004
|
stmts.push(
|
|
4704
5005
|
...nextStmts,
|
|
4705
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
5006
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4706
5007
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4707
5008
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4708
5009
|
);
|
|
@@ -4959,7 +5260,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4959
5260
|
stmts.push(
|
|
4960
5261
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4961
5262
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4962
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === '
|
|
5263
|
+
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'parseError')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
4963
5264
|
);
|
|
4964
5265
|
return { stmts, valueVar: ndV, endVar };
|
|
4965
5266
|
}
|
|
@@ -5049,6 +5350,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5049
5350
|
`${ind0}if (!${okVar}) {`,
|
|
5050
5351
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5051
5352
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5353
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5354
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5355
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5356
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5052
5357
|
`${ind0} ${valVar} = ${errV}`,
|
|
5053
5358
|
`${ind0} ${endVar} = ${pos}`,
|
|
5054
5359
|
`${ind0} ${okVar} = true`,
|
|
@@ -5215,7 +5520,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5215
5520
|
case "guard": {
|
|
5216
5521
|
const fnIdx = ctx.mapFns.length;
|
|
5217
5522
|
ctx.mapFns.push(def.predicate);
|
|
5218
|
-
ctx.mapFnSrcs.push(null);
|
|
5523
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5219
5524
|
const vv = v(ctx);
|
|
5220
5525
|
return {
|
|
5221
5526
|
stmts: [
|
|
@@ -5230,7 +5535,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5230
5535
|
const evIdx = ctx.mapFns.length;
|
|
5231
5536
|
const extra = def.extra;
|
|
5232
5537
|
ctx.mapFns.push((() => extra));
|
|
5233
|
-
ctx.mapFnSrcs.push(null);
|
|
5538
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5234
5539
|
const innerParser = def.parser;
|
|
5235
5540
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5236
5541
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5474,7 +5779,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5474
5779
|
}
|
|
5475
5780
|
return deps;
|
|
5476
5781
|
}
|
|
5477
|
-
function compile(combinator, mapFnSources) {
|
|
5782
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5478
5783
|
markUnusedValues(combinator);
|
|
5479
5784
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5480
5785
|
const ctx = {
|
|
@@ -5495,6 +5800,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5495
5800
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5496
5801
|
namedFnDecls: [],
|
|
5497
5802
|
capturing: hasNodeDef(combinator),
|
|
5803
|
+
recovery: opts?.recovery ?? false,
|
|
5498
5804
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5499
5805
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5500
5806
|
};
|
|
@@ -5547,7 +5853,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5547
5853
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5548
5854
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5549
5855
|
},
|
|
5550
|
-
// Note: collects
|
|
5856
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5551
5857
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5552
5858
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5553
5859
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5593,6 +5899,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
5593
5899
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5594
5900
|
namedFnDecls: [],
|
|
5595
5901
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5902
|
+
recovery: opts?.recovery ?? false,
|
|
5596
5903
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5597
5904
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5598
5905
|
};
|
|
@@ -5688,6 +5995,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5688
5995
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5689
5996
|
namedFnDecls: [],
|
|
5690
5997
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5998
|
+
recovery: opts?.recovery ?? false,
|
|
5691
5999
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5692
6000
|
ns,
|
|
5693
6001
|
deferFirstSetRefs: true,
|
|
@@ -6335,6 +6643,42 @@ function materializePiece(p, trivia2) {
|
|
|
6335
6643
|
return pieces;
|
|
6336
6644
|
}
|
|
6337
6645
|
|
|
6646
|
+
// src/combinators/guard.ts
|
|
6647
|
+
function guard(predicate) {
|
|
6648
|
+
const meta = {
|
|
6649
|
+
firstSet: { kind: "any" },
|
|
6650
|
+
canMatchNewline: false,
|
|
6651
|
+
isTrivia: false
|
|
6652
|
+
};
|
|
6653
|
+
return {
|
|
6654
|
+
_tag: "guard",
|
|
6655
|
+
_meta: meta,
|
|
6656
|
+
_def: { tag: "guard", predicate },
|
|
6657
|
+
parse(_input, pos, ctx) {
|
|
6658
|
+
if (predicate(ctx.state))
|
|
6659
|
+
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
6660
|
+
return { ok: false, expected: ["guard"], span: { start: pos, end: pos } };
|
|
6661
|
+
}
|
|
6662
|
+
};
|
|
6663
|
+
}
|
|
6664
|
+
|
|
6665
|
+
// src/combinators/withCtx.ts
|
|
6666
|
+
function withCtx(extra, combinator) {
|
|
6667
|
+
const meta = {
|
|
6668
|
+
firstSet: combinator._meta.firstSet,
|
|
6669
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
6670
|
+
isTrivia: false
|
|
6671
|
+
};
|
|
6672
|
+
return {
|
|
6673
|
+
_tag: "withCtx",
|
|
6674
|
+
_meta: meta,
|
|
6675
|
+
_def: { tag: "withCtx", extra, parser: combinator },
|
|
6676
|
+
parse(input, pos, ctx) {
|
|
6677
|
+
return combinator.parse(input, pos, { ...ctx, state: extra });
|
|
6678
|
+
}
|
|
6679
|
+
};
|
|
6680
|
+
}
|
|
6681
|
+
|
|
6338
6682
|
// src/cst/offset-model.ts
|
|
6339
6683
|
var { isFinite } = Number;
|
|
6340
6684
|
|
|
@@ -6366,6 +6710,35 @@ var SUPPORTED = {
|
|
|
6366
6710
|
function isScopeEntry(v2) {
|
|
6367
6711
|
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
6368
6712
|
}
|
|
6713
|
+
function propName(p) {
|
|
6714
|
+
if (p.computed) return null;
|
|
6715
|
+
const key = p.key;
|
|
6716
|
+
return key.type === "Identifier" ? key.name ?? null : key.type === "Literal" ? String(key.value) : null;
|
|
6717
|
+
}
|
|
6718
|
+
function isGatedArmExpr(e) {
|
|
6719
|
+
if (e.type !== "ObjectExpression") return false;
|
|
6720
|
+
let hasGate = false, hasCombinator = false;
|
|
6721
|
+
for (const prop of e.properties) {
|
|
6722
|
+
if (prop.type !== "Property") continue;
|
|
6723
|
+
const name = propName(prop);
|
|
6724
|
+
if (name === "gate") hasGate = true;
|
|
6725
|
+
else if (name === "combinator") hasCombinator = true;
|
|
6726
|
+
}
|
|
6727
|
+
return hasGate && hasCombinator;
|
|
6728
|
+
}
|
|
6729
|
+
function gatedArmParts(e) {
|
|
6730
|
+
let gate;
|
|
6731
|
+
let combinator;
|
|
6732
|
+
for (const prop of e.properties) {
|
|
6733
|
+
if (prop.type !== "Property") return null;
|
|
6734
|
+
const op = prop;
|
|
6735
|
+
const name = propName(op);
|
|
6736
|
+
if (name === "gate") gate = op.value;
|
|
6737
|
+
else if (name === "combinator") combinator = op.value;
|
|
6738
|
+
else return null;
|
|
6739
|
+
}
|
|
6740
|
+
return gate && combinator ? { gate, combinator } : null;
|
|
6741
|
+
}
|
|
6369
6742
|
function isCombinator(v2) {
|
|
6370
6743
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
6371
6744
|
}
|
|
@@ -6547,6 +6920,72 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
6547
6920
|
return null;
|
|
6548
6921
|
}
|
|
6549
6922
|
}
|
|
6923
|
+
if (callee.name === "guard") {
|
|
6924
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6925
|
+
const [predArg] = node2.arguments;
|
|
6926
|
+
if (!predArg || predArg.type === "SpreadElement") return null;
|
|
6927
|
+
const predSrc = code.slice(predArg.start, predArg.end);
|
|
6928
|
+
mfs.push(predSrc);
|
|
6929
|
+
try {
|
|
6930
|
+
const combi = guard(() => true);
|
|
6931
|
+
if (combi._def.tag !== "guard") return null;
|
|
6932
|
+
combi._def.predSrc = predSrc;
|
|
6933
|
+
return combi;
|
|
6934
|
+
} catch {
|
|
6935
|
+
return null;
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
if (callee.name === "withCtx") {
|
|
6939
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6940
|
+
const [extraArg, innerArg] = node2.arguments;
|
|
6941
|
+
if (!extraArg || !innerArg || extraArg.type === "SpreadElement" || innerArg.type === "SpreadElement") return null;
|
|
6942
|
+
const extraSrc = code.slice(extraArg.start, extraArg.end);
|
|
6943
|
+
mfs.push(extraSrc);
|
|
6944
|
+
const inner = anyValue(innerArg, scope, code, mfs);
|
|
6945
|
+
if (!isCombinator(inner)) return null;
|
|
6946
|
+
try {
|
|
6947
|
+
const combi = withCtx({}, inner);
|
|
6948
|
+
if (combi._def.tag !== "withCtx") return null;
|
|
6949
|
+
combi._def.extraSrc = extraSrc;
|
|
6950
|
+
return combi;
|
|
6951
|
+
} catch {
|
|
6952
|
+
return null;
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6955
|
+
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
6956
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6957
|
+
const arms = [];
|
|
6958
|
+
const gateSrcs = [];
|
|
6959
|
+
for (const argNode of node2.arguments) {
|
|
6960
|
+
if (argNode.type === "SpreadElement") return null;
|
|
6961
|
+
if (isGatedArmExpr(argNode)) {
|
|
6962
|
+
const parts = gatedArmParts(argNode);
|
|
6963
|
+
if (!parts) return null;
|
|
6964
|
+
const gateSrc = code.slice(parts.gate.start, parts.gate.end);
|
|
6965
|
+
mfs.push(gateSrc);
|
|
6966
|
+
const combi = anyValue(parts.combinator, scope, code, mfs);
|
|
6967
|
+
if (!isCombinator(combi)) return null;
|
|
6968
|
+
arms.push({ gate: () => true, combinator: combi });
|
|
6969
|
+
gateSrcs.push(gateSrc);
|
|
6970
|
+
} else {
|
|
6971
|
+
const combi = anyValue(argNode, scope, code, mfs);
|
|
6972
|
+
if (!isCombinator(combi)) return null;
|
|
6973
|
+
arms.push(combi);
|
|
6974
|
+
gateSrcs.push(null);
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6977
|
+
try {
|
|
6978
|
+
const combi = choice(...arms);
|
|
6979
|
+
if (combi._def.tag !== "choice") return null;
|
|
6980
|
+
combi._def.gateSrcs = gateSrcs;
|
|
6981
|
+
for (let i = 0; i < combi._def.gates.length; i++) {
|
|
6982
|
+
if (combi._def.gates[i] !== null !== (gateSrcs[i] !== null)) return null;
|
|
6983
|
+
}
|
|
6984
|
+
return combi;
|
|
6985
|
+
} catch {
|
|
6986
|
+
return null;
|
|
6987
|
+
}
|
|
6988
|
+
}
|
|
6550
6989
|
const factory = SUPPORTED[callee.name];
|
|
6551
6990
|
if (!factory) return null;
|
|
6552
6991
|
const args = node2.arguments.map((arg) => {
|
|
@@ -6609,9 +7048,9 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
6609
7048
|
if (typeof key !== "string" && typeof key !== "number") return null;
|
|
6610
7049
|
return obj[key] ?? null;
|
|
6611
7050
|
}
|
|
6612
|
-
const
|
|
6613
|
-
if (!
|
|
6614
|
-
return obj[
|
|
7051
|
+
const propName2 = mem.property.name;
|
|
7052
|
+
if (!propName2) return null;
|
|
7053
|
+
return obj[propName2] ?? null;
|
|
6615
7054
|
}
|
|
6616
7055
|
if (node2.type === "CallExpression") {
|
|
6617
7056
|
const callee = node2.callee;
|
|
@@ -6856,7 +7295,7 @@ var plugin_default = (0, import_unplugin.createUnplugin)((opts = {}) => ({
|
|
|
6856
7295
|
if (!code.includes("parseman")) return null;
|
|
6857
7296
|
if (!code.includes("macro")) return null;
|
|
6858
7297
|
const moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE, ...opts.moduleAliases ?? []]);
|
|
6859
|
-
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true);
|
|
7298
|
+
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true);
|
|
6860
7299
|
if (result?.warnings.length) {
|
|
6861
7300
|
for (const w of result.warnings) {
|
|
6862
7301
|
if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
|
|
@@ -6960,7 +7399,7 @@ function extractImportBindings(body) {
|
|
|
6960
7399
|
}
|
|
6961
7400
|
return out;
|
|
6962
7401
|
}
|
|
6963
|
-
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false) {
|
|
7402
|
+
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false) {
|
|
6964
7403
|
let result;
|
|
6965
7404
|
try {
|
|
6966
7405
|
result = (0, import_oxc_parser.parseSync)(id, code);
|
|
@@ -7031,7 +7470,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7031
7470
|
(p) => p.key?.name === "trivia"
|
|
7032
7471
|
)?.value : void 0;
|
|
7033
7472
|
const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
|
|
7034
|
-
const compiled = compileRuleMap([...ruleMap], gTrivia ? { trivia: gTrivia } :
|
|
7473
|
+
const compiled = compileRuleMap([...ruleMap], { ...gTrivia ? { trivia: gTrivia } : {}, recovery });
|
|
7035
7474
|
if (!compiled) {
|
|
7036
7475
|
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
7037
7476
|
return null;
|
|
@@ -7129,7 +7568,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7129
7568
|
const ns = nsFor(label2);
|
|
7130
7569
|
const ir = serializeRuleMap(entries);
|
|
7131
7570
|
if (ir) return { carried: [{ ns, ir }] };
|
|
7132
|
-
const p = compileLinkable(entries, ns, composing ? { trivia: composing } :
|
|
7571
|
+
const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, recovery });
|
|
7133
7572
|
return p ? { carried: [p] } : null;
|
|
7134
7573
|
};
|
|
7135
7574
|
const argPieces = (arg, label2, composing) => {
|
|
@@ -7305,7 +7744,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7305
7744
|
const refEntry = scope.get(varName);
|
|
7306
7745
|
const refCombi = refEntry?.combi ?? null;
|
|
7307
7746
|
if (refCombi) {
|
|
7308
|
-
const compiled2 = compile(refCombi);
|
|
7747
|
+
const compiled2 = compile(refCombi, void 0, { recovery });
|
|
7309
7748
|
if (compiled2.inlineExpression === null) {
|
|
7310
7749
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
7311
7750
|
continue;
|
|
@@ -7322,7 +7761,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7322
7761
|
let replacement = compiledRules.replacement;
|
|
7323
7762
|
if (exportPrefix) {
|
|
7324
7763
|
const ns = nsFor(varName);
|
|
7325
|
-
const pieces = compileLinkable([...compiledRules.ruleMap], ns);
|
|
7764
|
+
const pieces = compileLinkable([...compiledRules.ruleMap], ns, { recovery });
|
|
7326
7765
|
if (pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
|
|
7327
7766
|
const ir = serializeRuleMap([...compiledRules.ruleMap]);
|
|
7328
7767
|
replacement = withCarriedPieces(replacement, [ir ? { ns, ir } : pieces]);
|
|
@@ -7358,7 +7797,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7358
7797
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
7359
7798
|
continue;
|
|
7360
7799
|
}
|
|
7361
|
-
const compiled = compile(parser2);
|
|
7800
|
+
const compiled = compile(parser2, void 0, { recovery });
|
|
7362
7801
|
if (compiled.inlineExpression === null) {
|
|
7363
7802
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
7364
7803
|
continue;
|