parseman 0.25.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/combinators/choice.d.ts.map +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/types.d.ts +7 -7
- package/dist/cst/types.d.ts.map +1 -1
- package/dist/functional/doc.d.ts +37 -2
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/functional/run.d.ts +12 -1
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +540 -211
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +540 -211
- 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 +603 -145
- 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 +603 -145
- package/dist/plugin/index.js.map +4 -4
- package/dist/recovery/scan.d.ts +54 -0
- package/dist/recovery/scan.d.ts.map +1 -0
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.js.map +1 -1
- package/dist/types.d.ts +60 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/dist/combinators/recover-list.d.ts +0 -41
- package/dist/combinators/recover-list.d.ts.map +0 -1
- package/dist/combinators/recover.d.ts +0 -20
- package/dist/combinators/recover.d.ts.map +0 -1
package/dist/index.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);
|
|
@@ -829,12 +836,163 @@ function keywords(words, opts = {}) {
|
|
|
829
836
|
};
|
|
830
837
|
}
|
|
831
838
|
|
|
839
|
+
// src/recovery/scan.ts
|
|
840
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
841
|
+
const s = {
|
|
842
|
+
_probe: ctx._probe,
|
|
843
|
+
_errors: ctx._errors,
|
|
844
|
+
_cstLeaves: ctx._cstLeaves,
|
|
845
|
+
_cstChildren: ctx._cstChildren,
|
|
846
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
847
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
848
|
+
_triviaLog: ctx._triviaLog,
|
|
849
|
+
_fields: ctx._fields,
|
|
850
|
+
_cstBuf: ctx._cstBuf,
|
|
851
|
+
_tolerant: ctx._tolerant,
|
|
852
|
+
_sync: ctx._sync
|
|
853
|
+
};
|
|
854
|
+
ctx._probe = void 0;
|
|
855
|
+
ctx._errors = void 0;
|
|
856
|
+
ctx._cstLeaves = void 0;
|
|
857
|
+
ctx._cstChildren = void 0;
|
|
858
|
+
ctx._cstRawChildren = void 0;
|
|
859
|
+
ctx._cstTriviaLog = void 0;
|
|
860
|
+
ctx._triviaLog = void 0;
|
|
861
|
+
ctx._fields = void 0;
|
|
862
|
+
ctx._cstBuf = void 0;
|
|
863
|
+
ctx._tolerant = void 0;
|
|
864
|
+
ctx._sync = void 0;
|
|
865
|
+
try {
|
|
866
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
867
|
+
} finally {
|
|
868
|
+
ctx._probe = s._probe;
|
|
869
|
+
ctx._errors = s._errors;
|
|
870
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
871
|
+
ctx._cstChildren = s._cstChildren;
|
|
872
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
873
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
874
|
+
ctx._triviaLog = s._triviaLog;
|
|
875
|
+
ctx._fields = s._fields;
|
|
876
|
+
ctx._cstBuf = s._cstBuf;
|
|
877
|
+
ctx._tolerant = s._tolerant;
|
|
878
|
+
ctx._sync = s._sync;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function orSentinel(a, b) {
|
|
882
|
+
if (b === void 0) return a;
|
|
883
|
+
return {
|
|
884
|
+
_tag: "orSentinel",
|
|
885
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
886
|
+
_def: { tag: "unknown" },
|
|
887
|
+
parse(input, pos, ctx) {
|
|
888
|
+
const ra = a.parse(input, pos, ctx);
|
|
889
|
+
if (ra.ok) return ra;
|
|
890
|
+
return b.parse(input, pos, ctx);
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
function firstSetSentinel(fs) {
|
|
895
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
896
|
+
const ranges = fs.ranges;
|
|
897
|
+
return {
|
|
898
|
+
_tag: "firstSetSentinel",
|
|
899
|
+
_meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
|
|
900
|
+
_def: { tag: "unknown" },
|
|
901
|
+
parse(input, pos) {
|
|
902
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
903
|
+
if (code !== void 0) {
|
|
904
|
+
for (const r of ranges) {
|
|
905
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
913
|
+
let scanPos = from;
|
|
914
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
915
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
916
|
+
ctx._errors?.push(error);
|
|
917
|
+
return { error, end: scanPos };
|
|
918
|
+
}
|
|
919
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
920
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
921
|
+
}
|
|
922
|
+
function captureError(ctx, error) {
|
|
923
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
924
|
+
}
|
|
925
|
+
var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
|
|
926
|
+
|
|
927
|
+
// src/combinators/expect.ts
|
|
928
|
+
function deriveExpected(c) {
|
|
929
|
+
const def = c._def;
|
|
930
|
+
switch (def.tag) {
|
|
931
|
+
case "literal":
|
|
932
|
+
return [JSON.stringify(def.value)];
|
|
933
|
+
case "regex":
|
|
934
|
+
return [`/${def.source}/`];
|
|
935
|
+
case "keywords":
|
|
936
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
937
|
+
case "label":
|
|
938
|
+
return [def.label];
|
|
939
|
+
case "choice":
|
|
940
|
+
return def.parsers.flatMap(deriveExpected);
|
|
941
|
+
case "sequence":
|
|
942
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
943
|
+
case "node":
|
|
944
|
+
case "grammar":
|
|
945
|
+
case "trivia":
|
|
946
|
+
case "token":
|
|
947
|
+
case "optional":
|
|
948
|
+
case "many":
|
|
949
|
+
case "oneOrMore":
|
|
950
|
+
case "transform":
|
|
951
|
+
case "not":
|
|
952
|
+
return deriveExpected(def.parser);
|
|
953
|
+
case "lazy": {
|
|
954
|
+
const name = c._ruleName;
|
|
955
|
+
try {
|
|
956
|
+
return deriveExpected(def.thunk());
|
|
957
|
+
} catch {
|
|
958
|
+
return name ? [name] : [];
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
default:
|
|
962
|
+
return [];
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
function expect(combinator, label2) {
|
|
966
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
967
|
+
const meta = {
|
|
968
|
+
firstSet: combinator._meta.firstSet,
|
|
969
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
970
|
+
isTrivia: false
|
|
971
|
+
};
|
|
972
|
+
return {
|
|
973
|
+
_tag: "expect",
|
|
974
|
+
_meta: meta,
|
|
975
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
976
|
+
parse(input, pos, ctx) {
|
|
977
|
+
const result = combinator.parse(input, pos, ctx);
|
|
978
|
+
if (result.ok) return result;
|
|
979
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
980
|
+
ctx._errors?.push(error);
|
|
981
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
982
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
function isParseError(value) {
|
|
987
|
+
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
988
|
+
}
|
|
989
|
+
|
|
832
990
|
// src/combinators/choice.ts
|
|
833
991
|
function choice(...args) {
|
|
834
992
|
const parsers = args.map((a) => "gate" in a ? a.combinator : a);
|
|
835
993
|
const gates = args.map((a) => "gate" in a ? a.gate : null);
|
|
836
994
|
const hasGates = gates.some((g) => g !== null);
|
|
837
|
-
const disjoint =
|
|
995
|
+
const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
|
|
838
996
|
let combined = { kind: "empty" };
|
|
839
997
|
for (const p of parsers) combined = union(combined, p._meta.firstSet);
|
|
840
998
|
const meta = {
|
|
@@ -873,17 +1031,21 @@ function choice(...args) {
|
|
|
873
1031
|
const expected = [];
|
|
874
1032
|
if (disjoint && pos < input.length) {
|
|
875
1033
|
const code = input.codePointAt(pos);
|
|
876
|
-
let
|
|
877
|
-
if (
|
|
878
|
-
for (
|
|
879
|
-
if (inFirstSet(code,
|
|
880
|
-
|
|
1034
|
+
let idx = code < 128 ? asciiDispatch[code] : -1;
|
|
1035
|
+
if (idx < 0) {
|
|
1036
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1037
|
+
if (inFirstSet(code, parsers[i]._meta.firstSet)) {
|
|
1038
|
+
idx = i;
|
|
881
1039
|
break;
|
|
882
1040
|
}
|
|
883
1041
|
}
|
|
884
1042
|
}
|
|
885
|
-
if (
|
|
886
|
-
const
|
|
1043
|
+
if (idx >= 0) {
|
|
1044
|
+
const gate = gates[idx];
|
|
1045
|
+
if (gate && !gate(ctx.state)) {
|
|
1046
|
+
return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
|
|
1047
|
+
}
|
|
1048
|
+
const result = parsers[idx].parse(input, pos, ctx);
|
|
887
1049
|
if (result.ok) return result;
|
|
888
1050
|
expected.push(...result.expected);
|
|
889
1051
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
@@ -1064,13 +1226,13 @@ function areDisjoint(sets) {
|
|
|
1064
1226
|
return true;
|
|
1065
1227
|
}
|
|
1066
1228
|
function buildAsciiDispatch(parsers) {
|
|
1067
|
-
const table = Array(128).fill(
|
|
1068
|
-
for (
|
|
1069
|
-
const fs =
|
|
1229
|
+
const table = Array(128).fill(-1);
|
|
1230
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1231
|
+
const fs = parsers[i]._meta.firstSet;
|
|
1070
1232
|
if (fs.kind !== "ranges") continue;
|
|
1071
1233
|
for (const { lo, hi } of fs.ranges) {
|
|
1072
1234
|
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1073
|
-
table[code] =
|
|
1235
|
+
table[code] = i;
|
|
1074
1236
|
}
|
|
1075
1237
|
}
|
|
1076
1238
|
}
|
|
@@ -1215,10 +1377,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1215
1377
|
}
|
|
1216
1378
|
function saveTriviaMark(ctx) {
|
|
1217
1379
|
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 };
|
|
1380
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1219
1381
|
}
|
|
1220
1382
|
function rollbackTrivia(ctx, mark) {
|
|
1221
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1383
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1222
1384
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1223
1385
|
}
|
|
1224
1386
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1462,11 +1624,59 @@ function sequence(...parsers) {
|
|
|
1462
1624
|
isTrivia: false
|
|
1463
1625
|
};
|
|
1464
1626
|
const def = { tag: "sequence", parsers };
|
|
1627
|
+
let followSentinels;
|
|
1628
|
+
function parseTolerant(input, pos, ctx) {
|
|
1629
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1630
|
+
const fs = parsers.slice(i + 1).reduce(
|
|
1631
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1632
|
+
{ kind: "empty" }
|
|
1633
|
+
);
|
|
1634
|
+
return firstSetSentinel(fs);
|
|
1635
|
+
});
|
|
1636
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1637
|
+
let cur = pos;
|
|
1638
|
+
const inheritedSync = ctx._sync;
|
|
1639
|
+
try {
|
|
1640
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1641
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1642
|
+
if (ctx.trivia && i > 0) {
|
|
1643
|
+
const mark = saveTriviaMark(ctx);
|
|
1644
|
+
let scanEnd;
|
|
1645
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1646
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1647
|
+
scan.commit();
|
|
1648
|
+
scanEnd = scan.end;
|
|
1649
|
+
} else {
|
|
1650
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1651
|
+
}
|
|
1652
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1653
|
+
if (!result2.ok) return result2;
|
|
1654
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1655
|
+
else rollbackTrivia(ctx, mark);
|
|
1656
|
+
if (values !== void 0) values.push(result2.value);
|
|
1657
|
+
continue;
|
|
1658
|
+
}
|
|
1659
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1660
|
+
if (!result.ok) return result;
|
|
1661
|
+
if (values !== void 0) values.push(result.value);
|
|
1662
|
+
cur = result.span.end;
|
|
1663
|
+
}
|
|
1664
|
+
} finally {
|
|
1665
|
+
ctx._sync = inheritedSync;
|
|
1666
|
+
}
|
|
1667
|
+
return {
|
|
1668
|
+
ok: true,
|
|
1669
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1670
|
+
value: values ?? void 0,
|
|
1671
|
+
span: { start: pos, end: cur }
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1465
1674
|
return {
|
|
1466
1675
|
_tag: "sequence",
|
|
1467
1676
|
_meta: meta,
|
|
1468
1677
|
_def: def,
|
|
1469
1678
|
parse(input, pos, ctx) {
|
|
1679
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1470
1680
|
const values = def.valueUnused ? void 0 : [];
|
|
1471
1681
|
let cur = pos;
|
|
1472
1682
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1525,7 +1735,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1525
1735
|
const result = combinator.parse(input, pos, ctx);
|
|
1526
1736
|
if (!result.ok) {
|
|
1527
1737
|
rollbackTrivia(ctx, mark);
|
|
1528
|
-
return { fail: result };
|
|
1738
|
+
return { fail: result, failPos: pos };
|
|
1529
1739
|
}
|
|
1530
1740
|
if (result.span.end === pos) {
|
|
1531
1741
|
rollbackTrivia(ctx, mark);
|
|
@@ -1540,6 +1750,7 @@ function many(combinator) {
|
|
|
1540
1750
|
isTrivia: false
|
|
1541
1751
|
};
|
|
1542
1752
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1753
|
+
let expected;
|
|
1543
1754
|
return {
|
|
1544
1755
|
_tag: "many",
|
|
1545
1756
|
_meta: meta,
|
|
@@ -1549,7 +1760,18 @@ function many(combinator) {
|
|
|
1549
1760
|
let cur = pos;
|
|
1550
1761
|
while (cur < input.length) {
|
|
1551
1762
|
const item = repItem(combinator, input, cur, ctx);
|
|
1552
|
-
if (item === "stop"
|
|
1763
|
+
if (item === "stop") break;
|
|
1764
|
+
if ("fail" in item) {
|
|
1765
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1766
|
+
if (sync === void 0) break;
|
|
1767
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1768
|
+
expected ??= deriveExpected(combinator);
|
|
1769
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1770
|
+
if (values !== void 0) values.push(error);
|
|
1771
|
+
captureError(ctx, error);
|
|
1772
|
+
cur = end;
|
|
1773
|
+
continue;
|
|
1774
|
+
}
|
|
1553
1775
|
if (values !== void 0) values.push(item.value);
|
|
1554
1776
|
cur = item.end;
|
|
1555
1777
|
}
|
|
@@ -1564,6 +1786,7 @@ function oneOrMore(combinator) {
|
|
|
1564
1786
|
isTrivia: false
|
|
1565
1787
|
};
|
|
1566
1788
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1789
|
+
let expected;
|
|
1567
1790
|
return {
|
|
1568
1791
|
_tag: "oneOrMore",
|
|
1569
1792
|
_meta: meta,
|
|
@@ -1575,7 +1798,18 @@ function oneOrMore(combinator) {
|
|
|
1575
1798
|
let cur = first.span.end;
|
|
1576
1799
|
while (cur < input.length) {
|
|
1577
1800
|
const item = repItem(combinator, input, cur, ctx);
|
|
1578
|
-
if (item === "stop"
|
|
1801
|
+
if (item === "stop") break;
|
|
1802
|
+
if ("fail" in item) {
|
|
1803
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1804
|
+
if (sync === void 0) break;
|
|
1805
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1806
|
+
expected ??= deriveExpected(combinator);
|
|
1807
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1808
|
+
if (values !== void 0) values.push(error);
|
|
1809
|
+
captureError(ctx, error);
|
|
1810
|
+
cur = end;
|
|
1811
|
+
continue;
|
|
1812
|
+
}
|
|
1579
1813
|
if (values !== void 0) values.push(item.value);
|
|
1580
1814
|
cur = item.end;
|
|
1581
1815
|
}
|
|
@@ -1621,15 +1855,29 @@ function sepBy(combinator, separator) {
|
|
|
1621
1855
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1622
1856
|
isTrivia: false
|
|
1623
1857
|
};
|
|
1858
|
+
let expected;
|
|
1624
1859
|
return {
|
|
1625
1860
|
_tag: "sepBy",
|
|
1626
1861
|
_meta: meta,
|
|
1627
1862
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1628
1863
|
parse(input, pos, ctx) {
|
|
1629
1864
|
const first = combinator.parse(input, pos, ctx);
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1865
|
+
const values = [];
|
|
1866
|
+
let cur;
|
|
1867
|
+
if (first.ok) {
|
|
1868
|
+
values.push(first.value);
|
|
1869
|
+
cur = first.span.end;
|
|
1870
|
+
} else {
|
|
1871
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1872
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1873
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1874
|
+
}
|
|
1875
|
+
expected ??= deriveExpected(combinator);
|
|
1876
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1877
|
+
values.push(rec.error);
|
|
1878
|
+
captureError(ctx, rec.error);
|
|
1879
|
+
cur = rec.end;
|
|
1880
|
+
}
|
|
1633
1881
|
while (cur < input.length) {
|
|
1634
1882
|
const loopMark = saveTriviaMark(ctx);
|
|
1635
1883
|
let sepPos = cur;
|
|
@@ -1659,6 +1907,15 @@ function sepBy(combinator, separator) {
|
|
|
1659
1907
|
}
|
|
1660
1908
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1661
1909
|
if (!next.ok) {
|
|
1910
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1911
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
1912
|
+
expected ??= deriveExpected(combinator);
|
|
1913
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
1914
|
+
values.push(rec.error);
|
|
1915
|
+
captureError(ctx, rec.error);
|
|
1916
|
+
cur = rec.end;
|
|
1917
|
+
continue;
|
|
1918
|
+
}
|
|
1662
1919
|
rollbackTrivia(ctx, loopMark);
|
|
1663
1920
|
break;
|
|
1664
1921
|
}
|
|
@@ -1832,7 +2089,7 @@ function rules(a, b) {
|
|
|
1832
2089
|
cache[key] = parser2;
|
|
1833
2090
|
}
|
|
1834
2091
|
}
|
|
1835
|
-
if (options?.trivia
|
|
2092
|
+
if (options?.trivia != null) {
|
|
1836
2093
|
for (const key of Object.keys(definitions)) {
|
|
1837
2094
|
const rule = cache[key];
|
|
1838
2095
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1862,7 +2119,9 @@ function not(combinator) {
|
|
|
1862
2119
|
_meta: meta,
|
|
1863
2120
|
_def: { tag: "not", parser: combinator },
|
|
1864
2121
|
parse(input, pos, ctx) {
|
|
2122
|
+
const mark = saveCstMark(ctx);
|
|
1865
2123
|
const result = combinator.parse(input, pos, ctx);
|
|
2124
|
+
rollbackCstCapture(ctx, mark);
|
|
1866
2125
|
if (result.ok) {
|
|
1867
2126
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1868
2127
|
}
|
|
@@ -1976,7 +2235,7 @@ function unwrapChild(child) {
|
|
|
1976
2235
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1977
2236
|
}
|
|
1978
2237
|
function isCstChild(value) {
|
|
1979
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2238
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
1980
2239
|
}
|
|
1981
2240
|
function missingInferredType() {
|
|
1982
2241
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2254,65 +2513,6 @@ function token(root) {
|
|
|
2254
2513
|
};
|
|
2255
2514
|
}
|
|
2256
2515
|
|
|
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
2516
|
// src/compiler/scannable-run.ts
|
|
2317
2517
|
var BACKSLASH = 92;
|
|
2318
2518
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2384,20 +2584,39 @@ function parseSeqParts(source) {
|
|
|
2384
2584
|
lit = [];
|
|
2385
2585
|
}
|
|
2386
2586
|
};
|
|
2387
|
-
const
|
|
2587
|
+
const braceQuant = (at) => {
|
|
2588
|
+
const close = source.indexOf("}", at);
|
|
2589
|
+
if (close === -1) return null;
|
|
2590
|
+
const body = source.slice(at + 1, close);
|
|
2591
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2592
|
+
if (!m) return null;
|
|
2593
|
+
const min = Number(m[1]);
|
|
2594
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2595
|
+
if (max < 1 || min > max) return null;
|
|
2596
|
+
return { min, max, len: close - at + 1 };
|
|
2597
|
+
};
|
|
2598
|
+
const runFrom = (ranges, negated, at) => {
|
|
2599
|
+
const q = source[at];
|
|
2388
2600
|
if (q === "+") {
|
|
2389
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2601
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2390
2602
|
return 1;
|
|
2391
2603
|
}
|
|
2392
2604
|
if (q === "*") {
|
|
2393
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2605
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2394
2606
|
return 1;
|
|
2395
2607
|
}
|
|
2396
2608
|
if (q === "?") {
|
|
2397
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2609
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2398
2610
|
return 1;
|
|
2399
2611
|
}
|
|
2400
|
-
|
|
2612
|
+
if (q === "{") {
|
|
2613
|
+
const b = braceQuant(at);
|
|
2614
|
+
if (b) {
|
|
2615
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2616
|
+
return b.len;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2401
2620
|
return 0;
|
|
2402
2621
|
};
|
|
2403
2622
|
let i = 0;
|
|
@@ -2422,7 +2641,7 @@ function parseSeqParts(source) {
|
|
|
2422
2641
|
if (!ranges) return null;
|
|
2423
2642
|
flush();
|
|
2424
2643
|
i = k + 1;
|
|
2425
|
-
i += runFrom(ranges, neg,
|
|
2644
|
+
i += runFrom(ranges, neg, i);
|
|
2426
2645
|
continue;
|
|
2427
2646
|
}
|
|
2428
2647
|
if (ch === "\\") {
|
|
@@ -2430,7 +2649,7 @@ function parseSeqParts(source) {
|
|
|
2430
2649
|
if (e === "d" || e === "w" || e === "s") {
|
|
2431
2650
|
flush();
|
|
2432
2651
|
i += 2;
|
|
2433
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2652
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2434
2653
|
continue;
|
|
2435
2654
|
}
|
|
2436
2655
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2519,7 +2738,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2519
2738
|
let hasMandatory = false;
|
|
2520
2739
|
for (let k = 0; k < parts.length; k++) {
|
|
2521
2740
|
const p = parts[k];
|
|
2522
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2741
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2523
2742
|
if (mandatory) hasMandatory = true;
|
|
2524
2743
|
if (p.part === "group") {
|
|
2525
2744
|
const exposure = groupPartExposure(p);
|
|
@@ -2530,9 +2749,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2530
2749
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2531
2750
|
}
|
|
2532
2751
|
}
|
|
2533
|
-
const
|
|
2534
|
-
|
|
2535
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2752
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2753
|
+
if (needsDisjoint) {
|
|
2536
2754
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2537
2755
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2538
2756
|
}
|
|
@@ -2589,8 +2807,8 @@ function fixedClassSeq(shape) {
|
|
|
2589
2807
|
if (p.part === "lit") {
|
|
2590
2808
|
if (p.optional) return null;
|
|
2591
2809
|
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 });
|
|
2810
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2811
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2594
2812
|
} else {
|
|
2595
2813
|
return null;
|
|
2596
2814
|
}
|
|
@@ -2642,7 +2860,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2642
2860
|
const last = shape.parts[shape.parts.length - 1];
|
|
2643
2861
|
if (last.part === "lit") return null;
|
|
2644
2862
|
if (last.part === "run") {
|
|
2645
|
-
if (last.
|
|
2863
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2646
2864
|
return null;
|
|
2647
2865
|
}
|
|
2648
2866
|
return groupPartExposure(last);
|
|
@@ -2779,7 +2997,7 @@ function partFirstAccept(part) {
|
|
|
2779
2997
|
function seqFirstAccept(parts) {
|
|
2780
2998
|
const sets = [];
|
|
2781
2999
|
for (const p of parts) {
|
|
2782
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
3000
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2783
3001
|
sets.push(partFirstAccept(p));
|
|
2784
3002
|
if (mandatory) break;
|
|
2785
3003
|
}
|
|
@@ -3194,7 +3412,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3194
3412
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3195
3413
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3196
3414
|
}
|
|
3197
|
-
} else if (p.part === "run" &&
|
|
3415
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3416
|
+
const s = mint("_s");
|
|
3417
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3418
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3419
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3420
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3421
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3198
3422
|
if (p.min === 1) {
|
|
3199
3423
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3200
3424
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3204,8 +3428,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3204
3428
|
} else if (p.part === "run") {
|
|
3205
3429
|
const s = mint("_s");
|
|
3206
3430
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3207
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3208
|
-
if (p.min
|
|
3431
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3432
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3209
3433
|
} else {
|
|
3210
3434
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3211
3435
|
if (!p.unbounded) {
|
|
@@ -3664,21 +3888,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3664
3888
|
}
|
|
3665
3889
|
return name;
|
|
3666
3890
|
}
|
|
3891
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3892
|
+
if (!ctx.recovery) return "";
|
|
3893
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3894
|
+
const pb = v(ctx, "_pb");
|
|
3895
|
+
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} } } } `;
|
|
3896
|
+
}
|
|
3667
3897
|
function failBody(ctx, expected, posExpr) {
|
|
3898
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3668
3899
|
if (ctx.failLabel) {
|
|
3669
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3670
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3900
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3901
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3671
3902
|
}
|
|
3672
|
-
return failReturn(expected, posExpr);
|
|
3903
|
+
return probe + failReturn(expected, posExpr);
|
|
3673
3904
|
}
|
|
3674
3905
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3906
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3675
3907
|
if (ctx.failLabel) {
|
|
3676
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3908
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3677
3909
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3678
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3910
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3679
3911
|
}
|
|
3680
|
-
if (!constant) return
|
|
3681
|
-
return failReturnArr(expectedArr, posExpr);
|
|
3912
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3913
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3682
3914
|
}
|
|
3683
3915
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3684
3916
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4178,6 +4410,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4178
4410
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4179
4411
|
return { stmts, valueVar: vv, endVar };
|
|
4180
4412
|
}
|
|
4413
|
+
function syncSentinelExpr(fs) {
|
|
4414
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
4415
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs.ranges)} })`;
|
|
4416
|
+
}
|
|
4181
4417
|
function emitSeqValues(def, ctx, pos) {
|
|
4182
4418
|
const startV = v(ctx, "_start");
|
|
4183
4419
|
const curV = v(ctx, "_cur");
|
|
@@ -4186,7 +4422,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4186
4422
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4187
4423
|
];
|
|
4188
4424
|
const valueVars = [];
|
|
4425
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4426
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4427
|
+
const publishSync = (i) => {
|
|
4428
|
+
if (!ctx.recovery) return "";
|
|
4429
|
+
const fs = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4430
|
+
const ref2 = syncSentinelExpr(fs);
|
|
4431
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4432
|
+
};
|
|
4189
4433
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4434
|
+
const syncPub = publishSync(i);
|
|
4435
|
+
if (syncPub) stmts.push(syncPub);
|
|
4190
4436
|
if (i > 0 && ctx.activeTrivia) {
|
|
4191
4437
|
if (ctx.capturing) {
|
|
4192
4438
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4211,7 +4457,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4211
4457
|
continue;
|
|
4212
4458
|
} else {
|
|
4213
4459
|
const trivFn = ensureTriviaFn(ctx);
|
|
4214
|
-
|
|
4460
|
+
const scanEndV = v(ctx, "_sne");
|
|
4461
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4462
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4463
|
+
stmts.push(...r2.stmts);
|
|
4464
|
+
const endAfterV = v(ctx, "_sea");
|
|
4465
|
+
stmts.push(
|
|
4466
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4467
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4468
|
+
);
|
|
4469
|
+
valueVars.push(r2.valueVar);
|
|
4470
|
+
continue;
|
|
4215
4471
|
}
|
|
4216
4472
|
}
|
|
4217
4473
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4289,6 +4545,21 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
|
|
|
4289
4545
|
`${ind(ctx)}${endV} = ${endVar}`
|
|
4290
4546
|
];
|
|
4291
4547
|
}
|
|
4548
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4549
|
+
const p = def.parsers[i];
|
|
4550
|
+
const gate = def.gates[i];
|
|
4551
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4552
|
+
const gateIdx = ctx.mapFns.length;
|
|
4553
|
+
ctx.mapFns.push(gate);
|
|
4554
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4555
|
+
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4556
|
+
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4557
|
+
ctx.indent++;
|
|
4558
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4559
|
+
ctx.indent--;
|
|
4560
|
+
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4561
|
+
return stmts;
|
|
4562
|
+
}
|
|
4292
4563
|
function emitChoice(def, ctx, pos) {
|
|
4293
4564
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4294
4565
|
if (def.disjoint) {
|
|
@@ -4304,12 +4575,11 @@ function emitChoice(def, ctx, pos) {
|
|
|
4304
4575
|
stmts.push(`${ind(ctx)}switch (${codeV}) {`);
|
|
4305
4576
|
ctx.indent++;
|
|
4306
4577
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4307
|
-
const p = def.parsers[i];
|
|
4308
4578
|
for (const cp of plan.cases[i]) stmts.push(`${ind(ctx)}case ${cp}:`);
|
|
4309
4579
|
stmts.push(`${ind(ctx)}{`);
|
|
4310
4580
|
ctx.indent++;
|
|
4311
4581
|
stmts.push(
|
|
4312
|
-
...
|
|
4582
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
4313
4583
|
`${ind(ctx)}break`
|
|
4314
4584
|
);
|
|
4315
4585
|
ctx.indent--;
|
|
@@ -4321,13 +4591,14 @@ function emitChoice(def, ctx, pos) {
|
|
|
4321
4591
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4322
4592
|
}
|
|
4323
4593
|
let first = true;
|
|
4324
|
-
for (
|
|
4594
|
+
for (let i = 0; i < def.parsers.length; i++) {
|
|
4595
|
+
const p = def.parsers[i];
|
|
4325
4596
|
const cond = firstSetCond(codeV, p._meta.firstSet);
|
|
4326
4597
|
const kw = first ? "if" : "else if";
|
|
4327
4598
|
first = false;
|
|
4328
4599
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4329
4600
|
ctx.indent++;
|
|
4330
|
-
stmts.push(...
|
|
4601
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
4331
4602
|
ctx.indent--;
|
|
4332
4603
|
stmts.push(`${ind(ctx)}}`);
|
|
4333
4604
|
}
|
|
@@ -4441,7 +4712,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4441
4712
|
if (gate) {
|
|
4442
4713
|
const gateIdx = ctx.mapFns.length;
|
|
4443
4714
|
ctx.mapFns.push(gate);
|
|
4444
|
-
ctx.mapFnSrcs.push(null);
|
|
4715
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4445
4716
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4446
4717
|
}
|
|
4447
4718
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4546,6 +4817,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4546
4817
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4547
4818
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4548
4819
|
];
|
|
4820
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4821
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4549
4822
|
if (def.min === 1) {
|
|
4550
4823
|
const firstR = emit(def.parser, ctx, curV);
|
|
4551
4824
|
stmts.push(...firstR.stmts);
|
|
@@ -4579,10 +4852,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4579
4852
|
}
|
|
4580
4853
|
}
|
|
4581
4854
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4582
|
-
stmts.push(
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4855
|
+
stmts.push(...iterStmts);
|
|
4856
|
+
if (ctx.recovery) {
|
|
4857
|
+
const rrV = v(ctx, "_rr");
|
|
4858
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4859
|
+
stmts.push(
|
|
4860
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4861
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4862
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4863
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4864
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4865
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4866
|
+
`${ind(ctx)} continue`,
|
|
4867
|
+
`${ind(ctx)} }`,
|
|
4868
|
+
`${ind(ctx)} break`,
|
|
4869
|
+
`${ind(ctx)}}`,
|
|
4870
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4871
|
+
);
|
|
4872
|
+
} else {
|
|
4873
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4874
|
+
}
|
|
4586
4875
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4587
4876
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4588
4877
|
ctx.indent--;
|
|
@@ -4604,20 +4893,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4604
4893
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4605
4894
|
const arrV = v(ctx, "_arr");
|
|
4606
4895
|
const curV = v(ctx, "_cur");
|
|
4896
|
+
const rec = !!ctx.recovery;
|
|
4897
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4898
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4899
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4900
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4607
4901
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4608
4902
|
const stmts = [
|
|
4609
4903
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4610
4904
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4611
|
-
...
|
|
4612
|
-
|
|
4905
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4906
|
+
...firstStmts
|
|
4613
4907
|
];
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
)
|
|
4620
|
-
|
|
4908
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4909
|
+
if (!rec) return [originalFail];
|
|
4910
|
+
const rr = v(ctx, "_rr");
|
|
4911
|
+
return [
|
|
4912
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
4913
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
4914
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
4915
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
4916
|
+
`${ind(ctx)} }`,
|
|
4917
|
+
`${ind(ctx)} ${rb}break`,
|
|
4918
|
+
`${ind(ctx)}}`
|
|
4919
|
+
];
|
|
4920
|
+
};
|
|
4921
|
+
if (rec) {
|
|
4922
|
+
const rr0 = v(ctx, "_rr0");
|
|
4923
|
+
const didV = v(ctx, "_did");
|
|
4924
|
+
stmts.push(
|
|
4925
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
4926
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
4927
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
4928
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
4929
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
4930
|
+
`${ind(ctx)}}`,
|
|
4931
|
+
`${ind(ctx)}if (${didV}) {`
|
|
4932
|
+
);
|
|
4933
|
+
ctx.indent++;
|
|
4934
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
4935
|
+
ctx.indent++;
|
|
4936
|
+
} else {
|
|
4937
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
4938
|
+
ctx.indent++;
|
|
4939
|
+
stmts.push(
|
|
4940
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
4941
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
4942
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
4943
|
+
);
|
|
4944
|
+
ctx.indent++;
|
|
4945
|
+
}
|
|
4621
4946
|
let sepAtPos = curV;
|
|
4622
4947
|
if (ctx.activeTrivia) {
|
|
4623
4948
|
if (ctx.capturing) {
|
|
@@ -4643,8 +4968,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4643
4968
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4644
4969
|
stmts.push(
|
|
4645
4970
|
...nextStmts,
|
|
4646
|
-
|
|
4647
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
4971
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4648
4972
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4649
4973
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4650
4974
|
);
|
|
@@ -4660,7 +4984,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4660
4984
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4661
4985
|
stmts.push(
|
|
4662
4986
|
...nextStmts,
|
|
4663
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
4987
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4664
4988
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4665
4989
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4666
4990
|
);
|
|
@@ -4680,7 +5004,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4680
5004
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4681
5005
|
stmts.push(
|
|
4682
5006
|
...nextStmts,
|
|
4683
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
5007
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4684
5008
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4685
5009
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4686
5010
|
);
|
|
@@ -4937,7 +5261,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4937
5261
|
stmts.push(
|
|
4938
5262
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4939
5263
|
`${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 === '
|
|
5264
|
+
`${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
5265
|
);
|
|
4942
5266
|
return { stmts, valueVar: ndV, endVar };
|
|
4943
5267
|
}
|
|
@@ -5027,6 +5351,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5027
5351
|
`${ind0}if (!${okVar}) {`,
|
|
5028
5352
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5029
5353
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5354
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5355
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5356
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5357
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5030
5358
|
`${ind0} ${valVar} = ${errV}`,
|
|
5031
5359
|
`${ind0} ${endVar} = ${pos}`,
|
|
5032
5360
|
`${ind0} ${okVar} = true`,
|
|
@@ -5193,7 +5521,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5193
5521
|
case "guard": {
|
|
5194
5522
|
const fnIdx = ctx.mapFns.length;
|
|
5195
5523
|
ctx.mapFns.push(def.predicate);
|
|
5196
|
-
ctx.mapFnSrcs.push(null);
|
|
5524
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5197
5525
|
const vv = v(ctx);
|
|
5198
5526
|
return {
|
|
5199
5527
|
stmts: [
|
|
@@ -5208,7 +5536,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5208
5536
|
const evIdx = ctx.mapFns.length;
|
|
5209
5537
|
const extra = def.extra;
|
|
5210
5538
|
ctx.mapFns.push((() => extra));
|
|
5211
|
-
ctx.mapFnSrcs.push(null);
|
|
5539
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5212
5540
|
const innerParser = def.parser;
|
|
5213
5541
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5214
5542
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5452,7 +5780,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5452
5780
|
}
|
|
5453
5781
|
return deps;
|
|
5454
5782
|
}
|
|
5455
|
-
function compile(combinator, mapFnSources) {
|
|
5783
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5456
5784
|
markUnusedValues(combinator);
|
|
5457
5785
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5458
5786
|
const ctx = {
|
|
@@ -5473,6 +5801,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5473
5801
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5474
5802
|
namedFnDecls: [],
|
|
5475
5803
|
capturing: hasNodeDef(combinator),
|
|
5804
|
+
recovery: opts?.recovery ?? false,
|
|
5476
5805
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5477
5806
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5478
5807
|
};
|
|
@@ -5525,7 +5854,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5525
5854
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5526
5855
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5527
5856
|
},
|
|
5528
|
-
// Note: collects
|
|
5857
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5529
5858
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5530
5859
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5531
5860
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5582,6 +5911,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5582
5911
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5583
5912
|
namedFnDecls: [],
|
|
5584
5913
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5914
|
+
recovery: opts?.recovery ?? false,
|
|
5585
5915
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5586
5916
|
ns,
|
|
5587
5917
|
deferFirstSetRefs: true,
|
|
@@ -6327,46 +6657,13 @@ function withCtx(extra, combinator) {
|
|
|
6327
6657
|
};
|
|
6328
6658
|
}
|
|
6329
6659
|
|
|
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
6660
|
// src/combinators/completions.ts
|
|
6365
|
-
function completionsAt(
|
|
6661
|
+
function completionsAt(target, input, offset, options = {}) {
|
|
6366
6662
|
const probe = { offset, best: null };
|
|
6367
|
-
const ctx = { trackLines: false, _probe: probe };
|
|
6368
|
-
const
|
|
6369
|
-
|
|
6663
|
+
const ctx = { trackLines: false, _probe: probe, ...options.tolerant ? { _tolerant: true, _rec: REC } : {} };
|
|
6664
|
+
const sliced = input.slice(0, offset);
|
|
6665
|
+
const result = "parseWithContext" in target ? target.parseWithContext(sliced, ctx, 0) : target.parse(sliced, 0, ctx);
|
|
6666
|
+
if (result.ok) return options.tolerant ? probe.best?.expected ?? [] : [];
|
|
6370
6667
|
const best = deeperFail(probe.best, result);
|
|
6371
6668
|
return best?.expected ?? [];
|
|
6372
6669
|
}
|
|
@@ -6376,23 +6673,6 @@ function deeperFail(a, b) {
|
|
|
6376
6673
|
return a.span.start >= b.span.start ? a : b;
|
|
6377
6674
|
}
|
|
6378
6675
|
|
|
6379
|
-
// src/combinators/recover-list.ts
|
|
6380
|
-
function tolerantElement(item, sentinel, until) {
|
|
6381
|
-
const el = transform(
|
|
6382
|
-
sequence(not(until), recover(item, sentinel)),
|
|
6383
|
-
([, value]) => value
|
|
6384
|
-
);
|
|
6385
|
-
if (el._def.tag === "transform") el._def.fnSrc = "([, value]) => value";
|
|
6386
|
-
return el;
|
|
6387
|
-
}
|
|
6388
|
-
function sepByRecover(item, separator, until) {
|
|
6389
|
-
const sentinel = choice(separator, until);
|
|
6390
|
-
return sepBy(tolerantElement(item, sentinel, until), separator);
|
|
6391
|
-
}
|
|
6392
|
-
function manyRecover(item, until) {
|
|
6393
|
-
return many(tolerantElement(item, until, until));
|
|
6394
|
-
}
|
|
6395
|
-
|
|
6396
6676
|
// src/cst/relative-spans.ts
|
|
6397
6677
|
function relativize(node2, parentBase = 0) {
|
|
6398
6678
|
return {
|
|
@@ -6487,6 +6767,9 @@ function editNode(node2, at, delta, parentBase, parentShift, stats) {
|
|
|
6487
6767
|
}
|
|
6488
6768
|
|
|
6489
6769
|
// src/functional/doc.ts
|
|
6770
|
+
function mkCtx(state, build, tolerant) {
|
|
6771
|
+
return tolerant ? { trackLines: false, state, build, _tolerant: true, _rec: REC, _errors: [] } : { trackLines: false, state, build };
|
|
6772
|
+
}
|
|
6490
6773
|
function asRuleFn(entry) {
|
|
6491
6774
|
return typeof entry === "function" ? entry : (input, pos, ctx) => entry.parse(input, pos, ctx);
|
|
6492
6775
|
}
|
|
@@ -6593,8 +6876,8 @@ function graftRelative(root, path, newNode, delta) {
|
|
|
6593
6876
|
children: newChildren
|
|
6594
6877
|
};
|
|
6595
6878
|
}
|
|
6596
|
-
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build) {
|
|
6597
|
-
const ctx =
|
|
6879
|
+
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build, tolerant) {
|
|
6880
|
+
const ctx = mkCtx(null, build, tolerant);
|
|
6598
6881
|
const out = [];
|
|
6599
6882
|
let pos = reStart;
|
|
6600
6883
|
let guard2 = 0;
|
|
@@ -6618,7 +6901,7 @@ function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build) {
|
|
|
6618
6901
|
}
|
|
6619
6902
|
return pos === reEnd ? out : null;
|
|
6620
6903
|
}
|
|
6621
|
-
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build) {
|
|
6904
|
+
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build, tolerant) {
|
|
6622
6905
|
const kids = C.children;
|
|
6623
6906
|
if (kids.length === 0) return null;
|
|
6624
6907
|
let h = 0;
|
|
@@ -6659,7 +6942,7 @@ function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registr
|
|
|
6659
6942
|
const reStart = h > 0 ? cStart + kids[h - 1].span.end : cStart;
|
|
6660
6943
|
const reEnd = cStart + kids[t].span.start + delta;
|
|
6661
6944
|
if (reEnd < reStart) return null;
|
|
6662
|
-
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build);
|
|
6945
|
+
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6663
6946
|
if (!middle) return null;
|
|
6664
6947
|
if (middle.length > 0) {
|
|
6665
6948
|
const last2 = middle[middle.length - 1];
|
|
@@ -6669,7 +6952,7 @@ function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registr
|
|
|
6669
6952
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6670
6953
|
if (newInput[reEnd] === sentinel) continue;
|
|
6671
6954
|
const probed = newInput.slice(0, reEnd) + sentinel.repeat(newInput.length - reEnd);
|
|
6672
|
-
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build);
|
|
6955
|
+
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6673
6956
|
if (!probe || probe.length !== middle.length) return null;
|
|
6674
6957
|
for (let i = 0; i < middle.length; i++) if (!structurallyEqual(probe[i], middle[i])) return null;
|
|
6675
6958
|
}
|
|
@@ -6697,6 +6980,11 @@ function structurallyEqual(a, b) {
|
|
|
6697
6980
|
if (at === "leaf" || at === "trivia") {
|
|
6698
6981
|
return a.value === b.value;
|
|
6699
6982
|
}
|
|
6983
|
+
if (at === "parseError") {
|
|
6984
|
+
const ae = a.expected ?? [];
|
|
6985
|
+
const be = b.expected ?? [];
|
|
6986
|
+
return ae.length === be.length && ae.every((x, i) => x === be[i]);
|
|
6987
|
+
}
|
|
6700
6988
|
if (a.type !== b.type) return false;
|
|
6701
6989
|
const ac = a.children;
|
|
6702
6990
|
const bc = b.children;
|
|
@@ -6706,13 +6994,13 @@ function structurallyEqual(a, b) {
|
|
|
6706
6994
|
}
|
|
6707
6995
|
return true;
|
|
6708
6996
|
}
|
|
6709
|
-
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced) {
|
|
6997
|
+
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced, tolerant) {
|
|
6710
6998
|
if (!produced.ok) return false;
|
|
6711
6999
|
if (boundary >= newInput.length) return true;
|
|
6712
7000
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6713
7001
|
if (newInput[boundary] === sentinel) continue;
|
|
6714
7002
|
const probed = newInput.slice(0, boundary) + sentinel.repeat(newInput.length - boundary);
|
|
6715
|
-
const ctx =
|
|
7003
|
+
const ctx = mkCtx(state, build, tolerant);
|
|
6716
7004
|
let r;
|
|
6717
7005
|
try {
|
|
6718
7006
|
r = ruleFn(probed, start, ctx);
|
|
@@ -6744,8 +7032,9 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6744
7032
|
_abs;
|
|
6745
7033
|
_rel;
|
|
6746
7034
|
errors;
|
|
7035
|
+
unconsumedFrom;
|
|
6747
7036
|
input;
|
|
6748
|
-
constructor(registry, rootRule, opts, trees, errors, input) {
|
|
7037
|
+
constructor(registry, rootRule, opts, trees, errors, unconsumedFrom, input) {
|
|
6749
7038
|
this._registry = registry;
|
|
6750
7039
|
this._fns = {};
|
|
6751
7040
|
this._reps = /* @__PURE__ */ new Set();
|
|
@@ -6758,6 +7047,7 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6758
7047
|
this._abs = trees.abs;
|
|
6759
7048
|
this._rel = trees.rel;
|
|
6760
7049
|
this.errors = errors;
|
|
7050
|
+
this.unconsumedFrom = unconsumedFrom;
|
|
6761
7051
|
this.input = input;
|
|
6762
7052
|
}
|
|
6763
7053
|
/**
|
|
@@ -6780,6 +7070,19 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6780
7070
|
if (!rel) throw new Error("spanAt on a failed parse (tree is null)");
|
|
6781
7071
|
return absoluteSpanCST(rel, path);
|
|
6782
7072
|
}
|
|
7073
|
+
/**
|
|
7074
|
+
* Wrap a reused (grafted/spliced) RELATIVE tree, recomputing `errors` and
|
|
7075
|
+
* `unconsumedFrom` from it so both stay consistent with the tree across the
|
|
7076
|
+
* edit (the flat errors are recovered errors embedded in the reused subtrees;
|
|
7077
|
+
* unconsumedFrom re-derives trailing junk over the new input).
|
|
7078
|
+
*/
|
|
7079
|
+
wrapReuse(newTree, newInput) {
|
|
7080
|
+
const trivia2 = triviaOf(this._registry[this._rootRule], this._opts);
|
|
7081
|
+
const end = newTree.span.end;
|
|
7082
|
+
const errors = collectEmbeddedErrors(newTree, 0, []);
|
|
7083
|
+
const unconsumedFrom = unconsumedAfter(end, newInput, trivia2);
|
|
7084
|
+
return new _ParseDocImpl(this._registry, this._rootRule, this._opts, { rel: newTree }, errors, unconsumedFrom, newInput);
|
|
7085
|
+
}
|
|
6783
7086
|
edit(from, to, replacement) {
|
|
6784
7087
|
const newInput = this.input.slice(0, from) + replacement + this.input.slice(to);
|
|
6785
7088
|
const reparse = () => parseDoc(this._registry, this._rootRule, newInput, this._opts);
|
|
@@ -6801,22 +7104,22 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6801
7104
|
const ruleFn = this._fns[node2.type];
|
|
6802
7105
|
if (!ruleFn) continue;
|
|
6803
7106
|
if (!(absStart <= from && to <= absEnd)) continue;
|
|
6804
|
-
const ctx =
|
|
7107
|
+
const ctx = mkCtx(node2.state, this._opts.build, !!this._opts.tolerant);
|
|
6805
7108
|
const r = ruleFn(newInput, absStart, ctx);
|
|
6806
7109
|
if (!r.ok) continue;
|
|
6807
7110
|
if (r.span.end !== absEnd + delta) continue;
|
|
6808
|
-
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r)) {
|
|
7111
|
+
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r, !!this._opts.tolerant)) {
|
|
6809
7112
|
continue;
|
|
6810
7113
|
}
|
|
6811
7114
|
const parentBase = absStart - node2.span.start;
|
|
6812
7115
|
const newRel = relativizeCST(r.value, parentBase);
|
|
6813
7116
|
if (delta === 0) {
|
|
6814
7117
|
const newTree2 = replaceAtPath(rebuild, root, path, newRel);
|
|
6815
|
-
return
|
|
7118
|
+
return this.wrapReuse(newTree2, newInput);
|
|
6816
7119
|
}
|
|
6817
7120
|
if (this._opts.rebuild) return reparse();
|
|
6818
7121
|
const newTree = graftRelative(root, path, newRel, delta);
|
|
6819
|
-
return
|
|
7122
|
+
return this.wrapReuse(newTree, newInput);
|
|
6820
7123
|
}
|
|
6821
7124
|
if (this._opts.structuralReuse && delta !== 0 && !this._opts.rebuild) {
|
|
6822
7125
|
const spliceCandidates = [...candidates, { node: root, path: [] }];
|
|
@@ -6824,22 +7127,50 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6824
7127
|
if (!this._reps.has(node2.type)) continue;
|
|
6825
7128
|
const { start: cStart, end: cEnd } = absoluteSpanCST(root, path);
|
|
6826
7129
|
if (!(cStart <= from && to <= cEnd)) continue;
|
|
6827
|
-
const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build);
|
|
6828
|
-
if (spliced) return
|
|
7130
|
+
const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build, !!this._opts.tolerant);
|
|
7131
|
+
if (spliced) return this.wrapReuse(spliced, newInput);
|
|
6829
7132
|
}
|
|
6830
7133
|
}
|
|
6831
7134
|
return reparse();
|
|
6832
7135
|
}
|
|
6833
7136
|
};
|
|
7137
|
+
function triviaOf(entry, opts) {
|
|
7138
|
+
if (opts.trivia) return opts.trivia;
|
|
7139
|
+
if (entry === void 0 || typeof entry === "function") return void 0;
|
|
7140
|
+
const meta = entry._meta;
|
|
7141
|
+
return meta ? meta.grammarTrivia : void 0;
|
|
7142
|
+
}
|
|
7143
|
+
function unconsumedAfter(end, input, trivia2) {
|
|
7144
|
+
let pos = end;
|
|
7145
|
+
if (trivia2 && pos < input.length) {
|
|
7146
|
+
const t = trivia2.parse(input, pos, { trackLines: false });
|
|
7147
|
+
if (t.ok && t.span.end > pos) pos = t.span.end;
|
|
7148
|
+
}
|
|
7149
|
+
return pos < input.length ? pos : null;
|
|
7150
|
+
}
|
|
7151
|
+
function collectEmbeddedErrors(node2, base, out) {
|
|
7152
|
+
const c = node2;
|
|
7153
|
+
if (!c || typeof c !== "object" || !c.span) return out;
|
|
7154
|
+
const start = base + c.span.start;
|
|
7155
|
+
if (c._tag === "parseError") {
|
|
7156
|
+
out.push({ _tag: "parseError", span: { start, end: base + c.span.end }, expected: c.expected ?? [] });
|
|
7157
|
+
return out;
|
|
7158
|
+
}
|
|
7159
|
+
if (Array.isArray(c.children)) for (const k of c.children) collectEmbeddedErrors(k, start, out);
|
|
7160
|
+
return out;
|
|
7161
|
+
}
|
|
6834
7162
|
function parseDoc(registry, rootRule, input, opts = {}) {
|
|
6835
7163
|
const entry = registry[rootRule];
|
|
6836
7164
|
if (!entry) throw new Error(`No rule '${rootRule}' in registry`);
|
|
6837
|
-
const ctx =
|
|
7165
|
+
const ctx = mkCtx(opts.state, opts.build, !!opts.tolerant);
|
|
6838
7166
|
const r = asRuleFn(entry)(input, 0, ctx);
|
|
6839
7167
|
if (r.ok) {
|
|
6840
|
-
|
|
7168
|
+
const errors = ctx._errors ? [...ctx._errors] : [];
|
|
7169
|
+
const unconsumedFrom = unconsumedAfter(r.span.end, input, triviaOf(entry, opts));
|
|
7170
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: r.value }, errors, unconsumedFrom, input);
|
|
6841
7171
|
}
|
|
6842
|
-
|
|
7172
|
+
const fail = { _tag: "parseError", span: r.span, expected: r.expected };
|
|
7173
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
|
|
6843
7174
|
}
|
|
6844
7175
|
|
|
6845
7176
|
// src/functional/run.ts
|
|
@@ -6860,7 +7191,8 @@ function run(entry, input, options = {}) {
|
|
|
6860
7191
|
build: options.build,
|
|
6861
7192
|
state: options.state,
|
|
6862
7193
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
6863
|
-
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {}
|
|
7194
|
+
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7195
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
6864
7196
|
};
|
|
6865
7197
|
const r = invoke(entry, input, 0, ctx);
|
|
6866
7198
|
let unconsumedFrom = null;
|
|
@@ -7246,7 +7578,6 @@ export {
|
|
|
7246
7578
|
literal,
|
|
7247
7579
|
makeWord,
|
|
7248
7580
|
many,
|
|
7249
|
-
manyRecover,
|
|
7250
7581
|
noTrivia,
|
|
7251
7582
|
node,
|
|
7252
7583
|
not,
|
|
@@ -7256,7 +7587,6 @@ export {
|
|
|
7256
7587
|
parse,
|
|
7257
7588
|
parseDoc,
|
|
7258
7589
|
parser,
|
|
7259
|
-
recover,
|
|
7260
7590
|
ref,
|
|
7261
7591
|
regex,
|
|
7262
7592
|
relativize,
|
|
@@ -7265,7 +7595,6 @@ export {
|
|
|
7265
7595
|
run,
|
|
7266
7596
|
scanTo,
|
|
7267
7597
|
sepBy,
|
|
7268
|
-
sepByRecover,
|
|
7269
7598
|
sequence,
|
|
7270
7599
|
shiftAbsolute,
|
|
7271
7600
|
skip,
|