parseman 0.24.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/README.md +1 -1
- 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/relative-spans.d.ts +32 -0
- package/dist/cst/relative-spans.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 +89 -4
- 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 +807 -278
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +807 -278
- 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 +67 -6
- package/dist/spec/index.cjs.map +3 -3
- package/dist/spec/index.d.ts +10 -2
- package/dist/spec/index.d.ts.map +1 -1
- package/dist/spec/index.js +67 -6
- package/dist/spec/index.js.map +3 -3
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/spec/railroad.d.ts +12 -0
- package/dist/spec/railroad.d.ts.map +1 -1
- package/dist/types.d.ts +60 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -2
- 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.js
CHANGED
|
@@ -297,7 +297,13 @@ function saveCstMark(ctx) {
|
|
|
297
297
|
raw: cstRawLen(ctx),
|
|
298
298
|
tlog: cstTlLen(ctx),
|
|
299
299
|
leaves: cstLeavesLen(ctx),
|
|
300
|
-
fields: ctx._fields?.length ?? 0
|
|
300
|
+
fields: ctx._fields?.length ?? 0,
|
|
301
|
+
// Speculative rollback must truncate the flat recovery-error sink in lockstep
|
|
302
|
+
// with the CST leaves: a branch that recovered (pushing a ParseError to
|
|
303
|
+
// ctx._errors AND embedding it as a CST child via captureError) then failed
|
|
304
|
+
// must remove BOTH, or the flat error survives as a GHOST that a tree walk
|
|
305
|
+
// can't see (flat run().errors would disagree with the embedded set).
|
|
306
|
+
errors: ctx._errors?.length ?? 0
|
|
301
307
|
};
|
|
302
308
|
}
|
|
303
309
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -313,6 +319,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
313
319
|
if (len === 0) b[keySingle] = void 0;
|
|
314
320
|
}
|
|
315
321
|
function rollbackCstCapture(ctx, mark) {
|
|
322
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
316
323
|
const b = ctx._cstBuf;
|
|
317
324
|
if (b) {
|
|
318
325
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -1256,10 +1263,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1256
1263
|
}
|
|
1257
1264
|
function saveTriviaMark(ctx) {
|
|
1258
1265
|
const m = saveCstMark(ctx);
|
|
1259
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1266
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1260
1267
|
}
|
|
1261
1268
|
function rollbackTrivia(ctx, mark) {
|
|
1262
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1269
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1263
1270
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1264
1271
|
}
|
|
1265
1272
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1493,6 +1500,93 @@ function scanBlockComment(input, cur) {
|
|
|
1493
1500
|
return close === -1 ? cur : close + 2;
|
|
1494
1501
|
}
|
|
1495
1502
|
|
|
1503
|
+
// src/recovery/scan.ts
|
|
1504
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
1505
|
+
const s = {
|
|
1506
|
+
_probe: ctx._probe,
|
|
1507
|
+
_errors: ctx._errors,
|
|
1508
|
+
_cstLeaves: ctx._cstLeaves,
|
|
1509
|
+
_cstChildren: ctx._cstChildren,
|
|
1510
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
1511
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
1512
|
+
_triviaLog: ctx._triviaLog,
|
|
1513
|
+
_fields: ctx._fields,
|
|
1514
|
+
_cstBuf: ctx._cstBuf,
|
|
1515
|
+
_tolerant: ctx._tolerant,
|
|
1516
|
+
_sync: ctx._sync
|
|
1517
|
+
};
|
|
1518
|
+
ctx._probe = void 0;
|
|
1519
|
+
ctx._errors = void 0;
|
|
1520
|
+
ctx._cstLeaves = void 0;
|
|
1521
|
+
ctx._cstChildren = void 0;
|
|
1522
|
+
ctx._cstRawChildren = void 0;
|
|
1523
|
+
ctx._cstTriviaLog = void 0;
|
|
1524
|
+
ctx._triviaLog = void 0;
|
|
1525
|
+
ctx._fields = void 0;
|
|
1526
|
+
ctx._cstBuf = void 0;
|
|
1527
|
+
ctx._tolerant = void 0;
|
|
1528
|
+
ctx._sync = void 0;
|
|
1529
|
+
try {
|
|
1530
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
1531
|
+
} finally {
|
|
1532
|
+
ctx._probe = s._probe;
|
|
1533
|
+
ctx._errors = s._errors;
|
|
1534
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
1535
|
+
ctx._cstChildren = s._cstChildren;
|
|
1536
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
1537
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
1538
|
+
ctx._triviaLog = s._triviaLog;
|
|
1539
|
+
ctx._fields = s._fields;
|
|
1540
|
+
ctx._cstBuf = s._cstBuf;
|
|
1541
|
+
ctx._tolerant = s._tolerant;
|
|
1542
|
+
ctx._sync = s._sync;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
function orSentinel(a, b) {
|
|
1546
|
+
if (b === void 0) return a;
|
|
1547
|
+
return {
|
|
1548
|
+
_tag: "orSentinel",
|
|
1549
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
1550
|
+
_def: { tag: "unknown" },
|
|
1551
|
+
parse(input, pos, ctx) {
|
|
1552
|
+
const ra = a.parse(input, pos, ctx);
|
|
1553
|
+
if (ra.ok) return ra;
|
|
1554
|
+
return b.parse(input, pos, ctx);
|
|
1555
|
+
}
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
function firstSetSentinel(fs2) {
|
|
1559
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
1560
|
+
const ranges = fs2.ranges;
|
|
1561
|
+
return {
|
|
1562
|
+
_tag: "firstSetSentinel",
|
|
1563
|
+
_meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
|
|
1564
|
+
_def: { tag: "unknown" },
|
|
1565
|
+
parse(input, pos) {
|
|
1566
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
1567
|
+
if (code !== void 0) {
|
|
1568
|
+
for (const r of ranges) {
|
|
1569
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
1577
|
+
let scanPos = from;
|
|
1578
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
1579
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
1580
|
+
ctx._errors?.push(error);
|
|
1581
|
+
return { error, end: scanPos };
|
|
1582
|
+
}
|
|
1583
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
1584
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
1585
|
+
}
|
|
1586
|
+
function captureError(ctx, error) {
|
|
1587
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1496
1590
|
// src/combinators/sequence.ts
|
|
1497
1591
|
function sequence(...parsers) {
|
|
1498
1592
|
const meta = {
|
|
@@ -1503,11 +1597,59 @@ function sequence(...parsers) {
|
|
|
1503
1597
|
isTrivia: false
|
|
1504
1598
|
};
|
|
1505
1599
|
const def = { tag: "sequence", parsers };
|
|
1600
|
+
let followSentinels;
|
|
1601
|
+
function parseTolerant(input, pos, ctx) {
|
|
1602
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1603
|
+
const fs2 = parsers.slice(i + 1).reduce(
|
|
1604
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1605
|
+
{ kind: "empty" }
|
|
1606
|
+
);
|
|
1607
|
+
return firstSetSentinel(fs2);
|
|
1608
|
+
});
|
|
1609
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1610
|
+
let cur = pos;
|
|
1611
|
+
const inheritedSync = ctx._sync;
|
|
1612
|
+
try {
|
|
1613
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1614
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1615
|
+
if (ctx.trivia && i > 0) {
|
|
1616
|
+
const mark = saveTriviaMark(ctx);
|
|
1617
|
+
let scanEnd;
|
|
1618
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1619
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1620
|
+
scan.commit();
|
|
1621
|
+
scanEnd = scan.end;
|
|
1622
|
+
} else {
|
|
1623
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1624
|
+
}
|
|
1625
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1626
|
+
if (!result2.ok) return result2;
|
|
1627
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1628
|
+
else rollbackTrivia(ctx, mark);
|
|
1629
|
+
if (values !== void 0) values.push(result2.value);
|
|
1630
|
+
continue;
|
|
1631
|
+
}
|
|
1632
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1633
|
+
if (!result.ok) return result;
|
|
1634
|
+
if (values !== void 0) values.push(result.value);
|
|
1635
|
+
cur = result.span.end;
|
|
1636
|
+
}
|
|
1637
|
+
} finally {
|
|
1638
|
+
ctx._sync = inheritedSync;
|
|
1639
|
+
}
|
|
1640
|
+
return {
|
|
1641
|
+
ok: true,
|
|
1642
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1643
|
+
value: values ?? void 0,
|
|
1644
|
+
span: { start: pos, end: cur }
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1506
1647
|
return {
|
|
1507
1648
|
_tag: "sequence",
|
|
1508
1649
|
_meta: meta,
|
|
1509
1650
|
_def: def,
|
|
1510
1651
|
parse(input, pos, ctx) {
|
|
1652
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1511
1653
|
const values = def.valueUnused ? void 0 : [];
|
|
1512
1654
|
let cur = pos;
|
|
1513
1655
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1546,6 +1688,66 @@ function sequence(...parsers) {
|
|
|
1546
1688
|
};
|
|
1547
1689
|
}
|
|
1548
1690
|
|
|
1691
|
+
// src/combinators/expect.ts
|
|
1692
|
+
function deriveExpected(c) {
|
|
1693
|
+
const def = c._def;
|
|
1694
|
+
switch (def.tag) {
|
|
1695
|
+
case "literal":
|
|
1696
|
+
return [JSON.stringify(def.value)];
|
|
1697
|
+
case "regex":
|
|
1698
|
+
return [`/${def.source}/`];
|
|
1699
|
+
case "keywords":
|
|
1700
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1701
|
+
case "label":
|
|
1702
|
+
return [def.label];
|
|
1703
|
+
case "choice":
|
|
1704
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1705
|
+
case "sequence":
|
|
1706
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1707
|
+
case "node":
|
|
1708
|
+
case "grammar":
|
|
1709
|
+
case "trivia":
|
|
1710
|
+
case "token":
|
|
1711
|
+
case "optional":
|
|
1712
|
+
case "many":
|
|
1713
|
+
case "oneOrMore":
|
|
1714
|
+
case "transform":
|
|
1715
|
+
case "not":
|
|
1716
|
+
return deriveExpected(def.parser);
|
|
1717
|
+
case "lazy": {
|
|
1718
|
+
const name = c._ruleName;
|
|
1719
|
+
try {
|
|
1720
|
+
return deriveExpected(def.thunk());
|
|
1721
|
+
} catch {
|
|
1722
|
+
return name ? [name] : [];
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
default:
|
|
1726
|
+
return [];
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
function expect(combinator, label2) {
|
|
1730
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1731
|
+
const meta = {
|
|
1732
|
+
firstSet: combinator._meta.firstSet,
|
|
1733
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1734
|
+
isTrivia: false
|
|
1735
|
+
};
|
|
1736
|
+
return {
|
|
1737
|
+
_tag: "expect",
|
|
1738
|
+
_meta: meta,
|
|
1739
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1740
|
+
parse(input, pos, ctx) {
|
|
1741
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1742
|
+
if (result.ok) return result;
|
|
1743
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
1744
|
+
ctx._errors?.push(error);
|
|
1745
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1746
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1549
1751
|
// src/combinators/repeat.ts
|
|
1550
1752
|
function repItem(combinator, input, cur, ctx) {
|
|
1551
1753
|
const mark = saveTriviaMark(ctx);
|
|
@@ -1566,7 +1768,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1566
1768
|
const result = combinator.parse(input, pos, ctx);
|
|
1567
1769
|
if (!result.ok) {
|
|
1568
1770
|
rollbackTrivia(ctx, mark);
|
|
1569
|
-
return { fail: result };
|
|
1771
|
+
return { fail: result, failPos: pos };
|
|
1570
1772
|
}
|
|
1571
1773
|
if (result.span.end === pos) {
|
|
1572
1774
|
rollbackTrivia(ctx, mark);
|
|
@@ -1581,6 +1783,7 @@ function many(combinator) {
|
|
|
1581
1783
|
isTrivia: false
|
|
1582
1784
|
};
|
|
1583
1785
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1786
|
+
let expected;
|
|
1584
1787
|
return {
|
|
1585
1788
|
_tag: "many",
|
|
1586
1789
|
_meta: meta,
|
|
@@ -1590,7 +1793,18 @@ function many(combinator) {
|
|
|
1590
1793
|
let cur = pos;
|
|
1591
1794
|
while (cur < input.length) {
|
|
1592
1795
|
const item = repItem(combinator, input, cur, ctx);
|
|
1593
|
-
if (item === "stop"
|
|
1796
|
+
if (item === "stop") break;
|
|
1797
|
+
if ("fail" in item) {
|
|
1798
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1799
|
+
if (sync === void 0) break;
|
|
1800
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1801
|
+
expected ??= deriveExpected(combinator);
|
|
1802
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1803
|
+
if (values !== void 0) values.push(error);
|
|
1804
|
+
captureError(ctx, error);
|
|
1805
|
+
cur = end;
|
|
1806
|
+
continue;
|
|
1807
|
+
}
|
|
1594
1808
|
if (values !== void 0) values.push(item.value);
|
|
1595
1809
|
cur = item.end;
|
|
1596
1810
|
}
|
|
@@ -1605,6 +1819,7 @@ function oneOrMore(combinator) {
|
|
|
1605
1819
|
isTrivia: false
|
|
1606
1820
|
};
|
|
1607
1821
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1822
|
+
let expected;
|
|
1608
1823
|
return {
|
|
1609
1824
|
_tag: "oneOrMore",
|
|
1610
1825
|
_meta: meta,
|
|
@@ -1616,7 +1831,18 @@ function oneOrMore(combinator) {
|
|
|
1616
1831
|
let cur = first.span.end;
|
|
1617
1832
|
while (cur < input.length) {
|
|
1618
1833
|
const item = repItem(combinator, input, cur, ctx);
|
|
1619
|
-
if (item === "stop"
|
|
1834
|
+
if (item === "stop") break;
|
|
1835
|
+
if ("fail" in item) {
|
|
1836
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1837
|
+
if (sync === void 0) break;
|
|
1838
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1839
|
+
expected ??= deriveExpected(combinator);
|
|
1840
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1841
|
+
if (values !== void 0) values.push(error);
|
|
1842
|
+
captureError(ctx, error);
|
|
1843
|
+
cur = end;
|
|
1844
|
+
continue;
|
|
1845
|
+
}
|
|
1620
1846
|
if (values !== void 0) values.push(item.value);
|
|
1621
1847
|
cur = item.end;
|
|
1622
1848
|
}
|
|
@@ -1662,15 +1888,29 @@ function sepBy(combinator, separator) {
|
|
|
1662
1888
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1663
1889
|
isTrivia: false
|
|
1664
1890
|
};
|
|
1891
|
+
let expected;
|
|
1665
1892
|
return {
|
|
1666
1893
|
_tag: "sepBy",
|
|
1667
1894
|
_meta: meta,
|
|
1668
1895
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1669
1896
|
parse(input, pos, ctx) {
|
|
1670
1897
|
const first = combinator.parse(input, pos, ctx);
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1898
|
+
const values = [];
|
|
1899
|
+
let cur;
|
|
1900
|
+
if (first.ok) {
|
|
1901
|
+
values.push(first.value);
|
|
1902
|
+
cur = first.span.end;
|
|
1903
|
+
} else {
|
|
1904
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1905
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1906
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1907
|
+
}
|
|
1908
|
+
expected ??= deriveExpected(combinator);
|
|
1909
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1910
|
+
values.push(rec.error);
|
|
1911
|
+
captureError(ctx, rec.error);
|
|
1912
|
+
cur = rec.end;
|
|
1913
|
+
}
|
|
1674
1914
|
while (cur < input.length) {
|
|
1675
1915
|
const loopMark = saveTriviaMark(ctx);
|
|
1676
1916
|
let sepPos = cur;
|
|
@@ -1700,6 +1940,15 @@ function sepBy(combinator, separator) {
|
|
|
1700
1940
|
}
|
|
1701
1941
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1702
1942
|
if (!next.ok) {
|
|
1943
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1944
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
1945
|
+
expected ??= deriveExpected(combinator);
|
|
1946
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
1947
|
+
values.push(rec.error);
|
|
1948
|
+
captureError(ctx, rec.error);
|
|
1949
|
+
cur = rec.end;
|
|
1950
|
+
continue;
|
|
1951
|
+
}
|
|
1703
1952
|
rollbackTrivia(ctx, loopMark);
|
|
1704
1953
|
break;
|
|
1705
1954
|
}
|
|
@@ -1836,7 +2085,7 @@ function rules(a, b) {
|
|
|
1836
2085
|
cache[key] = parser2;
|
|
1837
2086
|
}
|
|
1838
2087
|
}
|
|
1839
|
-
if (options?.trivia
|
|
2088
|
+
if (options?.trivia != null) {
|
|
1840
2089
|
for (const key of Object.keys(definitions)) {
|
|
1841
2090
|
const rule = cache[key];
|
|
1842
2091
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1866,7 +2115,9 @@ function not(combinator) {
|
|
|
1866
2115
|
_meta: meta,
|
|
1867
2116
|
_def: { tag: "not", parser: combinator },
|
|
1868
2117
|
parse(input, pos, ctx) {
|
|
2118
|
+
const mark = saveCstMark(ctx);
|
|
1869
2119
|
const result = combinator.parse(input, pos, ctx);
|
|
2120
|
+
rollbackCstCapture(ctx, mark);
|
|
1870
2121
|
if (result.ok) {
|
|
1871
2122
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1872
2123
|
}
|
|
@@ -1980,7 +2231,7 @@ function unwrapChild(child) {
|
|
|
1980
2231
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1981
2232
|
}
|
|
1982
2233
|
function isCstChild(value) {
|
|
1983
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2234
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
1984
2235
|
}
|
|
1985
2236
|
function missingInferredType() {
|
|
1986
2237
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2233,65 +2484,6 @@ function token(root) {
|
|
|
2233
2484
|
};
|
|
2234
2485
|
}
|
|
2235
2486
|
|
|
2236
|
-
// src/combinators/expect.ts
|
|
2237
|
-
function deriveExpected(c) {
|
|
2238
|
-
const def = c._def;
|
|
2239
|
-
switch (def.tag) {
|
|
2240
|
-
case "literal":
|
|
2241
|
-
return [JSON.stringify(def.value)];
|
|
2242
|
-
case "regex":
|
|
2243
|
-
return [`/${def.source}/`];
|
|
2244
|
-
case "keywords":
|
|
2245
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2246
|
-
case "label":
|
|
2247
|
-
return [def.label];
|
|
2248
|
-
case "choice":
|
|
2249
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2250
|
-
case "sequence":
|
|
2251
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2252
|
-
case "node":
|
|
2253
|
-
case "grammar":
|
|
2254
|
-
case "trivia":
|
|
2255
|
-
case "token":
|
|
2256
|
-
case "optional":
|
|
2257
|
-
case "many":
|
|
2258
|
-
case "oneOrMore":
|
|
2259
|
-
case "transform":
|
|
2260
|
-
case "not":
|
|
2261
|
-
return deriveExpected(def.parser);
|
|
2262
|
-
case "lazy": {
|
|
2263
|
-
const name = c._ruleName;
|
|
2264
|
-
try {
|
|
2265
|
-
return deriveExpected(def.thunk());
|
|
2266
|
-
} catch {
|
|
2267
|
-
return name ? [name] : [];
|
|
2268
|
-
}
|
|
2269
|
-
}
|
|
2270
|
-
default:
|
|
2271
|
-
return [];
|
|
2272
|
-
}
|
|
2273
|
-
}
|
|
2274
|
-
function expect(combinator, label2) {
|
|
2275
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2276
|
-
const meta = {
|
|
2277
|
-
firstSet: combinator._meta.firstSet,
|
|
2278
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2279
|
-
isTrivia: false
|
|
2280
|
-
};
|
|
2281
|
-
return {
|
|
2282
|
-
_tag: "expect",
|
|
2283
|
-
_meta: meta,
|
|
2284
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2285
|
-
parse(input, pos, ctx) {
|
|
2286
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2287
|
-
if (result.ok) return result;
|
|
2288
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2289
|
-
ctx._errors?.push(error);
|
|
2290
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2291
|
-
}
|
|
2292
|
-
};
|
|
2293
|
-
}
|
|
2294
|
-
|
|
2295
2487
|
// src/compiler/scannable-run.ts
|
|
2296
2488
|
var BACKSLASH = 92;
|
|
2297
2489
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2363,20 +2555,39 @@ function parseSeqParts(source) {
|
|
|
2363
2555
|
lit = [];
|
|
2364
2556
|
}
|
|
2365
2557
|
};
|
|
2366
|
-
const
|
|
2558
|
+
const braceQuant = (at) => {
|
|
2559
|
+
const close = source.indexOf("}", at);
|
|
2560
|
+
if (close === -1) return null;
|
|
2561
|
+
const body = source.slice(at + 1, close);
|
|
2562
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2563
|
+
if (!m) return null;
|
|
2564
|
+
const min = Number(m[1]);
|
|
2565
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2566
|
+
if (max < 1 || min > max) return null;
|
|
2567
|
+
return { min, max, len: close - at + 1 };
|
|
2568
|
+
};
|
|
2569
|
+
const runFrom = (ranges, negated, at) => {
|
|
2570
|
+
const q = source[at];
|
|
2367
2571
|
if (q === "+") {
|
|
2368
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2572
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2369
2573
|
return 1;
|
|
2370
2574
|
}
|
|
2371
2575
|
if (q === "*") {
|
|
2372
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2576
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2373
2577
|
return 1;
|
|
2374
2578
|
}
|
|
2375
2579
|
if (q === "?") {
|
|
2376
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2580
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2377
2581
|
return 1;
|
|
2378
2582
|
}
|
|
2379
|
-
|
|
2583
|
+
if (q === "{") {
|
|
2584
|
+
const b = braceQuant(at);
|
|
2585
|
+
if (b) {
|
|
2586
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2587
|
+
return b.len;
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2380
2591
|
return 0;
|
|
2381
2592
|
};
|
|
2382
2593
|
let i = 0;
|
|
@@ -2401,7 +2612,7 @@ function parseSeqParts(source) {
|
|
|
2401
2612
|
if (!ranges) return null;
|
|
2402
2613
|
flush();
|
|
2403
2614
|
i = k + 1;
|
|
2404
|
-
i += runFrom(ranges, neg,
|
|
2615
|
+
i += runFrom(ranges, neg, i);
|
|
2405
2616
|
continue;
|
|
2406
2617
|
}
|
|
2407
2618
|
if (ch === "\\") {
|
|
@@ -2409,7 +2620,7 @@ function parseSeqParts(source) {
|
|
|
2409
2620
|
if (e === "d" || e === "w" || e === "s") {
|
|
2410
2621
|
flush();
|
|
2411
2622
|
i += 2;
|
|
2412
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2623
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2413
2624
|
continue;
|
|
2414
2625
|
}
|
|
2415
2626
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2498,7 +2709,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2498
2709
|
let hasMandatory = false;
|
|
2499
2710
|
for (let k = 0; k < parts.length; k++) {
|
|
2500
2711
|
const p = parts[k];
|
|
2501
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2712
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2502
2713
|
if (mandatory) hasMandatory = true;
|
|
2503
2714
|
if (p.part === "group") {
|
|
2504
2715
|
const exposure = groupPartExposure(p);
|
|
@@ -2509,9 +2720,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2509
2720
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2510
2721
|
}
|
|
2511
2722
|
}
|
|
2512
|
-
const
|
|
2513
|
-
|
|
2514
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2723
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2724
|
+
if (needsDisjoint) {
|
|
2515
2725
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2516
2726
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2517
2727
|
}
|
|
@@ -2568,8 +2778,8 @@ function fixedClassSeq(shape) {
|
|
|
2568
2778
|
if (p.part === "lit") {
|
|
2569
2779
|
if (p.optional) return null;
|
|
2570
2780
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2571
|
-
} else if (p.part === "run" &&
|
|
2572
|
-
out.push({ ranges: p.ranges, negated: p.negated });
|
|
2781
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2782
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2573
2783
|
} else {
|
|
2574
2784
|
return null;
|
|
2575
2785
|
}
|
|
@@ -2621,7 +2831,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2621
2831
|
const last = shape.parts[shape.parts.length - 1];
|
|
2622
2832
|
if (last.part === "lit") return null;
|
|
2623
2833
|
if (last.part === "run") {
|
|
2624
|
-
if (last.
|
|
2834
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2625
2835
|
return null;
|
|
2626
2836
|
}
|
|
2627
2837
|
return groupPartExposure(last);
|
|
@@ -2758,7 +2968,7 @@ function partFirstAccept(part) {
|
|
|
2758
2968
|
function seqFirstAccept(parts) {
|
|
2759
2969
|
const sets = [];
|
|
2760
2970
|
for (const p of parts) {
|
|
2761
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2971
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2762
2972
|
sets.push(partFirstAccept(p));
|
|
2763
2973
|
if (mandatory) break;
|
|
2764
2974
|
}
|
|
@@ -3173,7 +3383,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3173
3383
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3174
3384
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3175
3385
|
}
|
|
3176
|
-
} else if (p.part === "run" &&
|
|
3386
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3387
|
+
const s = mint("_s");
|
|
3388
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3389
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3390
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3391
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3392
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3177
3393
|
if (p.min === 1) {
|
|
3178
3394
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3179
3395
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3183,8 +3399,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3183
3399
|
} else if (p.part === "run") {
|
|
3184
3400
|
const s = mint("_s");
|
|
3185
3401
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3186
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3187
|
-
if (p.min
|
|
3402
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3403
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3188
3404
|
} else {
|
|
3189
3405
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3190
3406
|
if (!p.unbounded) {
|
|
@@ -3651,21 +3867,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3651
3867
|
}
|
|
3652
3868
|
return name;
|
|
3653
3869
|
}
|
|
3870
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3871
|
+
if (!ctx.recovery) return "";
|
|
3872
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3873
|
+
const pb = v(ctx, "_pb");
|
|
3874
|
+
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} } } } `;
|
|
3875
|
+
}
|
|
3654
3876
|
function failBody(ctx, expected, posExpr) {
|
|
3877
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3655
3878
|
if (ctx.failLabel) {
|
|
3656
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3657
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3879
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3880
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3658
3881
|
}
|
|
3659
|
-
return failReturn(expected, posExpr);
|
|
3882
|
+
return probe + failReturn(expected, posExpr);
|
|
3660
3883
|
}
|
|
3661
3884
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3885
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3662
3886
|
if (ctx.failLabel) {
|
|
3663
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3887
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3664
3888
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3665
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3889
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3666
3890
|
}
|
|
3667
|
-
if (!constant) return
|
|
3668
|
-
return failReturnArr(expectedArr, posExpr);
|
|
3891
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3892
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3669
3893
|
}
|
|
3670
3894
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3671
3895
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4165,6 +4389,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4165
4389
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4166
4390
|
return { stmts, valueVar: vv, endVar };
|
|
4167
4391
|
}
|
|
4392
|
+
function syncSentinelExpr(fs2) {
|
|
4393
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
4394
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs2.ranges)} })`;
|
|
4395
|
+
}
|
|
4168
4396
|
function emitSeqValues(def, ctx, pos) {
|
|
4169
4397
|
const startV = v(ctx, "_start");
|
|
4170
4398
|
const curV = v(ctx, "_cur");
|
|
@@ -4173,7 +4401,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4173
4401
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4174
4402
|
];
|
|
4175
4403
|
const valueVars = [];
|
|
4404
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4405
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4406
|
+
const publishSync = (i) => {
|
|
4407
|
+
if (!ctx.recovery) return "";
|
|
4408
|
+
const fs2 = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4409
|
+
const ref2 = syncSentinelExpr(fs2);
|
|
4410
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4411
|
+
};
|
|
4176
4412
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4413
|
+
const syncPub = publishSync(i);
|
|
4414
|
+
if (syncPub) stmts.push(syncPub);
|
|
4177
4415
|
if (i > 0 && ctx.activeTrivia) {
|
|
4178
4416
|
if (ctx.capturing) {
|
|
4179
4417
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4198,7 +4436,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4198
4436
|
continue;
|
|
4199
4437
|
} else {
|
|
4200
4438
|
const trivFn = ensureTriviaFn(ctx);
|
|
4201
|
-
|
|
4439
|
+
const scanEndV = v(ctx, "_sne");
|
|
4440
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4441
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4442
|
+
stmts.push(...r2.stmts);
|
|
4443
|
+
const endAfterV = v(ctx, "_sea");
|
|
4444
|
+
stmts.push(
|
|
4445
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4446
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4447
|
+
);
|
|
4448
|
+
valueVars.push(r2.valueVar);
|
|
4449
|
+
continue;
|
|
4202
4450
|
}
|
|
4203
4451
|
}
|
|
4204
4452
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4428,7 +4676,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4428
4676
|
if (gate) {
|
|
4429
4677
|
const gateIdx = ctx.mapFns.length;
|
|
4430
4678
|
ctx.mapFns.push(gate);
|
|
4431
|
-
ctx.mapFnSrcs.push(null);
|
|
4679
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4432
4680
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4433
4681
|
}
|
|
4434
4682
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4533,6 +4781,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4533
4781
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4534
4782
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4535
4783
|
];
|
|
4784
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4785
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4536
4786
|
if (def.min === 1) {
|
|
4537
4787
|
const firstR = emit(def.parser, ctx, curV);
|
|
4538
4788
|
stmts.push(...firstR.stmts);
|
|
@@ -4566,10 +4816,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4566
4816
|
}
|
|
4567
4817
|
}
|
|
4568
4818
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4569
|
-
stmts.push(
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4819
|
+
stmts.push(...iterStmts);
|
|
4820
|
+
if (ctx.recovery) {
|
|
4821
|
+
const rrV = v(ctx, "_rr");
|
|
4822
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4823
|
+
stmts.push(
|
|
4824
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4825
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4826
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4827
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4828
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4829
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4830
|
+
`${ind(ctx)} continue`,
|
|
4831
|
+
`${ind(ctx)} }`,
|
|
4832
|
+
`${ind(ctx)} break`,
|
|
4833
|
+
`${ind(ctx)}}`,
|
|
4834
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4835
|
+
);
|
|
4836
|
+
} else {
|
|
4837
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4838
|
+
}
|
|
4573
4839
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4574
4840
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4575
4841
|
ctx.indent--;
|
|
@@ -4591,20 +4857,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4591
4857
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4592
4858
|
const arrV = v(ctx, "_arr");
|
|
4593
4859
|
const curV = v(ctx, "_cur");
|
|
4860
|
+
const rec = !!ctx.recovery;
|
|
4861
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4862
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4863
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4864
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4594
4865
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4595
4866
|
const stmts = [
|
|
4596
4867
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4597
4868
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4598
|
-
...
|
|
4599
|
-
|
|
4869
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4870
|
+
...firstStmts
|
|
4600
4871
|
];
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
)
|
|
4607
|
-
|
|
4872
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4873
|
+
if (!rec) return [originalFail];
|
|
4874
|
+
const rr = v(ctx, "_rr");
|
|
4875
|
+
return [
|
|
4876
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
4877
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
4878
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
4879
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
4880
|
+
`${ind(ctx)} }`,
|
|
4881
|
+
`${ind(ctx)} ${rb}break`,
|
|
4882
|
+
`${ind(ctx)}}`
|
|
4883
|
+
];
|
|
4884
|
+
};
|
|
4885
|
+
if (rec) {
|
|
4886
|
+
const rr0 = v(ctx, "_rr0");
|
|
4887
|
+
const didV = v(ctx, "_did");
|
|
4888
|
+
stmts.push(
|
|
4889
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
4890
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
4891
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
4892
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
4893
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
4894
|
+
`${ind(ctx)}}`,
|
|
4895
|
+
`${ind(ctx)}if (${didV}) {`
|
|
4896
|
+
);
|
|
4897
|
+
ctx.indent++;
|
|
4898
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
4899
|
+
ctx.indent++;
|
|
4900
|
+
} else {
|
|
4901
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
4902
|
+
ctx.indent++;
|
|
4903
|
+
stmts.push(
|
|
4904
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
4905
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
4906
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
4907
|
+
);
|
|
4908
|
+
ctx.indent++;
|
|
4909
|
+
}
|
|
4608
4910
|
let sepAtPos = curV;
|
|
4609
4911
|
if (ctx.activeTrivia) {
|
|
4610
4912
|
if (ctx.capturing) {
|
|
@@ -4630,8 +4932,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4630
4932
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4631
4933
|
stmts.push(
|
|
4632
4934
|
...nextStmts,
|
|
4633
|
-
|
|
4634
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
4935
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4635
4936
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4636
4937
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4637
4938
|
);
|
|
@@ -4647,7 +4948,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4647
4948
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4648
4949
|
stmts.push(
|
|
4649
4950
|
...nextStmts,
|
|
4650
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
4951
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4651
4952
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4652
4953
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4653
4954
|
);
|
|
@@ -4667,7 +4968,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4667
4968
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4668
4969
|
stmts.push(
|
|
4669
4970
|
...nextStmts,
|
|
4670
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
4971
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4671
4972
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4672
4973
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4673
4974
|
);
|
|
@@ -4924,7 +5225,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4924
5225
|
stmts.push(
|
|
4925
5226
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4926
5227
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4927
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === '
|
|
5228
|
+
`${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} } })`
|
|
4928
5229
|
);
|
|
4929
5230
|
return { stmts, valueVar: ndV, endVar };
|
|
4930
5231
|
}
|
|
@@ -5014,6 +5315,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5014
5315
|
`${ind0}if (!${okVar}) {`,
|
|
5015
5316
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5016
5317
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5318
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5319
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5320
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5321
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5017
5322
|
`${ind0} ${valVar} = ${errV}`,
|
|
5018
5323
|
`${ind0} ${endVar} = ${pos}`,
|
|
5019
5324
|
`${ind0} ${okVar} = true`,
|
|
@@ -5180,7 +5485,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5180
5485
|
case "guard": {
|
|
5181
5486
|
const fnIdx = ctx.mapFns.length;
|
|
5182
5487
|
ctx.mapFns.push(def.predicate);
|
|
5183
|
-
ctx.mapFnSrcs.push(null);
|
|
5488
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5184
5489
|
const vv = v(ctx);
|
|
5185
5490
|
return {
|
|
5186
5491
|
stmts: [
|
|
@@ -5195,7 +5500,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5195
5500
|
const evIdx = ctx.mapFns.length;
|
|
5196
5501
|
const extra = def.extra;
|
|
5197
5502
|
ctx.mapFns.push((() => extra));
|
|
5198
|
-
ctx.mapFnSrcs.push(null);
|
|
5503
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5199
5504
|
const innerParser = def.parser;
|
|
5200
5505
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5201
5506
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5439,7 +5744,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5439
5744
|
}
|
|
5440
5745
|
return deps;
|
|
5441
5746
|
}
|
|
5442
|
-
function compile(combinator, mapFnSources) {
|
|
5747
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5443
5748
|
markUnusedValues(combinator);
|
|
5444
5749
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5445
5750
|
const ctx = {
|
|
@@ -5460,6 +5765,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5460
5765
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5461
5766
|
namedFnDecls: [],
|
|
5462
5767
|
capturing: hasNodeDef(combinator),
|
|
5768
|
+
recovery: opts?.recovery ?? false,
|
|
5463
5769
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5464
5770
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5465
5771
|
};
|
|
@@ -5512,7 +5818,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5512
5818
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5513
5819
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5514
5820
|
},
|
|
5515
|
-
// Note: collects
|
|
5821
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5516
5822
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5517
5823
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5518
5824
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5558,6 +5864,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
5558
5864
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5559
5865
|
namedFnDecls: [],
|
|
5560
5866
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5867
|
+
recovery: opts?.recovery ?? false,
|
|
5561
5868
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5562
5869
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5563
5870
|
};
|
|
@@ -5653,6 +5960,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5653
5960
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5654
5961
|
namedFnDecls: [],
|
|
5655
5962
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5963
|
+
recovery: opts?.recovery ?? false,
|
|
5656
5964
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5657
5965
|
ns,
|
|
5658
5966
|
deferFirstSetRefs: true,
|
|
@@ -6300,6 +6608,42 @@ function materializePiece(p, trivia2) {
|
|
|
6300
6608
|
return pieces;
|
|
6301
6609
|
}
|
|
6302
6610
|
|
|
6611
|
+
// src/combinators/guard.ts
|
|
6612
|
+
function guard(predicate) {
|
|
6613
|
+
const meta = {
|
|
6614
|
+
firstSet: { kind: "any" },
|
|
6615
|
+
canMatchNewline: false,
|
|
6616
|
+
isTrivia: false
|
|
6617
|
+
};
|
|
6618
|
+
return {
|
|
6619
|
+
_tag: "guard",
|
|
6620
|
+
_meta: meta,
|
|
6621
|
+
_def: { tag: "guard", predicate },
|
|
6622
|
+
parse(_input, pos, ctx) {
|
|
6623
|
+
if (predicate(ctx.state))
|
|
6624
|
+
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
6625
|
+
return { ok: false, expected: ["guard"], span: { start: pos, end: pos } };
|
|
6626
|
+
}
|
|
6627
|
+
};
|
|
6628
|
+
}
|
|
6629
|
+
|
|
6630
|
+
// src/combinators/withCtx.ts
|
|
6631
|
+
function withCtx(extra, combinator) {
|
|
6632
|
+
const meta = {
|
|
6633
|
+
firstSet: combinator._meta.firstSet,
|
|
6634
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
6635
|
+
isTrivia: false
|
|
6636
|
+
};
|
|
6637
|
+
return {
|
|
6638
|
+
_tag: "withCtx",
|
|
6639
|
+
_meta: meta,
|
|
6640
|
+
_def: { tag: "withCtx", extra, parser: combinator },
|
|
6641
|
+
parse(input, pos, ctx) {
|
|
6642
|
+
return combinator.parse(input, pos, { ...ctx, state: extra });
|
|
6643
|
+
}
|
|
6644
|
+
};
|
|
6645
|
+
}
|
|
6646
|
+
|
|
6303
6647
|
// src/cst/offset-model.ts
|
|
6304
6648
|
var { isFinite } = Number;
|
|
6305
6649
|
|
|
@@ -6331,6 +6675,35 @@ var SUPPORTED = {
|
|
|
6331
6675
|
function isScopeEntry(v2) {
|
|
6332
6676
|
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
6333
6677
|
}
|
|
6678
|
+
function propName(p) {
|
|
6679
|
+
if (p.computed) return null;
|
|
6680
|
+
const key = p.key;
|
|
6681
|
+
return key.type === "Identifier" ? key.name ?? null : key.type === "Literal" ? String(key.value) : null;
|
|
6682
|
+
}
|
|
6683
|
+
function isGatedArmExpr(e) {
|
|
6684
|
+
if (e.type !== "ObjectExpression") return false;
|
|
6685
|
+
let hasGate = false, hasCombinator = false;
|
|
6686
|
+
for (const prop of e.properties) {
|
|
6687
|
+
if (prop.type !== "Property") continue;
|
|
6688
|
+
const name = propName(prop);
|
|
6689
|
+
if (name === "gate") hasGate = true;
|
|
6690
|
+
else if (name === "combinator") hasCombinator = true;
|
|
6691
|
+
}
|
|
6692
|
+
return hasGate && hasCombinator;
|
|
6693
|
+
}
|
|
6694
|
+
function gatedArmParts(e) {
|
|
6695
|
+
let gate;
|
|
6696
|
+
let combinator;
|
|
6697
|
+
for (const prop of e.properties) {
|
|
6698
|
+
if (prop.type !== "Property") return null;
|
|
6699
|
+
const op = prop;
|
|
6700
|
+
const name = propName(op);
|
|
6701
|
+
if (name === "gate") gate = op.value;
|
|
6702
|
+
else if (name === "combinator") combinator = op.value;
|
|
6703
|
+
else return null;
|
|
6704
|
+
}
|
|
6705
|
+
return gate && combinator ? { gate, combinator } : null;
|
|
6706
|
+
}
|
|
6334
6707
|
function isCombinator(v2) {
|
|
6335
6708
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
6336
6709
|
}
|
|
@@ -6512,6 +6885,72 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
6512
6885
|
return null;
|
|
6513
6886
|
}
|
|
6514
6887
|
}
|
|
6888
|
+
if (callee.name === "guard") {
|
|
6889
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6890
|
+
const [predArg] = node2.arguments;
|
|
6891
|
+
if (!predArg || predArg.type === "SpreadElement") return null;
|
|
6892
|
+
const predSrc = code.slice(predArg.start, predArg.end);
|
|
6893
|
+
mfs.push(predSrc);
|
|
6894
|
+
try {
|
|
6895
|
+
const combi = guard(() => true);
|
|
6896
|
+
if (combi._def.tag !== "guard") return null;
|
|
6897
|
+
combi._def.predSrc = predSrc;
|
|
6898
|
+
return combi;
|
|
6899
|
+
} catch {
|
|
6900
|
+
return null;
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6903
|
+
if (callee.name === "withCtx") {
|
|
6904
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6905
|
+
const [extraArg, innerArg] = node2.arguments;
|
|
6906
|
+
if (!extraArg || !innerArg || extraArg.type === "SpreadElement" || innerArg.type === "SpreadElement") return null;
|
|
6907
|
+
const extraSrc = code.slice(extraArg.start, extraArg.end);
|
|
6908
|
+
mfs.push(extraSrc);
|
|
6909
|
+
const inner = anyValue(innerArg, scope, code, mfs);
|
|
6910
|
+
if (!isCombinator(inner)) return null;
|
|
6911
|
+
try {
|
|
6912
|
+
const combi = withCtx({}, inner);
|
|
6913
|
+
if (combi._def.tag !== "withCtx") return null;
|
|
6914
|
+
combi._def.extraSrc = extraSrc;
|
|
6915
|
+
return combi;
|
|
6916
|
+
} catch {
|
|
6917
|
+
return null;
|
|
6918
|
+
}
|
|
6919
|
+
}
|
|
6920
|
+
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
6921
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6922
|
+
const arms = [];
|
|
6923
|
+
const gateSrcs = [];
|
|
6924
|
+
for (const argNode of node2.arguments) {
|
|
6925
|
+
if (argNode.type === "SpreadElement") return null;
|
|
6926
|
+
if (isGatedArmExpr(argNode)) {
|
|
6927
|
+
const parts = gatedArmParts(argNode);
|
|
6928
|
+
if (!parts) return null;
|
|
6929
|
+
const gateSrc = code.slice(parts.gate.start, parts.gate.end);
|
|
6930
|
+
mfs.push(gateSrc);
|
|
6931
|
+
const combi = anyValue(parts.combinator, scope, code, mfs);
|
|
6932
|
+
if (!isCombinator(combi)) return null;
|
|
6933
|
+
arms.push({ gate: () => true, combinator: combi });
|
|
6934
|
+
gateSrcs.push(gateSrc);
|
|
6935
|
+
} else {
|
|
6936
|
+
const combi = anyValue(argNode, scope, code, mfs);
|
|
6937
|
+
if (!isCombinator(combi)) return null;
|
|
6938
|
+
arms.push(combi);
|
|
6939
|
+
gateSrcs.push(null);
|
|
6940
|
+
}
|
|
6941
|
+
}
|
|
6942
|
+
try {
|
|
6943
|
+
const combi = choice(...arms);
|
|
6944
|
+
if (combi._def.tag !== "choice") return null;
|
|
6945
|
+
combi._def.gateSrcs = gateSrcs;
|
|
6946
|
+
for (let i = 0; i < combi._def.gates.length; i++) {
|
|
6947
|
+
if (combi._def.gates[i] !== null !== (gateSrcs[i] !== null)) return null;
|
|
6948
|
+
}
|
|
6949
|
+
return combi;
|
|
6950
|
+
} catch {
|
|
6951
|
+
return null;
|
|
6952
|
+
}
|
|
6953
|
+
}
|
|
6515
6954
|
const factory = SUPPORTED[callee.name];
|
|
6516
6955
|
if (!factory) return null;
|
|
6517
6956
|
const args = node2.arguments.map((arg) => {
|
|
@@ -6574,9 +7013,9 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
6574
7013
|
if (typeof key !== "string" && typeof key !== "number") return null;
|
|
6575
7014
|
return obj[key] ?? null;
|
|
6576
7015
|
}
|
|
6577
|
-
const
|
|
6578
|
-
if (!
|
|
6579
|
-
return obj[
|
|
7016
|
+
const propName2 = mem.property.name;
|
|
7017
|
+
if (!propName2) return null;
|
|
7018
|
+
return obj[propName2] ?? null;
|
|
6580
7019
|
}
|
|
6581
7020
|
if (node2.type === "CallExpression") {
|
|
6582
7021
|
const callee = node2.callee;
|
|
@@ -6821,7 +7260,7 @@ var plugin_default = createUnplugin((opts = {}) => ({
|
|
|
6821
7260
|
if (!code.includes("parseman")) return null;
|
|
6822
7261
|
if (!code.includes("macro")) return null;
|
|
6823
7262
|
const moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE, ...opts.moduleAliases ?? []]);
|
|
6824
|
-
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true);
|
|
7263
|
+
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true);
|
|
6825
7264
|
if (result?.warnings.length) {
|
|
6826
7265
|
for (const w of result.warnings) {
|
|
6827
7266
|
if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
|
|
@@ -6925,7 +7364,7 @@ function extractImportBindings(body) {
|
|
|
6925
7364
|
}
|
|
6926
7365
|
return out;
|
|
6927
7366
|
}
|
|
6928
|
-
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false) {
|
|
7367
|
+
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false) {
|
|
6929
7368
|
let result;
|
|
6930
7369
|
try {
|
|
6931
7370
|
result = parseSync(id, code);
|
|
@@ -6996,7 +7435,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
6996
7435
|
(p) => p.key?.name === "trivia"
|
|
6997
7436
|
)?.value : void 0;
|
|
6998
7437
|
const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
|
|
6999
|
-
const compiled = compileRuleMap([...ruleMap], gTrivia ? { trivia: gTrivia } :
|
|
7438
|
+
const compiled = compileRuleMap([...ruleMap], { ...gTrivia ? { trivia: gTrivia } : {}, recovery });
|
|
7000
7439
|
if (!compiled) {
|
|
7001
7440
|
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
7002
7441
|
return null;
|
|
@@ -7094,7 +7533,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7094
7533
|
const ns = nsFor(label2);
|
|
7095
7534
|
const ir = serializeRuleMap(entries);
|
|
7096
7535
|
if (ir) return { carried: [{ ns, ir }] };
|
|
7097
|
-
const p = compileLinkable(entries, ns, composing ? { trivia: composing } :
|
|
7536
|
+
const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, recovery });
|
|
7098
7537
|
return p ? { carried: [p] } : null;
|
|
7099
7538
|
};
|
|
7100
7539
|
const argPieces = (arg, label2, composing) => {
|
|
@@ -7270,7 +7709,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7270
7709
|
const refEntry = scope.get(varName);
|
|
7271
7710
|
const refCombi = refEntry?.combi ?? null;
|
|
7272
7711
|
if (refCombi) {
|
|
7273
|
-
const compiled2 = compile(refCombi);
|
|
7712
|
+
const compiled2 = compile(refCombi, void 0, { recovery });
|
|
7274
7713
|
if (compiled2.inlineExpression === null) {
|
|
7275
7714
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
7276
7715
|
continue;
|
|
@@ -7287,7 +7726,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7287
7726
|
let replacement = compiledRules.replacement;
|
|
7288
7727
|
if (exportPrefix) {
|
|
7289
7728
|
const ns = nsFor(varName);
|
|
7290
|
-
const pieces = compileLinkable([...compiledRules.ruleMap], ns);
|
|
7729
|
+
const pieces = compileLinkable([...compiledRules.ruleMap], ns, { recovery });
|
|
7291
7730
|
if (pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
|
|
7292
7731
|
const ir = serializeRuleMap([...compiledRules.ruleMap]);
|
|
7293
7732
|
replacement = withCarriedPieces(replacement, [ir ? { ns, ir } : pieces]);
|
|
@@ -7323,7 +7762,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7323
7762
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
7324
7763
|
continue;
|
|
7325
7764
|
}
|
|
7326
|
-
const compiled = compile(parser2);
|
|
7765
|
+
const compiled = compile(parser2, void 0, { recovery });
|
|
7327
7766
|
if (compiled.inlineExpression === null) {
|
|
7328
7767
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
7329
7768
|
continue;
|