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.cjs
CHANGED
|
@@ -55,7 +55,6 @@ __export(index_exports, {
|
|
|
55
55
|
literal: () => literal,
|
|
56
56
|
makeWord: () => makeWord,
|
|
57
57
|
many: () => many,
|
|
58
|
-
manyRecover: () => manyRecover,
|
|
59
58
|
noTrivia: () => noTrivia,
|
|
60
59
|
node: () => node,
|
|
61
60
|
not: () => not,
|
|
@@ -65,7 +64,6 @@ __export(index_exports, {
|
|
|
65
64
|
parse: () => parse,
|
|
66
65
|
parseDoc: () => parseDoc,
|
|
67
66
|
parser: () => parser,
|
|
68
|
-
recover: () => recover,
|
|
69
67
|
ref: () => ref,
|
|
70
68
|
regex: () => regex,
|
|
71
69
|
relativize: () => relativize,
|
|
@@ -74,7 +72,6 @@ __export(index_exports, {
|
|
|
74
72
|
run: () => run,
|
|
75
73
|
scanTo: () => scanTo,
|
|
76
74
|
sepBy: () => sepBy,
|
|
77
|
-
sepByRecover: () => sepByRecover,
|
|
78
75
|
sequence: () => sequence,
|
|
79
76
|
shiftAbsolute: () => shiftAbsolute,
|
|
80
77
|
skip: () => skip,
|
|
@@ -344,7 +341,13 @@ function saveCstMark(ctx) {
|
|
|
344
341
|
raw: cstRawLen(ctx),
|
|
345
342
|
tlog: cstTlLen(ctx),
|
|
346
343
|
leaves: cstLeavesLen(ctx),
|
|
347
|
-
fields: ctx._fields?.length ?? 0
|
|
344
|
+
fields: ctx._fields?.length ?? 0,
|
|
345
|
+
// Speculative rollback must truncate the flat recovery-error sink in lockstep
|
|
346
|
+
// with the CST leaves: a branch that recovered (pushing a ParseError to
|
|
347
|
+
// ctx._errors AND embedding it as a CST child via captureError) then failed
|
|
348
|
+
// must remove BOTH, or the flat error survives as a GHOST that a tree walk
|
|
349
|
+
// can't see (flat run().errors would disagree with the embedded set).
|
|
350
|
+
errors: ctx._errors?.length ?? 0
|
|
348
351
|
};
|
|
349
352
|
}
|
|
350
353
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -360,6 +363,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
360
363
|
if (len === 0) b[keySingle] = void 0;
|
|
361
364
|
}
|
|
362
365
|
function rollbackCstCapture(ctx, mark) {
|
|
366
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
363
367
|
const b = ctx._cstBuf;
|
|
364
368
|
if (b) {
|
|
365
369
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -920,12 +924,163 @@ function keywords(words, opts = {}) {
|
|
|
920
924
|
};
|
|
921
925
|
}
|
|
922
926
|
|
|
927
|
+
// src/recovery/scan.ts
|
|
928
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
929
|
+
const s = {
|
|
930
|
+
_probe: ctx._probe,
|
|
931
|
+
_errors: ctx._errors,
|
|
932
|
+
_cstLeaves: ctx._cstLeaves,
|
|
933
|
+
_cstChildren: ctx._cstChildren,
|
|
934
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
935
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
936
|
+
_triviaLog: ctx._triviaLog,
|
|
937
|
+
_fields: ctx._fields,
|
|
938
|
+
_cstBuf: ctx._cstBuf,
|
|
939
|
+
_tolerant: ctx._tolerant,
|
|
940
|
+
_sync: ctx._sync
|
|
941
|
+
};
|
|
942
|
+
ctx._probe = void 0;
|
|
943
|
+
ctx._errors = void 0;
|
|
944
|
+
ctx._cstLeaves = void 0;
|
|
945
|
+
ctx._cstChildren = void 0;
|
|
946
|
+
ctx._cstRawChildren = void 0;
|
|
947
|
+
ctx._cstTriviaLog = void 0;
|
|
948
|
+
ctx._triviaLog = void 0;
|
|
949
|
+
ctx._fields = void 0;
|
|
950
|
+
ctx._cstBuf = void 0;
|
|
951
|
+
ctx._tolerant = void 0;
|
|
952
|
+
ctx._sync = void 0;
|
|
953
|
+
try {
|
|
954
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
955
|
+
} finally {
|
|
956
|
+
ctx._probe = s._probe;
|
|
957
|
+
ctx._errors = s._errors;
|
|
958
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
959
|
+
ctx._cstChildren = s._cstChildren;
|
|
960
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
961
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
962
|
+
ctx._triviaLog = s._triviaLog;
|
|
963
|
+
ctx._fields = s._fields;
|
|
964
|
+
ctx._cstBuf = s._cstBuf;
|
|
965
|
+
ctx._tolerant = s._tolerant;
|
|
966
|
+
ctx._sync = s._sync;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
function orSentinel(a, b) {
|
|
970
|
+
if (b === void 0) return a;
|
|
971
|
+
return {
|
|
972
|
+
_tag: "orSentinel",
|
|
973
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
974
|
+
_def: { tag: "unknown" },
|
|
975
|
+
parse(input, pos, ctx) {
|
|
976
|
+
const ra = a.parse(input, pos, ctx);
|
|
977
|
+
if (ra.ok) return ra;
|
|
978
|
+
return b.parse(input, pos, ctx);
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
function firstSetSentinel(fs) {
|
|
983
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
984
|
+
const ranges = fs.ranges;
|
|
985
|
+
return {
|
|
986
|
+
_tag: "firstSetSentinel",
|
|
987
|
+
_meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
|
|
988
|
+
_def: { tag: "unknown" },
|
|
989
|
+
parse(input, pos) {
|
|
990
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
991
|
+
if (code !== void 0) {
|
|
992
|
+
for (const r of ranges) {
|
|
993
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
1001
|
+
let scanPos = from;
|
|
1002
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
1003
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
1004
|
+
ctx._errors?.push(error);
|
|
1005
|
+
return { error, end: scanPos };
|
|
1006
|
+
}
|
|
1007
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
1008
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
1009
|
+
}
|
|
1010
|
+
function captureError(ctx, error) {
|
|
1011
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1012
|
+
}
|
|
1013
|
+
var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
|
|
1014
|
+
|
|
1015
|
+
// src/combinators/expect.ts
|
|
1016
|
+
function deriveExpected(c) {
|
|
1017
|
+
const def = c._def;
|
|
1018
|
+
switch (def.tag) {
|
|
1019
|
+
case "literal":
|
|
1020
|
+
return [JSON.stringify(def.value)];
|
|
1021
|
+
case "regex":
|
|
1022
|
+
return [`/${def.source}/`];
|
|
1023
|
+
case "keywords":
|
|
1024
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1025
|
+
case "label":
|
|
1026
|
+
return [def.label];
|
|
1027
|
+
case "choice":
|
|
1028
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1029
|
+
case "sequence":
|
|
1030
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1031
|
+
case "node":
|
|
1032
|
+
case "grammar":
|
|
1033
|
+
case "trivia":
|
|
1034
|
+
case "token":
|
|
1035
|
+
case "optional":
|
|
1036
|
+
case "many":
|
|
1037
|
+
case "oneOrMore":
|
|
1038
|
+
case "transform":
|
|
1039
|
+
case "not":
|
|
1040
|
+
return deriveExpected(def.parser);
|
|
1041
|
+
case "lazy": {
|
|
1042
|
+
const name = c._ruleName;
|
|
1043
|
+
try {
|
|
1044
|
+
return deriveExpected(def.thunk());
|
|
1045
|
+
} catch {
|
|
1046
|
+
return name ? [name] : [];
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
default:
|
|
1050
|
+
return [];
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
function expect(combinator, label2) {
|
|
1054
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1055
|
+
const meta = {
|
|
1056
|
+
firstSet: combinator._meta.firstSet,
|
|
1057
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1058
|
+
isTrivia: false
|
|
1059
|
+
};
|
|
1060
|
+
return {
|
|
1061
|
+
_tag: "expect",
|
|
1062
|
+
_meta: meta,
|
|
1063
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1064
|
+
parse(input, pos, ctx) {
|
|
1065
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1066
|
+
if (result.ok) return result;
|
|
1067
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
1068
|
+
ctx._errors?.push(error);
|
|
1069
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1070
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
function isParseError(value) {
|
|
1075
|
+
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
1076
|
+
}
|
|
1077
|
+
|
|
923
1078
|
// src/combinators/choice.ts
|
|
924
1079
|
function choice(...args) {
|
|
925
1080
|
const parsers = args.map((a) => "gate" in a ? a.combinator : a);
|
|
926
1081
|
const gates = args.map((a) => "gate" in a ? a.gate : null);
|
|
927
1082
|
const hasGates = gates.some((g) => g !== null);
|
|
928
|
-
const disjoint =
|
|
1083
|
+
const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
|
|
929
1084
|
let combined = { kind: "empty" };
|
|
930
1085
|
for (const p of parsers) combined = union(combined, p._meta.firstSet);
|
|
931
1086
|
const meta = {
|
|
@@ -964,17 +1119,21 @@ function choice(...args) {
|
|
|
964
1119
|
const expected = [];
|
|
965
1120
|
if (disjoint && pos < input.length) {
|
|
966
1121
|
const code = input.codePointAt(pos);
|
|
967
|
-
let
|
|
968
|
-
if (
|
|
969
|
-
for (
|
|
970
|
-
if (inFirstSet(code,
|
|
971
|
-
|
|
1122
|
+
let idx = code < 128 ? asciiDispatch[code] : -1;
|
|
1123
|
+
if (idx < 0) {
|
|
1124
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1125
|
+
if (inFirstSet(code, parsers[i]._meta.firstSet)) {
|
|
1126
|
+
idx = i;
|
|
972
1127
|
break;
|
|
973
1128
|
}
|
|
974
1129
|
}
|
|
975
1130
|
}
|
|
976
|
-
if (
|
|
977
|
-
const
|
|
1131
|
+
if (idx >= 0) {
|
|
1132
|
+
const gate = gates[idx];
|
|
1133
|
+
if (gate && !gate(ctx.state)) {
|
|
1134
|
+
return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
|
|
1135
|
+
}
|
|
1136
|
+
const result = parsers[idx].parse(input, pos, ctx);
|
|
978
1137
|
if (result.ok) return result;
|
|
979
1138
|
expected.push(...result.expected);
|
|
980
1139
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
@@ -1155,13 +1314,13 @@ function areDisjoint(sets) {
|
|
|
1155
1314
|
return true;
|
|
1156
1315
|
}
|
|
1157
1316
|
function buildAsciiDispatch(parsers) {
|
|
1158
|
-
const table = Array(128).fill(
|
|
1159
|
-
for (
|
|
1160
|
-
const fs =
|
|
1317
|
+
const table = Array(128).fill(-1);
|
|
1318
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1319
|
+
const fs = parsers[i]._meta.firstSet;
|
|
1161
1320
|
if (fs.kind !== "ranges") continue;
|
|
1162
1321
|
for (const { lo, hi } of fs.ranges) {
|
|
1163
1322
|
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1164
|
-
table[code] =
|
|
1323
|
+
table[code] = i;
|
|
1165
1324
|
}
|
|
1166
1325
|
}
|
|
1167
1326
|
}
|
|
@@ -1306,10 +1465,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1306
1465
|
}
|
|
1307
1466
|
function saveTriviaMark(ctx) {
|
|
1308
1467
|
const m = saveCstMark(ctx);
|
|
1309
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1468
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1310
1469
|
}
|
|
1311
1470
|
function rollbackTrivia(ctx, mark) {
|
|
1312
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1471
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1313
1472
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1314
1473
|
}
|
|
1315
1474
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1553,11 +1712,59 @@ function sequence(...parsers) {
|
|
|
1553
1712
|
isTrivia: false
|
|
1554
1713
|
};
|
|
1555
1714
|
const def = { tag: "sequence", parsers };
|
|
1715
|
+
let followSentinels;
|
|
1716
|
+
function parseTolerant(input, pos, ctx) {
|
|
1717
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1718
|
+
const fs = parsers.slice(i + 1).reduce(
|
|
1719
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1720
|
+
{ kind: "empty" }
|
|
1721
|
+
);
|
|
1722
|
+
return firstSetSentinel(fs);
|
|
1723
|
+
});
|
|
1724
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1725
|
+
let cur = pos;
|
|
1726
|
+
const inheritedSync = ctx._sync;
|
|
1727
|
+
try {
|
|
1728
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1729
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1730
|
+
if (ctx.trivia && i > 0) {
|
|
1731
|
+
const mark = saveTriviaMark(ctx);
|
|
1732
|
+
let scanEnd;
|
|
1733
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1734
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1735
|
+
scan.commit();
|
|
1736
|
+
scanEnd = scan.end;
|
|
1737
|
+
} else {
|
|
1738
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1739
|
+
}
|
|
1740
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1741
|
+
if (!result2.ok) return result2;
|
|
1742
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1743
|
+
else rollbackTrivia(ctx, mark);
|
|
1744
|
+
if (values !== void 0) values.push(result2.value);
|
|
1745
|
+
continue;
|
|
1746
|
+
}
|
|
1747
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1748
|
+
if (!result.ok) return result;
|
|
1749
|
+
if (values !== void 0) values.push(result.value);
|
|
1750
|
+
cur = result.span.end;
|
|
1751
|
+
}
|
|
1752
|
+
} finally {
|
|
1753
|
+
ctx._sync = inheritedSync;
|
|
1754
|
+
}
|
|
1755
|
+
return {
|
|
1756
|
+
ok: true,
|
|
1757
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1758
|
+
value: values ?? void 0,
|
|
1759
|
+
span: { start: pos, end: cur }
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1556
1762
|
return {
|
|
1557
1763
|
_tag: "sequence",
|
|
1558
1764
|
_meta: meta,
|
|
1559
1765
|
_def: def,
|
|
1560
1766
|
parse(input, pos, ctx) {
|
|
1767
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1561
1768
|
const values = def.valueUnused ? void 0 : [];
|
|
1562
1769
|
let cur = pos;
|
|
1563
1770
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1616,7 +1823,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1616
1823
|
const result = combinator.parse(input, pos, ctx);
|
|
1617
1824
|
if (!result.ok) {
|
|
1618
1825
|
rollbackTrivia(ctx, mark);
|
|
1619
|
-
return { fail: result };
|
|
1826
|
+
return { fail: result, failPos: pos };
|
|
1620
1827
|
}
|
|
1621
1828
|
if (result.span.end === pos) {
|
|
1622
1829
|
rollbackTrivia(ctx, mark);
|
|
@@ -1631,6 +1838,7 @@ function many(combinator) {
|
|
|
1631
1838
|
isTrivia: false
|
|
1632
1839
|
};
|
|
1633
1840
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1841
|
+
let expected;
|
|
1634
1842
|
return {
|
|
1635
1843
|
_tag: "many",
|
|
1636
1844
|
_meta: meta,
|
|
@@ -1640,7 +1848,18 @@ function many(combinator) {
|
|
|
1640
1848
|
let cur = pos;
|
|
1641
1849
|
while (cur < input.length) {
|
|
1642
1850
|
const item = repItem(combinator, input, cur, ctx);
|
|
1643
|
-
if (item === "stop"
|
|
1851
|
+
if (item === "stop") break;
|
|
1852
|
+
if ("fail" in item) {
|
|
1853
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1854
|
+
if (sync === void 0) break;
|
|
1855
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1856
|
+
expected ??= deriveExpected(combinator);
|
|
1857
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1858
|
+
if (values !== void 0) values.push(error);
|
|
1859
|
+
captureError(ctx, error);
|
|
1860
|
+
cur = end;
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1644
1863
|
if (values !== void 0) values.push(item.value);
|
|
1645
1864
|
cur = item.end;
|
|
1646
1865
|
}
|
|
@@ -1655,6 +1874,7 @@ function oneOrMore(combinator) {
|
|
|
1655
1874
|
isTrivia: false
|
|
1656
1875
|
};
|
|
1657
1876
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1877
|
+
let expected;
|
|
1658
1878
|
return {
|
|
1659
1879
|
_tag: "oneOrMore",
|
|
1660
1880
|
_meta: meta,
|
|
@@ -1666,7 +1886,18 @@ function oneOrMore(combinator) {
|
|
|
1666
1886
|
let cur = first.span.end;
|
|
1667
1887
|
while (cur < input.length) {
|
|
1668
1888
|
const item = repItem(combinator, input, cur, ctx);
|
|
1669
|
-
if (item === "stop"
|
|
1889
|
+
if (item === "stop") break;
|
|
1890
|
+
if ("fail" in item) {
|
|
1891
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1892
|
+
if (sync === void 0) break;
|
|
1893
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1894
|
+
expected ??= deriveExpected(combinator);
|
|
1895
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1896
|
+
if (values !== void 0) values.push(error);
|
|
1897
|
+
captureError(ctx, error);
|
|
1898
|
+
cur = end;
|
|
1899
|
+
continue;
|
|
1900
|
+
}
|
|
1670
1901
|
if (values !== void 0) values.push(item.value);
|
|
1671
1902
|
cur = item.end;
|
|
1672
1903
|
}
|
|
@@ -1712,15 +1943,29 @@ function sepBy(combinator, separator) {
|
|
|
1712
1943
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1713
1944
|
isTrivia: false
|
|
1714
1945
|
};
|
|
1946
|
+
let expected;
|
|
1715
1947
|
return {
|
|
1716
1948
|
_tag: "sepBy",
|
|
1717
1949
|
_meta: meta,
|
|
1718
1950
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1719
1951
|
parse(input, pos, ctx) {
|
|
1720
1952
|
const first = combinator.parse(input, pos, ctx);
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1953
|
+
const values = [];
|
|
1954
|
+
let cur;
|
|
1955
|
+
if (first.ok) {
|
|
1956
|
+
values.push(first.value);
|
|
1957
|
+
cur = first.span.end;
|
|
1958
|
+
} else {
|
|
1959
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1960
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1961
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1962
|
+
}
|
|
1963
|
+
expected ??= deriveExpected(combinator);
|
|
1964
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1965
|
+
values.push(rec.error);
|
|
1966
|
+
captureError(ctx, rec.error);
|
|
1967
|
+
cur = rec.end;
|
|
1968
|
+
}
|
|
1724
1969
|
while (cur < input.length) {
|
|
1725
1970
|
const loopMark = saveTriviaMark(ctx);
|
|
1726
1971
|
let sepPos = cur;
|
|
@@ -1750,6 +1995,15 @@ function sepBy(combinator, separator) {
|
|
|
1750
1995
|
}
|
|
1751
1996
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1752
1997
|
if (!next.ok) {
|
|
1998
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1999
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2000
|
+
expected ??= deriveExpected(combinator);
|
|
2001
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
2002
|
+
values.push(rec.error);
|
|
2003
|
+
captureError(ctx, rec.error);
|
|
2004
|
+
cur = rec.end;
|
|
2005
|
+
continue;
|
|
2006
|
+
}
|
|
1753
2007
|
rollbackTrivia(ctx, loopMark);
|
|
1754
2008
|
break;
|
|
1755
2009
|
}
|
|
@@ -1923,7 +2177,7 @@ function rules(a, b) {
|
|
|
1923
2177
|
cache[key] = parser2;
|
|
1924
2178
|
}
|
|
1925
2179
|
}
|
|
1926
|
-
if (options?.trivia
|
|
2180
|
+
if (options?.trivia != null) {
|
|
1927
2181
|
for (const key of Object.keys(definitions)) {
|
|
1928
2182
|
const rule = cache[key];
|
|
1929
2183
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1953,7 +2207,9 @@ function not(combinator) {
|
|
|
1953
2207
|
_meta: meta,
|
|
1954
2208
|
_def: { tag: "not", parser: combinator },
|
|
1955
2209
|
parse(input, pos, ctx) {
|
|
2210
|
+
const mark = saveCstMark(ctx);
|
|
1956
2211
|
const result = combinator.parse(input, pos, ctx);
|
|
2212
|
+
rollbackCstCapture(ctx, mark);
|
|
1957
2213
|
if (result.ok) {
|
|
1958
2214
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1959
2215
|
}
|
|
@@ -2067,7 +2323,7 @@ function unwrapChild(child) {
|
|
|
2067
2323
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
2068
2324
|
}
|
|
2069
2325
|
function isCstChild(value) {
|
|
2070
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2326
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
2071
2327
|
}
|
|
2072
2328
|
function missingInferredType() {
|
|
2073
2329
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2345,65 +2601,6 @@ function token(root) {
|
|
|
2345
2601
|
};
|
|
2346
2602
|
}
|
|
2347
2603
|
|
|
2348
|
-
// src/combinators/expect.ts
|
|
2349
|
-
function deriveExpected(c) {
|
|
2350
|
-
const def = c._def;
|
|
2351
|
-
switch (def.tag) {
|
|
2352
|
-
case "literal":
|
|
2353
|
-
return [JSON.stringify(def.value)];
|
|
2354
|
-
case "regex":
|
|
2355
|
-
return [`/${def.source}/`];
|
|
2356
|
-
case "keywords":
|
|
2357
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2358
|
-
case "label":
|
|
2359
|
-
return [def.label];
|
|
2360
|
-
case "choice":
|
|
2361
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2362
|
-
case "sequence":
|
|
2363
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2364
|
-
case "node":
|
|
2365
|
-
case "grammar":
|
|
2366
|
-
case "trivia":
|
|
2367
|
-
case "token":
|
|
2368
|
-
case "optional":
|
|
2369
|
-
case "many":
|
|
2370
|
-
case "oneOrMore":
|
|
2371
|
-
case "transform":
|
|
2372
|
-
case "not":
|
|
2373
|
-
return deriveExpected(def.parser);
|
|
2374
|
-
case "lazy": {
|
|
2375
|
-
const name = c._ruleName;
|
|
2376
|
-
try {
|
|
2377
|
-
return deriveExpected(def.thunk());
|
|
2378
|
-
} catch {
|
|
2379
|
-
return name ? [name] : [];
|
|
2380
|
-
}
|
|
2381
|
-
}
|
|
2382
|
-
default:
|
|
2383
|
-
return [];
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
function expect(combinator, label2) {
|
|
2387
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2388
|
-
const meta = {
|
|
2389
|
-
firstSet: combinator._meta.firstSet,
|
|
2390
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2391
|
-
isTrivia: false
|
|
2392
|
-
};
|
|
2393
|
-
return {
|
|
2394
|
-
_tag: "expect",
|
|
2395
|
-
_meta: meta,
|
|
2396
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2397
|
-
parse(input, pos, ctx) {
|
|
2398
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2399
|
-
if (result.ok) return result;
|
|
2400
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2401
|
-
ctx._errors?.push(error);
|
|
2402
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2403
|
-
}
|
|
2404
|
-
};
|
|
2405
|
-
}
|
|
2406
|
-
|
|
2407
2604
|
// src/compiler/scannable-run.ts
|
|
2408
2605
|
var BACKSLASH = 92;
|
|
2409
2606
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2475,20 +2672,39 @@ function parseSeqParts(source) {
|
|
|
2475
2672
|
lit = [];
|
|
2476
2673
|
}
|
|
2477
2674
|
};
|
|
2478
|
-
const
|
|
2675
|
+
const braceQuant = (at) => {
|
|
2676
|
+
const close = source.indexOf("}", at);
|
|
2677
|
+
if (close === -1) return null;
|
|
2678
|
+
const body = source.slice(at + 1, close);
|
|
2679
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2680
|
+
if (!m) return null;
|
|
2681
|
+
const min = Number(m[1]);
|
|
2682
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2683
|
+
if (max < 1 || min > max) return null;
|
|
2684
|
+
return { min, max, len: close - at + 1 };
|
|
2685
|
+
};
|
|
2686
|
+
const runFrom = (ranges, negated, at) => {
|
|
2687
|
+
const q = source[at];
|
|
2479
2688
|
if (q === "+") {
|
|
2480
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2689
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2481
2690
|
return 1;
|
|
2482
2691
|
}
|
|
2483
2692
|
if (q === "*") {
|
|
2484
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2693
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2485
2694
|
return 1;
|
|
2486
2695
|
}
|
|
2487
2696
|
if (q === "?") {
|
|
2488
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2697
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2489
2698
|
return 1;
|
|
2490
2699
|
}
|
|
2491
|
-
|
|
2700
|
+
if (q === "{") {
|
|
2701
|
+
const b = braceQuant(at);
|
|
2702
|
+
if (b) {
|
|
2703
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2704
|
+
return b.len;
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2492
2708
|
return 0;
|
|
2493
2709
|
};
|
|
2494
2710
|
let i = 0;
|
|
@@ -2513,7 +2729,7 @@ function parseSeqParts(source) {
|
|
|
2513
2729
|
if (!ranges) return null;
|
|
2514
2730
|
flush();
|
|
2515
2731
|
i = k + 1;
|
|
2516
|
-
i += runFrom(ranges, neg,
|
|
2732
|
+
i += runFrom(ranges, neg, i);
|
|
2517
2733
|
continue;
|
|
2518
2734
|
}
|
|
2519
2735
|
if (ch === "\\") {
|
|
@@ -2521,7 +2737,7 @@ function parseSeqParts(source) {
|
|
|
2521
2737
|
if (e === "d" || e === "w" || e === "s") {
|
|
2522
2738
|
flush();
|
|
2523
2739
|
i += 2;
|
|
2524
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2740
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2525
2741
|
continue;
|
|
2526
2742
|
}
|
|
2527
2743
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2610,7 +2826,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2610
2826
|
let hasMandatory = false;
|
|
2611
2827
|
for (let k = 0; k < parts.length; k++) {
|
|
2612
2828
|
const p = parts[k];
|
|
2613
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2829
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2614
2830
|
if (mandatory) hasMandatory = true;
|
|
2615
2831
|
if (p.part === "group") {
|
|
2616
2832
|
const exposure = groupPartExposure(p);
|
|
@@ -2621,9 +2837,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2621
2837
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2622
2838
|
}
|
|
2623
2839
|
}
|
|
2624
|
-
const
|
|
2625
|
-
|
|
2626
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2840
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2841
|
+
if (needsDisjoint) {
|
|
2627
2842
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2628
2843
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2629
2844
|
}
|
|
@@ -2680,8 +2895,8 @@ function fixedClassSeq(shape) {
|
|
|
2680
2895
|
if (p.part === "lit") {
|
|
2681
2896
|
if (p.optional) return null;
|
|
2682
2897
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2683
|
-
} else if (p.part === "run" &&
|
|
2684
|
-
out.push({ ranges: p.ranges, negated: p.negated });
|
|
2898
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2899
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2685
2900
|
} else {
|
|
2686
2901
|
return null;
|
|
2687
2902
|
}
|
|
@@ -2733,7 +2948,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2733
2948
|
const last = shape.parts[shape.parts.length - 1];
|
|
2734
2949
|
if (last.part === "lit") return null;
|
|
2735
2950
|
if (last.part === "run") {
|
|
2736
|
-
if (last.
|
|
2951
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2737
2952
|
return null;
|
|
2738
2953
|
}
|
|
2739
2954
|
return groupPartExposure(last);
|
|
@@ -2870,7 +3085,7 @@ function partFirstAccept(part) {
|
|
|
2870
3085
|
function seqFirstAccept(parts) {
|
|
2871
3086
|
const sets = [];
|
|
2872
3087
|
for (const p of parts) {
|
|
2873
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
3088
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2874
3089
|
sets.push(partFirstAccept(p));
|
|
2875
3090
|
if (mandatory) break;
|
|
2876
3091
|
}
|
|
@@ -3285,7 +3500,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3285
3500
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3286
3501
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3287
3502
|
}
|
|
3288
|
-
} else if (p.part === "run" &&
|
|
3503
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3504
|
+
const s = mint("_s");
|
|
3505
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3506
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3507
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3508
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3509
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3289
3510
|
if (p.min === 1) {
|
|
3290
3511
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3291
3512
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3295,8 +3516,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3295
3516
|
} else if (p.part === "run") {
|
|
3296
3517
|
const s = mint("_s");
|
|
3297
3518
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3298
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3299
|
-
if (p.min
|
|
3519
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3520
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3300
3521
|
} else {
|
|
3301
3522
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3302
3523
|
if (!p.unbounded) {
|
|
@@ -3755,21 +3976,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3755
3976
|
}
|
|
3756
3977
|
return name;
|
|
3757
3978
|
}
|
|
3979
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3980
|
+
if (!ctx.recovery) return "";
|
|
3981
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3982
|
+
const pb = v(ctx, "_pb");
|
|
3983
|
+
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} } } } `;
|
|
3984
|
+
}
|
|
3758
3985
|
function failBody(ctx, expected, posExpr) {
|
|
3986
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3759
3987
|
if (ctx.failLabel) {
|
|
3760
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3761
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3988
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3989
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3762
3990
|
}
|
|
3763
|
-
return failReturn(expected, posExpr);
|
|
3991
|
+
return probe + failReturn(expected, posExpr);
|
|
3764
3992
|
}
|
|
3765
3993
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3994
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3766
3995
|
if (ctx.failLabel) {
|
|
3767
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3996
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3768
3997
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3769
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3998
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3770
3999
|
}
|
|
3771
|
-
if (!constant) return
|
|
3772
|
-
return failReturnArr(expectedArr, posExpr);
|
|
4000
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4001
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3773
4002
|
}
|
|
3774
4003
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3775
4004
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4269,6 +4498,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4269
4498
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4270
4499
|
return { stmts, valueVar: vv, endVar };
|
|
4271
4500
|
}
|
|
4501
|
+
function syncSentinelExpr(fs) {
|
|
4502
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
4503
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs.ranges)} })`;
|
|
4504
|
+
}
|
|
4272
4505
|
function emitSeqValues(def, ctx, pos) {
|
|
4273
4506
|
const startV = v(ctx, "_start");
|
|
4274
4507
|
const curV = v(ctx, "_cur");
|
|
@@ -4277,7 +4510,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4277
4510
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4278
4511
|
];
|
|
4279
4512
|
const valueVars = [];
|
|
4513
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4514
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4515
|
+
const publishSync = (i) => {
|
|
4516
|
+
if (!ctx.recovery) return "";
|
|
4517
|
+
const fs = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4518
|
+
const ref2 = syncSentinelExpr(fs);
|
|
4519
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4520
|
+
};
|
|
4280
4521
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4522
|
+
const syncPub = publishSync(i);
|
|
4523
|
+
if (syncPub) stmts.push(syncPub);
|
|
4281
4524
|
if (i > 0 && ctx.activeTrivia) {
|
|
4282
4525
|
if (ctx.capturing) {
|
|
4283
4526
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4302,7 +4545,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4302
4545
|
continue;
|
|
4303
4546
|
} else {
|
|
4304
4547
|
const trivFn = ensureTriviaFn(ctx);
|
|
4305
|
-
|
|
4548
|
+
const scanEndV = v(ctx, "_sne");
|
|
4549
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4550
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4551
|
+
stmts.push(...r2.stmts);
|
|
4552
|
+
const endAfterV = v(ctx, "_sea");
|
|
4553
|
+
stmts.push(
|
|
4554
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4555
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4556
|
+
);
|
|
4557
|
+
valueVars.push(r2.valueVar);
|
|
4558
|
+
continue;
|
|
4306
4559
|
}
|
|
4307
4560
|
}
|
|
4308
4561
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4380,6 +4633,21 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
|
|
|
4380
4633
|
`${ind(ctx)}${endV} = ${endVar}`
|
|
4381
4634
|
];
|
|
4382
4635
|
}
|
|
4636
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4637
|
+
const p = def.parsers[i];
|
|
4638
|
+
const gate = def.gates[i];
|
|
4639
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4640
|
+
const gateIdx = ctx.mapFns.length;
|
|
4641
|
+
ctx.mapFns.push(gate);
|
|
4642
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4643
|
+
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4644
|
+
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4645
|
+
ctx.indent++;
|
|
4646
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4647
|
+
ctx.indent--;
|
|
4648
|
+
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4649
|
+
return stmts;
|
|
4650
|
+
}
|
|
4383
4651
|
function emitChoice(def, ctx, pos) {
|
|
4384
4652
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4385
4653
|
if (def.disjoint) {
|
|
@@ -4395,12 +4663,11 @@ function emitChoice(def, ctx, pos) {
|
|
|
4395
4663
|
stmts.push(`${ind(ctx)}switch (${codeV}) {`);
|
|
4396
4664
|
ctx.indent++;
|
|
4397
4665
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4398
|
-
const p = def.parsers[i];
|
|
4399
4666
|
for (const cp of plan.cases[i]) stmts.push(`${ind(ctx)}case ${cp}:`);
|
|
4400
4667
|
stmts.push(`${ind(ctx)}{`);
|
|
4401
4668
|
ctx.indent++;
|
|
4402
4669
|
stmts.push(
|
|
4403
|
-
...
|
|
4670
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
4404
4671
|
`${ind(ctx)}break`
|
|
4405
4672
|
);
|
|
4406
4673
|
ctx.indent--;
|
|
@@ -4412,13 +4679,14 @@ function emitChoice(def, ctx, pos) {
|
|
|
4412
4679
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4413
4680
|
}
|
|
4414
4681
|
let first = true;
|
|
4415
|
-
for (
|
|
4682
|
+
for (let i = 0; i < def.parsers.length; i++) {
|
|
4683
|
+
const p = def.parsers[i];
|
|
4416
4684
|
const cond = firstSetCond(codeV, p._meta.firstSet);
|
|
4417
4685
|
const kw = first ? "if" : "else if";
|
|
4418
4686
|
first = false;
|
|
4419
4687
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4420
4688
|
ctx.indent++;
|
|
4421
|
-
stmts.push(...
|
|
4689
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
4422
4690
|
ctx.indent--;
|
|
4423
4691
|
stmts.push(`${ind(ctx)}}`);
|
|
4424
4692
|
}
|
|
@@ -4532,7 +4800,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4532
4800
|
if (gate) {
|
|
4533
4801
|
const gateIdx = ctx.mapFns.length;
|
|
4534
4802
|
ctx.mapFns.push(gate);
|
|
4535
|
-
ctx.mapFnSrcs.push(null);
|
|
4803
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4536
4804
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4537
4805
|
}
|
|
4538
4806
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4637,6 +4905,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4637
4905
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4638
4906
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4639
4907
|
];
|
|
4908
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4909
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4640
4910
|
if (def.min === 1) {
|
|
4641
4911
|
const firstR = emit(def.parser, ctx, curV);
|
|
4642
4912
|
stmts.push(...firstR.stmts);
|
|
@@ -4670,10 +4940,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4670
4940
|
}
|
|
4671
4941
|
}
|
|
4672
4942
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4673
|
-
stmts.push(
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4943
|
+
stmts.push(...iterStmts);
|
|
4944
|
+
if (ctx.recovery) {
|
|
4945
|
+
const rrV = v(ctx, "_rr");
|
|
4946
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4947
|
+
stmts.push(
|
|
4948
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4949
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4950
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4951
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4952
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4953
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4954
|
+
`${ind(ctx)} continue`,
|
|
4955
|
+
`${ind(ctx)} }`,
|
|
4956
|
+
`${ind(ctx)} break`,
|
|
4957
|
+
`${ind(ctx)}}`,
|
|
4958
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4959
|
+
);
|
|
4960
|
+
} else {
|
|
4961
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4962
|
+
}
|
|
4677
4963
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4678
4964
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4679
4965
|
ctx.indent--;
|
|
@@ -4695,20 +4981,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4695
4981
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4696
4982
|
const arrV = v(ctx, "_arr");
|
|
4697
4983
|
const curV = v(ctx, "_cur");
|
|
4984
|
+
const rec = !!ctx.recovery;
|
|
4985
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4986
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4987
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4988
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4698
4989
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4699
4990
|
const stmts = [
|
|
4700
4991
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4701
4992
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4702
|
-
...
|
|
4703
|
-
|
|
4993
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4994
|
+
...firstStmts
|
|
4704
4995
|
];
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
)
|
|
4711
|
-
|
|
4996
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4997
|
+
if (!rec) return [originalFail];
|
|
4998
|
+
const rr = v(ctx, "_rr");
|
|
4999
|
+
return [
|
|
5000
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
5001
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
5002
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
5003
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
5004
|
+
`${ind(ctx)} }`,
|
|
5005
|
+
`${ind(ctx)} ${rb}break`,
|
|
5006
|
+
`${ind(ctx)}}`
|
|
5007
|
+
];
|
|
5008
|
+
};
|
|
5009
|
+
if (rec) {
|
|
5010
|
+
const rr0 = v(ctx, "_rr0");
|
|
5011
|
+
const didV = v(ctx, "_did");
|
|
5012
|
+
stmts.push(
|
|
5013
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
5014
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
5015
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
5016
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
5017
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
5018
|
+
`${ind(ctx)}}`,
|
|
5019
|
+
`${ind(ctx)}if (${didV}) {`
|
|
5020
|
+
);
|
|
5021
|
+
ctx.indent++;
|
|
5022
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
5023
|
+
ctx.indent++;
|
|
5024
|
+
} else {
|
|
5025
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
5026
|
+
ctx.indent++;
|
|
5027
|
+
stmts.push(
|
|
5028
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
5029
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
5030
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
5031
|
+
);
|
|
5032
|
+
ctx.indent++;
|
|
5033
|
+
}
|
|
4712
5034
|
let sepAtPos = curV;
|
|
4713
5035
|
if (ctx.activeTrivia) {
|
|
4714
5036
|
if (ctx.capturing) {
|
|
@@ -4734,8 +5056,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4734
5056
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4735
5057
|
stmts.push(
|
|
4736
5058
|
...nextStmts,
|
|
4737
|
-
|
|
4738
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
5059
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4739
5060
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4740
5061
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4741
5062
|
);
|
|
@@ -4751,7 +5072,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4751
5072
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4752
5073
|
stmts.push(
|
|
4753
5074
|
...nextStmts,
|
|
4754
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
5075
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4755
5076
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4756
5077
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4757
5078
|
);
|
|
@@ -4771,7 +5092,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4771
5092
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4772
5093
|
stmts.push(
|
|
4773
5094
|
...nextStmts,
|
|
4774
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
5095
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4775
5096
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4776
5097
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4777
5098
|
);
|
|
@@ -5028,7 +5349,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
5028
5349
|
stmts.push(
|
|
5029
5350
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
5030
5351
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
5031
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === '
|
|
5352
|
+
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'parseError')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
5032
5353
|
);
|
|
5033
5354
|
return { stmts, valueVar: ndV, endVar };
|
|
5034
5355
|
}
|
|
@@ -5118,6 +5439,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5118
5439
|
`${ind0}if (!${okVar}) {`,
|
|
5119
5440
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5120
5441
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5442
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5443
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5444
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5445
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5121
5446
|
`${ind0} ${valVar} = ${errV}`,
|
|
5122
5447
|
`${ind0} ${endVar} = ${pos}`,
|
|
5123
5448
|
`${ind0} ${okVar} = true`,
|
|
@@ -5284,7 +5609,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5284
5609
|
case "guard": {
|
|
5285
5610
|
const fnIdx = ctx.mapFns.length;
|
|
5286
5611
|
ctx.mapFns.push(def.predicate);
|
|
5287
|
-
ctx.mapFnSrcs.push(null);
|
|
5612
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5288
5613
|
const vv = v(ctx);
|
|
5289
5614
|
return {
|
|
5290
5615
|
stmts: [
|
|
@@ -5299,7 +5624,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5299
5624
|
const evIdx = ctx.mapFns.length;
|
|
5300
5625
|
const extra = def.extra;
|
|
5301
5626
|
ctx.mapFns.push((() => extra));
|
|
5302
|
-
ctx.mapFnSrcs.push(null);
|
|
5627
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5303
5628
|
const innerParser = def.parser;
|
|
5304
5629
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5305
5630
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5543,7 +5868,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5543
5868
|
}
|
|
5544
5869
|
return deps;
|
|
5545
5870
|
}
|
|
5546
|
-
function compile(combinator, mapFnSources) {
|
|
5871
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5547
5872
|
markUnusedValues(combinator);
|
|
5548
5873
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5549
5874
|
const ctx = {
|
|
@@ -5564,6 +5889,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5564
5889
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5565
5890
|
namedFnDecls: [],
|
|
5566
5891
|
capturing: hasNodeDef(combinator),
|
|
5892
|
+
recovery: opts?.recovery ?? false,
|
|
5567
5893
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5568
5894
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5569
5895
|
};
|
|
@@ -5616,7 +5942,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5616
5942
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5617
5943
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5618
5944
|
},
|
|
5619
|
-
// Note: collects
|
|
5945
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5620
5946
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5621
5947
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5622
5948
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5673,6 +5999,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5673
5999
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5674
6000
|
namedFnDecls: [],
|
|
5675
6001
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
6002
|
+
recovery: opts?.recovery ?? false,
|
|
5676
6003
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5677
6004
|
ns,
|
|
5678
6005
|
deferFirstSetRefs: true,
|
|
@@ -6418,46 +6745,13 @@ function withCtx(extra, combinator) {
|
|
|
6418
6745
|
};
|
|
6419
6746
|
}
|
|
6420
6747
|
|
|
6421
|
-
// src/combinators/recover.ts
|
|
6422
|
-
function recover(combinator, sentinel) {
|
|
6423
|
-
const meta = {
|
|
6424
|
-
firstSet: { kind: "any" },
|
|
6425
|
-
canMatchNewline: true,
|
|
6426
|
-
isTrivia: false
|
|
6427
|
-
};
|
|
6428
|
-
const expected = deriveExpected(combinator);
|
|
6429
|
-
return {
|
|
6430
|
-
_tag: "recover",
|
|
6431
|
-
_meta: meta,
|
|
6432
|
-
_def: { tag: "recover", parser: combinator, sentinel },
|
|
6433
|
-
parse(input, pos, ctx) {
|
|
6434
|
-
const result = combinator.parse(input, pos, ctx);
|
|
6435
|
-
if (result.ok) return result;
|
|
6436
|
-
let scanPos = pos;
|
|
6437
|
-
while (scanPos < input.length) {
|
|
6438
|
-
if (sentinel.parse(input, scanPos, ctx).ok) break;
|
|
6439
|
-
scanPos++;
|
|
6440
|
-
}
|
|
6441
|
-
const error = {
|
|
6442
|
-
_tag: "parseError",
|
|
6443
|
-
span: { start: pos, end: scanPos },
|
|
6444
|
-
expected
|
|
6445
|
-
};
|
|
6446
|
-
ctx._errors?.push(error);
|
|
6447
|
-
return { ok: true, value: error, span: { start: pos, end: scanPos } };
|
|
6448
|
-
}
|
|
6449
|
-
};
|
|
6450
|
-
}
|
|
6451
|
-
function isParseError(value) {
|
|
6452
|
-
return typeof value === "object" && value !== null && value._tag === "parseError";
|
|
6453
|
-
}
|
|
6454
|
-
|
|
6455
6748
|
// src/combinators/completions.ts
|
|
6456
|
-
function completionsAt(
|
|
6749
|
+
function completionsAt(target, input, offset, options = {}) {
|
|
6457
6750
|
const probe = { offset, best: null };
|
|
6458
|
-
const ctx = { trackLines: false, _probe: probe };
|
|
6459
|
-
const
|
|
6460
|
-
|
|
6751
|
+
const ctx = { trackLines: false, _probe: probe, ...options.tolerant ? { _tolerant: true, _rec: REC } : {} };
|
|
6752
|
+
const sliced = input.slice(0, offset);
|
|
6753
|
+
const result = "parseWithContext" in target ? target.parseWithContext(sliced, ctx, 0) : target.parse(sliced, 0, ctx);
|
|
6754
|
+
if (result.ok) return options.tolerant ? probe.best?.expected ?? [] : [];
|
|
6461
6755
|
const best = deeperFail(probe.best, result);
|
|
6462
6756
|
return best?.expected ?? [];
|
|
6463
6757
|
}
|
|
@@ -6467,23 +6761,6 @@ function deeperFail(a, b) {
|
|
|
6467
6761
|
return a.span.start >= b.span.start ? a : b;
|
|
6468
6762
|
}
|
|
6469
6763
|
|
|
6470
|
-
// src/combinators/recover-list.ts
|
|
6471
|
-
function tolerantElement(item, sentinel, until) {
|
|
6472
|
-
const el = transform(
|
|
6473
|
-
sequence(not(until), recover(item, sentinel)),
|
|
6474
|
-
([, value]) => value
|
|
6475
|
-
);
|
|
6476
|
-
if (el._def.tag === "transform") el._def.fnSrc = "([, value]) => value";
|
|
6477
|
-
return el;
|
|
6478
|
-
}
|
|
6479
|
-
function sepByRecover(item, separator, until) {
|
|
6480
|
-
const sentinel = choice(separator, until);
|
|
6481
|
-
return sepBy(tolerantElement(item, sentinel, until), separator);
|
|
6482
|
-
}
|
|
6483
|
-
function manyRecover(item, until) {
|
|
6484
|
-
return many(tolerantElement(item, until, until));
|
|
6485
|
-
}
|
|
6486
|
-
|
|
6487
6764
|
// src/cst/relative-spans.ts
|
|
6488
6765
|
function relativize(node2, parentBase = 0) {
|
|
6489
6766
|
return {
|
|
@@ -6578,6 +6855,9 @@ function editNode(node2, at, delta, parentBase, parentShift, stats) {
|
|
|
6578
6855
|
}
|
|
6579
6856
|
|
|
6580
6857
|
// src/functional/doc.ts
|
|
6858
|
+
function mkCtx(state, build, tolerant) {
|
|
6859
|
+
return tolerant ? { trackLines: false, state, build, _tolerant: true, _rec: REC, _errors: [] } : { trackLines: false, state, build };
|
|
6860
|
+
}
|
|
6581
6861
|
function asRuleFn(entry) {
|
|
6582
6862
|
return typeof entry === "function" ? entry : (input, pos, ctx) => entry.parse(input, pos, ctx);
|
|
6583
6863
|
}
|
|
@@ -6684,8 +6964,8 @@ function graftRelative(root, path, newNode, delta) {
|
|
|
6684
6964
|
children: newChildren
|
|
6685
6965
|
};
|
|
6686
6966
|
}
|
|
6687
|
-
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build) {
|
|
6688
|
-
const ctx =
|
|
6967
|
+
function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build, tolerant) {
|
|
6968
|
+
const ctx = mkCtx(null, build, tolerant);
|
|
6689
6969
|
const out = [];
|
|
6690
6970
|
let pos = reStart;
|
|
6691
6971
|
let guard2 = 0;
|
|
@@ -6709,7 +6989,7 @@ function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build) {
|
|
|
6709
6989
|
}
|
|
6710
6990
|
return pos === reEnd ? out : null;
|
|
6711
6991
|
}
|
|
6712
|
-
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build) {
|
|
6992
|
+
function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build, tolerant) {
|
|
6713
6993
|
const kids = C.children;
|
|
6714
6994
|
if (kids.length === 0) return null;
|
|
6715
6995
|
let h = 0;
|
|
@@ -6750,7 +7030,7 @@ function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registr
|
|
|
6750
7030
|
const reStart = h > 0 ? cStart + kids[h - 1].span.end : cStart;
|
|
6751
7031
|
const reEnd = cStart + kids[t].span.start + delta;
|
|
6752
7032
|
if (reEnd < reStart) return null;
|
|
6753
|
-
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build);
|
|
7033
|
+
const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6754
7034
|
if (!middle) return null;
|
|
6755
7035
|
if (middle.length > 0) {
|
|
6756
7036
|
const last2 = middle[middle.length - 1];
|
|
@@ -6760,7 +7040,7 @@ function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registr
|
|
|
6760
7040
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6761
7041
|
if (newInput[reEnd] === sentinel) continue;
|
|
6762
7042
|
const probed = newInput.slice(0, reEnd) + sentinel.repeat(newInput.length - reEnd);
|
|
6763
|
-
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build);
|
|
7043
|
+
const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build, tolerant);
|
|
6764
7044
|
if (!probe || probe.length !== middle.length) return null;
|
|
6765
7045
|
for (let i = 0; i < middle.length; i++) if (!structurallyEqual(probe[i], middle[i])) return null;
|
|
6766
7046
|
}
|
|
@@ -6788,6 +7068,11 @@ function structurallyEqual(a, b) {
|
|
|
6788
7068
|
if (at === "leaf" || at === "trivia") {
|
|
6789
7069
|
return a.value === b.value;
|
|
6790
7070
|
}
|
|
7071
|
+
if (at === "parseError") {
|
|
7072
|
+
const ae = a.expected ?? [];
|
|
7073
|
+
const be = b.expected ?? [];
|
|
7074
|
+
return ae.length === be.length && ae.every((x, i) => x === be[i]);
|
|
7075
|
+
}
|
|
6791
7076
|
if (a.type !== b.type) return false;
|
|
6792
7077
|
const ac = a.children;
|
|
6793
7078
|
const bc = b.children;
|
|
@@ -6797,13 +7082,13 @@ function structurallyEqual(a, b) {
|
|
|
6797
7082
|
}
|
|
6798
7083
|
return true;
|
|
6799
7084
|
}
|
|
6800
|
-
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced) {
|
|
7085
|
+
function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produced, tolerant) {
|
|
6801
7086
|
if (!produced.ok) return false;
|
|
6802
7087
|
if (boundary >= newInput.length) return true;
|
|
6803
7088
|
for (const sentinel of [" ", "\uFFFF"]) {
|
|
6804
7089
|
if (newInput[boundary] === sentinel) continue;
|
|
6805
7090
|
const probed = newInput.slice(0, boundary) + sentinel.repeat(newInput.length - boundary);
|
|
6806
|
-
const ctx =
|
|
7091
|
+
const ctx = mkCtx(state, build, tolerant);
|
|
6807
7092
|
let r;
|
|
6808
7093
|
try {
|
|
6809
7094
|
r = ruleFn(probed, start, ctx);
|
|
@@ -6835,8 +7120,9 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6835
7120
|
_abs;
|
|
6836
7121
|
_rel;
|
|
6837
7122
|
errors;
|
|
7123
|
+
unconsumedFrom;
|
|
6838
7124
|
input;
|
|
6839
|
-
constructor(registry, rootRule, opts, trees, errors, input) {
|
|
7125
|
+
constructor(registry, rootRule, opts, trees, errors, unconsumedFrom, input) {
|
|
6840
7126
|
this._registry = registry;
|
|
6841
7127
|
this._fns = {};
|
|
6842
7128
|
this._reps = /* @__PURE__ */ new Set();
|
|
@@ -6849,6 +7135,7 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6849
7135
|
this._abs = trees.abs;
|
|
6850
7136
|
this._rel = trees.rel;
|
|
6851
7137
|
this.errors = errors;
|
|
7138
|
+
this.unconsumedFrom = unconsumedFrom;
|
|
6852
7139
|
this.input = input;
|
|
6853
7140
|
}
|
|
6854
7141
|
/**
|
|
@@ -6871,6 +7158,19 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6871
7158
|
if (!rel) throw new Error("spanAt on a failed parse (tree is null)");
|
|
6872
7159
|
return absoluteSpanCST(rel, path);
|
|
6873
7160
|
}
|
|
7161
|
+
/**
|
|
7162
|
+
* Wrap a reused (grafted/spliced) RELATIVE tree, recomputing `errors` and
|
|
7163
|
+
* `unconsumedFrom` from it so both stay consistent with the tree across the
|
|
7164
|
+
* edit (the flat errors are recovered errors embedded in the reused subtrees;
|
|
7165
|
+
* unconsumedFrom re-derives trailing junk over the new input).
|
|
7166
|
+
*/
|
|
7167
|
+
wrapReuse(newTree, newInput) {
|
|
7168
|
+
const trivia2 = triviaOf(this._registry[this._rootRule], this._opts);
|
|
7169
|
+
const end = newTree.span.end;
|
|
7170
|
+
const errors = collectEmbeddedErrors(newTree, 0, []);
|
|
7171
|
+
const unconsumedFrom = unconsumedAfter(end, newInput, trivia2);
|
|
7172
|
+
return new _ParseDocImpl(this._registry, this._rootRule, this._opts, { rel: newTree }, errors, unconsumedFrom, newInput);
|
|
7173
|
+
}
|
|
6874
7174
|
edit(from, to, replacement) {
|
|
6875
7175
|
const newInput = this.input.slice(0, from) + replacement + this.input.slice(to);
|
|
6876
7176
|
const reparse = () => parseDoc(this._registry, this._rootRule, newInput, this._opts);
|
|
@@ -6892,22 +7192,22 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6892
7192
|
const ruleFn = this._fns[node2.type];
|
|
6893
7193
|
if (!ruleFn) continue;
|
|
6894
7194
|
if (!(absStart <= from && to <= absEnd)) continue;
|
|
6895
|
-
const ctx =
|
|
7195
|
+
const ctx = mkCtx(node2.state, this._opts.build, !!this._opts.tolerant);
|
|
6896
7196
|
const r = ruleFn(newInput, absStart, ctx);
|
|
6897
7197
|
if (!r.ok) continue;
|
|
6898
7198
|
if (r.span.end !== absEnd + delta) continue;
|
|
6899
|
-
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r)) {
|
|
7199
|
+
if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r, !!this._opts.tolerant)) {
|
|
6900
7200
|
continue;
|
|
6901
7201
|
}
|
|
6902
7202
|
const parentBase = absStart - node2.span.start;
|
|
6903
7203
|
const newRel = relativizeCST(r.value, parentBase);
|
|
6904
7204
|
if (delta === 0) {
|
|
6905
7205
|
const newTree2 = replaceAtPath(rebuild, root, path, newRel);
|
|
6906
|
-
return
|
|
7206
|
+
return this.wrapReuse(newTree2, newInput);
|
|
6907
7207
|
}
|
|
6908
7208
|
if (this._opts.rebuild) return reparse();
|
|
6909
7209
|
const newTree = graftRelative(root, path, newRel, delta);
|
|
6910
|
-
return
|
|
7210
|
+
return this.wrapReuse(newTree, newInput);
|
|
6911
7211
|
}
|
|
6912
7212
|
if (this._opts.structuralReuse && delta !== 0 && !this._opts.rebuild) {
|
|
6913
7213
|
const spliceCandidates = [...candidates, { node: root, path: [] }];
|
|
@@ -6915,22 +7215,50 @@ var ParseDocImpl = class _ParseDocImpl {
|
|
|
6915
7215
|
if (!this._reps.has(node2.type)) continue;
|
|
6916
7216
|
const { start: cStart, end: cEnd } = absoluteSpanCST(root, path);
|
|
6917
7217
|
if (!(cStart <= from && to <= cEnd)) continue;
|
|
6918
|
-
const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build);
|
|
6919
|
-
if (spliced) return
|
|
7218
|
+
const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build, !!this._opts.tolerant);
|
|
7219
|
+
if (spliced) return this.wrapReuse(spliced, newInput);
|
|
6920
7220
|
}
|
|
6921
7221
|
}
|
|
6922
7222
|
return reparse();
|
|
6923
7223
|
}
|
|
6924
7224
|
};
|
|
7225
|
+
function triviaOf(entry, opts) {
|
|
7226
|
+
if (opts.trivia) return opts.trivia;
|
|
7227
|
+
if (entry === void 0 || typeof entry === "function") return void 0;
|
|
7228
|
+
const meta = entry._meta;
|
|
7229
|
+
return meta ? meta.grammarTrivia : void 0;
|
|
7230
|
+
}
|
|
7231
|
+
function unconsumedAfter(end, input, trivia2) {
|
|
7232
|
+
let pos = end;
|
|
7233
|
+
if (trivia2 && pos < input.length) {
|
|
7234
|
+
const t = trivia2.parse(input, pos, { trackLines: false });
|
|
7235
|
+
if (t.ok && t.span.end > pos) pos = t.span.end;
|
|
7236
|
+
}
|
|
7237
|
+
return pos < input.length ? pos : null;
|
|
7238
|
+
}
|
|
7239
|
+
function collectEmbeddedErrors(node2, base, out) {
|
|
7240
|
+
const c = node2;
|
|
7241
|
+
if (!c || typeof c !== "object" || !c.span) return out;
|
|
7242
|
+
const start = base + c.span.start;
|
|
7243
|
+
if (c._tag === "parseError") {
|
|
7244
|
+
out.push({ _tag: "parseError", span: { start, end: base + c.span.end }, expected: c.expected ?? [] });
|
|
7245
|
+
return out;
|
|
7246
|
+
}
|
|
7247
|
+
if (Array.isArray(c.children)) for (const k of c.children) collectEmbeddedErrors(k, start, out);
|
|
7248
|
+
return out;
|
|
7249
|
+
}
|
|
6925
7250
|
function parseDoc(registry, rootRule, input, opts = {}) {
|
|
6926
7251
|
const entry = registry[rootRule];
|
|
6927
7252
|
if (!entry) throw new Error(`No rule '${rootRule}' in registry`);
|
|
6928
|
-
const ctx =
|
|
7253
|
+
const ctx = mkCtx(opts.state, opts.build, !!opts.tolerant);
|
|
6929
7254
|
const r = asRuleFn(entry)(input, 0, ctx);
|
|
6930
7255
|
if (r.ok) {
|
|
6931
|
-
|
|
7256
|
+
const errors = ctx._errors ? [...ctx._errors] : [];
|
|
7257
|
+
const unconsumedFrom = unconsumedAfter(r.span.end, input, triviaOf(entry, opts));
|
|
7258
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: r.value }, errors, unconsumedFrom, input);
|
|
6932
7259
|
}
|
|
6933
|
-
|
|
7260
|
+
const fail = { _tag: "parseError", span: r.span, expected: r.expected };
|
|
7261
|
+
return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
|
|
6934
7262
|
}
|
|
6935
7263
|
|
|
6936
7264
|
// src/functional/run.ts
|
|
@@ -6951,7 +7279,8 @@ function run(entry, input, options = {}) {
|
|
|
6951
7279
|
build: options.build,
|
|
6952
7280
|
state: options.state,
|
|
6953
7281
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
6954
|
-
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {}
|
|
7282
|
+
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7283
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
6955
7284
|
};
|
|
6956
7285
|
const r = invoke(entry, input, 0, ctx);
|
|
6957
7286
|
let unconsumedFrom = null;
|