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/index.cjs
CHANGED
|
@@ -55,7 +55,6 @@ __export(index_exports, {
|
|
|
55
55
|
literal: () => literal,
|
|
56
56
|
makeWord: () => makeWord,
|
|
57
57
|
many: () => many,
|
|
58
|
-
manyRecover: () => manyRecover,
|
|
59
58
|
noTrivia: () => noTrivia,
|
|
60
59
|
node: () => node,
|
|
61
60
|
not: () => not,
|
|
@@ -65,7 +64,6 @@ __export(index_exports, {
|
|
|
65
64
|
parse: () => parse,
|
|
66
65
|
parseDoc: () => parseDoc,
|
|
67
66
|
parser: () => parser,
|
|
68
|
-
recover: () => recover,
|
|
69
67
|
ref: () => ref,
|
|
70
68
|
regex: () => regex,
|
|
71
69
|
relativize: () => relativize,
|
|
@@ -74,7 +72,6 @@ __export(index_exports, {
|
|
|
74
72
|
run: () => run,
|
|
75
73
|
scanTo: () => scanTo,
|
|
76
74
|
sepBy: () => sepBy,
|
|
77
|
-
sepByRecover: () => sepByRecover,
|
|
78
75
|
sequence: () => sequence,
|
|
79
76
|
shiftAbsolute: () => shiftAbsolute,
|
|
80
77
|
skip: () => skip,
|
|
@@ -344,7 +341,13 @@ function saveCstMark(ctx) {
|
|
|
344
341
|
raw: cstRawLen(ctx),
|
|
345
342
|
tlog: cstTlLen(ctx),
|
|
346
343
|
leaves: cstLeavesLen(ctx),
|
|
347
|
-
fields: ctx._fields?.length ?? 0
|
|
344
|
+
fields: ctx._fields?.length ?? 0,
|
|
345
|
+
// Speculative rollback must truncate the flat recovery-error sink in lockstep
|
|
346
|
+
// with the CST leaves: a branch that recovered (pushing a ParseError to
|
|
347
|
+
// ctx._errors AND embedding it as a CST child via captureError) then failed
|
|
348
|
+
// must remove BOTH, or the flat error survives as a GHOST that a tree walk
|
|
349
|
+
// can't see (flat run().errors would disagree with the embedded set).
|
|
350
|
+
errors: ctx._errors?.length ?? 0
|
|
348
351
|
};
|
|
349
352
|
}
|
|
350
353
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -360,6 +363,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
360
363
|
if (len === 0) b[keySingle] = void 0;
|
|
361
364
|
}
|
|
362
365
|
function rollbackCstCapture(ctx, mark) {
|
|
366
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
363
367
|
const b = ctx._cstBuf;
|
|
364
368
|
if (b) {
|
|
365
369
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -1306,10 +1310,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1306
1310
|
}
|
|
1307
1311
|
function saveTriviaMark(ctx) {
|
|
1308
1312
|
const m = saveCstMark(ctx);
|
|
1309
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1313
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1310
1314
|
}
|
|
1311
1315
|
function rollbackTrivia(ctx, mark) {
|
|
1312
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1316
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1313
1317
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1314
1318
|
}
|
|
1315
1319
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1543,6 +1547,94 @@ function scanBlockComment(input, cur) {
|
|
|
1543
1547
|
return close === -1 ? cur : close + 2;
|
|
1544
1548
|
}
|
|
1545
1549
|
|
|
1550
|
+
// src/recovery/scan.ts
|
|
1551
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
1552
|
+
const s = {
|
|
1553
|
+
_probe: ctx._probe,
|
|
1554
|
+
_errors: ctx._errors,
|
|
1555
|
+
_cstLeaves: ctx._cstLeaves,
|
|
1556
|
+
_cstChildren: ctx._cstChildren,
|
|
1557
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
1558
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
1559
|
+
_triviaLog: ctx._triviaLog,
|
|
1560
|
+
_fields: ctx._fields,
|
|
1561
|
+
_cstBuf: ctx._cstBuf,
|
|
1562
|
+
_tolerant: ctx._tolerant,
|
|
1563
|
+
_sync: ctx._sync
|
|
1564
|
+
};
|
|
1565
|
+
ctx._probe = void 0;
|
|
1566
|
+
ctx._errors = void 0;
|
|
1567
|
+
ctx._cstLeaves = void 0;
|
|
1568
|
+
ctx._cstChildren = void 0;
|
|
1569
|
+
ctx._cstRawChildren = void 0;
|
|
1570
|
+
ctx._cstTriviaLog = void 0;
|
|
1571
|
+
ctx._triviaLog = void 0;
|
|
1572
|
+
ctx._fields = void 0;
|
|
1573
|
+
ctx._cstBuf = void 0;
|
|
1574
|
+
ctx._tolerant = void 0;
|
|
1575
|
+
ctx._sync = void 0;
|
|
1576
|
+
try {
|
|
1577
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
1578
|
+
} finally {
|
|
1579
|
+
ctx._probe = s._probe;
|
|
1580
|
+
ctx._errors = s._errors;
|
|
1581
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
1582
|
+
ctx._cstChildren = s._cstChildren;
|
|
1583
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
1584
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
1585
|
+
ctx._triviaLog = s._triviaLog;
|
|
1586
|
+
ctx._fields = s._fields;
|
|
1587
|
+
ctx._cstBuf = s._cstBuf;
|
|
1588
|
+
ctx._tolerant = s._tolerant;
|
|
1589
|
+
ctx._sync = s._sync;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
function orSentinel(a, b) {
|
|
1593
|
+
if (b === void 0) return a;
|
|
1594
|
+
return {
|
|
1595
|
+
_tag: "orSentinel",
|
|
1596
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
1597
|
+
_def: { tag: "unknown" },
|
|
1598
|
+
parse(input, pos, ctx) {
|
|
1599
|
+
const ra = a.parse(input, pos, ctx);
|
|
1600
|
+
if (ra.ok) return ra;
|
|
1601
|
+
return b.parse(input, pos, ctx);
|
|
1602
|
+
}
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
function firstSetSentinel(fs) {
|
|
1606
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
1607
|
+
const ranges = fs.ranges;
|
|
1608
|
+
return {
|
|
1609
|
+
_tag: "firstSetSentinel",
|
|
1610
|
+
_meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
|
|
1611
|
+
_def: { tag: "unknown" },
|
|
1612
|
+
parse(input, pos) {
|
|
1613
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
1614
|
+
if (code !== void 0) {
|
|
1615
|
+
for (const r of ranges) {
|
|
1616
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
1624
|
+
let scanPos = from;
|
|
1625
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
1626
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
1627
|
+
ctx._errors?.push(error);
|
|
1628
|
+
return { error, end: scanPos };
|
|
1629
|
+
}
|
|
1630
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
1631
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
1632
|
+
}
|
|
1633
|
+
function captureError(ctx, error) {
|
|
1634
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1635
|
+
}
|
|
1636
|
+
var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
|
|
1637
|
+
|
|
1546
1638
|
// src/combinators/sequence.ts
|
|
1547
1639
|
function sequence(...parsers) {
|
|
1548
1640
|
const meta = {
|
|
@@ -1553,11 +1645,59 @@ function sequence(...parsers) {
|
|
|
1553
1645
|
isTrivia: false
|
|
1554
1646
|
};
|
|
1555
1647
|
const def = { tag: "sequence", parsers };
|
|
1648
|
+
let followSentinels;
|
|
1649
|
+
function parseTolerant(input, pos, ctx) {
|
|
1650
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1651
|
+
const fs = parsers.slice(i + 1).reduce(
|
|
1652
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1653
|
+
{ kind: "empty" }
|
|
1654
|
+
);
|
|
1655
|
+
return firstSetSentinel(fs);
|
|
1656
|
+
});
|
|
1657
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1658
|
+
let cur = pos;
|
|
1659
|
+
const inheritedSync = ctx._sync;
|
|
1660
|
+
try {
|
|
1661
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1662
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1663
|
+
if (ctx.trivia && i > 0) {
|
|
1664
|
+
const mark = saveTriviaMark(ctx);
|
|
1665
|
+
let scanEnd;
|
|
1666
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1667
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1668
|
+
scan.commit();
|
|
1669
|
+
scanEnd = scan.end;
|
|
1670
|
+
} else {
|
|
1671
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1672
|
+
}
|
|
1673
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1674
|
+
if (!result2.ok) return result2;
|
|
1675
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1676
|
+
else rollbackTrivia(ctx, mark);
|
|
1677
|
+
if (values !== void 0) values.push(result2.value);
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1680
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1681
|
+
if (!result.ok) return result;
|
|
1682
|
+
if (values !== void 0) values.push(result.value);
|
|
1683
|
+
cur = result.span.end;
|
|
1684
|
+
}
|
|
1685
|
+
} finally {
|
|
1686
|
+
ctx._sync = inheritedSync;
|
|
1687
|
+
}
|
|
1688
|
+
return {
|
|
1689
|
+
ok: true,
|
|
1690
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1691
|
+
value: values ?? void 0,
|
|
1692
|
+
span: { start: pos, end: cur }
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1556
1695
|
return {
|
|
1557
1696
|
_tag: "sequence",
|
|
1558
1697
|
_meta: meta,
|
|
1559
1698
|
_def: def,
|
|
1560
1699
|
parse(input, pos, ctx) {
|
|
1700
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1561
1701
|
const values = def.valueUnused ? void 0 : [];
|
|
1562
1702
|
let cur = pos;
|
|
1563
1703
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1596,6 +1736,69 @@ function sequence(...parsers) {
|
|
|
1596
1736
|
};
|
|
1597
1737
|
}
|
|
1598
1738
|
|
|
1739
|
+
// src/combinators/expect.ts
|
|
1740
|
+
function deriveExpected(c) {
|
|
1741
|
+
const def = c._def;
|
|
1742
|
+
switch (def.tag) {
|
|
1743
|
+
case "literal":
|
|
1744
|
+
return [JSON.stringify(def.value)];
|
|
1745
|
+
case "regex":
|
|
1746
|
+
return [`/${def.source}/`];
|
|
1747
|
+
case "keywords":
|
|
1748
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1749
|
+
case "label":
|
|
1750
|
+
return [def.label];
|
|
1751
|
+
case "choice":
|
|
1752
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1753
|
+
case "sequence":
|
|
1754
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1755
|
+
case "node":
|
|
1756
|
+
case "grammar":
|
|
1757
|
+
case "trivia":
|
|
1758
|
+
case "token":
|
|
1759
|
+
case "optional":
|
|
1760
|
+
case "many":
|
|
1761
|
+
case "oneOrMore":
|
|
1762
|
+
case "transform":
|
|
1763
|
+
case "not":
|
|
1764
|
+
return deriveExpected(def.parser);
|
|
1765
|
+
case "lazy": {
|
|
1766
|
+
const name = c._ruleName;
|
|
1767
|
+
try {
|
|
1768
|
+
return deriveExpected(def.thunk());
|
|
1769
|
+
} catch {
|
|
1770
|
+
return name ? [name] : [];
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
default:
|
|
1774
|
+
return [];
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
function expect(combinator, label2) {
|
|
1778
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1779
|
+
const meta = {
|
|
1780
|
+
firstSet: combinator._meta.firstSet,
|
|
1781
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1782
|
+
isTrivia: false
|
|
1783
|
+
};
|
|
1784
|
+
return {
|
|
1785
|
+
_tag: "expect",
|
|
1786
|
+
_meta: meta,
|
|
1787
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1788
|
+
parse(input, pos, ctx) {
|
|
1789
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1790
|
+
if (result.ok) return result;
|
|
1791
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
1792
|
+
ctx._errors?.push(error);
|
|
1793
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1794
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1795
|
+
}
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
function isParseError(value) {
|
|
1799
|
+
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1599
1802
|
// src/combinators/repeat.ts
|
|
1600
1803
|
function repItem(combinator, input, cur, ctx) {
|
|
1601
1804
|
const mark = saveTriviaMark(ctx);
|
|
@@ -1616,7 +1819,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1616
1819
|
const result = combinator.parse(input, pos, ctx);
|
|
1617
1820
|
if (!result.ok) {
|
|
1618
1821
|
rollbackTrivia(ctx, mark);
|
|
1619
|
-
return { fail: result };
|
|
1822
|
+
return { fail: result, failPos: pos };
|
|
1620
1823
|
}
|
|
1621
1824
|
if (result.span.end === pos) {
|
|
1622
1825
|
rollbackTrivia(ctx, mark);
|
|
@@ -1631,6 +1834,7 @@ function many(combinator) {
|
|
|
1631
1834
|
isTrivia: false
|
|
1632
1835
|
};
|
|
1633
1836
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1837
|
+
let expected;
|
|
1634
1838
|
return {
|
|
1635
1839
|
_tag: "many",
|
|
1636
1840
|
_meta: meta,
|
|
@@ -1640,7 +1844,18 @@ function many(combinator) {
|
|
|
1640
1844
|
let cur = pos;
|
|
1641
1845
|
while (cur < input.length) {
|
|
1642
1846
|
const item = repItem(combinator, input, cur, ctx);
|
|
1643
|
-
if (item === "stop"
|
|
1847
|
+
if (item === "stop") break;
|
|
1848
|
+
if ("fail" in item) {
|
|
1849
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1850
|
+
if (sync === void 0) break;
|
|
1851
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1852
|
+
expected ??= deriveExpected(combinator);
|
|
1853
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1854
|
+
if (values !== void 0) values.push(error);
|
|
1855
|
+
captureError(ctx, error);
|
|
1856
|
+
cur = end;
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1644
1859
|
if (values !== void 0) values.push(item.value);
|
|
1645
1860
|
cur = item.end;
|
|
1646
1861
|
}
|
|
@@ -1655,6 +1870,7 @@ function oneOrMore(combinator) {
|
|
|
1655
1870
|
isTrivia: false
|
|
1656
1871
|
};
|
|
1657
1872
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1873
|
+
let expected;
|
|
1658
1874
|
return {
|
|
1659
1875
|
_tag: "oneOrMore",
|
|
1660
1876
|
_meta: meta,
|
|
@@ -1666,7 +1882,18 @@ function oneOrMore(combinator) {
|
|
|
1666
1882
|
let cur = first.span.end;
|
|
1667
1883
|
while (cur < input.length) {
|
|
1668
1884
|
const item = repItem(combinator, input, cur, ctx);
|
|
1669
|
-
if (item === "stop"
|
|
1885
|
+
if (item === "stop") break;
|
|
1886
|
+
if ("fail" in item) {
|
|
1887
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1888
|
+
if (sync === void 0) break;
|
|
1889
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1890
|
+
expected ??= deriveExpected(combinator);
|
|
1891
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1892
|
+
if (values !== void 0) values.push(error);
|
|
1893
|
+
captureError(ctx, error);
|
|
1894
|
+
cur = end;
|
|
1895
|
+
continue;
|
|
1896
|
+
}
|
|
1670
1897
|
if (values !== void 0) values.push(item.value);
|
|
1671
1898
|
cur = item.end;
|
|
1672
1899
|
}
|
|
@@ -1712,15 +1939,29 @@ function sepBy(combinator, separator) {
|
|
|
1712
1939
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1713
1940
|
isTrivia: false
|
|
1714
1941
|
};
|
|
1942
|
+
let expected;
|
|
1715
1943
|
return {
|
|
1716
1944
|
_tag: "sepBy",
|
|
1717
1945
|
_meta: meta,
|
|
1718
1946
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1719
1947
|
parse(input, pos, ctx) {
|
|
1720
1948
|
const first = combinator.parse(input, pos, ctx);
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1949
|
+
const values = [];
|
|
1950
|
+
let cur;
|
|
1951
|
+
if (first.ok) {
|
|
1952
|
+
values.push(first.value);
|
|
1953
|
+
cur = first.span.end;
|
|
1954
|
+
} else {
|
|
1955
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1956
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1957
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1958
|
+
}
|
|
1959
|
+
expected ??= deriveExpected(combinator);
|
|
1960
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1961
|
+
values.push(rec.error);
|
|
1962
|
+
captureError(ctx, rec.error);
|
|
1963
|
+
cur = rec.end;
|
|
1964
|
+
}
|
|
1724
1965
|
while (cur < input.length) {
|
|
1725
1966
|
const loopMark = saveTriviaMark(ctx);
|
|
1726
1967
|
let sepPos = cur;
|
|
@@ -1750,6 +1991,15 @@ function sepBy(combinator, separator) {
|
|
|
1750
1991
|
}
|
|
1751
1992
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1752
1993
|
if (!next.ok) {
|
|
1994
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1995
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
1996
|
+
expected ??= deriveExpected(combinator);
|
|
1997
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
1998
|
+
values.push(rec.error);
|
|
1999
|
+
captureError(ctx, rec.error);
|
|
2000
|
+
cur = rec.end;
|
|
2001
|
+
continue;
|
|
2002
|
+
}
|
|
1753
2003
|
rollbackTrivia(ctx, loopMark);
|
|
1754
2004
|
break;
|
|
1755
2005
|
}
|
|
@@ -1923,7 +2173,7 @@ function rules(a, b) {
|
|
|
1923
2173
|
cache[key] = parser2;
|
|
1924
2174
|
}
|
|
1925
2175
|
}
|
|
1926
|
-
if (options?.trivia
|
|
2176
|
+
if (options?.trivia != null) {
|
|
1927
2177
|
for (const key of Object.keys(definitions)) {
|
|
1928
2178
|
const rule = cache[key];
|
|
1929
2179
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1953,7 +2203,9 @@ function not(combinator) {
|
|
|
1953
2203
|
_meta: meta,
|
|
1954
2204
|
_def: { tag: "not", parser: combinator },
|
|
1955
2205
|
parse(input, pos, ctx) {
|
|
2206
|
+
const mark = saveCstMark(ctx);
|
|
1956
2207
|
const result = combinator.parse(input, pos, ctx);
|
|
2208
|
+
rollbackCstCapture(ctx, mark);
|
|
1957
2209
|
if (result.ok) {
|
|
1958
2210
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1959
2211
|
}
|
|
@@ -2067,7 +2319,7 @@ function unwrapChild(child) {
|
|
|
2067
2319
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
2068
2320
|
}
|
|
2069
2321
|
function isCstChild(value) {
|
|
2070
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2322
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
2071
2323
|
}
|
|
2072
2324
|
function missingInferredType() {
|
|
2073
2325
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2345,65 +2597,6 @@ function token(root) {
|
|
|
2345
2597
|
};
|
|
2346
2598
|
}
|
|
2347
2599
|
|
|
2348
|
-
// src/combinators/expect.ts
|
|
2349
|
-
function deriveExpected(c) {
|
|
2350
|
-
const def = c._def;
|
|
2351
|
-
switch (def.tag) {
|
|
2352
|
-
case "literal":
|
|
2353
|
-
return [JSON.stringify(def.value)];
|
|
2354
|
-
case "regex":
|
|
2355
|
-
return [`/${def.source}/`];
|
|
2356
|
-
case "keywords":
|
|
2357
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2358
|
-
case "label":
|
|
2359
|
-
return [def.label];
|
|
2360
|
-
case "choice":
|
|
2361
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2362
|
-
case "sequence":
|
|
2363
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2364
|
-
case "node":
|
|
2365
|
-
case "grammar":
|
|
2366
|
-
case "trivia":
|
|
2367
|
-
case "token":
|
|
2368
|
-
case "optional":
|
|
2369
|
-
case "many":
|
|
2370
|
-
case "oneOrMore":
|
|
2371
|
-
case "transform":
|
|
2372
|
-
case "not":
|
|
2373
|
-
return deriveExpected(def.parser);
|
|
2374
|
-
case "lazy": {
|
|
2375
|
-
const name = c._ruleName;
|
|
2376
|
-
try {
|
|
2377
|
-
return deriveExpected(def.thunk());
|
|
2378
|
-
} catch {
|
|
2379
|
-
return name ? [name] : [];
|
|
2380
|
-
}
|
|
2381
|
-
}
|
|
2382
|
-
default:
|
|
2383
|
-
return [];
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
function expect(combinator, label2) {
|
|
2387
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2388
|
-
const meta = {
|
|
2389
|
-
firstSet: combinator._meta.firstSet,
|
|
2390
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2391
|
-
isTrivia: false
|
|
2392
|
-
};
|
|
2393
|
-
return {
|
|
2394
|
-
_tag: "expect",
|
|
2395
|
-
_meta: meta,
|
|
2396
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2397
|
-
parse(input, pos, ctx) {
|
|
2398
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2399
|
-
if (result.ok) return result;
|
|
2400
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2401
|
-
ctx._errors?.push(error);
|
|
2402
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2403
|
-
}
|
|
2404
|
-
};
|
|
2405
|
-
}
|
|
2406
|
-
|
|
2407
2600
|
// src/compiler/scannable-run.ts
|
|
2408
2601
|
var BACKSLASH = 92;
|
|
2409
2602
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2475,20 +2668,39 @@ function parseSeqParts(source) {
|
|
|
2475
2668
|
lit = [];
|
|
2476
2669
|
}
|
|
2477
2670
|
};
|
|
2478
|
-
const
|
|
2671
|
+
const braceQuant = (at) => {
|
|
2672
|
+
const close = source.indexOf("}", at);
|
|
2673
|
+
if (close === -1) return null;
|
|
2674
|
+
const body = source.slice(at + 1, close);
|
|
2675
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2676
|
+
if (!m) return null;
|
|
2677
|
+
const min = Number(m[1]);
|
|
2678
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2679
|
+
if (max < 1 || min > max) return null;
|
|
2680
|
+
return { min, max, len: close - at + 1 };
|
|
2681
|
+
};
|
|
2682
|
+
const runFrom = (ranges, negated, at) => {
|
|
2683
|
+
const q = source[at];
|
|
2479
2684
|
if (q === "+") {
|
|
2480
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2685
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2481
2686
|
return 1;
|
|
2482
2687
|
}
|
|
2483
2688
|
if (q === "*") {
|
|
2484
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2689
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2485
2690
|
return 1;
|
|
2486
2691
|
}
|
|
2487
2692
|
if (q === "?") {
|
|
2488
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2693
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2489
2694
|
return 1;
|
|
2490
2695
|
}
|
|
2491
|
-
|
|
2696
|
+
if (q === "{") {
|
|
2697
|
+
const b = braceQuant(at);
|
|
2698
|
+
if (b) {
|
|
2699
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2700
|
+
return b.len;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2492
2704
|
return 0;
|
|
2493
2705
|
};
|
|
2494
2706
|
let i = 0;
|
|
@@ -2513,7 +2725,7 @@ function parseSeqParts(source) {
|
|
|
2513
2725
|
if (!ranges) return null;
|
|
2514
2726
|
flush();
|
|
2515
2727
|
i = k + 1;
|
|
2516
|
-
i += runFrom(ranges, neg,
|
|
2728
|
+
i += runFrom(ranges, neg, i);
|
|
2517
2729
|
continue;
|
|
2518
2730
|
}
|
|
2519
2731
|
if (ch === "\\") {
|
|
@@ -2521,7 +2733,7 @@ function parseSeqParts(source) {
|
|
|
2521
2733
|
if (e === "d" || e === "w" || e === "s") {
|
|
2522
2734
|
flush();
|
|
2523
2735
|
i += 2;
|
|
2524
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2736
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2525
2737
|
continue;
|
|
2526
2738
|
}
|
|
2527
2739
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2610,7 +2822,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2610
2822
|
let hasMandatory = false;
|
|
2611
2823
|
for (let k = 0; k < parts.length; k++) {
|
|
2612
2824
|
const p = parts[k];
|
|
2613
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2825
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2614
2826
|
if (mandatory) hasMandatory = true;
|
|
2615
2827
|
if (p.part === "group") {
|
|
2616
2828
|
const exposure = groupPartExposure(p);
|
|
@@ -2621,9 +2833,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2621
2833
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2622
2834
|
}
|
|
2623
2835
|
}
|
|
2624
|
-
const
|
|
2625
|
-
|
|
2626
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2836
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2837
|
+
if (needsDisjoint) {
|
|
2627
2838
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2628
2839
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2629
2840
|
}
|
|
@@ -2680,8 +2891,8 @@ function fixedClassSeq(shape) {
|
|
|
2680
2891
|
if (p.part === "lit") {
|
|
2681
2892
|
if (p.optional) return null;
|
|
2682
2893
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2683
|
-
} else if (p.part === "run" &&
|
|
2684
|
-
out.push({ ranges: p.ranges, negated: p.negated });
|
|
2894
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2895
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2685
2896
|
} else {
|
|
2686
2897
|
return null;
|
|
2687
2898
|
}
|
|
@@ -2733,7 +2944,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2733
2944
|
const last = shape.parts[shape.parts.length - 1];
|
|
2734
2945
|
if (last.part === "lit") return null;
|
|
2735
2946
|
if (last.part === "run") {
|
|
2736
|
-
if (last.
|
|
2947
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2737
2948
|
return null;
|
|
2738
2949
|
}
|
|
2739
2950
|
return groupPartExposure(last);
|
|
@@ -2870,7 +3081,7 @@ function partFirstAccept(part) {
|
|
|
2870
3081
|
function seqFirstAccept(parts) {
|
|
2871
3082
|
const sets = [];
|
|
2872
3083
|
for (const p of parts) {
|
|
2873
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
3084
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2874
3085
|
sets.push(partFirstAccept(p));
|
|
2875
3086
|
if (mandatory) break;
|
|
2876
3087
|
}
|
|
@@ -3285,7 +3496,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3285
3496
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3286
3497
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3287
3498
|
}
|
|
3288
|
-
} else if (p.part === "run" &&
|
|
3499
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3500
|
+
const s = mint("_s");
|
|
3501
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3502
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3503
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3504
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3505
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3289
3506
|
if (p.min === 1) {
|
|
3290
3507
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3291
3508
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3295,8 +3512,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3295
3512
|
} else if (p.part === "run") {
|
|
3296
3513
|
const s = mint("_s");
|
|
3297
3514
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3298
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3299
|
-
if (p.min
|
|
3515
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3516
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3300
3517
|
} else {
|
|
3301
3518
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3302
3519
|
if (!p.unbounded) {
|
|
@@ -3755,21 +3972,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3755
3972
|
}
|
|
3756
3973
|
return name;
|
|
3757
3974
|
}
|
|
3975
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3976
|
+
if (!ctx.recovery) return "";
|
|
3977
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3978
|
+
const pb = v(ctx, "_pb");
|
|
3979
|
+
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} } } } `;
|
|
3980
|
+
}
|
|
3758
3981
|
function failBody(ctx, expected, posExpr) {
|
|
3982
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3759
3983
|
if (ctx.failLabel) {
|
|
3760
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3761
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3984
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3985
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3762
3986
|
}
|
|
3763
|
-
return failReturn(expected, posExpr);
|
|
3987
|
+
return probe + failReturn(expected, posExpr);
|
|
3764
3988
|
}
|
|
3765
3989
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3990
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3766
3991
|
if (ctx.failLabel) {
|
|
3767
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3992
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3768
3993
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3769
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3994
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3770
3995
|
}
|
|
3771
|
-
if (!constant) return
|
|
3772
|
-
return failReturnArr(expectedArr, posExpr);
|
|
3996
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3997
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3773
3998
|
}
|
|
3774
3999
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3775
4000
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4269,6 +4494,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4269
4494
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4270
4495
|
return { stmts, valueVar: vv, endVar };
|
|
4271
4496
|
}
|
|
4497
|
+
function syncSentinelExpr(fs) {
|
|
4498
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
4499
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs.ranges)} })`;
|
|
4500
|
+
}
|
|
4272
4501
|
function emitSeqValues(def, ctx, pos) {
|
|
4273
4502
|
const startV = v(ctx, "_start");
|
|
4274
4503
|
const curV = v(ctx, "_cur");
|
|
@@ -4277,7 +4506,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4277
4506
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4278
4507
|
];
|
|
4279
4508
|
const valueVars = [];
|
|
4509
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4510
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4511
|
+
const publishSync = (i) => {
|
|
4512
|
+
if (!ctx.recovery) return "";
|
|
4513
|
+
const fs = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4514
|
+
const ref2 = syncSentinelExpr(fs);
|
|
4515
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4516
|
+
};
|
|
4280
4517
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4518
|
+
const syncPub = publishSync(i);
|
|
4519
|
+
if (syncPub) stmts.push(syncPub);
|
|
4281
4520
|
if (i > 0 && ctx.activeTrivia) {
|
|
4282
4521
|
if (ctx.capturing) {
|
|
4283
4522
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4302,7 +4541,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4302
4541
|
continue;
|
|
4303
4542
|
} else {
|
|
4304
4543
|
const trivFn = ensureTriviaFn(ctx);
|
|
4305
|
-
|
|
4544
|
+
const scanEndV = v(ctx, "_sne");
|
|
4545
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4546
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4547
|
+
stmts.push(...r2.stmts);
|
|
4548
|
+
const endAfterV = v(ctx, "_sea");
|
|
4549
|
+
stmts.push(
|
|
4550
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4551
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4552
|
+
);
|
|
4553
|
+
valueVars.push(r2.valueVar);
|
|
4554
|
+
continue;
|
|
4306
4555
|
}
|
|
4307
4556
|
}
|
|
4308
4557
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4532,7 +4781,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4532
4781
|
if (gate) {
|
|
4533
4782
|
const gateIdx = ctx.mapFns.length;
|
|
4534
4783
|
ctx.mapFns.push(gate);
|
|
4535
|
-
ctx.mapFnSrcs.push(null);
|
|
4784
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4536
4785
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4537
4786
|
}
|
|
4538
4787
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4637,6 +4886,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4637
4886
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4638
4887
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4639
4888
|
];
|
|
4889
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4890
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4640
4891
|
if (def.min === 1) {
|
|
4641
4892
|
const firstR = emit(def.parser, ctx, curV);
|
|
4642
4893
|
stmts.push(...firstR.stmts);
|
|
@@ -4670,10 +4921,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4670
4921
|
}
|
|
4671
4922
|
}
|
|
4672
4923
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4673
|
-
stmts.push(
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4924
|
+
stmts.push(...iterStmts);
|
|
4925
|
+
if (ctx.recovery) {
|
|
4926
|
+
const rrV = v(ctx, "_rr");
|
|
4927
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4928
|
+
stmts.push(
|
|
4929
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4930
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4931
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4932
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4933
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4934
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4935
|
+
`${ind(ctx)} continue`,
|
|
4936
|
+
`${ind(ctx)} }`,
|
|
4937
|
+
`${ind(ctx)} break`,
|
|
4938
|
+
`${ind(ctx)}}`,
|
|
4939
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4940
|
+
);
|
|
4941
|
+
} else {
|
|
4942
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4943
|
+
}
|
|
4677
4944
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4678
4945
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4679
4946
|
ctx.indent--;
|
|
@@ -4695,20 +4962,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4695
4962
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4696
4963
|
const arrV = v(ctx, "_arr");
|
|
4697
4964
|
const curV = v(ctx, "_cur");
|
|
4965
|
+
const rec = !!ctx.recovery;
|
|
4966
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4967
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4968
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4969
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4698
4970
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4699
4971
|
const stmts = [
|
|
4700
4972
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4701
4973
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4702
|
-
...
|
|
4703
|
-
|
|
4974
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4975
|
+
...firstStmts
|
|
4704
4976
|
];
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
)
|
|
4711
|
-
|
|
4977
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4978
|
+
if (!rec) return [originalFail];
|
|
4979
|
+
const rr = v(ctx, "_rr");
|
|
4980
|
+
return [
|
|
4981
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
4982
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
4983
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
4984
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
4985
|
+
`${ind(ctx)} }`,
|
|
4986
|
+
`${ind(ctx)} ${rb}break`,
|
|
4987
|
+
`${ind(ctx)}}`
|
|
4988
|
+
];
|
|
4989
|
+
};
|
|
4990
|
+
if (rec) {
|
|
4991
|
+
const rr0 = v(ctx, "_rr0");
|
|
4992
|
+
const didV = v(ctx, "_did");
|
|
4993
|
+
stmts.push(
|
|
4994
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
4995
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
4996
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
4997
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
4998
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
4999
|
+
`${ind(ctx)}}`,
|
|
5000
|
+
`${ind(ctx)}if (${didV}) {`
|
|
5001
|
+
);
|
|
5002
|
+
ctx.indent++;
|
|
5003
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
5004
|
+
ctx.indent++;
|
|
5005
|
+
} else {
|
|
5006
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
5007
|
+
ctx.indent++;
|
|
5008
|
+
stmts.push(
|
|
5009
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
5010
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
5011
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
5012
|
+
);
|
|
5013
|
+
ctx.indent++;
|
|
5014
|
+
}
|
|
4712
5015
|
let sepAtPos = curV;
|
|
4713
5016
|
if (ctx.activeTrivia) {
|
|
4714
5017
|
if (ctx.capturing) {
|
|
@@ -4734,8 +5037,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4734
5037
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4735
5038
|
stmts.push(
|
|
4736
5039
|
...nextStmts,
|
|
4737
|
-
|
|
4738
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
5040
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4739
5041
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4740
5042
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4741
5043
|
);
|
|
@@ -4751,7 +5053,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4751
5053
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4752
5054
|
stmts.push(
|
|
4753
5055
|
...nextStmts,
|
|
4754
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
5056
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4755
5057
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4756
5058
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4757
5059
|
);
|
|
@@ -4771,7 +5073,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4771
5073
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4772
5074
|
stmts.push(
|
|
4773
5075
|
...nextStmts,
|
|
4774
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
5076
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4775
5077
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4776
5078
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4777
5079
|
);
|
|
@@ -5028,7 +5330,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
5028
5330
|
stmts.push(
|
|
5029
5331
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
5030
5332
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
5031
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === '
|
|
5333
|
+
`${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} } })`
|
|
5032
5334
|
);
|
|
5033
5335
|
return { stmts, valueVar: ndV, endVar };
|
|
5034
5336
|
}
|
|
@@ -5118,6 +5420,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5118
5420
|
`${ind0}if (!${okVar}) {`,
|
|
5119
5421
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5120
5422
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5423
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5424
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5425
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5426
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5121
5427
|
`${ind0} ${valVar} = ${errV}`,
|
|
5122
5428
|
`${ind0} ${endVar} = ${pos}`,
|
|
5123
5429
|
`${ind0} ${okVar} = true`,
|
|
@@ -5284,7 +5590,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5284
5590
|
case "guard": {
|
|
5285
5591
|
const fnIdx = ctx.mapFns.length;
|
|
5286
5592
|
ctx.mapFns.push(def.predicate);
|
|
5287
|
-
ctx.mapFnSrcs.push(null);
|
|
5593
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5288
5594
|
const vv = v(ctx);
|
|
5289
5595
|
return {
|
|
5290
5596
|
stmts: [
|
|
@@ -5299,7 +5605,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5299
5605
|
const evIdx = ctx.mapFns.length;
|
|
5300
5606
|
const extra = def.extra;
|
|
5301
5607
|
ctx.mapFns.push((() => extra));
|
|
5302
|
-
ctx.mapFnSrcs.push(null);
|
|
5608
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5303
5609
|
const innerParser = def.parser;
|
|
5304
5610
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5305
5611
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5543,7 +5849,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5543
5849
|
}
|
|
5544
5850
|
return deps;
|
|
5545
5851
|
}
|
|
5546
|
-
function compile(combinator, mapFnSources) {
|
|
5852
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5547
5853
|
markUnusedValues(combinator);
|
|
5548
5854
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5549
5855
|
const ctx = {
|
|
@@ -5564,6 +5870,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5564
5870
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5565
5871
|
namedFnDecls: [],
|
|
5566
5872
|
capturing: hasNodeDef(combinator),
|
|
5873
|
+
recovery: opts?.recovery ?? false,
|
|
5567
5874
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5568
5875
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5569
5876
|
};
|
|
@@ -5616,7 +5923,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5616
5923
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5617
5924
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5618
5925
|
},
|
|
5619
|
-
// Note: collects
|
|
5926
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5620
5927
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5621
5928
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5622
5929
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5673,6 +5980,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5673
5980
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5674
5981
|
namedFnDecls: [],
|
|
5675
5982
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5983
|
+
recovery: opts?.recovery ?? false,
|
|
5676
5984
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5677
5985
|
ns,
|
|
5678
5986
|
deferFirstSetRefs: true,
|
|
@@ -6418,46 +6726,13 @@ function withCtx(extra, combinator) {
|
|
|
6418
6726
|
};
|
|
6419
6727
|
}
|
|
6420
6728
|
|
|
6421
|
-
// src/combinators/recover.ts
|
|
6422
|
-
function recover(combinator, sentinel) {
|
|
6423
|
-
const meta = {
|
|
6424
|
-
firstSet: { kind: "any" },
|
|
6425
|
-
canMatchNewline: true,
|
|
6426
|
-
isTrivia: false
|
|
6427
|
-
};
|
|
6428
|
-
const expected = deriveExpected(combinator);
|
|
6429
|
-
return {
|
|
6430
|
-
_tag: "recover",
|
|
6431
|
-
_meta: meta,
|
|
6432
|
-
_def: { tag: "recover", parser: combinator, sentinel },
|
|
6433
|
-
parse(input, pos, ctx) {
|
|
6434
|
-
const result = combinator.parse(input, pos, ctx);
|
|
6435
|
-
if (result.ok) return result;
|
|
6436
|
-
let scanPos = pos;
|
|
6437
|
-
while (scanPos < input.length) {
|
|
6438
|
-
if (sentinel.parse(input, scanPos, ctx).ok) break;
|
|
6439
|
-
scanPos++;
|
|
6440
|
-
}
|
|
6441
|
-
const error = {
|
|
6442
|
-
_tag: "parseError",
|
|
6443
|
-
span: { start: pos, end: scanPos },
|
|
6444
|
-
expected
|
|
6445
|
-
};
|
|
6446
|
-
ctx._errors?.push(error);
|
|
6447
|
-
return { ok: true, value: error, span: { start: pos, end: scanPos } };
|
|
6448
|
-
}
|
|
6449
|
-
};
|
|
6450
|
-
}
|
|
6451
|
-
function isParseError(value) {
|
|
6452
|
-
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
6453
|
-
}
|
|
6454
|
-
|
|
6455
6729
|
// src/combinators/completions.ts
|
|
6456
|
-
function completionsAt(
|
|
6730
|
+
function completionsAt(target, input, offset, options = {}) {
|
|
6457
6731
|
const probe = { offset, best: null };
|
|
6458
|
-
const ctx = { trackLines: false, _probe: probe };
|
|
6459
|
-
const
|
|
6460
|
-
|
|
6732
|
+
const ctx = { trackLines: false, _probe: probe, ...options.tolerant ? { _tolerant: true, _rec: REC } : {} };
|
|
6733
|
+
const sliced = input.slice(0, offset);
|
|
6734
|
+
const result = "parseWithContext" in target ? target.parseWithContext(sliced, ctx, 0) : target.parse(sliced, 0, ctx);
|
|
6735
|
+
if (result.ok) return options.tolerant ? probe.best?.expected ?? [] : [];
|
|
6461
6736
|
const best = deeperFail(probe.best, result);
|
|
6462
6737
|
return best?.expected ?? [];
|
|
6463
6738
|
}
|
|
@@ -6467,23 +6742,6 @@ function deeperFail(a, b) {
|
|
|
6467
6742
|
return a.span.start >= b.span.start ? a : b;
|
|
6468
6743
|
}
|
|
6469
6744
|
|
|
6470
|
-
// src/combinators/recover-list.ts
|
|
6471
|
-
function tolerantElement(item, sentinel, until) {
|
|
6472
|
-
const el = transform(
|
|
6473
|
-
sequence(not(until), recover(item, sentinel)),
|
|
6474
|
-
([, value]) => value
|
|
6475
|
-
);
|
|
6476
|
-
if (el._def.tag === "transform") el._def.fnSrc = "([, value]) => value";
|
|
6477
|
-
return el;
|
|
6478
|
-
}
|
|
6479
|
-
function sepByRecover(item, separator, until) {
|
|
6480
|
-
const sentinel = choice(separator, until);
|
|
6481
|
-
return sepBy(tolerantElement(item, sentinel, until), separator);
|
|
6482
|
-
}
|
|
6483
|
-
function manyRecover(item, until) {
|
|
6484
|
-
return many(tolerantElement(item, until, until));
|
|
6485
|
-
}
|
|
6486
|
-
|
|
6487
6745
|
// src/cst/relative-spans.ts
|
|
6488
6746
|
function relativize(node2, parentBase = 0) {
|
|
6489
6747
|
return {
|
|
@@ -6578,6 +6836,9 @@ function editNode(node2, at, delta, parentBase, parentShift, stats) {
|
|
|
6578
6836
|
}
|
|
6579
6837
|
|
|
6580
6838
|
// src/functional/doc.ts
|
|
6839
|
+
function mkCtx(state, build, tolerant) {
|
|
6840
|
+
return tolerant ? { trackLines: false, state, build, _tolerant: true, _rec: REC, _errors: [] } : { trackLines: false, state, build };
|
|
6841
|
+
}
|
|
6581
6842
|
function asRuleFn(entry) {
|
|
6582
6843
|
return typeof entry === "function" ? entry : (input, pos, ctx) => entry.parse(input, pos, ctx);
|
|
6583
6844
|
}
|
|
@@ -6684,8 +6945,8 @@ function graftRelative(root, path, newNode, delta) {
|
|
|
6684
6945
|
children: newChildren
|
|
6685
6946
|
};
|
|
6686
6947
|
}
|
|
6687
|
-
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build) {
|
|
6688
|
-
const ctx =
|
|
6948
|
+
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build, tolerant) {
|
|
6949
|
+
const ctx = mkCtx(null, build, tolerant);
|
|
6689
6950
|
const out = [];
|
|
6690
6951
|
let pos = reStart;
|
|
6691
6952
|
let guard2 = 0;
|
|
@@ -6709,7 +6970,7 @@ function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build) {
|
|
|
6709
6970
|
}
|
|
6710
6971
|
return pos === reEnd ? out : null;
|
|
6711
6972
|
}
|
|
6712
|
-
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build) {
|
|
6973
|
+
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build, tolerant) {
|
|
6713
6974
|
const kids = C.children;
|
|
6714
6975
|
if (kids.length === 0) return null;
|
|
6715
6976
|
let h = 0;
|
|
@@ -6750,7 +7011,7 @@ function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registr
|
|
|
6750
7011
|
const reStart = h > 0 ? cStart + kids[h - 1].span.end : cStart;
|
|
6751
7012
|
const reEnd = cStart + kids[t].span.start + delta;
|
|
6752
7013
|
if (reEnd < reStart) return null;
|
|
6753
|
-
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build);
|
|
7014
|
+
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6754
7015
|
if (!middle) return null;
|
|
6755
7016
|
if (middle.length > 0) {
|
|
6756
7017
|
const last2 = middle[middle.length - 1];
|
|
@@ -6760,7 +7021,7 @@ function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registr
|
|
|
6760
7021
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6761
7022
|
if (newInput[reEnd] === sentinel) continue;
|
|
6762
7023
|
const probed = newInput.slice(0, reEnd) + sentinel.repeat(newInput.length - reEnd);
|
|
6763
|
-
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build);
|
|
7024
|
+
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6764
7025
|
if (!probe || probe.length !== middle.length) return null;
|
|
6765
7026
|
for (let i = 0; i < middle.length; i++) if (!structurallyEqual(probe[i], middle[i])) return null;
|
|
6766
7027
|
}
|
|
@@ -6788,6 +7049,11 @@ function structurallyEqual(a, b) {
|
|
|
6788
7049
|
if (at === "leaf" || at === "trivia") {
|
|
6789
7050
|
return a.value === b.value;
|
|
6790
7051
|
}
|
|
7052
|
+
if (at === "parseError") {
|
|
7053
|
+
const ae = a.expected ?? [];
|
|
7054
|
+
const be = b.expected ?? [];
|
|
7055
|
+
return ae.length === be.length && ae.every((x, i) => x === be[i]);
|
|
7056
|
+
}
|
|
6791
7057
|
if (a.type !== b.type) return false;
|
|
6792
7058
|
const ac = a.children;
|
|
6793
7059
|
const bc = b.children;
|
|
@@ -6797,13 +7063,13 @@ function structurallyEqual(a, b) {
|
|
|
6797
7063
|
}
|
|
6798
7064
|
return true;
|
|
6799
7065
|
}
|
|
6800
|
-
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced) {
|
|
7066
|
+
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced, tolerant) {
|
|
6801
7067
|
if (!produced.ok) return false;
|
|
6802
7068
|
if (boundary >= newInput.length) return true;
|
|
6803
7069
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6804
7070
|
if (newInput[boundary] === sentinel) continue;
|
|
6805
7071
|
const probed = newInput.slice(0, boundary) + sentinel.repeat(newInput.length - boundary);
|
|
6806
|
-
const ctx =
|
|
7072
|
+
const ctx = mkCtx(state, build, tolerant);
|
|
6807
7073
|
let r;
|
|
6808
7074
|
try {
|
|
6809
7075
|
r = ruleFn(probed, start, ctx);
|
|
@@ -6835,8 +7101,9 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6835
7101
|
_abs;
|
|
6836
7102
|
_rel;
|
|
6837
7103
|
errors;
|
|
7104
|
+
unconsumedFrom;
|
|
6838
7105
|
input;
|
|
6839
|
-
constructor(registry, rootRule, opts, trees, errors, input) {
|
|
7106
|
+
constructor(registry, rootRule, opts, trees, errors, unconsumedFrom, input) {
|
|
6840
7107
|
this._registry = registry;
|
|
6841
7108
|
this._fns = {};
|
|
6842
7109
|
this._reps = /* @__PURE__ */ new Set();
|
|
@@ -6849,6 +7116,7 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6849
7116
|
this._abs = trees.abs;
|
|
6850
7117
|
this._rel = trees.rel;
|
|
6851
7118
|
this.errors = errors;
|
|
7119
|
+
this.unconsumedFrom = unconsumedFrom;
|
|
6852
7120
|
this.input = input;
|
|
6853
7121
|
}
|
|
6854
7122
|
/**
|
|
@@ -6871,6 +7139,19 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6871
7139
|
if (!rel) throw new Error("spanAt on a failed parse (tree is null)");
|
|
6872
7140
|
return absoluteSpanCST(rel, path);
|
|
6873
7141
|
}
|
|
7142
|
+
/**
|
|
7143
|
+
* Wrap a reused (grafted/spliced) RELATIVE tree, recomputing `errors` and
|
|
7144
|
+
* `unconsumedFrom` from it so both stay consistent with the tree across the
|
|
7145
|
+
* edit (the flat errors are recovered errors embedded in the reused subtrees;
|
|
7146
|
+
* unconsumedFrom re-derives trailing junk over the new input).
|
|
7147
|
+
*/
|
|
7148
|
+
wrapReuse(newTree, newInput) {
|
|
7149
|
+
const trivia2 = triviaOf(this._registry[this._rootRule], this._opts);
|
|
7150
|
+
const end = newTree.span.end;
|
|
7151
|
+
const errors = collectEmbeddedErrors(newTree, 0, []);
|
|
7152
|
+
const unconsumedFrom = unconsumedAfter(end, newInput, trivia2);
|
|
7153
|
+
return new _ParseDocImpl(this._registry, this._rootRule, this._opts, { rel: newTree }, errors, unconsumedFrom, newInput);
|
|
7154
|
+
}
|
|
6874
7155
|
edit(from, to, replacement) {
|
|
6875
7156
|
const newInput = this.input.slice(0, from) + replacement + this.input.slice(to);
|
|
6876
7157
|
const reparse = () => parseDoc(this._registry, this._rootRule, newInput, this._opts);
|
|
@@ -6892,22 +7173,22 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6892
7173
|
const ruleFn = this._fns[node2.type];
|
|
6893
7174
|
if (!ruleFn) continue;
|
|
6894
7175
|
if (!(absStart <= from && to <= absEnd)) continue;
|
|
6895
|
-
const ctx =
|
|
7176
|
+
const ctx = mkCtx(node2.state, this._opts.build, !!this._opts.tolerant);
|
|
6896
7177
|
const r = ruleFn(newInput, absStart, ctx);
|
|
6897
7178
|
if (!r.ok) continue;
|
|
6898
7179
|
if (r.span.end !== absEnd + delta) continue;
|
|
6899
|
-
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r)) {
|
|
7180
|
+
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r, !!this._opts.tolerant)) {
|
|
6900
7181
|
continue;
|
|
6901
7182
|
}
|
|
6902
7183
|
const parentBase = absStart - node2.span.start;
|
|
6903
7184
|
const newRel = relativizeCST(r.value, parentBase);
|
|
6904
7185
|
if (delta === 0) {
|
|
6905
7186
|
const newTree2 = replaceAtPath(rebuild, root, path, newRel);
|
|
6906
|
-
return
|
|
7187
|
+
return this.wrapReuse(newTree2, newInput);
|
|
6907
7188
|
}
|
|
6908
7189
|
if (this._opts.rebuild) return reparse();
|
|
6909
7190
|
const newTree = graftRelative(root, path, newRel, delta);
|
|
6910
|
-
return
|
|
7191
|
+
return this.wrapReuse(newTree, newInput);
|
|
6911
7192
|
}
|
|
6912
7193
|
if (this._opts.structuralReuse && delta !== 0 && !this._opts.rebuild) {
|
|
6913
7194
|
const spliceCandidates = [...candidates, { node: root, path: [] }];
|
|
@@ -6915,22 +7196,50 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6915
7196
|
if (!this._reps.has(node2.type)) continue;
|
|
6916
7197
|
const { start: cStart, end: cEnd } = absoluteSpanCST(root, path);
|
|
6917
7198
|
if (!(cStart <= from && to <= cEnd)) continue;
|
|
6918
|
-
const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build);
|
|
6919
|
-
if (spliced) return
|
|
7199
|
+
const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build, !!this._opts.tolerant);
|
|
7200
|
+
if (spliced) return this.wrapReuse(spliced, newInput);
|
|
6920
7201
|
}
|
|
6921
7202
|
}
|
|
6922
7203
|
return reparse();
|
|
6923
7204
|
}
|
|
6924
7205
|
};
|
|
7206
|
+
function triviaOf(entry, opts) {
|
|
7207
|
+
if (opts.trivia) return opts.trivia;
|
|
7208
|
+
if (entry === void 0 || typeof entry === "function") return void 0;
|
|
7209
|
+
const meta = entry._meta;
|
|
7210
|
+
return meta ? meta.grammarTrivia : void 0;
|
|
7211
|
+
}
|
|
7212
|
+
function unconsumedAfter(end, input, trivia2) {
|
|
7213
|
+
let pos = end;
|
|
7214
|
+
if (trivia2 && pos < input.length) {
|
|
7215
|
+
const t = trivia2.parse(input, pos, { trackLines: false });
|
|
7216
|
+
if (t.ok && t.span.end > pos) pos = t.span.end;
|
|
7217
|
+
}
|
|
7218
|
+
return pos < input.length ? pos : null;
|
|
7219
|
+
}
|
|
7220
|
+
function collectEmbeddedErrors(node2, base, out) {
|
|
7221
|
+
const c = node2;
|
|
7222
|
+
if (!c || typeof c !== "object" || !c.span) return out;
|
|
7223
|
+
const start = base + c.span.start;
|
|
7224
|
+
if (c._tag === "parseError") {
|
|
7225
|
+
out.push({ _tag: "parseError", span: { start, end: base + c.span.end }, expected: c.expected ?? [] });
|
|
7226
|
+
return out;
|
|
7227
|
+
}
|
|
7228
|
+
if (Array.isArray(c.children)) for (const k of c.children) collectEmbeddedErrors(k, start, out);
|
|
7229
|
+
return out;
|
|
7230
|
+
}
|
|
6925
7231
|
function parseDoc(registry, rootRule, input, opts = {}) {
|
|
6926
7232
|
const entry = registry[rootRule];
|
|
6927
7233
|
if (!entry) throw new Error(`No rule '${rootRule}' in registry`);
|
|
6928
|
-
const ctx =
|
|
7234
|
+
const ctx = mkCtx(opts.state, opts.build, !!opts.tolerant);
|
|
6929
7235
|
const r = asRuleFn(entry)(input, 0, ctx);
|
|
6930
7236
|
if (r.ok) {
|
|
6931
|
-
|
|
7237
|
+
const errors = ctx._errors ? [...ctx._errors] : [];
|
|
7238
|
+
const unconsumedFrom = unconsumedAfter(r.span.end, input, triviaOf(entry, opts));
|
|
7239
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: r.value }, errors, unconsumedFrom, input);
|
|
6932
7240
|
}
|
|
6933
|
-
|
|
7241
|
+
const fail = { _tag: "parseError", span: r.span, expected: r.expected };
|
|
7242
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
|
|
6934
7243
|
}
|
|
6935
7244
|
|
|
6936
7245
|
// src/functional/run.ts
|
|
@@ -6951,7 +7260,8 @@ function run(entry, input, options = {}) {
|
|
|
6951
7260
|
build: options.build,
|
|
6952
7261
|
state: options.state,
|
|
6953
7262
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
6954
|
-
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {}
|
|
7263
|
+
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7264
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
6955
7265
|
};
|
|
6956
7266
|
const r = invoke(entry, input, 0, ctx);
|
|
6957
7267
|
let unconsumedFrom = null;
|