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.js
CHANGED
|
@@ -253,7 +253,13 @@ function saveCstMark(ctx) {
|
|
|
253
253
|
raw: cstRawLen(ctx),
|
|
254
254
|
tlog: cstTlLen(ctx),
|
|
255
255
|
leaves: cstLeavesLen(ctx),
|
|
256
|
-
fields: ctx._fields?.length ?? 0
|
|
256
|
+
fields: ctx._fields?.length ?? 0,
|
|
257
|
+
// Speculative rollback must truncate the flat recovery-error sink in lockstep
|
|
258
|
+
// with the CST leaves: a branch that recovered (pushing a ParseError to
|
|
259
|
+
// ctx._errors AND embedding it as a CST child via captureError) then failed
|
|
260
|
+
// must remove BOTH, or the flat error survives as a GHOST that a tree walk
|
|
261
|
+
// can't see (flat run().errors would disagree with the embedded set).
|
|
262
|
+
errors: ctx._errors?.length ?? 0
|
|
257
263
|
};
|
|
258
264
|
}
|
|
259
265
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -269,6 +275,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
269
275
|
if (len === 0) b[keySingle] = void 0;
|
|
270
276
|
}
|
|
271
277
|
function rollbackCstCapture(ctx, mark) {
|
|
278
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
272
279
|
const b = ctx._cstBuf;
|
|
273
280
|
if (b) {
|
|
274
281
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -1215,10 +1222,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1215
1222
|
}
|
|
1216
1223
|
function saveTriviaMark(ctx) {
|
|
1217
1224
|
const m = saveCstMark(ctx);
|
|
1218
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1225
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1219
1226
|
}
|
|
1220
1227
|
function rollbackTrivia(ctx, mark) {
|
|
1221
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1228
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1222
1229
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1223
1230
|
}
|
|
1224
1231
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1452,6 +1459,94 @@ function scanBlockComment(input, cur) {
|
|
|
1452
1459
|
return close === -1 ? cur : close + 2;
|
|
1453
1460
|
}
|
|
1454
1461
|
|
|
1462
|
+
// src/recovery/scan.ts
|
|
1463
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
1464
|
+
const s = {
|
|
1465
|
+
_probe: ctx._probe,
|
|
1466
|
+
_errors: ctx._errors,
|
|
1467
|
+
_cstLeaves: ctx._cstLeaves,
|
|
1468
|
+
_cstChildren: ctx._cstChildren,
|
|
1469
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
1470
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
1471
|
+
_triviaLog: ctx._triviaLog,
|
|
1472
|
+
_fields: ctx._fields,
|
|
1473
|
+
_cstBuf: ctx._cstBuf,
|
|
1474
|
+
_tolerant: ctx._tolerant,
|
|
1475
|
+
_sync: ctx._sync
|
|
1476
|
+
};
|
|
1477
|
+
ctx._probe = void 0;
|
|
1478
|
+
ctx._errors = void 0;
|
|
1479
|
+
ctx._cstLeaves = void 0;
|
|
1480
|
+
ctx._cstChildren = void 0;
|
|
1481
|
+
ctx._cstRawChildren = void 0;
|
|
1482
|
+
ctx._cstTriviaLog = void 0;
|
|
1483
|
+
ctx._triviaLog = void 0;
|
|
1484
|
+
ctx._fields = void 0;
|
|
1485
|
+
ctx._cstBuf = void 0;
|
|
1486
|
+
ctx._tolerant = void 0;
|
|
1487
|
+
ctx._sync = void 0;
|
|
1488
|
+
try {
|
|
1489
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
1490
|
+
} finally {
|
|
1491
|
+
ctx._probe = s._probe;
|
|
1492
|
+
ctx._errors = s._errors;
|
|
1493
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
1494
|
+
ctx._cstChildren = s._cstChildren;
|
|
1495
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
1496
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
1497
|
+
ctx._triviaLog = s._triviaLog;
|
|
1498
|
+
ctx._fields = s._fields;
|
|
1499
|
+
ctx._cstBuf = s._cstBuf;
|
|
1500
|
+
ctx._tolerant = s._tolerant;
|
|
1501
|
+
ctx._sync = s._sync;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
function orSentinel(a, b) {
|
|
1505
|
+
if (b === void 0) return a;
|
|
1506
|
+
return {
|
|
1507
|
+
_tag: "orSentinel",
|
|
1508
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
1509
|
+
_def: { tag: "unknown" },
|
|
1510
|
+
parse(input, pos, ctx) {
|
|
1511
|
+
const ra = a.parse(input, pos, ctx);
|
|
1512
|
+
if (ra.ok) return ra;
|
|
1513
|
+
return b.parse(input, pos, ctx);
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
function firstSetSentinel(fs) {
|
|
1518
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
1519
|
+
const ranges = fs.ranges;
|
|
1520
|
+
return {
|
|
1521
|
+
_tag: "firstSetSentinel",
|
|
1522
|
+
_meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
|
|
1523
|
+
_def: { tag: "unknown" },
|
|
1524
|
+
parse(input, pos) {
|
|
1525
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
1526
|
+
if (code !== void 0) {
|
|
1527
|
+
for (const r of ranges) {
|
|
1528
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
1536
|
+
let scanPos = from;
|
|
1537
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
1538
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
1539
|
+
ctx._errors?.push(error);
|
|
1540
|
+
return { error, end: scanPos };
|
|
1541
|
+
}
|
|
1542
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
1543
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
1544
|
+
}
|
|
1545
|
+
function captureError(ctx, error) {
|
|
1546
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1547
|
+
}
|
|
1548
|
+
var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
|
|
1549
|
+
|
|
1455
1550
|
// src/combinators/sequence.ts
|
|
1456
1551
|
function sequence(...parsers) {
|
|
1457
1552
|
const meta = {
|
|
@@ -1462,11 +1557,59 @@ function sequence(...parsers) {
|
|
|
1462
1557
|
isTrivia: false
|
|
1463
1558
|
};
|
|
1464
1559
|
const def = { tag: "sequence", parsers };
|
|
1560
|
+
let followSentinels;
|
|
1561
|
+
function parseTolerant(input, pos, ctx) {
|
|
1562
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1563
|
+
const fs = parsers.slice(i + 1).reduce(
|
|
1564
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1565
|
+
{ kind: "empty" }
|
|
1566
|
+
);
|
|
1567
|
+
return firstSetSentinel(fs);
|
|
1568
|
+
});
|
|
1569
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1570
|
+
let cur = pos;
|
|
1571
|
+
const inheritedSync = ctx._sync;
|
|
1572
|
+
try {
|
|
1573
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1574
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1575
|
+
if (ctx.trivia && i > 0) {
|
|
1576
|
+
const mark = saveTriviaMark(ctx);
|
|
1577
|
+
let scanEnd;
|
|
1578
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1579
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1580
|
+
scan.commit();
|
|
1581
|
+
scanEnd = scan.end;
|
|
1582
|
+
} else {
|
|
1583
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1584
|
+
}
|
|
1585
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1586
|
+
if (!result2.ok) return result2;
|
|
1587
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1588
|
+
else rollbackTrivia(ctx, mark);
|
|
1589
|
+
if (values !== void 0) values.push(result2.value);
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1593
|
+
if (!result.ok) return result;
|
|
1594
|
+
if (values !== void 0) values.push(result.value);
|
|
1595
|
+
cur = result.span.end;
|
|
1596
|
+
}
|
|
1597
|
+
} finally {
|
|
1598
|
+
ctx._sync = inheritedSync;
|
|
1599
|
+
}
|
|
1600
|
+
return {
|
|
1601
|
+
ok: true,
|
|
1602
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1603
|
+
value: values ?? void 0,
|
|
1604
|
+
span: { start: pos, end: cur }
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1465
1607
|
return {
|
|
1466
1608
|
_tag: "sequence",
|
|
1467
1609
|
_meta: meta,
|
|
1468
1610
|
_def: def,
|
|
1469
1611
|
parse(input, pos, ctx) {
|
|
1612
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1470
1613
|
const values = def.valueUnused ? void 0 : [];
|
|
1471
1614
|
let cur = pos;
|
|
1472
1615
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1505,6 +1648,69 @@ function sequence(...parsers) {
|
|
|
1505
1648
|
};
|
|
1506
1649
|
}
|
|
1507
1650
|
|
|
1651
|
+
// src/combinators/expect.ts
|
|
1652
|
+
function deriveExpected(c) {
|
|
1653
|
+
const def = c._def;
|
|
1654
|
+
switch (def.tag) {
|
|
1655
|
+
case "literal":
|
|
1656
|
+
return [JSON.stringify(def.value)];
|
|
1657
|
+
case "regex":
|
|
1658
|
+
return [`/${def.source}/`];
|
|
1659
|
+
case "keywords":
|
|
1660
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1661
|
+
case "label":
|
|
1662
|
+
return [def.label];
|
|
1663
|
+
case "choice":
|
|
1664
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1665
|
+
case "sequence":
|
|
1666
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1667
|
+
case "node":
|
|
1668
|
+
case "grammar":
|
|
1669
|
+
case "trivia":
|
|
1670
|
+
case "token":
|
|
1671
|
+
case "optional":
|
|
1672
|
+
case "many":
|
|
1673
|
+
case "oneOrMore":
|
|
1674
|
+
case "transform":
|
|
1675
|
+
case "not":
|
|
1676
|
+
return deriveExpected(def.parser);
|
|
1677
|
+
case "lazy": {
|
|
1678
|
+
const name = c._ruleName;
|
|
1679
|
+
try {
|
|
1680
|
+
return deriveExpected(def.thunk());
|
|
1681
|
+
} catch {
|
|
1682
|
+
return name ? [name] : [];
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
default:
|
|
1686
|
+
return [];
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
function expect(combinator, label2) {
|
|
1690
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1691
|
+
const meta = {
|
|
1692
|
+
firstSet: combinator._meta.firstSet,
|
|
1693
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1694
|
+
isTrivia: false
|
|
1695
|
+
};
|
|
1696
|
+
return {
|
|
1697
|
+
_tag: "expect",
|
|
1698
|
+
_meta: meta,
|
|
1699
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1700
|
+
parse(input, pos, ctx) {
|
|
1701
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1702
|
+
if (result.ok) return result;
|
|
1703
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
1704
|
+
ctx._errors?.push(error);
|
|
1705
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1706
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
function isParseError(value) {
|
|
1711
|
+
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1508
1714
|
// src/combinators/repeat.ts
|
|
1509
1715
|
function repItem(combinator, input, cur, ctx) {
|
|
1510
1716
|
const mark = saveTriviaMark(ctx);
|
|
@@ -1525,7 +1731,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1525
1731
|
const result = combinator.parse(input, pos, ctx);
|
|
1526
1732
|
if (!result.ok) {
|
|
1527
1733
|
rollbackTrivia(ctx, mark);
|
|
1528
|
-
return { fail: result };
|
|
1734
|
+
return { fail: result, failPos: pos };
|
|
1529
1735
|
}
|
|
1530
1736
|
if (result.span.end === pos) {
|
|
1531
1737
|
rollbackTrivia(ctx, mark);
|
|
@@ -1540,6 +1746,7 @@ function many(combinator) {
|
|
|
1540
1746
|
isTrivia: false
|
|
1541
1747
|
};
|
|
1542
1748
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1749
|
+
let expected;
|
|
1543
1750
|
return {
|
|
1544
1751
|
_tag: "many",
|
|
1545
1752
|
_meta: meta,
|
|
@@ -1549,7 +1756,18 @@ function many(combinator) {
|
|
|
1549
1756
|
let cur = pos;
|
|
1550
1757
|
while (cur < input.length) {
|
|
1551
1758
|
const item = repItem(combinator, input, cur, ctx);
|
|
1552
|
-
if (item === "stop"
|
|
1759
|
+
if (item === "stop") break;
|
|
1760
|
+
if ("fail" in item) {
|
|
1761
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1762
|
+
if (sync === void 0) break;
|
|
1763
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1764
|
+
expected ??= deriveExpected(combinator);
|
|
1765
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1766
|
+
if (values !== void 0) values.push(error);
|
|
1767
|
+
captureError(ctx, error);
|
|
1768
|
+
cur = end;
|
|
1769
|
+
continue;
|
|
1770
|
+
}
|
|
1553
1771
|
if (values !== void 0) values.push(item.value);
|
|
1554
1772
|
cur = item.end;
|
|
1555
1773
|
}
|
|
@@ -1564,6 +1782,7 @@ function oneOrMore(combinator) {
|
|
|
1564
1782
|
isTrivia: false
|
|
1565
1783
|
};
|
|
1566
1784
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1785
|
+
let expected;
|
|
1567
1786
|
return {
|
|
1568
1787
|
_tag: "oneOrMore",
|
|
1569
1788
|
_meta: meta,
|
|
@@ -1575,7 +1794,18 @@ function oneOrMore(combinator) {
|
|
|
1575
1794
|
let cur = first.span.end;
|
|
1576
1795
|
while (cur < input.length) {
|
|
1577
1796
|
const item = repItem(combinator, input, cur, ctx);
|
|
1578
|
-
if (item === "stop"
|
|
1797
|
+
if (item === "stop") break;
|
|
1798
|
+
if ("fail" in item) {
|
|
1799
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1800
|
+
if (sync === void 0) break;
|
|
1801
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1802
|
+
expected ??= deriveExpected(combinator);
|
|
1803
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1804
|
+
if (values !== void 0) values.push(error);
|
|
1805
|
+
captureError(ctx, error);
|
|
1806
|
+
cur = end;
|
|
1807
|
+
continue;
|
|
1808
|
+
}
|
|
1579
1809
|
if (values !== void 0) values.push(item.value);
|
|
1580
1810
|
cur = item.end;
|
|
1581
1811
|
}
|
|
@@ -1621,15 +1851,29 @@ function sepBy(combinator, separator) {
|
|
|
1621
1851
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1622
1852
|
isTrivia: false
|
|
1623
1853
|
};
|
|
1854
|
+
let expected;
|
|
1624
1855
|
return {
|
|
1625
1856
|
_tag: "sepBy",
|
|
1626
1857
|
_meta: meta,
|
|
1627
1858
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1628
1859
|
parse(input, pos, ctx) {
|
|
1629
1860
|
const first = combinator.parse(input, pos, ctx);
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1861
|
+
const values = [];
|
|
1862
|
+
let cur;
|
|
1863
|
+
if (first.ok) {
|
|
1864
|
+
values.push(first.value);
|
|
1865
|
+
cur = first.span.end;
|
|
1866
|
+
} else {
|
|
1867
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1868
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1869
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1870
|
+
}
|
|
1871
|
+
expected ??= deriveExpected(combinator);
|
|
1872
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1873
|
+
values.push(rec.error);
|
|
1874
|
+
captureError(ctx, rec.error);
|
|
1875
|
+
cur = rec.end;
|
|
1876
|
+
}
|
|
1633
1877
|
while (cur < input.length) {
|
|
1634
1878
|
const loopMark = saveTriviaMark(ctx);
|
|
1635
1879
|
let sepPos = cur;
|
|
@@ -1659,6 +1903,15 @@ function sepBy(combinator, separator) {
|
|
|
1659
1903
|
}
|
|
1660
1904
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1661
1905
|
if (!next.ok) {
|
|
1906
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1907
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
1908
|
+
expected ??= deriveExpected(combinator);
|
|
1909
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
1910
|
+
values.push(rec.error);
|
|
1911
|
+
captureError(ctx, rec.error);
|
|
1912
|
+
cur = rec.end;
|
|
1913
|
+
continue;
|
|
1914
|
+
}
|
|
1662
1915
|
rollbackTrivia(ctx, loopMark);
|
|
1663
1916
|
break;
|
|
1664
1917
|
}
|
|
@@ -1832,7 +2085,7 @@ function rules(a, b) {
|
|
|
1832
2085
|
cache[key] = parser2;
|
|
1833
2086
|
}
|
|
1834
2087
|
}
|
|
1835
|
-
if (options?.trivia
|
|
2088
|
+
if (options?.trivia != null) {
|
|
1836
2089
|
for (const key of Object.keys(definitions)) {
|
|
1837
2090
|
const rule = cache[key];
|
|
1838
2091
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1862,7 +2115,9 @@ function not(combinator) {
|
|
|
1862
2115
|
_meta: meta,
|
|
1863
2116
|
_def: { tag: "not", parser: combinator },
|
|
1864
2117
|
parse(input, pos, ctx) {
|
|
2118
|
+
const mark = saveCstMark(ctx);
|
|
1865
2119
|
const result = combinator.parse(input, pos, ctx);
|
|
2120
|
+
rollbackCstCapture(ctx, mark);
|
|
1866
2121
|
if (result.ok) {
|
|
1867
2122
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1868
2123
|
}
|
|
@@ -1976,7 +2231,7 @@ function unwrapChild(child) {
|
|
|
1976
2231
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1977
2232
|
}
|
|
1978
2233
|
function isCstChild(value) {
|
|
1979
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2234
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
1980
2235
|
}
|
|
1981
2236
|
function missingInferredType() {
|
|
1982
2237
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2254,65 +2509,6 @@ function token(root) {
|
|
|
2254
2509
|
};
|
|
2255
2510
|
}
|
|
2256
2511
|
|
|
2257
|
-
// src/combinators/expect.ts
|
|
2258
|
-
function deriveExpected(c) {
|
|
2259
|
-
const def = c._def;
|
|
2260
|
-
switch (def.tag) {
|
|
2261
|
-
case "literal":
|
|
2262
|
-
return [JSON.stringify(def.value)];
|
|
2263
|
-
case "regex":
|
|
2264
|
-
return [`/${def.source}/`];
|
|
2265
|
-
case "keywords":
|
|
2266
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2267
|
-
case "label":
|
|
2268
|
-
return [def.label];
|
|
2269
|
-
case "choice":
|
|
2270
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2271
|
-
case "sequence":
|
|
2272
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2273
|
-
case "node":
|
|
2274
|
-
case "grammar":
|
|
2275
|
-
case "trivia":
|
|
2276
|
-
case "token":
|
|
2277
|
-
case "optional":
|
|
2278
|
-
case "many":
|
|
2279
|
-
case "oneOrMore":
|
|
2280
|
-
case "transform":
|
|
2281
|
-
case "not":
|
|
2282
|
-
return deriveExpected(def.parser);
|
|
2283
|
-
case "lazy": {
|
|
2284
|
-
const name = c._ruleName;
|
|
2285
|
-
try {
|
|
2286
|
-
return deriveExpected(def.thunk());
|
|
2287
|
-
} catch {
|
|
2288
|
-
return name ? [name] : [];
|
|
2289
|
-
}
|
|
2290
|
-
}
|
|
2291
|
-
default:
|
|
2292
|
-
return [];
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
function expect(combinator, label2) {
|
|
2296
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2297
|
-
const meta = {
|
|
2298
|
-
firstSet: combinator._meta.firstSet,
|
|
2299
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2300
|
-
isTrivia: false
|
|
2301
|
-
};
|
|
2302
|
-
return {
|
|
2303
|
-
_tag: "expect",
|
|
2304
|
-
_meta: meta,
|
|
2305
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2306
|
-
parse(input, pos, ctx) {
|
|
2307
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2308
|
-
if (result.ok) return result;
|
|
2309
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2310
|
-
ctx._errors?.push(error);
|
|
2311
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2312
|
-
}
|
|
2313
|
-
};
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
2512
|
// src/compiler/scannable-run.ts
|
|
2317
2513
|
var BACKSLASH = 92;
|
|
2318
2514
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2384,20 +2580,39 @@ function parseSeqParts(source) {
|
|
|
2384
2580
|
lit = [];
|
|
2385
2581
|
}
|
|
2386
2582
|
};
|
|
2387
|
-
const
|
|
2583
|
+
const braceQuant = (at) => {
|
|
2584
|
+
const close = source.indexOf("}", at);
|
|
2585
|
+
if (close === -1) return null;
|
|
2586
|
+
const body = source.slice(at + 1, close);
|
|
2587
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2588
|
+
if (!m) return null;
|
|
2589
|
+
const min = Number(m[1]);
|
|
2590
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2591
|
+
if (max < 1 || min > max) return null;
|
|
2592
|
+
return { min, max, len: close - at + 1 };
|
|
2593
|
+
};
|
|
2594
|
+
const runFrom = (ranges, negated, at) => {
|
|
2595
|
+
const q = source[at];
|
|
2388
2596
|
if (q === "+") {
|
|
2389
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2597
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2390
2598
|
return 1;
|
|
2391
2599
|
}
|
|
2392
2600
|
if (q === "*") {
|
|
2393
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2601
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2394
2602
|
return 1;
|
|
2395
2603
|
}
|
|
2396
2604
|
if (q === "?") {
|
|
2397
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2605
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2398
2606
|
return 1;
|
|
2399
2607
|
}
|
|
2400
|
-
|
|
2608
|
+
if (q === "{") {
|
|
2609
|
+
const b = braceQuant(at);
|
|
2610
|
+
if (b) {
|
|
2611
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2612
|
+
return b.len;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2401
2616
|
return 0;
|
|
2402
2617
|
};
|
|
2403
2618
|
let i = 0;
|
|
@@ -2422,7 +2637,7 @@ function parseSeqParts(source) {
|
|
|
2422
2637
|
if (!ranges) return null;
|
|
2423
2638
|
flush();
|
|
2424
2639
|
i = k + 1;
|
|
2425
|
-
i += runFrom(ranges, neg,
|
|
2640
|
+
i += runFrom(ranges, neg, i);
|
|
2426
2641
|
continue;
|
|
2427
2642
|
}
|
|
2428
2643
|
if (ch === "\\") {
|
|
@@ -2430,7 +2645,7 @@ function parseSeqParts(source) {
|
|
|
2430
2645
|
if (e === "d" || e === "w" || e === "s") {
|
|
2431
2646
|
flush();
|
|
2432
2647
|
i += 2;
|
|
2433
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2648
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2434
2649
|
continue;
|
|
2435
2650
|
}
|
|
2436
2651
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2519,7 +2734,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2519
2734
|
let hasMandatory = false;
|
|
2520
2735
|
for (let k = 0; k < parts.length; k++) {
|
|
2521
2736
|
const p = parts[k];
|
|
2522
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2737
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2523
2738
|
if (mandatory) hasMandatory = true;
|
|
2524
2739
|
if (p.part === "group") {
|
|
2525
2740
|
const exposure = groupPartExposure(p);
|
|
@@ -2530,9 +2745,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2530
2745
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2531
2746
|
}
|
|
2532
2747
|
}
|
|
2533
|
-
const
|
|
2534
|
-
|
|
2535
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2748
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2749
|
+
if (needsDisjoint) {
|
|
2536
2750
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2537
2751
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2538
2752
|
}
|
|
@@ -2589,8 +2803,8 @@ function fixedClassSeq(shape) {
|
|
|
2589
2803
|
if (p.part === "lit") {
|
|
2590
2804
|
if (p.optional) return null;
|
|
2591
2805
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2592
|
-
} else if (p.part === "run" &&
|
|
2593
|
-
out.push({ ranges: p.ranges, negated: p.negated });
|
|
2806
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2807
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2594
2808
|
} else {
|
|
2595
2809
|
return null;
|
|
2596
2810
|
}
|
|
@@ -2642,7 +2856,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2642
2856
|
const last = shape.parts[shape.parts.length - 1];
|
|
2643
2857
|
if (last.part === "lit") return null;
|
|
2644
2858
|
if (last.part === "run") {
|
|
2645
|
-
if (last.
|
|
2859
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2646
2860
|
return null;
|
|
2647
2861
|
}
|
|
2648
2862
|
return groupPartExposure(last);
|
|
@@ -2779,7 +2993,7 @@ function partFirstAccept(part) {
|
|
|
2779
2993
|
function seqFirstAccept(parts) {
|
|
2780
2994
|
const sets = [];
|
|
2781
2995
|
for (const p of parts) {
|
|
2782
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2996
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2783
2997
|
sets.push(partFirstAccept(p));
|
|
2784
2998
|
if (mandatory) break;
|
|
2785
2999
|
}
|
|
@@ -3194,7 +3408,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3194
3408
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3195
3409
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3196
3410
|
}
|
|
3197
|
-
} else if (p.part === "run" &&
|
|
3411
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3412
|
+
const s = mint("_s");
|
|
3413
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3414
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3415
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3416
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3417
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3198
3418
|
if (p.min === 1) {
|
|
3199
3419
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3200
3420
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3204,8 +3424,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3204
3424
|
} else if (p.part === "run") {
|
|
3205
3425
|
const s = mint("_s");
|
|
3206
3426
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3207
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3208
|
-
if (p.min
|
|
3427
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3428
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3209
3429
|
} else {
|
|
3210
3430
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3211
3431
|
if (!p.unbounded) {
|
|
@@ -3664,21 +3884,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3664
3884
|
}
|
|
3665
3885
|
return name;
|
|
3666
3886
|
}
|
|
3887
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3888
|
+
if (!ctx.recovery) return "";
|
|
3889
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3890
|
+
const pb = v(ctx, "_pb");
|
|
3891
|
+
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} } } } `;
|
|
3892
|
+
}
|
|
3667
3893
|
function failBody(ctx, expected, posExpr) {
|
|
3894
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3668
3895
|
if (ctx.failLabel) {
|
|
3669
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3670
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3896
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3897
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3671
3898
|
}
|
|
3672
|
-
return failReturn(expected, posExpr);
|
|
3899
|
+
return probe + failReturn(expected, posExpr);
|
|
3673
3900
|
}
|
|
3674
3901
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3902
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3675
3903
|
if (ctx.failLabel) {
|
|
3676
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3904
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3677
3905
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3678
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3906
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3679
3907
|
}
|
|
3680
|
-
if (!constant) return
|
|
3681
|
-
return failReturnArr(expectedArr, posExpr);
|
|
3908
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3909
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3682
3910
|
}
|
|
3683
3911
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3684
3912
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4178,6 +4406,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4178
4406
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4179
4407
|
return { stmts, valueVar: vv, endVar };
|
|
4180
4408
|
}
|
|
4409
|
+
function syncSentinelExpr(fs) {
|
|
4410
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
4411
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs.ranges)} })`;
|
|
4412
|
+
}
|
|
4181
4413
|
function emitSeqValues(def, ctx, pos) {
|
|
4182
4414
|
const startV = v(ctx, "_start");
|
|
4183
4415
|
const curV = v(ctx, "_cur");
|
|
@@ -4186,7 +4418,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4186
4418
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4187
4419
|
];
|
|
4188
4420
|
const valueVars = [];
|
|
4421
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4422
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4423
|
+
const publishSync = (i) => {
|
|
4424
|
+
if (!ctx.recovery) return "";
|
|
4425
|
+
const fs = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4426
|
+
const ref2 = syncSentinelExpr(fs);
|
|
4427
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4428
|
+
};
|
|
4189
4429
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4430
|
+
const syncPub = publishSync(i);
|
|
4431
|
+
if (syncPub) stmts.push(syncPub);
|
|
4190
4432
|
if (i > 0 && ctx.activeTrivia) {
|
|
4191
4433
|
if (ctx.capturing) {
|
|
4192
4434
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4211,7 +4453,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4211
4453
|
continue;
|
|
4212
4454
|
} else {
|
|
4213
4455
|
const trivFn = ensureTriviaFn(ctx);
|
|
4214
|
-
|
|
4456
|
+
const scanEndV = v(ctx, "_sne");
|
|
4457
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4458
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4459
|
+
stmts.push(...r2.stmts);
|
|
4460
|
+
const endAfterV = v(ctx, "_sea");
|
|
4461
|
+
stmts.push(
|
|
4462
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4463
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4464
|
+
);
|
|
4465
|
+
valueVars.push(r2.valueVar);
|
|
4466
|
+
continue;
|
|
4215
4467
|
}
|
|
4216
4468
|
}
|
|
4217
4469
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4441,7 +4693,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4441
4693
|
if (gate) {
|
|
4442
4694
|
const gateIdx = ctx.mapFns.length;
|
|
4443
4695
|
ctx.mapFns.push(gate);
|
|
4444
|
-
ctx.mapFnSrcs.push(null);
|
|
4696
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4445
4697
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4446
4698
|
}
|
|
4447
4699
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4546,6 +4798,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4546
4798
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4547
4799
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4548
4800
|
];
|
|
4801
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4802
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4549
4803
|
if (def.min === 1) {
|
|
4550
4804
|
const firstR = emit(def.parser, ctx, curV);
|
|
4551
4805
|
stmts.push(...firstR.stmts);
|
|
@@ -4579,10 +4833,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4579
4833
|
}
|
|
4580
4834
|
}
|
|
4581
4835
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4582
|
-
stmts.push(
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4836
|
+
stmts.push(...iterStmts);
|
|
4837
|
+
if (ctx.recovery) {
|
|
4838
|
+
const rrV = v(ctx, "_rr");
|
|
4839
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4840
|
+
stmts.push(
|
|
4841
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4842
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4843
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4844
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4845
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4846
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4847
|
+
`${ind(ctx)} continue`,
|
|
4848
|
+
`${ind(ctx)} }`,
|
|
4849
|
+
`${ind(ctx)} break`,
|
|
4850
|
+
`${ind(ctx)}}`,
|
|
4851
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4852
|
+
);
|
|
4853
|
+
} else {
|
|
4854
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4855
|
+
}
|
|
4586
4856
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4587
4857
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4588
4858
|
ctx.indent--;
|
|
@@ -4604,20 +4874,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4604
4874
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4605
4875
|
const arrV = v(ctx, "_arr");
|
|
4606
4876
|
const curV = v(ctx, "_cur");
|
|
4877
|
+
const rec = !!ctx.recovery;
|
|
4878
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4879
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4880
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4881
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4607
4882
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4608
4883
|
const stmts = [
|
|
4609
4884
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4610
4885
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4611
|
-
...
|
|
4612
|
-
|
|
4886
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4887
|
+
...firstStmts
|
|
4613
4888
|
];
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
)
|
|
4620
|
-
|
|
4889
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4890
|
+
if (!rec) return [originalFail];
|
|
4891
|
+
const rr = v(ctx, "_rr");
|
|
4892
|
+
return [
|
|
4893
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
4894
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
4895
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
4896
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
4897
|
+
`${ind(ctx)} }`,
|
|
4898
|
+
`${ind(ctx)} ${rb}break`,
|
|
4899
|
+
`${ind(ctx)}}`
|
|
4900
|
+
];
|
|
4901
|
+
};
|
|
4902
|
+
if (rec) {
|
|
4903
|
+
const rr0 = v(ctx, "_rr0");
|
|
4904
|
+
const didV = v(ctx, "_did");
|
|
4905
|
+
stmts.push(
|
|
4906
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
4907
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
4908
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
4909
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
4910
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
4911
|
+
`${ind(ctx)}}`,
|
|
4912
|
+
`${ind(ctx)}if (${didV}) {`
|
|
4913
|
+
);
|
|
4914
|
+
ctx.indent++;
|
|
4915
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
4916
|
+
ctx.indent++;
|
|
4917
|
+
} else {
|
|
4918
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
4919
|
+
ctx.indent++;
|
|
4920
|
+
stmts.push(
|
|
4921
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
4922
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
4923
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
4924
|
+
);
|
|
4925
|
+
ctx.indent++;
|
|
4926
|
+
}
|
|
4621
4927
|
let sepAtPos = curV;
|
|
4622
4928
|
if (ctx.activeTrivia) {
|
|
4623
4929
|
if (ctx.capturing) {
|
|
@@ -4643,8 +4949,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4643
4949
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4644
4950
|
stmts.push(
|
|
4645
4951
|
...nextStmts,
|
|
4646
|
-
|
|
4647
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
4952
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4648
4953
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4649
4954
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4650
4955
|
);
|
|
@@ -4660,7 +4965,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4660
4965
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4661
4966
|
stmts.push(
|
|
4662
4967
|
...nextStmts,
|
|
4663
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
4968
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4664
4969
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4665
4970
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4666
4971
|
);
|
|
@@ -4680,7 +4985,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4680
4985
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4681
4986
|
stmts.push(
|
|
4682
4987
|
...nextStmts,
|
|
4683
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
4988
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4684
4989
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4685
4990
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4686
4991
|
);
|
|
@@ -4937,7 +5242,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4937
5242
|
stmts.push(
|
|
4938
5243
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4939
5244
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4940
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === '
|
|
5245
|
+
`${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} } })`
|
|
4941
5246
|
);
|
|
4942
5247
|
return { stmts, valueVar: ndV, endVar };
|
|
4943
5248
|
}
|
|
@@ -5027,6 +5332,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5027
5332
|
`${ind0}if (!${okVar}) {`,
|
|
5028
5333
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5029
5334
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5335
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5336
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5337
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5338
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5030
5339
|
`${ind0} ${valVar} = ${errV}`,
|
|
5031
5340
|
`${ind0} ${endVar} = ${pos}`,
|
|
5032
5341
|
`${ind0} ${okVar} = true`,
|
|
@@ -5193,7 +5502,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5193
5502
|
case "guard": {
|
|
5194
5503
|
const fnIdx = ctx.mapFns.length;
|
|
5195
5504
|
ctx.mapFns.push(def.predicate);
|
|
5196
|
-
ctx.mapFnSrcs.push(null);
|
|
5505
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5197
5506
|
const vv = v(ctx);
|
|
5198
5507
|
return {
|
|
5199
5508
|
stmts: [
|
|
@@ -5208,7 +5517,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5208
5517
|
const evIdx = ctx.mapFns.length;
|
|
5209
5518
|
const extra = def.extra;
|
|
5210
5519
|
ctx.mapFns.push((() => extra));
|
|
5211
|
-
ctx.mapFnSrcs.push(null);
|
|
5520
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5212
5521
|
const innerParser = def.parser;
|
|
5213
5522
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5214
5523
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5452,7 +5761,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5452
5761
|
}
|
|
5453
5762
|
return deps;
|
|
5454
5763
|
}
|
|
5455
|
-
function compile(combinator, mapFnSources) {
|
|
5764
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5456
5765
|
markUnusedValues(combinator);
|
|
5457
5766
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5458
5767
|
const ctx = {
|
|
@@ -5473,6 +5782,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5473
5782
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5474
5783
|
namedFnDecls: [],
|
|
5475
5784
|
capturing: hasNodeDef(combinator),
|
|
5785
|
+
recovery: opts?.recovery ?? false,
|
|
5476
5786
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5477
5787
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5478
5788
|
};
|
|
@@ -5525,7 +5835,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5525
5835
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5526
5836
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5527
5837
|
},
|
|
5528
|
-
// Note: collects
|
|
5838
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5529
5839
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5530
5840
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5531
5841
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5582,6 +5892,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5582
5892
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5583
5893
|
namedFnDecls: [],
|
|
5584
5894
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5895
|
+
recovery: opts?.recovery ?? false,
|
|
5585
5896
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5586
5897
|
ns,
|
|
5587
5898
|
deferFirstSetRefs: true,
|
|
@@ -6327,46 +6638,13 @@ function withCtx(extra, combinator) {
|
|
|
6327
6638
|
};
|
|
6328
6639
|
}
|
|
6329
6640
|
|
|
6330
|
-
// src/combinators/recover.ts
|
|
6331
|
-
function recover(combinator, sentinel) {
|
|
6332
|
-
const meta = {
|
|
6333
|
-
firstSet: { kind: "any" },
|
|
6334
|
-
canMatchNewline: true,
|
|
6335
|
-
isTrivia: false
|
|
6336
|
-
};
|
|
6337
|
-
const expected = deriveExpected(combinator);
|
|
6338
|
-
return {
|
|
6339
|
-
_tag: "recover",
|
|
6340
|
-
_meta: meta,
|
|
6341
|
-
_def: { tag: "recover", parser: combinator, sentinel },
|
|
6342
|
-
parse(input, pos, ctx) {
|
|
6343
|
-
const result = combinator.parse(input, pos, ctx);
|
|
6344
|
-
if (result.ok) return result;
|
|
6345
|
-
let scanPos = pos;
|
|
6346
|
-
while (scanPos < input.length) {
|
|
6347
|
-
if (sentinel.parse(input, scanPos, ctx).ok) break;
|
|
6348
|
-
scanPos++;
|
|
6349
|
-
}
|
|
6350
|
-
const error = {
|
|
6351
|
-
_tag: "parseError",
|
|
6352
|
-
span: { start: pos, end: scanPos },
|
|
6353
|
-
expected
|
|
6354
|
-
};
|
|
6355
|
-
ctx._errors?.push(error);
|
|
6356
|
-
return { ok: true, value: error, span: { start: pos, end: scanPos } };
|
|
6357
|
-
}
|
|
6358
|
-
};
|
|
6359
|
-
}
|
|
6360
|
-
function isParseError(value) {
|
|
6361
|
-
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
6362
|
-
}
|
|
6363
|
-
|
|
6364
6641
|
// src/combinators/completions.ts
|
|
6365
|
-
function completionsAt(
|
|
6642
|
+
function completionsAt(target, input, offset, options = {}) {
|
|
6366
6643
|
const probe = { offset, best: null };
|
|
6367
|
-
const ctx = { trackLines: false, _probe: probe };
|
|
6368
|
-
const
|
|
6369
|
-
|
|
6644
|
+
const ctx = { trackLines: false, _probe: probe, ...options.tolerant ? { _tolerant: true, _rec: REC } : {} };
|
|
6645
|
+
const sliced = input.slice(0, offset);
|
|
6646
|
+
const result = "parseWithContext" in target ? target.parseWithContext(sliced, ctx, 0) : target.parse(sliced, 0, ctx);
|
|
6647
|
+
if (result.ok) return options.tolerant ? probe.best?.expected ?? [] : [];
|
|
6370
6648
|
const best = deeperFail(probe.best, result);
|
|
6371
6649
|
return best?.expected ?? [];
|
|
6372
6650
|
}
|
|
@@ -6376,34 +6654,162 @@ function deeperFail(a, b) {
|
|
|
6376
6654
|
return a.span.start >= b.span.start ? a : b;
|
|
6377
6655
|
}
|
|
6378
6656
|
|
|
6379
|
-
// src/
|
|
6380
|
-
function
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6657
|
+
// src/cst/relative-spans.ts
|
|
6658
|
+
function relativize(node2, parentBase = 0) {
|
|
6659
|
+
return {
|
|
6660
|
+
start: node2.start - parentBase,
|
|
6661
|
+
end: node2.end - parentBase,
|
|
6662
|
+
children: node2.children.map((c) => relativize(c, node2.start))
|
|
6663
|
+
};
|
|
6664
|
+
}
|
|
6665
|
+
function absolutize(node2, parentBase = 0) {
|
|
6666
|
+
const start = parentBase + node2.start;
|
|
6667
|
+
return {
|
|
6668
|
+
start,
|
|
6669
|
+
end: parentBase + node2.end,
|
|
6670
|
+
children: node2.children.map((c) => absolutize(c, start))
|
|
6671
|
+
};
|
|
6672
|
+
}
|
|
6673
|
+
function absoluteSpanAt(root, path) {
|
|
6674
|
+
let base = 0;
|
|
6675
|
+
let node2 = root;
|
|
6676
|
+
for (const idx of path) {
|
|
6677
|
+
base += node2.start;
|
|
6678
|
+
const child = node2.children[idx];
|
|
6679
|
+
if (!child) throw new RangeError(`absoluteSpanAt: no child ${idx} on path ${path.join(".")}`);
|
|
6680
|
+
node2 = child;
|
|
6681
|
+
}
|
|
6682
|
+
return { start: base + node2.start, end: base + node2.end };
|
|
6683
|
+
}
|
|
6684
|
+
function relativizeCST(node2, parentBase = 0) {
|
|
6685
|
+
const span = { start: node2.span.start - parentBase, end: node2.span.end - parentBase };
|
|
6686
|
+
if (node2.children) {
|
|
6687
|
+
const base = node2.span.start;
|
|
6688
|
+
return { ...node2, span, children: node2.children.map((c) => relativizeCST(c, base)) };
|
|
6689
|
+
}
|
|
6690
|
+
return { ...node2, span };
|
|
6691
|
+
}
|
|
6692
|
+
function absolutizeCST(node2, parentBase = 0) {
|
|
6693
|
+
const start = parentBase + node2.span.start;
|
|
6694
|
+
const span = { start, end: parentBase + node2.span.end };
|
|
6695
|
+
if (node2.children) {
|
|
6696
|
+
return { ...node2, span, children: node2.children.map((c) => absolutizeCST(c, start)) };
|
|
6697
|
+
}
|
|
6698
|
+
return { ...node2, span };
|
|
6699
|
+
}
|
|
6700
|
+
function absoluteSpanCST(root, path) {
|
|
6701
|
+
let base = 0;
|
|
6702
|
+
let node2 = root;
|
|
6703
|
+
for (const idx of path) {
|
|
6704
|
+
base += node2.span.start;
|
|
6705
|
+
const child = node2.children?.[idx];
|
|
6706
|
+
if (!child) throw new RangeError(`absoluteSpanCST: no child ${idx} on path ${path.join(".")}`);
|
|
6707
|
+
node2 = child;
|
|
6708
|
+
}
|
|
6709
|
+
return { start: base + node2.span.start, end: base + node2.span.end };
|
|
6387
6710
|
}
|
|
6388
|
-
function
|
|
6389
|
-
const
|
|
6390
|
-
|
|
6711
|
+
function shiftAbsolute(node2, at, delta) {
|
|
6712
|
+
const s = node2.start >= at ? node2.start + delta : node2.start;
|
|
6713
|
+
const e = node2.end >= at ? node2.end + delta : node2.end;
|
|
6714
|
+
return {
|
|
6715
|
+
start: s,
|
|
6716
|
+
end: e,
|
|
6717
|
+
children: node2.children.map((c) => shiftAbsolute(c, at, delta))
|
|
6718
|
+
};
|
|
6391
6719
|
}
|
|
6392
|
-
function
|
|
6393
|
-
return
|
|
6720
|
+
function applyEdit(root, at, delta, stats) {
|
|
6721
|
+
return editNode(root, at, delta, 0, 0, stats);
|
|
6722
|
+
}
|
|
6723
|
+
function editNode(node2, at, delta, parentBase, parentShift, stats) {
|
|
6724
|
+
const absStart = parentBase + node2.start;
|
|
6725
|
+
const absEnd = parentBase + node2.end;
|
|
6726
|
+
if (absEnd < at) return node2;
|
|
6727
|
+
const startShifts = absStart >= at;
|
|
6728
|
+
if (startShifts && parentShift === delta) return node2;
|
|
6729
|
+
if (stats) stats.allocated++;
|
|
6730
|
+
const newAbsStart = startShifts ? absStart + delta : absStart;
|
|
6731
|
+
const newAbsEnd = absEnd + delta;
|
|
6732
|
+
const newParentBase = parentBase + parentShift;
|
|
6733
|
+
const newStart = newAbsStart - newParentBase;
|
|
6734
|
+
const newEnd = newAbsEnd - newParentBase;
|
|
6735
|
+
const ownShift = newAbsStart - absStart;
|
|
6736
|
+
let changed = false;
|
|
6737
|
+
const newChildren = [];
|
|
6738
|
+
for (const c of node2.children) {
|
|
6739
|
+
const nc = editNode(c, at, delta, absStart, ownShift, stats);
|
|
6740
|
+
if (nc !== c) changed = true;
|
|
6741
|
+
newChildren.push(nc);
|
|
6742
|
+
}
|
|
6743
|
+
return {
|
|
6744
|
+
start: newStart,
|
|
6745
|
+
end: newEnd,
|
|
6746
|
+
children: changed ? newChildren : node2.children
|
|
6747
|
+
};
|
|
6394
6748
|
}
|
|
6395
6749
|
|
|
6396
6750
|
// src/functional/doc.ts
|
|
6751
|
+
function mkCtx(state, build, tolerant) {
|
|
6752
|
+
return tolerant ? { trackLines: false, state, build, _tolerant: true, _rec: REC, _errors: [] } : { trackLines: false, state, build };
|
|
6753
|
+
}
|
|
6754
|
+
function asRuleFn(entry) {
|
|
6755
|
+
return typeof entry === "function" ? entry : (input, pos, ctx) => entry.parse(input, pos, ctx);
|
|
6756
|
+
}
|
|
6757
|
+
function defOf(entry) {
|
|
6758
|
+
return typeof entry === "object" && entry !== null && "_def" in entry ? entry._def : void 0;
|
|
6759
|
+
}
|
|
6760
|
+
function producesRepetition(def, depth = 0) {
|
|
6761
|
+
if (!def || depth > 24) return false;
|
|
6762
|
+
const d = def;
|
|
6763
|
+
switch (d.tag) {
|
|
6764
|
+
case "sepBy":
|
|
6765
|
+
case "many":
|
|
6766
|
+
case "oneOrMore":
|
|
6767
|
+
return true;
|
|
6768
|
+
// Rule entries and `ref`s wrap their body in a `lazy` thunk — resolve it. The
|
|
6769
|
+
// `depth` cap bounds any self-referential cycle (a repetition, if present, is
|
|
6770
|
+
// found shallowly before recursion goes deep).
|
|
6771
|
+
case "lazy": {
|
|
6772
|
+
const thunk = d.thunk;
|
|
6773
|
+
let inner;
|
|
6774
|
+
try {
|
|
6775
|
+
inner = typeof thunk === "function" ? thunk() : void 0;
|
|
6776
|
+
} catch {
|
|
6777
|
+
return false;
|
|
6778
|
+
}
|
|
6779
|
+
return producesRepetition(inner?._def, depth + 1);
|
|
6780
|
+
}
|
|
6781
|
+
// Transparent wrappers — look through to the inner parser.
|
|
6782
|
+
case "node":
|
|
6783
|
+
case "transform":
|
|
6784
|
+
case "token":
|
|
6785
|
+
case "label":
|
|
6786
|
+
case "field":
|
|
6787
|
+
case "expect":
|
|
6788
|
+
case "withCtx":
|
|
6789
|
+
case "grammar":
|
|
6790
|
+
case "optional":
|
|
6791
|
+
return producesRepetition(defOf(d.parser), depth + 1);
|
|
6792
|
+
case "skip":
|
|
6793
|
+
return producesRepetition(defOf(d.main), depth + 1);
|
|
6794
|
+
// A bracketed/anchored list is a sequence whose element run is a repetition.
|
|
6795
|
+
case "sequence":
|
|
6796
|
+
return d.parsers.some((p) => producesRepetition(defOf(p), depth + 1));
|
|
6797
|
+
default:
|
|
6798
|
+
return false;
|
|
6799
|
+
}
|
|
6800
|
+
}
|
|
6397
6801
|
var REENTRY_MAX_SPAN_FRACTION = 0.5;
|
|
6398
6802
|
function isNode(x) {
|
|
6399
6803
|
return typeof x === "object" && x !== null && x._tag === "node";
|
|
6400
6804
|
}
|
|
6401
|
-
function findContaining(node2, pos, path = []) {
|
|
6805
|
+
function findContaining(node2, nodeAbsStart, pos, path = []) {
|
|
6402
6806
|
for (let i = 0; i < node2.children.length; i++) {
|
|
6403
6807
|
const child = node2.children[i];
|
|
6404
6808
|
if (!isNode(child)) continue;
|
|
6405
|
-
|
|
6406
|
-
|
|
6809
|
+
const childAbsStart = nodeAbsStart + child.span.start;
|
|
6810
|
+
const childAbsEnd = nodeAbsStart + child.span.end;
|
|
6811
|
+
if (childAbsStart <= pos && pos < childAbsEnd) {
|
|
6812
|
+
const inner = findContaining(child, childAbsStart, pos, [...path, i]);
|
|
6407
6813
|
return inner ?? { node: child, path: [...path, i] };
|
|
6408
6814
|
}
|
|
6409
6815
|
}
|
|
@@ -6430,24 +6836,20 @@ function replaceAtPath(rebuild, root, path, newNode) {
|
|
|
6430
6836
|
function defaultRebuild(node2, children) {
|
|
6431
6837
|
return { ...node2, children };
|
|
6432
6838
|
}
|
|
6433
|
-
function
|
|
6839
|
+
function shiftRelStart(child, delta) {
|
|
6434
6840
|
const c = child;
|
|
6435
|
-
|
|
6436
|
-
if (Array.isArray(c.children)) {
|
|
6437
|
-
return { ...c, span, children: c.children.map((g) => shiftSpans(g, delta)) };
|
|
6438
|
-
}
|
|
6439
|
-
return { ...c, span };
|
|
6841
|
+
return { ...c, span: { start: c.span.start + delta, end: c.span.end + delta } };
|
|
6440
6842
|
}
|
|
6441
|
-
function
|
|
6843
|
+
function graftRelative(root, path, newNode, delta) {
|
|
6442
6844
|
if (path.length === 0) return newNode;
|
|
6443
6845
|
const [idx, ...rest] = path;
|
|
6444
6846
|
const oldChildren = root.children;
|
|
6445
6847
|
const newChildren = oldChildren.map((child, i) => {
|
|
6446
6848
|
if (i < idx) return child;
|
|
6447
6849
|
if (i === idx) {
|
|
6448
|
-
return rest.length === 0 ? newNode :
|
|
6850
|
+
return rest.length === 0 ? newNode : graftRelative(child, rest, newNode, delta);
|
|
6449
6851
|
}
|
|
6450
|
-
return
|
|
6852
|
+
return shiftRelStart(child, delta);
|
|
6451
6853
|
});
|
|
6452
6854
|
return {
|
|
6453
6855
|
...root,
|
|
@@ -6455,6 +6857,96 @@ function graftAndShift(root, path, newNode, delta) {
|
|
|
6455
6857
|
children: newChildren
|
|
6456
6858
|
};
|
|
6457
6859
|
}
|
|
6860
|
+
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build, tolerant) {
|
|
6861
|
+
const ctx = mkCtx(null, build, tolerant);
|
|
6862
|
+
const out = [];
|
|
6863
|
+
let pos = reStart;
|
|
6864
|
+
let guard2 = 0;
|
|
6865
|
+
while (pos < reEnd) {
|
|
6866
|
+
if (++guard2 > reEnd - reStart + 2) return null;
|
|
6867
|
+
if (separator && out.length > 0 && out[out.length - 1]._tag === "node") {
|
|
6868
|
+
if (pos + separator.length > reEnd || !input.startsWith(separator, pos)) return null;
|
|
6869
|
+
out.push({ _tag: "leaf", value: separator, span: { start: pos - cStart, end: pos + separator.length - cStart } });
|
|
6870
|
+
pos += separator.length;
|
|
6871
|
+
continue;
|
|
6872
|
+
}
|
|
6873
|
+
let r;
|
|
6874
|
+
try {
|
|
6875
|
+
r = ruleFn(input, pos, ctx);
|
|
6876
|
+
} catch {
|
|
6877
|
+
return null;
|
|
6878
|
+
}
|
|
6879
|
+
if (!r.ok || r.span.end <= pos || r.span.end > reEnd) return null;
|
|
6880
|
+
out.push(relativizeCST(r.value, cStart));
|
|
6881
|
+
pos = r.span.end;
|
|
6882
|
+
}
|
|
6883
|
+
return pos === reEnd ? out : null;
|
|
6884
|
+
}
|
|
6885
|
+
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build, tolerant) {
|
|
6886
|
+
const kids = C.children;
|
|
6887
|
+
if (kids.length === 0) return null;
|
|
6888
|
+
let h = 0;
|
|
6889
|
+
while (h < kids.length && cStart + kids[h].span.end <= from) h++;
|
|
6890
|
+
while (h > 0 && kids[h - 1]._tag === "node") h--;
|
|
6891
|
+
let t = kids.length;
|
|
6892
|
+
while (t > h && cStart + kids[t - 1].span.start >= to) t--;
|
|
6893
|
+
while (t < kids.length && kids[t]._tag !== "node") t++;
|
|
6894
|
+
if (t >= kids.length) return null;
|
|
6895
|
+
for (let i = t; i < kids.length; i++) {
|
|
6896
|
+
if (kids[i]._tag === "node" && kids[i].state != null) return null;
|
|
6897
|
+
}
|
|
6898
|
+
let elemType;
|
|
6899
|
+
let elemCount = 0;
|
|
6900
|
+
for (const k of kids) {
|
|
6901
|
+
if (k._tag !== "node") continue;
|
|
6902
|
+
elemCount++;
|
|
6903
|
+
if (elemType === void 0) elemType = k.type;
|
|
6904
|
+
else if (k.type !== elemType) return null;
|
|
6905
|
+
}
|
|
6906
|
+
if (elemType === void 0 || elemCount < 2) return null;
|
|
6907
|
+
const ruleFn = registry[elemType];
|
|
6908
|
+
if (!ruleFn) return null;
|
|
6909
|
+
let separator = null;
|
|
6910
|
+
for (let i = 1; i < kids.length - 1; i++) {
|
|
6911
|
+
if (kids[i - 1]._tag === "node" && kids[i + 1]._tag === "node") {
|
|
6912
|
+
if (kids[i]._tag !== "leaf") return null;
|
|
6913
|
+
const sep = kids[i].value ?? null;
|
|
6914
|
+
if (separator === null) separator = sep;
|
|
6915
|
+
else if (sep !== separator) return null;
|
|
6916
|
+
}
|
|
6917
|
+
}
|
|
6918
|
+
if (separator === null) return null;
|
|
6919
|
+
const first = kids[0];
|
|
6920
|
+
const last = kids[kids.length - 1];
|
|
6921
|
+
if (first._tag === "leaf" && first.value !== separator && from < cStart + first.span.end) return null;
|
|
6922
|
+
if (last._tag === "leaf" && last.value !== separator && to > cStart + last.span.start) return null;
|
|
6923
|
+
const reStart = h > 0 ? cStart + kids[h - 1].span.end : cStart;
|
|
6924
|
+
const reEnd = cStart + kids[t].span.start + delta;
|
|
6925
|
+
if (reEnd < reStart) return null;
|
|
6926
|
+
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6927
|
+
if (!middle) return null;
|
|
6928
|
+
if (middle.length > 0) {
|
|
6929
|
+
const last2 = middle[middle.length - 1];
|
|
6930
|
+
if (!(last2._tag === "leaf" && last2.value === separator)) return null;
|
|
6931
|
+
}
|
|
6932
|
+
if (reEnd < newInput.length) {
|
|
6933
|
+
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6934
|
+
if (newInput[reEnd] === sentinel) continue;
|
|
6935
|
+
const probed = newInput.slice(0, reEnd) + sentinel.repeat(newInput.length - reEnd);
|
|
6936
|
+
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6937
|
+
if (!probe || probe.length !== middle.length) return null;
|
|
6938
|
+
for (let i = 0; i < middle.length; i++) if (!structurallyEqual(probe[i], middle[i])) return null;
|
|
6939
|
+
}
|
|
6940
|
+
}
|
|
6941
|
+
const head = kids.slice(0, h);
|
|
6942
|
+
const tail = kids.slice(t).map((k) => shiftRelStart(k, delta));
|
|
6943
|
+
const newC = {
|
|
6944
|
+
...C,
|
|
6945
|
+
span: { start: C.span.start, end: C.span.end + delta },
|
|
6946
|
+
children: [...head, ...middle, ...tail]
|
|
6947
|
+
};
|
|
6948
|
+
return graftRelative(root, path, newC, delta);
|
|
6949
|
+
}
|
|
6458
6950
|
function structurallyEqual(a, b) {
|
|
6459
6951
|
if (a === b) return true;
|
|
6460
6952
|
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
@@ -6469,6 +6961,11 @@ function structurallyEqual(a, b) {
|
|
|
6469
6961
|
if (at === "leaf" || at === "trivia") {
|
|
6470
6962
|
return a.value === b.value;
|
|
6471
6963
|
}
|
|
6964
|
+
if (at === "parseError") {
|
|
6965
|
+
const ae = a.expected ?? [];
|
|
6966
|
+
const be = b.expected ?? [];
|
|
6967
|
+
return ae.length === be.length && ae.every((x, i) => x === be[i]);
|
|
6968
|
+
}
|
|
6472
6969
|
if (a.type !== b.type) return false;
|
|
6473
6970
|
const ac = a.children;
|
|
6474
6971
|
const bc = b.children;
|
|
@@ -6478,13 +6975,13 @@ function structurallyEqual(a, b) {
|
|
|
6478
6975
|
}
|
|
6479
6976
|
return true;
|
|
6480
6977
|
}
|
|
6481
|
-
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced) {
|
|
6978
|
+
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced, tolerant) {
|
|
6482
6979
|
if (!produced.ok) return false;
|
|
6483
6980
|
if (boundary >= newInput.length) return true;
|
|
6484
6981
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6485
6982
|
if (newInput[boundary] === sentinel) continue;
|
|
6486
6983
|
const probed = newInput.slice(0, boundary) + sentinel.repeat(newInput.length - boundary);
|
|
6487
|
-
const ctx =
|
|
6984
|
+
const ctx = mkCtx(state, build, tolerant);
|
|
6488
6985
|
let r;
|
|
6489
6986
|
try {
|
|
6490
6987
|
r = ruleFn(probed, start, ctx);
|
|
@@ -6498,27 +6995,83 @@ function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produce
|
|
|
6498
6995
|
}
|
|
6499
6996
|
var ParseDocImpl = class _ParseDocImpl {
|
|
6500
6997
|
_registry;
|
|
6998
|
+
/** Registry entries normalized to callable parse functions (memoized once). */
|
|
6999
|
+
_fns;
|
|
7000
|
+
/** Rule names the grammar proves are genuine repetitions — the ONLY splice-safe types. */
|
|
7001
|
+
_reps;
|
|
6501
7002
|
_rootRule;
|
|
6502
7003
|
_opts;
|
|
6503
|
-
|
|
7004
|
+
/**
|
|
7005
|
+
* The tree, held in whichever coordinate system it arrived in. A fresh parse
|
|
7006
|
+
* arrives ABSOLUTE (`_abs` set); an incremental graft arrives PARENT-RELATIVE
|
|
7007
|
+
* (`_rel` set). The public `tree` is always the RELATIVE form (so untouched
|
|
7008
|
+
* subtrees stay shared by identity across edits and reads are O(1)); it's
|
|
7009
|
+
* materialized from `_abs` once, on demand, and memoized. `undefined` = not yet
|
|
7010
|
+
* computed; `null` = failed parse. A fresh parse that's never edited nor
|
|
7011
|
+
* tree-read pays no conversion — important for the full-reparse fallback path.
|
|
7012
|
+
*/
|
|
7013
|
+
_abs;
|
|
7014
|
+
_rel;
|
|
6504
7015
|
errors;
|
|
7016
|
+
unconsumedFrom;
|
|
6505
7017
|
input;
|
|
6506
|
-
constructor(registry, rootRule, opts,
|
|
7018
|
+
constructor(registry, rootRule, opts, trees, errors, unconsumedFrom, input) {
|
|
6507
7019
|
this._registry = registry;
|
|
7020
|
+
this._fns = {};
|
|
7021
|
+
this._reps = /* @__PURE__ */ new Set();
|
|
7022
|
+
for (const [name, entry] of Object.entries(registry)) {
|
|
7023
|
+
this._fns[name] = asRuleFn(entry);
|
|
7024
|
+
if (producesRepetition(defOf(entry))) this._reps.add(name);
|
|
7025
|
+
}
|
|
6508
7026
|
this._rootRule = rootRule;
|
|
6509
7027
|
this._opts = opts;
|
|
6510
|
-
this.
|
|
7028
|
+
this._abs = trees.abs;
|
|
7029
|
+
this._rel = trees.rel;
|
|
6511
7030
|
this.errors = errors;
|
|
7031
|
+
this.unconsumedFrom = unconsumedFrom;
|
|
6512
7032
|
this.input = input;
|
|
6513
7033
|
}
|
|
7034
|
+
/**
|
|
7035
|
+
* The parse tree with PARENT-RELATIVE spans — a node's `span` is relative to
|
|
7036
|
+
* its parent's start (root base 0). This is the shareable representation:
|
|
7037
|
+
* untouched subtrees keep the same identity across `.edit()`s, and reading the
|
|
7038
|
+
* tree after a length-changing edit is O(1) (no offset rewrite). For absolute
|
|
7039
|
+
* positions use the O(depth) cursor `spanAt(path)`, or `absolutizeCST(tree)` to
|
|
7040
|
+
* materialize the whole absolute tree. (A fresh non-incremental `node().parse()`
|
|
7041
|
+
* result is unchanged — still absolute.)
|
|
7042
|
+
*/
|
|
7043
|
+
get tree() {
|
|
7044
|
+
if (this._rel === void 0) {
|
|
7045
|
+
this._rel = this._abs ? relativizeCST(this._abs, 0) : null;
|
|
7046
|
+
}
|
|
7047
|
+
return this._rel;
|
|
7048
|
+
}
|
|
7049
|
+
spanAt(path) {
|
|
7050
|
+
const rel = this.tree;
|
|
7051
|
+
if (!rel) throw new Error("spanAt on a failed parse (tree is null)");
|
|
7052
|
+
return absoluteSpanCST(rel, path);
|
|
7053
|
+
}
|
|
7054
|
+
/**
|
|
7055
|
+
* Wrap a reused (grafted/spliced) RELATIVE tree, recomputing `errors` and
|
|
7056
|
+
* `unconsumedFrom` from it so both stay consistent with the tree across the
|
|
7057
|
+
* edit (the flat errors are recovered errors embedded in the reused subtrees;
|
|
7058
|
+
* unconsumedFrom re-derives trailing junk over the new input).
|
|
7059
|
+
*/
|
|
7060
|
+
wrapReuse(newTree, newInput) {
|
|
7061
|
+
const trivia2 = triviaOf(this._registry[this._rootRule], this._opts);
|
|
7062
|
+
const end = newTree.span.end;
|
|
7063
|
+
const errors = collectEmbeddedErrors(newTree, 0, []);
|
|
7064
|
+
const unconsumedFrom = unconsumedAfter(end, newInput, trivia2);
|
|
7065
|
+
return new _ParseDocImpl(this._registry, this._rootRule, this._opts, { rel: newTree }, errors, unconsumedFrom, newInput);
|
|
7066
|
+
}
|
|
6514
7067
|
edit(from, to, replacement) {
|
|
6515
7068
|
const newInput = this.input.slice(0, from) + replacement + this.input.slice(to);
|
|
6516
7069
|
const reparse = () => parseDoc(this._registry, this._rootRule, newInput, this._opts);
|
|
6517
|
-
|
|
7070
|
+
const root = this.tree;
|
|
7071
|
+
if (!root) return reparse();
|
|
6518
7072
|
const delta = replacement.length - (to - from);
|
|
6519
|
-
const found = findContaining(
|
|
6520
|
-
|
|
6521
|
-
const ancestors = ancestorsAt(this.tree, found.path);
|
|
7073
|
+
const found = findContaining(root, 0, from) ?? { node: root, path: [] };
|
|
7074
|
+
const ancestors = ancestorsAt(root, found.path);
|
|
6522
7075
|
const candidates = [found];
|
|
6523
7076
|
const pathCopy = [...found.path];
|
|
6524
7077
|
for (let i = ancestors.length - 2; i >= 0; i--) {
|
|
@@ -6527,37 +7080,78 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6527
7080
|
}
|
|
6528
7081
|
const rebuild = this._opts.rebuild ?? defaultRebuild;
|
|
6529
7082
|
for (const { node: node2, path } of candidates) {
|
|
6530
|
-
|
|
6531
|
-
|
|
7083
|
+
const { start: absStart, end: absEnd } = absoluteSpanCST(root, path);
|
|
7084
|
+
if (absEnd - absStart > this.input.length * REENTRY_MAX_SPAN_FRACTION) break;
|
|
7085
|
+
const ruleFn = this._fns[node2.type];
|
|
6532
7086
|
if (!ruleFn) continue;
|
|
6533
|
-
if (!(
|
|
6534
|
-
const ctx =
|
|
6535
|
-
const r = ruleFn(newInput,
|
|
7087
|
+
if (!(absStart <= from && to <= absEnd)) continue;
|
|
7088
|
+
const ctx = mkCtx(node2.state, this._opts.build, !!this._opts.tolerant);
|
|
7089
|
+
const r = ruleFn(newInput, absStart, ctx);
|
|
6536
7090
|
if (!r.ok) continue;
|
|
6537
|
-
if (r.span.end !==
|
|
6538
|
-
if (!boundaryIsSafe(ruleFn, newInput,
|
|
7091
|
+
if (r.span.end !== absEnd + delta) continue;
|
|
7092
|
+
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r, !!this._opts.tolerant)) {
|
|
6539
7093
|
continue;
|
|
6540
7094
|
}
|
|
7095
|
+
const parentBase = absStart - node2.span.start;
|
|
7096
|
+
const newRel = relativizeCST(r.value, parentBase);
|
|
6541
7097
|
if (delta === 0) {
|
|
6542
|
-
const newTree2 = replaceAtPath(rebuild,
|
|
6543
|
-
return
|
|
7098
|
+
const newTree2 = replaceAtPath(rebuild, root, path, newRel);
|
|
7099
|
+
return this.wrapReuse(newTree2, newInput);
|
|
6544
7100
|
}
|
|
6545
7101
|
if (this._opts.rebuild) return reparse();
|
|
6546
|
-
const newTree =
|
|
6547
|
-
return
|
|
7102
|
+
const newTree = graftRelative(root, path, newRel, delta);
|
|
7103
|
+
return this.wrapReuse(newTree, newInput);
|
|
7104
|
+
}
|
|
7105
|
+
if (this._opts.structuralReuse && delta !== 0 && !this._opts.rebuild) {
|
|
7106
|
+
const spliceCandidates = [...candidates, { node: root, path: [] }];
|
|
7107
|
+
for (const { node: node2, path } of spliceCandidates) {
|
|
7108
|
+
if (!this._reps.has(node2.type)) continue;
|
|
7109
|
+
const { start: cStart, end: cEnd } = absoluteSpanCST(root, path);
|
|
7110
|
+
if (!(cStart <= from && to <= cEnd)) continue;
|
|
7111
|
+
const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build, !!this._opts.tolerant);
|
|
7112
|
+
if (spliced) return this.wrapReuse(spliced, newInput);
|
|
7113
|
+
}
|
|
6548
7114
|
}
|
|
6549
7115
|
return reparse();
|
|
6550
7116
|
}
|
|
6551
7117
|
};
|
|
7118
|
+
function triviaOf(entry, opts) {
|
|
7119
|
+
if (opts.trivia) return opts.trivia;
|
|
7120
|
+
if (entry === void 0 || typeof entry === "function") return void 0;
|
|
7121
|
+
const meta = entry._meta;
|
|
7122
|
+
return meta ? meta.grammarTrivia : void 0;
|
|
7123
|
+
}
|
|
7124
|
+
function unconsumedAfter(end, input, trivia2) {
|
|
7125
|
+
let pos = end;
|
|
7126
|
+
if (trivia2 && pos < input.length) {
|
|
7127
|
+
const t = trivia2.parse(input, pos, { trackLines: false });
|
|
7128
|
+
if (t.ok && t.span.end > pos) pos = t.span.end;
|
|
7129
|
+
}
|
|
7130
|
+
return pos < input.length ? pos : null;
|
|
7131
|
+
}
|
|
7132
|
+
function collectEmbeddedErrors(node2, base, out) {
|
|
7133
|
+
const c = node2;
|
|
7134
|
+
if (!c || typeof c !== "object" || !c.span) return out;
|
|
7135
|
+
const start = base + c.span.start;
|
|
7136
|
+
if (c._tag === "parseError") {
|
|
7137
|
+
out.push({ _tag: "parseError", span: { start, end: base + c.span.end }, expected: c.expected ?? [] });
|
|
7138
|
+
return out;
|
|
7139
|
+
}
|
|
7140
|
+
if (Array.isArray(c.children)) for (const k of c.children) collectEmbeddedErrors(k, start, out);
|
|
7141
|
+
return out;
|
|
7142
|
+
}
|
|
6552
7143
|
function parseDoc(registry, rootRule, input, opts = {}) {
|
|
6553
|
-
const
|
|
6554
|
-
if (!
|
|
6555
|
-
const ctx =
|
|
6556
|
-
const r =
|
|
7144
|
+
const entry = registry[rootRule];
|
|
7145
|
+
if (!entry) throw new Error(`No rule '${rootRule}' in registry`);
|
|
7146
|
+
const ctx = mkCtx(opts.state, opts.build, !!opts.tolerant);
|
|
7147
|
+
const r = asRuleFn(entry)(input, 0, ctx);
|
|
6557
7148
|
if (r.ok) {
|
|
6558
|
-
|
|
7149
|
+
const errors = ctx._errors ? [...ctx._errors] : [];
|
|
7150
|
+
const unconsumedFrom = unconsumedAfter(r.span.end, input, triviaOf(entry, opts));
|
|
7151
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: r.value }, errors, unconsumedFrom, input);
|
|
6559
7152
|
}
|
|
6560
|
-
|
|
7153
|
+
const fail = { _tag: "parseError", span: r.span, expected: r.expected };
|
|
7154
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
|
|
6561
7155
|
}
|
|
6562
7156
|
|
|
6563
7157
|
// src/functional/run.ts
|
|
@@ -6578,7 +7172,8 @@ function run(entry, input, options = {}) {
|
|
|
6578
7172
|
build: options.build,
|
|
6579
7173
|
state: options.state,
|
|
6580
7174
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
6581
|
-
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {}
|
|
7175
|
+
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7176
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
6582
7177
|
};
|
|
6583
7178
|
const r = invoke(entry, input, 0, ctx);
|
|
6584
7179
|
let unconsumedFrom = null;
|
|
@@ -6926,78 +7521,14 @@ function buildOffsetIndex(root, input = "") {
|
|
|
6926
7521
|
return new OffsetIndex(collectLeafSlots(root), 0, input.length);
|
|
6927
7522
|
}
|
|
6928
7523
|
|
|
6929
|
-
// src/cst/relative-spans.ts
|
|
6930
|
-
function relativize(node2, parentBase = 0) {
|
|
6931
|
-
return {
|
|
6932
|
-
start: node2.start - parentBase,
|
|
6933
|
-
end: node2.end - parentBase,
|
|
6934
|
-
children: node2.children.map((c) => relativize(c, node2.start))
|
|
6935
|
-
};
|
|
6936
|
-
}
|
|
6937
|
-
function absolutize(node2, parentBase = 0) {
|
|
6938
|
-
const start = parentBase + node2.start;
|
|
6939
|
-
return {
|
|
6940
|
-
start,
|
|
6941
|
-
end: parentBase + node2.end,
|
|
6942
|
-
children: node2.children.map((c) => absolutize(c, start))
|
|
6943
|
-
};
|
|
6944
|
-
}
|
|
6945
|
-
function absoluteSpanAt(root, path) {
|
|
6946
|
-
let base = 0;
|
|
6947
|
-
let node2 = root;
|
|
6948
|
-
for (const idx of path) {
|
|
6949
|
-
base += node2.start;
|
|
6950
|
-
const child = node2.children[idx];
|
|
6951
|
-
if (!child) throw new RangeError(`absoluteSpanAt: no child ${idx} on path ${path.join(".")}`);
|
|
6952
|
-
node2 = child;
|
|
6953
|
-
}
|
|
6954
|
-
return { start: base + node2.start, end: base + node2.end };
|
|
6955
|
-
}
|
|
6956
|
-
function shiftAbsolute(node2, at, delta) {
|
|
6957
|
-
const s = node2.start >= at ? node2.start + delta : node2.start;
|
|
6958
|
-
const e = node2.end >= at ? node2.end + delta : node2.end;
|
|
6959
|
-
return {
|
|
6960
|
-
start: s,
|
|
6961
|
-
end: e,
|
|
6962
|
-
children: node2.children.map((c) => shiftAbsolute(c, at, delta))
|
|
6963
|
-
};
|
|
6964
|
-
}
|
|
6965
|
-
function applyEdit(root, at, delta, stats) {
|
|
6966
|
-
return editNode(root, at, delta, 0, 0, stats);
|
|
6967
|
-
}
|
|
6968
|
-
function editNode(node2, at, delta, parentBase, parentShift, stats) {
|
|
6969
|
-
const absStart = parentBase + node2.start;
|
|
6970
|
-
const absEnd = parentBase + node2.end;
|
|
6971
|
-
if (absEnd < at) return node2;
|
|
6972
|
-
const startShifts = absStart >= at;
|
|
6973
|
-
if (startShifts && parentShift === delta) return node2;
|
|
6974
|
-
if (stats) stats.allocated++;
|
|
6975
|
-
const newAbsStart = startShifts ? absStart + delta : absStart;
|
|
6976
|
-
const newAbsEnd = absEnd + delta;
|
|
6977
|
-
const newParentBase = parentBase + parentShift;
|
|
6978
|
-
const newStart = newAbsStart - newParentBase;
|
|
6979
|
-
const newEnd = newAbsEnd - newParentBase;
|
|
6980
|
-
const ownShift = newAbsStart - absStart;
|
|
6981
|
-
let changed = false;
|
|
6982
|
-
const newChildren = [];
|
|
6983
|
-
for (const c of node2.children) {
|
|
6984
|
-
const nc = editNode(c, at, delta, absStart, ownShift, stats);
|
|
6985
|
-
if (nc !== c) changed = true;
|
|
6986
|
-
newChildren.push(nc);
|
|
6987
|
-
}
|
|
6988
|
-
return {
|
|
6989
|
-
start: newStart,
|
|
6990
|
-
end: newEnd,
|
|
6991
|
-
children: changed ? newChildren : node2.children
|
|
6992
|
-
};
|
|
6993
|
-
}
|
|
6994
|
-
|
|
6995
7524
|
// src/index.ts
|
|
6996
7525
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
6997
7526
|
export {
|
|
6998
7527
|
OffsetIndex,
|
|
6999
7528
|
absoluteSpanAt,
|
|
7529
|
+
absoluteSpanCST,
|
|
7000
7530
|
absolutize,
|
|
7531
|
+
absolutizeCST,
|
|
7001
7532
|
annotateSpan,
|
|
7002
7533
|
applyEdit,
|
|
7003
7534
|
balanced,
|
|
@@ -7028,7 +7559,6 @@ export {
|
|
|
7028
7559
|
literal,
|
|
7029
7560
|
makeWord,
|
|
7030
7561
|
many,
|
|
7031
|
-
manyRecover,
|
|
7032
7562
|
noTrivia,
|
|
7033
7563
|
node,
|
|
7034
7564
|
not,
|
|
@@ -7038,15 +7568,14 @@ export {
|
|
|
7038
7568
|
parse,
|
|
7039
7569
|
parseDoc,
|
|
7040
7570
|
parser,
|
|
7041
|
-
recover,
|
|
7042
7571
|
ref,
|
|
7043
7572
|
regex,
|
|
7044
7573
|
relativize,
|
|
7574
|
+
relativizeCST,
|
|
7045
7575
|
rules,
|
|
7046
7576
|
run,
|
|
7047
7577
|
scanTo,
|
|
7048
7578
|
sepBy,
|
|
7049
|
-
sepByRecover,
|
|
7050
7579
|
sequence,
|
|
7051
7580
|
shiftAbsolute,
|
|
7052
7581
|
skip,
|