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/index.cjs
CHANGED
|
@@ -22,7 +22,9 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
OffsetIndex: () => OffsetIndex,
|
|
24
24
|
absoluteSpanAt: () => absoluteSpanAt,
|
|
25
|
+
absoluteSpanCST: () => absoluteSpanCST,
|
|
25
26
|
absolutize: () => absolutize,
|
|
27
|
+
absolutizeCST: () => absolutizeCST,
|
|
26
28
|
annotateSpan: () => annotateSpan,
|
|
27
29
|
applyEdit: () => applyEdit,
|
|
28
30
|
balanced: () => balanced,
|
|
@@ -53,7 +55,6 @@ __export(index_exports, {
|
|
|
53
55
|
literal: () => literal,
|
|
54
56
|
makeWord: () => makeWord,
|
|
55
57
|
many: () => many,
|
|
56
|
-
manyRecover: () => manyRecover,
|
|
57
58
|
noTrivia: () => noTrivia,
|
|
58
59
|
node: () => node,
|
|
59
60
|
not: () => not,
|
|
@@ -63,15 +64,14 @@ __export(index_exports, {
|
|
|
63
64
|
parse: () => parse,
|
|
64
65
|
parseDoc: () => parseDoc,
|
|
65
66
|
parser: () => parser,
|
|
66
|
-
recover: () => recover,
|
|
67
67
|
ref: () => ref,
|
|
68
68
|
regex: () => regex,
|
|
69
69
|
relativize: () => relativize,
|
|
70
|
+
relativizeCST: () => relativizeCST,
|
|
70
71
|
rules: () => rules,
|
|
71
72
|
run: () => run,
|
|
72
73
|
scanTo: () => scanTo,
|
|
73
74
|
sepBy: () => sepBy,
|
|
74
|
-
sepByRecover: () => sepByRecover,
|
|
75
75
|
sequence: () => sequence,
|
|
76
76
|
shiftAbsolute: () => shiftAbsolute,
|
|
77
77
|
skip: () => skip,
|
|
@@ -341,7 +341,13 @@ function saveCstMark(ctx) {
|
|
|
341
341
|
raw: cstRawLen(ctx),
|
|
342
342
|
tlog: cstTlLen(ctx),
|
|
343
343
|
leaves: cstLeavesLen(ctx),
|
|
344
|
-
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
|
|
345
351
|
};
|
|
346
352
|
}
|
|
347
353
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -357,6 +363,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
357
363
|
if (len === 0) b[keySingle] = void 0;
|
|
358
364
|
}
|
|
359
365
|
function rollbackCstCapture(ctx, mark) {
|
|
366
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
360
367
|
const b = ctx._cstBuf;
|
|
361
368
|
if (b) {
|
|
362
369
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -1303,10 +1310,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1303
1310
|
}
|
|
1304
1311
|
function saveTriviaMark(ctx) {
|
|
1305
1312
|
const m = saveCstMark(ctx);
|
|
1306
|
-
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 };
|
|
1307
1314
|
}
|
|
1308
1315
|
function rollbackTrivia(ctx, mark) {
|
|
1309
|
-
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 });
|
|
1310
1317
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1311
1318
|
}
|
|
1312
1319
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1540,6 +1547,94 @@ function scanBlockComment(input, cur) {
|
|
|
1540
1547
|
return close === -1 ? cur : close + 2;
|
|
1541
1548
|
}
|
|
1542
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
|
+
|
|
1543
1638
|
// src/combinators/sequence.ts
|
|
1544
1639
|
function sequence(...parsers) {
|
|
1545
1640
|
const meta = {
|
|
@@ -1550,11 +1645,59 @@ function sequence(...parsers) {
|
|
|
1550
1645
|
isTrivia: false
|
|
1551
1646
|
};
|
|
1552
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
|
+
}
|
|
1553
1695
|
return {
|
|
1554
1696
|
_tag: "sequence",
|
|
1555
1697
|
_meta: meta,
|
|
1556
1698
|
_def: def,
|
|
1557
1699
|
parse(input, pos, ctx) {
|
|
1700
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1558
1701
|
const values = def.valueUnused ? void 0 : [];
|
|
1559
1702
|
let cur = pos;
|
|
1560
1703
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1593,6 +1736,69 @@ function sequence(...parsers) {
|
|
|
1593
1736
|
};
|
|
1594
1737
|
}
|
|
1595
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
|
+
|
|
1596
1802
|
// src/combinators/repeat.ts
|
|
1597
1803
|
function repItem(combinator, input, cur, ctx) {
|
|
1598
1804
|
const mark = saveTriviaMark(ctx);
|
|
@@ -1613,7 +1819,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1613
1819
|
const result = combinator.parse(input, pos, ctx);
|
|
1614
1820
|
if (!result.ok) {
|
|
1615
1821
|
rollbackTrivia(ctx, mark);
|
|
1616
|
-
return { fail: result };
|
|
1822
|
+
return { fail: result, failPos: pos };
|
|
1617
1823
|
}
|
|
1618
1824
|
if (result.span.end === pos) {
|
|
1619
1825
|
rollbackTrivia(ctx, mark);
|
|
@@ -1628,6 +1834,7 @@ function many(combinator) {
|
|
|
1628
1834
|
isTrivia: false
|
|
1629
1835
|
};
|
|
1630
1836
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1837
|
+
let expected;
|
|
1631
1838
|
return {
|
|
1632
1839
|
_tag: "many",
|
|
1633
1840
|
_meta: meta,
|
|
@@ -1637,7 +1844,18 @@ function many(combinator) {
|
|
|
1637
1844
|
let cur = pos;
|
|
1638
1845
|
while (cur < input.length) {
|
|
1639
1846
|
const item = repItem(combinator, input, cur, ctx);
|
|
1640
|
-
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
|
+
}
|
|
1641
1859
|
if (values !== void 0) values.push(item.value);
|
|
1642
1860
|
cur = item.end;
|
|
1643
1861
|
}
|
|
@@ -1652,6 +1870,7 @@ function oneOrMore(combinator) {
|
|
|
1652
1870
|
isTrivia: false
|
|
1653
1871
|
};
|
|
1654
1872
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1873
|
+
let expected;
|
|
1655
1874
|
return {
|
|
1656
1875
|
_tag: "oneOrMore",
|
|
1657
1876
|
_meta: meta,
|
|
@@ -1663,7 +1882,18 @@ function oneOrMore(combinator) {
|
|
|
1663
1882
|
let cur = first.span.end;
|
|
1664
1883
|
while (cur < input.length) {
|
|
1665
1884
|
const item = repItem(combinator, input, cur, ctx);
|
|
1666
|
-
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
|
+
}
|
|
1667
1897
|
if (values !== void 0) values.push(item.value);
|
|
1668
1898
|
cur = item.end;
|
|
1669
1899
|
}
|
|
@@ -1709,15 +1939,29 @@ function sepBy(combinator, separator) {
|
|
|
1709
1939
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1710
1940
|
isTrivia: false
|
|
1711
1941
|
};
|
|
1942
|
+
let expected;
|
|
1712
1943
|
return {
|
|
1713
1944
|
_tag: "sepBy",
|
|
1714
1945
|
_meta: meta,
|
|
1715
1946
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1716
1947
|
parse(input, pos, ctx) {
|
|
1717
1948
|
const first = combinator.parse(input, pos, ctx);
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
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
|
+
}
|
|
1721
1965
|
while (cur < input.length) {
|
|
1722
1966
|
const loopMark = saveTriviaMark(ctx);
|
|
1723
1967
|
let sepPos = cur;
|
|
@@ -1747,6 +1991,15 @@ function sepBy(combinator, separator) {
|
|
|
1747
1991
|
}
|
|
1748
1992
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1749
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
|
+
}
|
|
1750
2003
|
rollbackTrivia(ctx, loopMark);
|
|
1751
2004
|
break;
|
|
1752
2005
|
}
|
|
@@ -1920,7 +2173,7 @@ function rules(a, b) {
|
|
|
1920
2173
|
cache[key] = parser2;
|
|
1921
2174
|
}
|
|
1922
2175
|
}
|
|
1923
|
-
if (options?.trivia
|
|
2176
|
+
if (options?.trivia != null) {
|
|
1924
2177
|
for (const key of Object.keys(definitions)) {
|
|
1925
2178
|
const rule = cache[key];
|
|
1926
2179
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1950,7 +2203,9 @@ function not(combinator) {
|
|
|
1950
2203
|
_meta: meta,
|
|
1951
2204
|
_def: { tag: "not", parser: combinator },
|
|
1952
2205
|
parse(input, pos, ctx) {
|
|
2206
|
+
const mark = saveCstMark(ctx);
|
|
1953
2207
|
const result = combinator.parse(input, pos, ctx);
|
|
2208
|
+
rollbackCstCapture(ctx, mark);
|
|
1954
2209
|
if (result.ok) {
|
|
1955
2210
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1956
2211
|
}
|
|
@@ -2064,7 +2319,7 @@ function unwrapChild(child) {
|
|
|
2064
2319
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
2065
2320
|
}
|
|
2066
2321
|
function isCstChild(value) {
|
|
2067
|
-
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");
|
|
2068
2323
|
}
|
|
2069
2324
|
function missingInferredType() {
|
|
2070
2325
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2342,65 +2597,6 @@ function token(root) {
|
|
|
2342
2597
|
};
|
|
2343
2598
|
}
|
|
2344
2599
|
|
|
2345
|
-
// src/combinators/expect.ts
|
|
2346
|
-
function deriveExpected(c) {
|
|
2347
|
-
const def = c._def;
|
|
2348
|
-
switch (def.tag) {
|
|
2349
|
-
case "literal":
|
|
2350
|
-
return [JSON.stringify(def.value)];
|
|
2351
|
-
case "regex":
|
|
2352
|
-
return [`/${def.source}/`];
|
|
2353
|
-
case "keywords":
|
|
2354
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2355
|
-
case "label":
|
|
2356
|
-
return [def.label];
|
|
2357
|
-
case "choice":
|
|
2358
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2359
|
-
case "sequence":
|
|
2360
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2361
|
-
case "node":
|
|
2362
|
-
case "grammar":
|
|
2363
|
-
case "trivia":
|
|
2364
|
-
case "token":
|
|
2365
|
-
case "optional":
|
|
2366
|
-
case "many":
|
|
2367
|
-
case "oneOrMore":
|
|
2368
|
-
case "transform":
|
|
2369
|
-
case "not":
|
|
2370
|
-
return deriveExpected(def.parser);
|
|
2371
|
-
case "lazy": {
|
|
2372
|
-
const name = c._ruleName;
|
|
2373
|
-
try {
|
|
2374
|
-
return deriveExpected(def.thunk());
|
|
2375
|
-
} catch {
|
|
2376
|
-
return name ? [name] : [];
|
|
2377
|
-
}
|
|
2378
|
-
}
|
|
2379
|
-
default:
|
|
2380
|
-
return [];
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
function expect(combinator, label2) {
|
|
2384
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2385
|
-
const meta = {
|
|
2386
|
-
firstSet: combinator._meta.firstSet,
|
|
2387
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2388
|
-
isTrivia: false
|
|
2389
|
-
};
|
|
2390
|
-
return {
|
|
2391
|
-
_tag: "expect",
|
|
2392
|
-
_meta: meta,
|
|
2393
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2394
|
-
parse(input, pos, ctx) {
|
|
2395
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2396
|
-
if (result.ok) return result;
|
|
2397
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2398
|
-
ctx._errors?.push(error);
|
|
2399
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2400
|
-
}
|
|
2401
|
-
};
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
2600
|
// src/compiler/scannable-run.ts
|
|
2405
2601
|
var BACKSLASH = 92;
|
|
2406
2602
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2472,20 +2668,39 @@ function parseSeqParts(source) {
|
|
|
2472
2668
|
lit = [];
|
|
2473
2669
|
}
|
|
2474
2670
|
};
|
|
2475
|
-
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];
|
|
2476
2684
|
if (q === "+") {
|
|
2477
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2685
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2478
2686
|
return 1;
|
|
2479
2687
|
}
|
|
2480
2688
|
if (q === "*") {
|
|
2481
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2689
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2482
2690
|
return 1;
|
|
2483
2691
|
}
|
|
2484
2692
|
if (q === "?") {
|
|
2485
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2693
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2486
2694
|
return 1;
|
|
2487
2695
|
}
|
|
2488
|
-
|
|
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 });
|
|
2489
2704
|
return 0;
|
|
2490
2705
|
};
|
|
2491
2706
|
let i = 0;
|
|
@@ -2510,7 +2725,7 @@ function parseSeqParts(source) {
|
|
|
2510
2725
|
if (!ranges) return null;
|
|
2511
2726
|
flush();
|
|
2512
2727
|
i = k + 1;
|
|
2513
|
-
i += runFrom(ranges, neg,
|
|
2728
|
+
i += runFrom(ranges, neg, i);
|
|
2514
2729
|
continue;
|
|
2515
2730
|
}
|
|
2516
2731
|
if (ch === "\\") {
|
|
@@ -2518,7 +2733,7 @@ function parseSeqParts(source) {
|
|
|
2518
2733
|
if (e === "d" || e === "w" || e === "s") {
|
|
2519
2734
|
flush();
|
|
2520
2735
|
i += 2;
|
|
2521
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2736
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2522
2737
|
continue;
|
|
2523
2738
|
}
|
|
2524
2739
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2607,7 +2822,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2607
2822
|
let hasMandatory = false;
|
|
2608
2823
|
for (let k = 0; k < parts.length; k++) {
|
|
2609
2824
|
const p = parts[k];
|
|
2610
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2825
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2611
2826
|
if (mandatory) hasMandatory = true;
|
|
2612
2827
|
if (p.part === "group") {
|
|
2613
2828
|
const exposure = groupPartExposure(p);
|
|
@@ -2618,9 +2833,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2618
2833
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2619
2834
|
}
|
|
2620
2835
|
}
|
|
2621
|
-
const
|
|
2622
|
-
|
|
2623
|
-
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) {
|
|
2624
2838
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2625
2839
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2626
2840
|
}
|
|
@@ -2677,8 +2891,8 @@ function fixedClassSeq(shape) {
|
|
|
2677
2891
|
if (p.part === "lit") {
|
|
2678
2892
|
if (p.optional) return null;
|
|
2679
2893
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2680
|
-
} else if (p.part === "run" &&
|
|
2681
|
-
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 });
|
|
2682
2896
|
} else {
|
|
2683
2897
|
return null;
|
|
2684
2898
|
}
|
|
@@ -2730,7 +2944,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2730
2944
|
const last = shape.parts[shape.parts.length - 1];
|
|
2731
2945
|
if (last.part === "lit") return null;
|
|
2732
2946
|
if (last.part === "run") {
|
|
2733
|
-
if (last.
|
|
2947
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2734
2948
|
return null;
|
|
2735
2949
|
}
|
|
2736
2950
|
return groupPartExposure(last);
|
|
@@ -2867,7 +3081,7 @@ function partFirstAccept(part) {
|
|
|
2867
3081
|
function seqFirstAccept(parts) {
|
|
2868
3082
|
const sets = [];
|
|
2869
3083
|
for (const p of parts) {
|
|
2870
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
3084
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2871
3085
|
sets.push(partFirstAccept(p));
|
|
2872
3086
|
if (mandatory) break;
|
|
2873
3087
|
}
|
|
@@ -3282,7 +3496,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3282
3496
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3283
3497
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3284
3498
|
}
|
|
3285
|
-
} 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) {
|
|
3286
3506
|
if (p.min === 1) {
|
|
3287
3507
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3288
3508
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3292,8 +3512,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3292
3512
|
} else if (p.part === "run") {
|
|
3293
3513
|
const s = mint("_s");
|
|
3294
3514
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3295
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3296
|
-
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`);
|
|
3297
3517
|
} else {
|
|
3298
3518
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3299
3519
|
if (!p.unbounded) {
|
|
@@ -3752,21 +3972,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3752
3972
|
}
|
|
3753
3973
|
return name;
|
|
3754
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
|
+
}
|
|
3755
3981
|
function failBody(ctx, expected, posExpr) {
|
|
3982
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3756
3983
|
if (ctx.failLabel) {
|
|
3757
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3758
|
-
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} }`;
|
|
3759
3986
|
}
|
|
3760
|
-
return failReturn(expected, posExpr);
|
|
3987
|
+
return probe + failReturn(expected, posExpr);
|
|
3761
3988
|
}
|
|
3762
3989
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3990
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3763
3991
|
if (ctx.failLabel) {
|
|
3764
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3992
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3765
3993
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3766
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3994
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3767
3995
|
}
|
|
3768
|
-
if (!constant) return
|
|
3769
|
-
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);
|
|
3770
3998
|
}
|
|
3771
3999
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3772
4000
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4266,6 +4494,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4266
4494
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4267
4495
|
return { stmts, valueVar: vv, endVar };
|
|
4268
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
|
+
}
|
|
4269
4501
|
function emitSeqValues(def, ctx, pos) {
|
|
4270
4502
|
const startV = v(ctx, "_start");
|
|
4271
4503
|
const curV = v(ctx, "_cur");
|
|
@@ -4274,7 +4506,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4274
4506
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4275
4507
|
];
|
|
4276
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
|
+
};
|
|
4277
4517
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4518
|
+
const syncPub = publishSync(i);
|
|
4519
|
+
if (syncPub) stmts.push(syncPub);
|
|
4278
4520
|
if (i > 0 && ctx.activeTrivia) {
|
|
4279
4521
|
if (ctx.capturing) {
|
|
4280
4522
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4299,7 +4541,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4299
4541
|
continue;
|
|
4300
4542
|
} else {
|
|
4301
4543
|
const trivFn = ensureTriviaFn(ctx);
|
|
4302
|
-
|
|
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;
|
|
4303
4555
|
}
|
|
4304
4556
|
}
|
|
4305
4557
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4529,7 +4781,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4529
4781
|
if (gate) {
|
|
4530
4782
|
const gateIdx = ctx.mapFns.length;
|
|
4531
4783
|
ctx.mapFns.push(gate);
|
|
4532
|
-
ctx.mapFnSrcs.push(null);
|
|
4784
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4533
4785
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4534
4786
|
}
|
|
4535
4787
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4634,6 +4886,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4634
4886
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4635
4887
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4636
4888
|
];
|
|
4889
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4890
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4637
4891
|
if (def.min === 1) {
|
|
4638
4892
|
const firstR = emit(def.parser, ctx, curV);
|
|
4639
4893
|
stmts.push(...firstR.stmts);
|
|
@@ -4667,10 +4921,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4667
4921
|
}
|
|
4668
4922
|
}
|
|
4669
4923
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4670
|
-
stmts.push(
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
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
|
+
}
|
|
4674
4944
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4675
4945
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4676
4946
|
ctx.indent--;
|
|
@@ -4692,20 +4962,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4692
4962
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4693
4963
|
const arrV = v(ctx, "_arr");
|
|
4694
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;
|
|
4695
4970
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4696
4971
|
const stmts = [
|
|
4697
4972
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4698
4973
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4699
|
-
...
|
|
4700
|
-
|
|
4974
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4975
|
+
...firstStmts
|
|
4701
4976
|
];
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
)
|
|
4708
|
-
|
|
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
|
+
}
|
|
4709
5015
|
let sepAtPos = curV;
|
|
4710
5016
|
if (ctx.activeTrivia) {
|
|
4711
5017
|
if (ctx.capturing) {
|
|
@@ -4731,8 +5037,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4731
5037
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4732
5038
|
stmts.push(
|
|
4733
5039
|
...nextStmts,
|
|
4734
|
-
|
|
4735
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
5040
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4736
5041
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4737
5042
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4738
5043
|
);
|
|
@@ -4748,7 +5053,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4748
5053
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4749
5054
|
stmts.push(
|
|
4750
5055
|
...nextStmts,
|
|
4751
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
5056
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4752
5057
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4753
5058
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4754
5059
|
);
|
|
@@ -4768,7 +5073,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4768
5073
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4769
5074
|
stmts.push(
|
|
4770
5075
|
...nextStmts,
|
|
4771
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
5076
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4772
5077
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4773
5078
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4774
5079
|
);
|
|
@@ -5025,7 +5330,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
5025
5330
|
stmts.push(
|
|
5026
5331
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
5027
5332
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
5028
|
-
`${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} } })`
|
|
5029
5334
|
);
|
|
5030
5335
|
return { stmts, valueVar: ndV, endVar };
|
|
5031
5336
|
}
|
|
@@ -5115,6 +5420,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5115
5420
|
`${ind0}if (!${okVar}) {`,
|
|
5116
5421
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5117
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})`,
|
|
5118
5427
|
`${ind0} ${valVar} = ${errV}`,
|
|
5119
5428
|
`${ind0} ${endVar} = ${pos}`,
|
|
5120
5429
|
`${ind0} ${okVar} = true`,
|
|
@@ -5281,7 +5590,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5281
5590
|
case "guard": {
|
|
5282
5591
|
const fnIdx = ctx.mapFns.length;
|
|
5283
5592
|
ctx.mapFns.push(def.predicate);
|
|
5284
|
-
ctx.mapFnSrcs.push(null);
|
|
5593
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5285
5594
|
const vv = v(ctx);
|
|
5286
5595
|
return {
|
|
5287
5596
|
stmts: [
|
|
@@ -5296,7 +5605,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5296
5605
|
const evIdx = ctx.mapFns.length;
|
|
5297
5606
|
const extra = def.extra;
|
|
5298
5607
|
ctx.mapFns.push((() => extra));
|
|
5299
|
-
ctx.mapFnSrcs.push(null);
|
|
5608
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5300
5609
|
const innerParser = def.parser;
|
|
5301
5610
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5302
5611
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5540,7 +5849,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5540
5849
|
}
|
|
5541
5850
|
return deps;
|
|
5542
5851
|
}
|
|
5543
|
-
function compile(combinator, mapFnSources) {
|
|
5852
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5544
5853
|
markUnusedValues(combinator);
|
|
5545
5854
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5546
5855
|
const ctx = {
|
|
@@ -5561,6 +5870,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5561
5870
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5562
5871
|
namedFnDecls: [],
|
|
5563
5872
|
capturing: hasNodeDef(combinator),
|
|
5873
|
+
recovery: opts?.recovery ?? false,
|
|
5564
5874
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5565
5875
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5566
5876
|
};
|
|
@@ -5613,7 +5923,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5613
5923
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5614
5924
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5615
5925
|
},
|
|
5616
|
-
// Note: collects
|
|
5926
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5617
5927
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5618
5928
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5619
5929
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5670,6 +5980,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5670
5980
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5671
5981
|
namedFnDecls: [],
|
|
5672
5982
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5983
|
+
recovery: opts?.recovery ?? false,
|
|
5673
5984
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5674
5985
|
ns,
|
|
5675
5986
|
deferFirstSetRefs: true,
|
|
@@ -6415,46 +6726,13 @@ function withCtx(extra, combinator) {
|
|
|
6415
6726
|
};
|
|
6416
6727
|
}
|
|
6417
6728
|
|
|
6418
|
-
// src/combinators/recover.ts
|
|
6419
|
-
function recover(combinator, sentinel) {
|
|
6420
|
-
const meta = {
|
|
6421
|
-
firstSet: { kind: "any" },
|
|
6422
|
-
canMatchNewline: true,
|
|
6423
|
-
isTrivia: false
|
|
6424
|
-
};
|
|
6425
|
-
const expected = deriveExpected(combinator);
|
|
6426
|
-
return {
|
|
6427
|
-
_tag: "recover",
|
|
6428
|
-
_meta: meta,
|
|
6429
|
-
_def: { tag: "recover", parser: combinator, sentinel },
|
|
6430
|
-
parse(input, pos, ctx) {
|
|
6431
|
-
const result = combinator.parse(input, pos, ctx);
|
|
6432
|
-
if (result.ok) return result;
|
|
6433
|
-
let scanPos = pos;
|
|
6434
|
-
while (scanPos < input.length) {
|
|
6435
|
-
if (sentinel.parse(input, scanPos, ctx).ok) break;
|
|
6436
|
-
scanPos++;
|
|
6437
|
-
}
|
|
6438
|
-
const error = {
|
|
6439
|
-
_tag: "parseError",
|
|
6440
|
-
span: { start: pos, end: scanPos },
|
|
6441
|
-
expected
|
|
6442
|
-
};
|
|
6443
|
-
ctx._errors?.push(error);
|
|
6444
|
-
return { ok: true, value: error, span: { start: pos, end: scanPos } };
|
|
6445
|
-
}
|
|
6446
|
-
};
|
|
6447
|
-
}
|
|
6448
|
-
function isParseError(value) {
|
|
6449
|
-
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
6450
|
-
}
|
|
6451
|
-
|
|
6452
6729
|
// src/combinators/completions.ts
|
|
6453
|
-
function completionsAt(
|
|
6730
|
+
function completionsAt(target, input, offset, options = {}) {
|
|
6454
6731
|
const probe = { offset, best: null };
|
|
6455
|
-
const ctx = { trackLines: false, _probe: probe };
|
|
6456
|
-
const
|
|
6457
|
-
|
|
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 ?? [] : [];
|
|
6458
6736
|
const best = deeperFail(probe.best, result);
|
|
6459
6737
|
return best?.expected ?? [];
|
|
6460
6738
|
}
|
|
@@ -6464,34 +6742,162 @@ function deeperFail(a, b) {
|
|
|
6464
6742
|
return a.span.start >= b.span.start ? a : b;
|
|
6465
6743
|
}
|
|
6466
6744
|
|
|
6467
|
-
// src/
|
|
6468
|
-
function
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6745
|
+
// src/cst/relative-spans.ts
|
|
6746
|
+
function relativize(node2, parentBase = 0) {
|
|
6747
|
+
return {
|
|
6748
|
+
start: node2.start - parentBase,
|
|
6749
|
+
end: node2.end - parentBase,
|
|
6750
|
+
children: node2.children.map((c) => relativize(c, node2.start))
|
|
6751
|
+
};
|
|
6752
|
+
}
|
|
6753
|
+
function absolutize(node2, parentBase = 0) {
|
|
6754
|
+
const start = parentBase + node2.start;
|
|
6755
|
+
return {
|
|
6756
|
+
start,
|
|
6757
|
+
end: parentBase + node2.end,
|
|
6758
|
+
children: node2.children.map((c) => absolutize(c, start))
|
|
6759
|
+
};
|
|
6760
|
+
}
|
|
6761
|
+
function absoluteSpanAt(root, path) {
|
|
6762
|
+
let base = 0;
|
|
6763
|
+
let node2 = root;
|
|
6764
|
+
for (const idx of path) {
|
|
6765
|
+
base += node2.start;
|
|
6766
|
+
const child = node2.children[idx];
|
|
6767
|
+
if (!child) throw new RangeError(`absoluteSpanAt: no child ${idx} on path ${path.join(".")}`);
|
|
6768
|
+
node2 = child;
|
|
6769
|
+
}
|
|
6770
|
+
return { start: base + node2.start, end: base + node2.end };
|
|
6771
|
+
}
|
|
6772
|
+
function relativizeCST(node2, parentBase = 0) {
|
|
6773
|
+
const span = { start: node2.span.start - parentBase, end: node2.span.end - parentBase };
|
|
6774
|
+
if (node2.children) {
|
|
6775
|
+
const base = node2.span.start;
|
|
6776
|
+
return { ...node2, span, children: node2.children.map((c) => relativizeCST(c, base)) };
|
|
6777
|
+
}
|
|
6778
|
+
return { ...node2, span };
|
|
6779
|
+
}
|
|
6780
|
+
function absolutizeCST(node2, parentBase = 0) {
|
|
6781
|
+
const start = parentBase + node2.span.start;
|
|
6782
|
+
const span = { start, end: parentBase + node2.span.end };
|
|
6783
|
+
if (node2.children) {
|
|
6784
|
+
return { ...node2, span, children: node2.children.map((c) => absolutizeCST(c, start)) };
|
|
6785
|
+
}
|
|
6786
|
+
return { ...node2, span };
|
|
6787
|
+
}
|
|
6788
|
+
function absoluteSpanCST(root, path) {
|
|
6789
|
+
let base = 0;
|
|
6790
|
+
let node2 = root;
|
|
6791
|
+
for (const idx of path) {
|
|
6792
|
+
base += node2.span.start;
|
|
6793
|
+
const child = node2.children?.[idx];
|
|
6794
|
+
if (!child) throw new RangeError(`absoluteSpanCST: no child ${idx} on path ${path.join(".")}`);
|
|
6795
|
+
node2 = child;
|
|
6796
|
+
}
|
|
6797
|
+
return { start: base + node2.span.start, end: base + node2.span.end };
|
|
6475
6798
|
}
|
|
6476
|
-
function
|
|
6477
|
-
const
|
|
6478
|
-
|
|
6799
|
+
function shiftAbsolute(node2, at, delta) {
|
|
6800
|
+
const s = node2.start >= at ? node2.start + delta : node2.start;
|
|
6801
|
+
const e = node2.end >= at ? node2.end + delta : node2.end;
|
|
6802
|
+
return {
|
|
6803
|
+
start: s,
|
|
6804
|
+
end: e,
|
|
6805
|
+
children: node2.children.map((c) => shiftAbsolute(c, at, delta))
|
|
6806
|
+
};
|
|
6479
6807
|
}
|
|
6480
|
-
function
|
|
6481
|
-
return
|
|
6808
|
+
function applyEdit(root, at, delta, stats) {
|
|
6809
|
+
return editNode(root, at, delta, 0, 0, stats);
|
|
6810
|
+
}
|
|
6811
|
+
function editNode(node2, at, delta, parentBase, parentShift, stats) {
|
|
6812
|
+
const absStart = parentBase + node2.start;
|
|
6813
|
+
const absEnd = parentBase + node2.end;
|
|
6814
|
+
if (absEnd < at) return node2;
|
|
6815
|
+
const startShifts = absStart >= at;
|
|
6816
|
+
if (startShifts && parentShift === delta) return node2;
|
|
6817
|
+
if (stats) stats.allocated++;
|
|
6818
|
+
const newAbsStart = startShifts ? absStart + delta : absStart;
|
|
6819
|
+
const newAbsEnd = absEnd + delta;
|
|
6820
|
+
const newParentBase = parentBase + parentShift;
|
|
6821
|
+
const newStart = newAbsStart - newParentBase;
|
|
6822
|
+
const newEnd = newAbsEnd - newParentBase;
|
|
6823
|
+
const ownShift = newAbsStart - absStart;
|
|
6824
|
+
let changed = false;
|
|
6825
|
+
const newChildren = [];
|
|
6826
|
+
for (const c of node2.children) {
|
|
6827
|
+
const nc = editNode(c, at, delta, absStart, ownShift, stats);
|
|
6828
|
+
if (nc !== c) changed = true;
|
|
6829
|
+
newChildren.push(nc);
|
|
6830
|
+
}
|
|
6831
|
+
return {
|
|
6832
|
+
start: newStart,
|
|
6833
|
+
end: newEnd,
|
|
6834
|
+
children: changed ? newChildren : node2.children
|
|
6835
|
+
};
|
|
6482
6836
|
}
|
|
6483
6837
|
|
|
6484
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
|
+
}
|
|
6842
|
+
function asRuleFn(entry) {
|
|
6843
|
+
return typeof entry === "function" ? entry : (input, pos, ctx) => entry.parse(input, pos, ctx);
|
|
6844
|
+
}
|
|
6845
|
+
function defOf(entry) {
|
|
6846
|
+
return typeof entry === "object" && entry !== null && "_def" in entry ? entry._def : void 0;
|
|
6847
|
+
}
|
|
6848
|
+
function producesRepetition(def, depth = 0) {
|
|
6849
|
+
if (!def || depth > 24) return false;
|
|
6850
|
+
const d = def;
|
|
6851
|
+
switch (d.tag) {
|
|
6852
|
+
case "sepBy":
|
|
6853
|
+
case "many":
|
|
6854
|
+
case "oneOrMore":
|
|
6855
|
+
return true;
|
|
6856
|
+
// Rule entries and `ref`s wrap their body in a `lazy` thunk — resolve it. The
|
|
6857
|
+
// `depth` cap bounds any self-referential cycle (a repetition, if present, is
|
|
6858
|
+
// found shallowly before recursion goes deep).
|
|
6859
|
+
case "lazy": {
|
|
6860
|
+
const thunk = d.thunk;
|
|
6861
|
+
let inner;
|
|
6862
|
+
try {
|
|
6863
|
+
inner = typeof thunk === "function" ? thunk() : void 0;
|
|
6864
|
+
} catch {
|
|
6865
|
+
return false;
|
|
6866
|
+
}
|
|
6867
|
+
return producesRepetition(inner?._def, depth + 1);
|
|
6868
|
+
}
|
|
6869
|
+
// Transparent wrappers — look through to the inner parser.
|
|
6870
|
+
case "node":
|
|
6871
|
+
case "transform":
|
|
6872
|
+
case "token":
|
|
6873
|
+
case "label":
|
|
6874
|
+
case "field":
|
|
6875
|
+
case "expect":
|
|
6876
|
+
case "withCtx":
|
|
6877
|
+
case "grammar":
|
|
6878
|
+
case "optional":
|
|
6879
|
+
return producesRepetition(defOf(d.parser), depth + 1);
|
|
6880
|
+
case "skip":
|
|
6881
|
+
return producesRepetition(defOf(d.main), depth + 1);
|
|
6882
|
+
// A bracketed/anchored list is a sequence whose element run is a repetition.
|
|
6883
|
+
case "sequence":
|
|
6884
|
+
return d.parsers.some((p) => producesRepetition(defOf(p), depth + 1));
|
|
6885
|
+
default:
|
|
6886
|
+
return false;
|
|
6887
|
+
}
|
|
6888
|
+
}
|
|
6485
6889
|
var REENTRY_MAX_SPAN_FRACTION = 0.5;
|
|
6486
6890
|
function isNode(x) {
|
|
6487
6891
|
return typeof x === "object" && x !== null && x._tag === "node";
|
|
6488
6892
|
}
|
|
6489
|
-
function findContaining(node2, pos, path = []) {
|
|
6893
|
+
function findContaining(node2, nodeAbsStart, pos, path = []) {
|
|
6490
6894
|
for (let i = 0; i < node2.children.length; i++) {
|
|
6491
6895
|
const child = node2.children[i];
|
|
6492
6896
|
if (!isNode(child)) continue;
|
|
6493
|
-
|
|
6494
|
-
|
|
6897
|
+
const childAbsStart = nodeAbsStart + child.span.start;
|
|
6898
|
+
const childAbsEnd = nodeAbsStart + child.span.end;
|
|
6899
|
+
if (childAbsStart <= pos && pos < childAbsEnd) {
|
|
6900
|
+
const inner = findContaining(child, childAbsStart, pos, [...path, i]);
|
|
6495
6901
|
return inner ?? { node: child, path: [...path, i] };
|
|
6496
6902
|
}
|
|
6497
6903
|
}
|
|
@@ -6518,24 +6924,20 @@ function replaceAtPath(rebuild, root, path, newNode) {
|
|
|
6518
6924
|
function defaultRebuild(node2, children) {
|
|
6519
6925
|
return { ...node2, children };
|
|
6520
6926
|
}
|
|
6521
|
-
function
|
|
6927
|
+
function shiftRelStart(child, delta) {
|
|
6522
6928
|
const c = child;
|
|
6523
|
-
|
|
6524
|
-
if (Array.isArray(c.children)) {
|
|
6525
|
-
return { ...c, span, children: c.children.map((g) => shiftSpans(g, delta)) };
|
|
6526
|
-
}
|
|
6527
|
-
return { ...c, span };
|
|
6929
|
+
return { ...c, span: { start: c.span.start + delta, end: c.span.end + delta } };
|
|
6528
6930
|
}
|
|
6529
|
-
function
|
|
6931
|
+
function graftRelative(root, path, newNode, delta) {
|
|
6530
6932
|
if (path.length === 0) return newNode;
|
|
6531
6933
|
const [idx, ...rest] = path;
|
|
6532
6934
|
const oldChildren = root.children;
|
|
6533
6935
|
const newChildren = oldChildren.map((child, i) => {
|
|
6534
6936
|
if (i < idx) return child;
|
|
6535
6937
|
if (i === idx) {
|
|
6536
|
-
return rest.length === 0 ? newNode :
|
|
6938
|
+
return rest.length === 0 ? newNode : graftRelative(child, rest, newNode, delta);
|
|
6537
6939
|
}
|
|
6538
|
-
return
|
|
6940
|
+
return shiftRelStart(child, delta);
|
|
6539
6941
|
});
|
|
6540
6942
|
return {
|
|
6541
6943
|
...root,
|
|
@@ -6543,6 +6945,96 @@ function graftAndShift(root, path, newNode, delta) {
|
|
|
6543
6945
|
children: newChildren
|
|
6544
6946
|
};
|
|
6545
6947
|
}
|
|
6948
|
+
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build, tolerant) {
|
|
6949
|
+
const ctx = mkCtx(null, build, tolerant);
|
|
6950
|
+
const out = [];
|
|
6951
|
+
let pos = reStart;
|
|
6952
|
+
let guard2 = 0;
|
|
6953
|
+
while (pos < reEnd) {
|
|
6954
|
+
if (++guard2 > reEnd - reStart + 2) return null;
|
|
6955
|
+
if (separator && out.length > 0 && out[out.length - 1]._tag === "node") {
|
|
6956
|
+
if (pos + separator.length > reEnd || !input.startsWith(separator, pos)) return null;
|
|
6957
|
+
out.push({ _tag: "leaf", value: separator, span: { start: pos - cStart, end: pos + separator.length - cStart } });
|
|
6958
|
+
pos += separator.length;
|
|
6959
|
+
continue;
|
|
6960
|
+
}
|
|
6961
|
+
let r;
|
|
6962
|
+
try {
|
|
6963
|
+
r = ruleFn(input, pos, ctx);
|
|
6964
|
+
} catch {
|
|
6965
|
+
return null;
|
|
6966
|
+
}
|
|
6967
|
+
if (!r.ok || r.span.end <= pos || r.span.end > reEnd) return null;
|
|
6968
|
+
out.push(relativizeCST(r.value, cStart));
|
|
6969
|
+
pos = r.span.end;
|
|
6970
|
+
}
|
|
6971
|
+
return pos === reEnd ? out : null;
|
|
6972
|
+
}
|
|
6973
|
+
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build, tolerant) {
|
|
6974
|
+
const kids = C.children;
|
|
6975
|
+
if (kids.length === 0) return null;
|
|
6976
|
+
let h = 0;
|
|
6977
|
+
while (h < kids.length && cStart + kids[h].span.end <= from) h++;
|
|
6978
|
+
while (h > 0 && kids[h - 1]._tag === "node") h--;
|
|
6979
|
+
let t = kids.length;
|
|
6980
|
+
while (t > h && cStart + kids[t - 1].span.start >= to) t--;
|
|
6981
|
+
while (t < kids.length && kids[t]._tag !== "node") t++;
|
|
6982
|
+
if (t >= kids.length) return null;
|
|
6983
|
+
for (let i = t; i < kids.length; i++) {
|
|
6984
|
+
if (kids[i]._tag === "node" && kids[i].state != null) return null;
|
|
6985
|
+
}
|
|
6986
|
+
let elemType;
|
|
6987
|
+
let elemCount = 0;
|
|
6988
|
+
for (const k of kids) {
|
|
6989
|
+
if (k._tag !== "node") continue;
|
|
6990
|
+
elemCount++;
|
|
6991
|
+
if (elemType === void 0) elemType = k.type;
|
|
6992
|
+
else if (k.type !== elemType) return null;
|
|
6993
|
+
}
|
|
6994
|
+
if (elemType === void 0 || elemCount < 2) return null;
|
|
6995
|
+
const ruleFn = registry[elemType];
|
|
6996
|
+
if (!ruleFn) return null;
|
|
6997
|
+
let separator = null;
|
|
6998
|
+
for (let i = 1; i < kids.length - 1; i++) {
|
|
6999
|
+
if (kids[i - 1]._tag === "node" && kids[i + 1]._tag === "node") {
|
|
7000
|
+
if (kids[i]._tag !== "leaf") return null;
|
|
7001
|
+
const sep = kids[i].value ?? null;
|
|
7002
|
+
if (separator === null) separator = sep;
|
|
7003
|
+
else if (sep !== separator) return null;
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
7006
|
+
if (separator === null) return null;
|
|
7007
|
+
const first = kids[0];
|
|
7008
|
+
const last = kids[kids.length - 1];
|
|
7009
|
+
if (first._tag === "leaf" && first.value !== separator && from < cStart + first.span.end) return null;
|
|
7010
|
+
if (last._tag === "leaf" && last.value !== separator && to > cStart + last.span.start) return null;
|
|
7011
|
+
const reStart = h > 0 ? cStart + kids[h - 1].span.end : cStart;
|
|
7012
|
+
const reEnd = cStart + kids[t].span.start + delta;
|
|
7013
|
+
if (reEnd < reStart) return null;
|
|
7014
|
+
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
7015
|
+
if (!middle) return null;
|
|
7016
|
+
if (middle.length > 0) {
|
|
7017
|
+
const last2 = middle[middle.length - 1];
|
|
7018
|
+
if (!(last2._tag === "leaf" && last2.value === separator)) return null;
|
|
7019
|
+
}
|
|
7020
|
+
if (reEnd < newInput.length) {
|
|
7021
|
+
for (const sentinel of [" ", "\uFFFF"]) {
|
|
7022
|
+
if (newInput[reEnd] === sentinel) continue;
|
|
7023
|
+
const probed = newInput.slice(0, reEnd) + sentinel.repeat(newInput.length - reEnd);
|
|
7024
|
+
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
7025
|
+
if (!probe || probe.length !== middle.length) return null;
|
|
7026
|
+
for (let i = 0; i < middle.length; i++) if (!structurallyEqual(probe[i], middle[i])) return null;
|
|
7027
|
+
}
|
|
7028
|
+
}
|
|
7029
|
+
const head = kids.slice(0, h);
|
|
7030
|
+
const tail = kids.slice(t).map((k) => shiftRelStart(k, delta));
|
|
7031
|
+
const newC = {
|
|
7032
|
+
...C,
|
|
7033
|
+
span: { start: C.span.start, end: C.span.end + delta },
|
|
7034
|
+
children: [...head, ...middle, ...tail]
|
|
7035
|
+
};
|
|
7036
|
+
return graftRelative(root, path, newC, delta);
|
|
7037
|
+
}
|
|
6546
7038
|
function structurallyEqual(a, b) {
|
|
6547
7039
|
if (a === b) return true;
|
|
6548
7040
|
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
@@ -6557,6 +7049,11 @@ function structurallyEqual(a, b) {
|
|
|
6557
7049
|
if (at === "leaf" || at === "trivia") {
|
|
6558
7050
|
return a.value === b.value;
|
|
6559
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
|
+
}
|
|
6560
7057
|
if (a.type !== b.type) return false;
|
|
6561
7058
|
const ac = a.children;
|
|
6562
7059
|
const bc = b.children;
|
|
@@ -6566,13 +7063,13 @@ function structurallyEqual(a, b) {
|
|
|
6566
7063
|
}
|
|
6567
7064
|
return true;
|
|
6568
7065
|
}
|
|
6569
|
-
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced) {
|
|
7066
|
+
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced, tolerant) {
|
|
6570
7067
|
if (!produced.ok) return false;
|
|
6571
7068
|
if (boundary >= newInput.length) return true;
|
|
6572
7069
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6573
7070
|
if (newInput[boundary] === sentinel) continue;
|
|
6574
7071
|
const probed = newInput.slice(0, boundary) + sentinel.repeat(newInput.length - boundary);
|
|
6575
|
-
const ctx =
|
|
7072
|
+
const ctx = mkCtx(state, build, tolerant);
|
|
6576
7073
|
let r;
|
|
6577
7074
|
try {
|
|
6578
7075
|
r = ruleFn(probed, start, ctx);
|
|
@@ -6586,27 +7083,83 @@ function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produce
|
|
|
6586
7083
|
}
|
|
6587
7084
|
var ParseDocImpl = class _ParseDocImpl {
|
|
6588
7085
|
_registry;
|
|
7086
|
+
/** Registry entries normalized to callable parse functions (memoized once). */
|
|
7087
|
+
_fns;
|
|
7088
|
+
/** Rule names the grammar proves are genuine repetitions — the ONLY splice-safe types. */
|
|
7089
|
+
_reps;
|
|
6589
7090
|
_rootRule;
|
|
6590
7091
|
_opts;
|
|
6591
|
-
|
|
7092
|
+
/**
|
|
7093
|
+
* The tree, held in whichever coordinate system it arrived in. A fresh parse
|
|
7094
|
+
* arrives ABSOLUTE (`_abs` set); an incremental graft arrives PARENT-RELATIVE
|
|
7095
|
+
* (`_rel` set). The public `tree` is always the RELATIVE form (so untouched
|
|
7096
|
+
* subtrees stay shared by identity across edits and reads are O(1)); it's
|
|
7097
|
+
* materialized from `_abs` once, on demand, and memoized. `undefined` = not yet
|
|
7098
|
+
* computed; `null` = failed parse. A fresh parse that's never edited nor
|
|
7099
|
+
* tree-read pays no conversion — important for the full-reparse fallback path.
|
|
7100
|
+
*/
|
|
7101
|
+
_abs;
|
|
7102
|
+
_rel;
|
|
6592
7103
|
errors;
|
|
7104
|
+
unconsumedFrom;
|
|
6593
7105
|
input;
|
|
6594
|
-
constructor(registry, rootRule, opts,
|
|
7106
|
+
constructor(registry, rootRule, opts, trees, errors, unconsumedFrom, input) {
|
|
6595
7107
|
this._registry = registry;
|
|
7108
|
+
this._fns = {};
|
|
7109
|
+
this._reps = /* @__PURE__ */ new Set();
|
|
7110
|
+
for (const [name, entry] of Object.entries(registry)) {
|
|
7111
|
+
this._fns[name] = asRuleFn(entry);
|
|
7112
|
+
if (producesRepetition(defOf(entry))) this._reps.add(name);
|
|
7113
|
+
}
|
|
6596
7114
|
this._rootRule = rootRule;
|
|
6597
7115
|
this._opts = opts;
|
|
6598
|
-
this.
|
|
7116
|
+
this._abs = trees.abs;
|
|
7117
|
+
this._rel = trees.rel;
|
|
6599
7118
|
this.errors = errors;
|
|
7119
|
+
this.unconsumedFrom = unconsumedFrom;
|
|
6600
7120
|
this.input = input;
|
|
6601
7121
|
}
|
|
7122
|
+
/**
|
|
7123
|
+
* The parse tree with PARENT-RELATIVE spans — a node's `span` is relative to
|
|
7124
|
+
* its parent's start (root base 0). This is the shareable representation:
|
|
7125
|
+
* untouched subtrees keep the same identity across `.edit()`s, and reading the
|
|
7126
|
+
* tree after a length-changing edit is O(1) (no offset rewrite). For absolute
|
|
7127
|
+
* positions use the O(depth) cursor `spanAt(path)`, or `absolutizeCST(tree)` to
|
|
7128
|
+
* materialize the whole absolute tree. (A fresh non-incremental `node().parse()`
|
|
7129
|
+
* result is unchanged — still absolute.)
|
|
7130
|
+
*/
|
|
7131
|
+
get tree() {
|
|
7132
|
+
if (this._rel === void 0) {
|
|
7133
|
+
this._rel = this._abs ? relativizeCST(this._abs, 0) : null;
|
|
7134
|
+
}
|
|
7135
|
+
return this._rel;
|
|
7136
|
+
}
|
|
7137
|
+
spanAt(path) {
|
|
7138
|
+
const rel = this.tree;
|
|
7139
|
+
if (!rel) throw new Error("spanAt on a failed parse (tree is null)");
|
|
7140
|
+
return absoluteSpanCST(rel, path);
|
|
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
|
+
}
|
|
6602
7155
|
edit(from, to, replacement) {
|
|
6603
7156
|
const newInput = this.input.slice(0, from) + replacement + this.input.slice(to);
|
|
6604
7157
|
const reparse = () => parseDoc(this._registry, this._rootRule, newInput, this._opts);
|
|
6605
|
-
|
|
7158
|
+
const root = this.tree;
|
|
7159
|
+
if (!root) return reparse();
|
|
6606
7160
|
const delta = replacement.length - (to - from);
|
|
6607
|
-
const found = findContaining(
|
|
6608
|
-
|
|
6609
|
-
const ancestors = ancestorsAt(this.tree, found.path);
|
|
7161
|
+
const found = findContaining(root, 0, from) ?? { node: root, path: [] };
|
|
7162
|
+
const ancestors = ancestorsAt(root, found.path);
|
|
6610
7163
|
const candidates = [found];
|
|
6611
7164
|
const pathCopy = [...found.path];
|
|
6612
7165
|
for (let i = ancestors.length - 2; i >= 0; i--) {
|
|
@@ -6615,37 +7168,78 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6615
7168
|
}
|
|
6616
7169
|
const rebuild = this._opts.rebuild ?? defaultRebuild;
|
|
6617
7170
|
for (const { node: node2, path } of candidates) {
|
|
6618
|
-
|
|
6619
|
-
|
|
7171
|
+
const { start: absStart, end: absEnd } = absoluteSpanCST(root, path);
|
|
7172
|
+
if (absEnd - absStart > this.input.length * REENTRY_MAX_SPAN_FRACTION) break;
|
|
7173
|
+
const ruleFn = this._fns[node2.type];
|
|
6620
7174
|
if (!ruleFn) continue;
|
|
6621
|
-
if (!(
|
|
6622
|
-
const ctx =
|
|
6623
|
-
const r = ruleFn(newInput,
|
|
7175
|
+
if (!(absStart <= from && to <= absEnd)) continue;
|
|
7176
|
+
const ctx = mkCtx(node2.state, this._opts.build, !!this._opts.tolerant);
|
|
7177
|
+
const r = ruleFn(newInput, absStart, ctx);
|
|
6624
7178
|
if (!r.ok) continue;
|
|
6625
|
-
if (r.span.end !==
|
|
6626
|
-
if (!boundaryIsSafe(ruleFn, newInput,
|
|
7179
|
+
if (r.span.end !== absEnd + delta) continue;
|
|
7180
|
+
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r, !!this._opts.tolerant)) {
|
|
6627
7181
|
continue;
|
|
6628
7182
|
}
|
|
7183
|
+
const parentBase = absStart - node2.span.start;
|
|
7184
|
+
const newRel = relativizeCST(r.value, parentBase);
|
|
6629
7185
|
if (delta === 0) {
|
|
6630
|
-
const newTree2 = replaceAtPath(rebuild,
|
|
6631
|
-
return
|
|
7186
|
+
const newTree2 = replaceAtPath(rebuild, root, path, newRel);
|
|
7187
|
+
return this.wrapReuse(newTree2, newInput);
|
|
6632
7188
|
}
|
|
6633
7189
|
if (this._opts.rebuild) return reparse();
|
|
6634
|
-
const newTree =
|
|
6635
|
-
return
|
|
7190
|
+
const newTree = graftRelative(root, path, newRel, delta);
|
|
7191
|
+
return this.wrapReuse(newTree, newInput);
|
|
7192
|
+
}
|
|
7193
|
+
if (this._opts.structuralReuse && delta !== 0 && !this._opts.rebuild) {
|
|
7194
|
+
const spliceCandidates = [...candidates, { node: root, path: [] }];
|
|
7195
|
+
for (const { node: node2, path } of spliceCandidates) {
|
|
7196
|
+
if (!this._reps.has(node2.type)) continue;
|
|
7197
|
+
const { start: cStart, end: cEnd } = absoluteSpanCST(root, path);
|
|
7198
|
+
if (!(cStart <= from && to <= cEnd)) continue;
|
|
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);
|
|
7201
|
+
}
|
|
6636
7202
|
}
|
|
6637
7203
|
return reparse();
|
|
6638
7204
|
}
|
|
6639
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
|
+
}
|
|
6640
7231
|
function parseDoc(registry, rootRule, input, opts = {}) {
|
|
6641
|
-
const
|
|
6642
|
-
if (!
|
|
6643
|
-
const ctx =
|
|
6644
|
-
const r =
|
|
7232
|
+
const entry = registry[rootRule];
|
|
7233
|
+
if (!entry) throw new Error(`No rule '${rootRule}' in registry`);
|
|
7234
|
+
const ctx = mkCtx(opts.state, opts.build, !!opts.tolerant);
|
|
7235
|
+
const r = asRuleFn(entry)(input, 0, ctx);
|
|
6645
7236
|
if (r.ok) {
|
|
6646
|
-
|
|
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);
|
|
6647
7240
|
}
|
|
6648
|
-
|
|
7241
|
+
const fail = { _tag: "parseError", span: r.span, expected: r.expected };
|
|
7242
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
|
|
6649
7243
|
}
|
|
6650
7244
|
|
|
6651
7245
|
// src/functional/run.ts
|
|
@@ -6666,7 +7260,8 @@ function run(entry, input, options = {}) {
|
|
|
6666
7260
|
build: options.build,
|
|
6667
7261
|
state: options.state,
|
|
6668
7262
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
6669
|
-
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {}
|
|
7263
|
+
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7264
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
6670
7265
|
};
|
|
6671
7266
|
const r = invoke(entry, input, 0, ctx);
|
|
6672
7267
|
let unconsumedFrom = null;
|
|
@@ -7014,72 +7609,6 @@ function buildOffsetIndex(root, input = "") {
|
|
|
7014
7609
|
return new OffsetIndex(collectLeafSlots(root), 0, input.length);
|
|
7015
7610
|
}
|
|
7016
7611
|
|
|
7017
|
-
// src/cst/relative-spans.ts
|
|
7018
|
-
function relativize(node2, parentBase = 0) {
|
|
7019
|
-
return {
|
|
7020
|
-
start: node2.start - parentBase,
|
|
7021
|
-
end: node2.end - parentBase,
|
|
7022
|
-
children: node2.children.map((c) => relativize(c, node2.start))
|
|
7023
|
-
};
|
|
7024
|
-
}
|
|
7025
|
-
function absolutize(node2, parentBase = 0) {
|
|
7026
|
-
const start = parentBase + node2.start;
|
|
7027
|
-
return {
|
|
7028
|
-
start,
|
|
7029
|
-
end: parentBase + node2.end,
|
|
7030
|
-
children: node2.children.map((c) => absolutize(c, start))
|
|
7031
|
-
};
|
|
7032
|
-
}
|
|
7033
|
-
function absoluteSpanAt(root, path) {
|
|
7034
|
-
let base = 0;
|
|
7035
|
-
let node2 = root;
|
|
7036
|
-
for (const idx of path) {
|
|
7037
|
-
base += node2.start;
|
|
7038
|
-
const child = node2.children[idx];
|
|
7039
|
-
if (!child) throw new RangeError(`absoluteSpanAt: no child ${idx} on path ${path.join(".")}`);
|
|
7040
|
-
node2 = child;
|
|
7041
|
-
}
|
|
7042
|
-
return { start: base + node2.start, end: base + node2.end };
|
|
7043
|
-
}
|
|
7044
|
-
function shiftAbsolute(node2, at, delta) {
|
|
7045
|
-
const s = node2.start >= at ? node2.start + delta : node2.start;
|
|
7046
|
-
const e = node2.end >= at ? node2.end + delta : node2.end;
|
|
7047
|
-
return {
|
|
7048
|
-
start: s,
|
|
7049
|
-
end: e,
|
|
7050
|
-
children: node2.children.map((c) => shiftAbsolute(c, at, delta))
|
|
7051
|
-
};
|
|
7052
|
-
}
|
|
7053
|
-
function applyEdit(root, at, delta, stats) {
|
|
7054
|
-
return editNode(root, at, delta, 0, 0, stats);
|
|
7055
|
-
}
|
|
7056
|
-
function editNode(node2, at, delta, parentBase, parentShift, stats) {
|
|
7057
|
-
const absStart = parentBase + node2.start;
|
|
7058
|
-
const absEnd = parentBase + node2.end;
|
|
7059
|
-
if (absEnd < at) return node2;
|
|
7060
|
-
const startShifts = absStart >= at;
|
|
7061
|
-
if (startShifts && parentShift === delta) return node2;
|
|
7062
|
-
if (stats) stats.allocated++;
|
|
7063
|
-
const newAbsStart = startShifts ? absStart + delta : absStart;
|
|
7064
|
-
const newAbsEnd = absEnd + delta;
|
|
7065
|
-
const newParentBase = parentBase + parentShift;
|
|
7066
|
-
const newStart = newAbsStart - newParentBase;
|
|
7067
|
-
const newEnd = newAbsEnd - newParentBase;
|
|
7068
|
-
const ownShift = newAbsStart - absStart;
|
|
7069
|
-
let changed = false;
|
|
7070
|
-
const newChildren = [];
|
|
7071
|
-
for (const c of node2.children) {
|
|
7072
|
-
const nc = editNode(c, at, delta, absStart, ownShift, stats);
|
|
7073
|
-
if (nc !== c) changed = true;
|
|
7074
|
-
newChildren.push(nc);
|
|
7075
|
-
}
|
|
7076
|
-
return {
|
|
7077
|
-
start: newStart,
|
|
7078
|
-
end: newEnd,
|
|
7079
|
-
children: changed ? newChildren : node2.children
|
|
7080
|
-
};
|
|
7081
|
-
}
|
|
7082
|
-
|
|
7083
7612
|
// src/index.ts
|
|
7084
7613
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
7085
7614
|
//# sourceMappingURL=index.cjs.map
|