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/plugin/index.cjs
CHANGED
|
@@ -332,7 +332,13 @@ function saveCstMark(ctx) {
|
|
|
332
332
|
raw: cstRawLen(ctx),
|
|
333
333
|
tlog: cstTlLen(ctx),
|
|
334
334
|
leaves: cstLeavesLen(ctx),
|
|
335
|
-
fields: ctx._fields?.length ?? 0
|
|
335
|
+
fields: ctx._fields?.length ?? 0,
|
|
336
|
+
// Speculative rollback must truncate the flat recovery-error sink in lockstep
|
|
337
|
+
// with the CST leaves: a branch that recovered (pushing a ParseError to
|
|
338
|
+
// ctx._errors AND embedding it as a CST child via captureError) then failed
|
|
339
|
+
// must remove BOTH, or the flat error survives as a GHOST that a tree walk
|
|
340
|
+
// can't see (flat run().errors would disagree with the embedded set).
|
|
341
|
+
errors: ctx._errors?.length ?? 0
|
|
336
342
|
};
|
|
337
343
|
}
|
|
338
344
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -348,6 +354,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
348
354
|
if (len === 0) b[keySingle] = void 0;
|
|
349
355
|
}
|
|
350
356
|
function rollbackCstCapture(ctx, mark) {
|
|
357
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
351
358
|
const b = ctx._cstBuf;
|
|
352
359
|
if (b) {
|
|
353
360
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -905,12 +912,159 @@ function keywords(words, opts = {}) {
|
|
|
905
912
|
};
|
|
906
913
|
}
|
|
907
914
|
|
|
915
|
+
// src/recovery/scan.ts
|
|
916
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
917
|
+
const s = {
|
|
918
|
+
_probe: ctx._probe,
|
|
919
|
+
_errors: ctx._errors,
|
|
920
|
+
_cstLeaves: ctx._cstLeaves,
|
|
921
|
+
_cstChildren: ctx._cstChildren,
|
|
922
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
923
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
924
|
+
_triviaLog: ctx._triviaLog,
|
|
925
|
+
_fields: ctx._fields,
|
|
926
|
+
_cstBuf: ctx._cstBuf,
|
|
927
|
+
_tolerant: ctx._tolerant,
|
|
928
|
+
_sync: ctx._sync
|
|
929
|
+
};
|
|
930
|
+
ctx._probe = void 0;
|
|
931
|
+
ctx._errors = void 0;
|
|
932
|
+
ctx._cstLeaves = void 0;
|
|
933
|
+
ctx._cstChildren = void 0;
|
|
934
|
+
ctx._cstRawChildren = void 0;
|
|
935
|
+
ctx._cstTriviaLog = void 0;
|
|
936
|
+
ctx._triviaLog = void 0;
|
|
937
|
+
ctx._fields = void 0;
|
|
938
|
+
ctx._cstBuf = void 0;
|
|
939
|
+
ctx._tolerant = void 0;
|
|
940
|
+
ctx._sync = void 0;
|
|
941
|
+
try {
|
|
942
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
943
|
+
} finally {
|
|
944
|
+
ctx._probe = s._probe;
|
|
945
|
+
ctx._errors = s._errors;
|
|
946
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
947
|
+
ctx._cstChildren = s._cstChildren;
|
|
948
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
949
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
950
|
+
ctx._triviaLog = s._triviaLog;
|
|
951
|
+
ctx._fields = s._fields;
|
|
952
|
+
ctx._cstBuf = s._cstBuf;
|
|
953
|
+
ctx._tolerant = s._tolerant;
|
|
954
|
+
ctx._sync = s._sync;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
function orSentinel(a, b) {
|
|
958
|
+
if (b === void 0) return a;
|
|
959
|
+
return {
|
|
960
|
+
_tag: "orSentinel",
|
|
961
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
962
|
+
_def: { tag: "unknown" },
|
|
963
|
+
parse(input, pos, ctx) {
|
|
964
|
+
const ra = a.parse(input, pos, ctx);
|
|
965
|
+
if (ra.ok) return ra;
|
|
966
|
+
return b.parse(input, pos, ctx);
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
function firstSetSentinel(fs2) {
|
|
971
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
972
|
+
const ranges = fs2.ranges;
|
|
973
|
+
return {
|
|
974
|
+
_tag: "firstSetSentinel",
|
|
975
|
+
_meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
|
|
976
|
+
_def: { tag: "unknown" },
|
|
977
|
+
parse(input, pos) {
|
|
978
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
979
|
+
if (code !== void 0) {
|
|
980
|
+
for (const r of ranges) {
|
|
981
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
989
|
+
let scanPos = from;
|
|
990
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
991
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
992
|
+
ctx._errors?.push(error);
|
|
993
|
+
return { error, end: scanPos };
|
|
994
|
+
}
|
|
995
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
996
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
997
|
+
}
|
|
998
|
+
function captureError(ctx, error) {
|
|
999
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/combinators/expect.ts
|
|
1003
|
+
function deriveExpected(c) {
|
|
1004
|
+
const def = c._def;
|
|
1005
|
+
switch (def.tag) {
|
|
1006
|
+
case "literal":
|
|
1007
|
+
return [JSON.stringify(def.value)];
|
|
1008
|
+
case "regex":
|
|
1009
|
+
return [`/${def.source}/`];
|
|
1010
|
+
case "keywords":
|
|
1011
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1012
|
+
case "label":
|
|
1013
|
+
return [def.label];
|
|
1014
|
+
case "choice":
|
|
1015
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1016
|
+
case "sequence":
|
|
1017
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1018
|
+
case "node":
|
|
1019
|
+
case "grammar":
|
|
1020
|
+
case "trivia":
|
|
1021
|
+
case "token":
|
|
1022
|
+
case "optional":
|
|
1023
|
+
case "many":
|
|
1024
|
+
case "oneOrMore":
|
|
1025
|
+
case "transform":
|
|
1026
|
+
case "not":
|
|
1027
|
+
return deriveExpected(def.parser);
|
|
1028
|
+
case "lazy": {
|
|
1029
|
+
const name = c._ruleName;
|
|
1030
|
+
try {
|
|
1031
|
+
return deriveExpected(def.thunk());
|
|
1032
|
+
} catch {
|
|
1033
|
+
return name ? [name] : [];
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
default:
|
|
1037
|
+
return [];
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
function expect(combinator, label2) {
|
|
1041
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1042
|
+
const meta = {
|
|
1043
|
+
firstSet: combinator._meta.firstSet,
|
|
1044
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1045
|
+
isTrivia: false
|
|
1046
|
+
};
|
|
1047
|
+
return {
|
|
1048
|
+
_tag: "expect",
|
|
1049
|
+
_meta: meta,
|
|
1050
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1051
|
+
parse(input, pos, ctx) {
|
|
1052
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1053
|
+
if (result.ok) return result;
|
|
1054
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
1055
|
+
ctx._errors?.push(error);
|
|
1056
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1057
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
|
|
908
1062
|
// src/combinators/choice.ts
|
|
909
1063
|
function choice(...args) {
|
|
910
1064
|
const parsers = args.map((a) => "gate" in a ? a.combinator : a);
|
|
911
1065
|
const gates = args.map((a) => "gate" in a ? a.gate : null);
|
|
912
1066
|
const hasGates = gates.some((g) => g !== null);
|
|
913
|
-
const disjoint =
|
|
1067
|
+
const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
|
|
914
1068
|
let combined = { kind: "empty" };
|
|
915
1069
|
for (const p of parsers) combined = union(combined, p._meta.firstSet);
|
|
916
1070
|
const meta = {
|
|
@@ -949,17 +1103,21 @@ function choice(...args) {
|
|
|
949
1103
|
const expected = [];
|
|
950
1104
|
if (disjoint && pos < input.length) {
|
|
951
1105
|
const code = input.codePointAt(pos);
|
|
952
|
-
let
|
|
953
|
-
if (
|
|
954
|
-
for (
|
|
955
|
-
if (inFirstSet(code,
|
|
956
|
-
|
|
1106
|
+
let idx = code < 128 ? asciiDispatch[code] : -1;
|
|
1107
|
+
if (idx < 0) {
|
|
1108
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1109
|
+
if (inFirstSet(code, parsers[i]._meta.firstSet)) {
|
|
1110
|
+
idx = i;
|
|
957
1111
|
break;
|
|
958
1112
|
}
|
|
959
1113
|
}
|
|
960
1114
|
}
|
|
961
|
-
if (
|
|
962
|
-
const
|
|
1115
|
+
if (idx >= 0) {
|
|
1116
|
+
const gate = gates[idx];
|
|
1117
|
+
if (gate && !gate(ctx.state)) {
|
|
1118
|
+
return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
|
|
1119
|
+
}
|
|
1120
|
+
const result = parsers[idx].parse(input, pos, ctx);
|
|
963
1121
|
if (result.ok) return result;
|
|
964
1122
|
expected.push(...result.expected);
|
|
965
1123
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
@@ -1140,13 +1298,13 @@ function areDisjoint(sets) {
|
|
|
1140
1298
|
return true;
|
|
1141
1299
|
}
|
|
1142
1300
|
function buildAsciiDispatch(parsers) {
|
|
1143
|
-
const table = Array(128).fill(
|
|
1144
|
-
for (
|
|
1145
|
-
const fs2 =
|
|
1301
|
+
const table = Array(128).fill(-1);
|
|
1302
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1303
|
+
const fs2 = parsers[i]._meta.firstSet;
|
|
1146
1304
|
if (fs2.kind !== "ranges") continue;
|
|
1147
1305
|
for (const { lo, hi } of fs2.ranges) {
|
|
1148
1306
|
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1149
|
-
table[code] =
|
|
1307
|
+
table[code] = i;
|
|
1150
1308
|
}
|
|
1151
1309
|
}
|
|
1152
1310
|
}
|
|
@@ -1291,10 +1449,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1291
1449
|
}
|
|
1292
1450
|
function saveTriviaMark(ctx) {
|
|
1293
1451
|
const m = saveCstMark(ctx);
|
|
1294
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1452
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1295
1453
|
}
|
|
1296
1454
|
function rollbackTrivia(ctx, mark) {
|
|
1297
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1455
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1298
1456
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1299
1457
|
}
|
|
1300
1458
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1538,11 +1696,59 @@ function sequence(...parsers) {
|
|
|
1538
1696
|
isTrivia: false
|
|
1539
1697
|
};
|
|
1540
1698
|
const def = { tag: "sequence", parsers };
|
|
1699
|
+
let followSentinels;
|
|
1700
|
+
function parseTolerant(input, pos, ctx) {
|
|
1701
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1702
|
+
const fs2 = parsers.slice(i + 1).reduce(
|
|
1703
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1704
|
+
{ kind: "empty" }
|
|
1705
|
+
);
|
|
1706
|
+
return firstSetSentinel(fs2);
|
|
1707
|
+
});
|
|
1708
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1709
|
+
let cur = pos;
|
|
1710
|
+
const inheritedSync = ctx._sync;
|
|
1711
|
+
try {
|
|
1712
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1713
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1714
|
+
if (ctx.trivia && i > 0) {
|
|
1715
|
+
const mark = saveTriviaMark(ctx);
|
|
1716
|
+
let scanEnd;
|
|
1717
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1718
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1719
|
+
scan.commit();
|
|
1720
|
+
scanEnd = scan.end;
|
|
1721
|
+
} else {
|
|
1722
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1723
|
+
}
|
|
1724
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1725
|
+
if (!result2.ok) return result2;
|
|
1726
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1727
|
+
else rollbackTrivia(ctx, mark);
|
|
1728
|
+
if (values !== void 0) values.push(result2.value);
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1731
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1732
|
+
if (!result.ok) return result;
|
|
1733
|
+
if (values !== void 0) values.push(result.value);
|
|
1734
|
+
cur = result.span.end;
|
|
1735
|
+
}
|
|
1736
|
+
} finally {
|
|
1737
|
+
ctx._sync = inheritedSync;
|
|
1738
|
+
}
|
|
1739
|
+
return {
|
|
1740
|
+
ok: true,
|
|
1741
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1742
|
+
value: values ?? void 0,
|
|
1743
|
+
span: { start: pos, end: cur }
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1541
1746
|
return {
|
|
1542
1747
|
_tag: "sequence",
|
|
1543
1748
|
_meta: meta,
|
|
1544
1749
|
_def: def,
|
|
1545
1750
|
parse(input, pos, ctx) {
|
|
1751
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1546
1752
|
const values = def.valueUnused ? void 0 : [];
|
|
1547
1753
|
let cur = pos;
|
|
1548
1754
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1601,7 +1807,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1601
1807
|
const result = combinator.parse(input, pos, ctx);
|
|
1602
1808
|
if (!result.ok) {
|
|
1603
1809
|
rollbackTrivia(ctx, mark);
|
|
1604
|
-
return { fail: result };
|
|
1810
|
+
return { fail: result, failPos: pos };
|
|
1605
1811
|
}
|
|
1606
1812
|
if (result.span.end === pos) {
|
|
1607
1813
|
rollbackTrivia(ctx, mark);
|
|
@@ -1616,6 +1822,7 @@ function many(combinator) {
|
|
|
1616
1822
|
isTrivia: false
|
|
1617
1823
|
};
|
|
1618
1824
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1825
|
+
let expected;
|
|
1619
1826
|
return {
|
|
1620
1827
|
_tag: "many",
|
|
1621
1828
|
_meta: meta,
|
|
@@ -1625,7 +1832,18 @@ function many(combinator) {
|
|
|
1625
1832
|
let cur = pos;
|
|
1626
1833
|
while (cur < input.length) {
|
|
1627
1834
|
const item = repItem(combinator, input, cur, ctx);
|
|
1628
|
-
if (item === "stop"
|
|
1835
|
+
if (item === "stop") break;
|
|
1836
|
+
if ("fail" in item) {
|
|
1837
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1838
|
+
if (sync === void 0) break;
|
|
1839
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1840
|
+
expected ??= deriveExpected(combinator);
|
|
1841
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1842
|
+
if (values !== void 0) values.push(error);
|
|
1843
|
+
captureError(ctx, error);
|
|
1844
|
+
cur = end;
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1629
1847
|
if (values !== void 0) values.push(item.value);
|
|
1630
1848
|
cur = item.end;
|
|
1631
1849
|
}
|
|
@@ -1640,6 +1858,7 @@ function oneOrMore(combinator) {
|
|
|
1640
1858
|
isTrivia: false
|
|
1641
1859
|
};
|
|
1642
1860
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1861
|
+
let expected;
|
|
1643
1862
|
return {
|
|
1644
1863
|
_tag: "oneOrMore",
|
|
1645
1864
|
_meta: meta,
|
|
@@ -1651,7 +1870,18 @@ function oneOrMore(combinator) {
|
|
|
1651
1870
|
let cur = first.span.end;
|
|
1652
1871
|
while (cur < input.length) {
|
|
1653
1872
|
const item = repItem(combinator, input, cur, ctx);
|
|
1654
|
-
if (item === "stop"
|
|
1873
|
+
if (item === "stop") break;
|
|
1874
|
+
if ("fail" in item) {
|
|
1875
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1876
|
+
if (sync === void 0) break;
|
|
1877
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1878
|
+
expected ??= deriveExpected(combinator);
|
|
1879
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1880
|
+
if (values !== void 0) values.push(error);
|
|
1881
|
+
captureError(ctx, error);
|
|
1882
|
+
cur = end;
|
|
1883
|
+
continue;
|
|
1884
|
+
}
|
|
1655
1885
|
if (values !== void 0) values.push(item.value);
|
|
1656
1886
|
cur = item.end;
|
|
1657
1887
|
}
|
|
@@ -1697,15 +1927,29 @@ function sepBy(combinator, separator) {
|
|
|
1697
1927
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1698
1928
|
isTrivia: false
|
|
1699
1929
|
};
|
|
1930
|
+
let expected;
|
|
1700
1931
|
return {
|
|
1701
1932
|
_tag: "sepBy",
|
|
1702
1933
|
_meta: meta,
|
|
1703
1934
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1704
1935
|
parse(input, pos, ctx) {
|
|
1705
1936
|
const first = combinator.parse(input, pos, ctx);
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1937
|
+
const values = [];
|
|
1938
|
+
let cur;
|
|
1939
|
+
if (first.ok) {
|
|
1940
|
+
values.push(first.value);
|
|
1941
|
+
cur = first.span.end;
|
|
1942
|
+
} else {
|
|
1943
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1944
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1945
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1946
|
+
}
|
|
1947
|
+
expected ??= deriveExpected(combinator);
|
|
1948
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1949
|
+
values.push(rec.error);
|
|
1950
|
+
captureError(ctx, rec.error);
|
|
1951
|
+
cur = rec.end;
|
|
1952
|
+
}
|
|
1709
1953
|
while (cur < input.length) {
|
|
1710
1954
|
const loopMark = saveTriviaMark(ctx);
|
|
1711
1955
|
let sepPos = cur;
|
|
@@ -1735,6 +1979,15 @@ function sepBy(combinator, separator) {
|
|
|
1735
1979
|
}
|
|
1736
1980
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1737
1981
|
if (!next.ok) {
|
|
1982
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1983
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
1984
|
+
expected ??= deriveExpected(combinator);
|
|
1985
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
1986
|
+
values.push(rec.error);
|
|
1987
|
+
captureError(ctx, rec.error);
|
|
1988
|
+
cur = rec.end;
|
|
1989
|
+
continue;
|
|
1990
|
+
}
|
|
1738
1991
|
rollbackTrivia(ctx, loopMark);
|
|
1739
1992
|
break;
|
|
1740
1993
|
}
|
|
@@ -1871,7 +2124,7 @@ function rules(a, b) {
|
|
|
1871
2124
|
cache[key] = parser2;
|
|
1872
2125
|
}
|
|
1873
2126
|
}
|
|
1874
|
-
if (options?.trivia
|
|
2127
|
+
if (options?.trivia != null) {
|
|
1875
2128
|
for (const key of Object.keys(definitions)) {
|
|
1876
2129
|
const rule = cache[key];
|
|
1877
2130
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1901,7 +2154,9 @@ function not(combinator) {
|
|
|
1901
2154
|
_meta: meta,
|
|
1902
2155
|
_def: { tag: "not", parser: combinator },
|
|
1903
2156
|
parse(input, pos, ctx) {
|
|
2157
|
+
const mark = saveCstMark(ctx);
|
|
1904
2158
|
const result = combinator.parse(input, pos, ctx);
|
|
2159
|
+
rollbackCstCapture(ctx, mark);
|
|
1905
2160
|
if (result.ok) {
|
|
1906
2161
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1907
2162
|
}
|
|
@@ -2015,7 +2270,7 @@ function unwrapChild(child) {
|
|
|
2015
2270
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
2016
2271
|
}
|
|
2017
2272
|
function isCstChild(value) {
|
|
2018
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2273
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
2019
2274
|
}
|
|
2020
2275
|
function missingInferredType() {
|
|
2021
2276
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2268,65 +2523,6 @@ function token(root) {
|
|
|
2268
2523
|
};
|
|
2269
2524
|
}
|
|
2270
2525
|
|
|
2271
|
-
// src/combinators/expect.ts
|
|
2272
|
-
function deriveExpected(c) {
|
|
2273
|
-
const def = c._def;
|
|
2274
|
-
switch (def.tag) {
|
|
2275
|
-
case "literal":
|
|
2276
|
-
return [JSON.stringify(def.value)];
|
|
2277
|
-
case "regex":
|
|
2278
|
-
return [`/${def.source}/`];
|
|
2279
|
-
case "keywords":
|
|
2280
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2281
|
-
case "label":
|
|
2282
|
-
return [def.label];
|
|
2283
|
-
case "choice":
|
|
2284
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2285
|
-
case "sequence":
|
|
2286
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2287
|
-
case "node":
|
|
2288
|
-
case "grammar":
|
|
2289
|
-
case "trivia":
|
|
2290
|
-
case "token":
|
|
2291
|
-
case "optional":
|
|
2292
|
-
case "many":
|
|
2293
|
-
case "oneOrMore":
|
|
2294
|
-
case "transform":
|
|
2295
|
-
case "not":
|
|
2296
|
-
return deriveExpected(def.parser);
|
|
2297
|
-
case "lazy": {
|
|
2298
|
-
const name = c._ruleName;
|
|
2299
|
-
try {
|
|
2300
|
-
return deriveExpected(def.thunk());
|
|
2301
|
-
} catch {
|
|
2302
|
-
return name ? [name] : [];
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
default:
|
|
2306
|
-
return [];
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2309
|
-
function expect(combinator, label2) {
|
|
2310
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2311
|
-
const meta = {
|
|
2312
|
-
firstSet: combinator._meta.firstSet,
|
|
2313
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2314
|
-
isTrivia: false
|
|
2315
|
-
};
|
|
2316
|
-
return {
|
|
2317
|
-
_tag: "expect",
|
|
2318
|
-
_meta: meta,
|
|
2319
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2320
|
-
parse(input, pos, ctx) {
|
|
2321
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2322
|
-
if (result.ok) return result;
|
|
2323
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2324
|
-
ctx._errors?.push(error);
|
|
2325
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2326
|
-
}
|
|
2327
|
-
};
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
2526
|
// src/compiler/scannable-run.ts
|
|
2331
2527
|
var BACKSLASH = 92;
|
|
2332
2528
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2398,20 +2594,39 @@ function parseSeqParts(source) {
|
|
|
2398
2594
|
lit = [];
|
|
2399
2595
|
}
|
|
2400
2596
|
};
|
|
2401
|
-
const
|
|
2597
|
+
const braceQuant = (at) => {
|
|
2598
|
+
const close = source.indexOf("}", at);
|
|
2599
|
+
if (close === -1) return null;
|
|
2600
|
+
const body = source.slice(at + 1, close);
|
|
2601
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2602
|
+
if (!m) return null;
|
|
2603
|
+
const min = Number(m[1]);
|
|
2604
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2605
|
+
if (max < 1 || min > max) return null;
|
|
2606
|
+
return { min, max, len: close - at + 1 };
|
|
2607
|
+
};
|
|
2608
|
+
const runFrom = (ranges, negated, at) => {
|
|
2609
|
+
const q = source[at];
|
|
2402
2610
|
if (q === "+") {
|
|
2403
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2611
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2404
2612
|
return 1;
|
|
2405
2613
|
}
|
|
2406
2614
|
if (q === "*") {
|
|
2407
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2615
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2408
2616
|
return 1;
|
|
2409
2617
|
}
|
|
2410
2618
|
if (q === "?") {
|
|
2411
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2619
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2412
2620
|
return 1;
|
|
2413
2621
|
}
|
|
2414
|
-
|
|
2622
|
+
if (q === "{") {
|
|
2623
|
+
const b = braceQuant(at);
|
|
2624
|
+
if (b) {
|
|
2625
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2626
|
+
return b.len;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2415
2630
|
return 0;
|
|
2416
2631
|
};
|
|
2417
2632
|
let i = 0;
|
|
@@ -2436,7 +2651,7 @@ function parseSeqParts(source) {
|
|
|
2436
2651
|
if (!ranges) return null;
|
|
2437
2652
|
flush();
|
|
2438
2653
|
i = k + 1;
|
|
2439
|
-
i += runFrom(ranges, neg,
|
|
2654
|
+
i += runFrom(ranges, neg, i);
|
|
2440
2655
|
continue;
|
|
2441
2656
|
}
|
|
2442
2657
|
if (ch === "\\") {
|
|
@@ -2444,7 +2659,7 @@ function parseSeqParts(source) {
|
|
|
2444
2659
|
if (e === "d" || e === "w" || e === "s") {
|
|
2445
2660
|
flush();
|
|
2446
2661
|
i += 2;
|
|
2447
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2662
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2448
2663
|
continue;
|
|
2449
2664
|
}
|
|
2450
2665
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2533,7 +2748,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2533
2748
|
let hasMandatory = false;
|
|
2534
2749
|
for (let k = 0; k < parts.length; k++) {
|
|
2535
2750
|
const p = parts[k];
|
|
2536
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2751
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2537
2752
|
if (mandatory) hasMandatory = true;
|
|
2538
2753
|
if (p.part === "group") {
|
|
2539
2754
|
const exposure = groupPartExposure(p);
|
|
@@ -2544,9 +2759,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2544
2759
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2545
2760
|
}
|
|
2546
2761
|
}
|
|
2547
|
-
const
|
|
2548
|
-
|
|
2549
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2762
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2763
|
+
if (needsDisjoint) {
|
|
2550
2764
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2551
2765
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2552
2766
|
}
|
|
@@ -2603,8 +2817,8 @@ function fixedClassSeq(shape) {
|
|
|
2603
2817
|
if (p.part === "lit") {
|
|
2604
2818
|
if (p.optional) return null;
|
|
2605
2819
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2606
|
-
} else if (p.part === "run" &&
|
|
2607
|
-
out.push({ ranges: p.ranges, negated: p.negated });
|
|
2820
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2821
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2608
2822
|
} else {
|
|
2609
2823
|
return null;
|
|
2610
2824
|
}
|
|
@@ -2656,7 +2870,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2656
2870
|
const last = shape.parts[shape.parts.length - 1];
|
|
2657
2871
|
if (last.part === "lit") return null;
|
|
2658
2872
|
if (last.part === "run") {
|
|
2659
|
-
if (last.
|
|
2873
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2660
2874
|
return null;
|
|
2661
2875
|
}
|
|
2662
2876
|
return groupPartExposure(last);
|
|
@@ -2793,7 +3007,7 @@ function partFirstAccept(part) {
|
|
|
2793
3007
|
function seqFirstAccept(parts) {
|
|
2794
3008
|
const sets = [];
|
|
2795
3009
|
for (const p of parts) {
|
|
2796
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
3010
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2797
3011
|
sets.push(partFirstAccept(p));
|
|
2798
3012
|
if (mandatory) break;
|
|
2799
3013
|
}
|
|
@@ -3208,7 +3422,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3208
3422
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3209
3423
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3210
3424
|
}
|
|
3211
|
-
} else if (p.part === "run" &&
|
|
3425
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3426
|
+
const s = mint("_s");
|
|
3427
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3428
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3429
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3430
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3431
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3212
3432
|
if (p.min === 1) {
|
|
3213
3433
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3214
3434
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3218,8 +3438,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3218
3438
|
} else if (p.part === "run") {
|
|
3219
3439
|
const s = mint("_s");
|
|
3220
3440
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3221
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3222
|
-
if (p.min
|
|
3441
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3442
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3223
3443
|
} else {
|
|
3224
3444
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3225
3445
|
if (!p.unbounded) {
|
|
@@ -3686,21 +3906,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3686
3906
|
}
|
|
3687
3907
|
return name;
|
|
3688
3908
|
}
|
|
3909
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3910
|
+
if (!ctx.recovery) return "";
|
|
3911
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3912
|
+
const pb = v(ctx, "_pb");
|
|
3913
|
+
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} } } } `;
|
|
3914
|
+
}
|
|
3689
3915
|
function failBody(ctx, expected, posExpr) {
|
|
3916
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3690
3917
|
if (ctx.failLabel) {
|
|
3691
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3692
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3918
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3919
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3693
3920
|
}
|
|
3694
|
-
return failReturn(expected, posExpr);
|
|
3921
|
+
return probe + failReturn(expected, posExpr);
|
|
3695
3922
|
}
|
|
3696
3923
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3924
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3697
3925
|
if (ctx.failLabel) {
|
|
3698
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3926
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3699
3927
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3700
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3928
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3701
3929
|
}
|
|
3702
|
-
if (!constant) return
|
|
3703
|
-
return failReturnArr(expectedArr, posExpr);
|
|
3930
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3931
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3704
3932
|
}
|
|
3705
3933
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3706
3934
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4200,6 +4428,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4200
4428
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4201
4429
|
return { stmts, valueVar: vv, endVar };
|
|
4202
4430
|
}
|
|
4431
|
+
function syncSentinelExpr(fs2) {
|
|
4432
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
4433
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs2.ranges)} })`;
|
|
4434
|
+
}
|
|
4203
4435
|
function emitSeqValues(def, ctx, pos) {
|
|
4204
4436
|
const startV = v(ctx, "_start");
|
|
4205
4437
|
const curV = v(ctx, "_cur");
|
|
@@ -4208,7 +4440,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4208
4440
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4209
4441
|
];
|
|
4210
4442
|
const valueVars = [];
|
|
4443
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4444
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4445
|
+
const publishSync = (i) => {
|
|
4446
|
+
if (!ctx.recovery) return "";
|
|
4447
|
+
const fs2 = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4448
|
+
const ref2 = syncSentinelExpr(fs2);
|
|
4449
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4450
|
+
};
|
|
4211
4451
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4452
|
+
const syncPub = publishSync(i);
|
|
4453
|
+
if (syncPub) stmts.push(syncPub);
|
|
4212
4454
|
if (i > 0 && ctx.activeTrivia) {
|
|
4213
4455
|
if (ctx.capturing) {
|
|
4214
4456
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4233,7 +4475,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4233
4475
|
continue;
|
|
4234
4476
|
} else {
|
|
4235
4477
|
const trivFn = ensureTriviaFn(ctx);
|
|
4236
|
-
|
|
4478
|
+
const scanEndV = v(ctx, "_sne");
|
|
4479
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4480
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4481
|
+
stmts.push(...r2.stmts);
|
|
4482
|
+
const endAfterV = v(ctx, "_sea");
|
|
4483
|
+
stmts.push(
|
|
4484
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4485
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4486
|
+
);
|
|
4487
|
+
valueVars.push(r2.valueVar);
|
|
4488
|
+
continue;
|
|
4237
4489
|
}
|
|
4238
4490
|
}
|
|
4239
4491
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4311,6 +4563,21 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
|
|
|
4311
4563
|
`${ind(ctx)}${endV} = ${endVar}`
|
|
4312
4564
|
];
|
|
4313
4565
|
}
|
|
4566
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4567
|
+
const p = def.parsers[i];
|
|
4568
|
+
const gate = def.gates[i];
|
|
4569
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4570
|
+
const gateIdx = ctx.mapFns.length;
|
|
4571
|
+
ctx.mapFns.push(gate);
|
|
4572
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4573
|
+
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4574
|
+
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4575
|
+
ctx.indent++;
|
|
4576
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4577
|
+
ctx.indent--;
|
|
4578
|
+
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4579
|
+
return stmts;
|
|
4580
|
+
}
|
|
4314
4581
|
function emitChoice(def, ctx, pos) {
|
|
4315
4582
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4316
4583
|
if (def.disjoint) {
|
|
@@ -4326,12 +4593,11 @@ function emitChoice(def, ctx, pos) {
|
|
|
4326
4593
|
stmts.push(`${ind(ctx)}switch (${codeV}) {`);
|
|
4327
4594
|
ctx.indent++;
|
|
4328
4595
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4329
|
-
const p = def.parsers[i];
|
|
4330
4596
|
for (const cp of plan.cases[i]) stmts.push(`${ind(ctx)}case ${cp}:`);
|
|
4331
4597
|
stmts.push(`${ind(ctx)}{`);
|
|
4332
4598
|
ctx.indent++;
|
|
4333
4599
|
stmts.push(
|
|
4334
|
-
...
|
|
4600
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
4335
4601
|
`${ind(ctx)}break`
|
|
4336
4602
|
);
|
|
4337
4603
|
ctx.indent--;
|
|
@@ -4343,13 +4609,14 @@ function emitChoice(def, ctx, pos) {
|
|
|
4343
4609
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4344
4610
|
}
|
|
4345
4611
|
let first = true;
|
|
4346
|
-
for (
|
|
4612
|
+
for (let i = 0; i < def.parsers.length; i++) {
|
|
4613
|
+
const p = def.parsers[i];
|
|
4347
4614
|
const cond = firstSetCond(codeV, p._meta.firstSet);
|
|
4348
4615
|
const kw = first ? "if" : "else if";
|
|
4349
4616
|
first = false;
|
|
4350
4617
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4351
4618
|
ctx.indent++;
|
|
4352
|
-
stmts.push(...
|
|
4619
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
4353
4620
|
ctx.indent--;
|
|
4354
4621
|
stmts.push(`${ind(ctx)}}`);
|
|
4355
4622
|
}
|
|
@@ -4463,7 +4730,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4463
4730
|
if (gate) {
|
|
4464
4731
|
const gateIdx = ctx.mapFns.length;
|
|
4465
4732
|
ctx.mapFns.push(gate);
|
|
4466
|
-
ctx.mapFnSrcs.push(null);
|
|
4733
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4467
4734
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4468
4735
|
}
|
|
4469
4736
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4568,6 +4835,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4568
4835
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4569
4836
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4570
4837
|
];
|
|
4838
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4839
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4571
4840
|
if (def.min === 1) {
|
|
4572
4841
|
const firstR = emit(def.parser, ctx, curV);
|
|
4573
4842
|
stmts.push(...firstR.stmts);
|
|
@@ -4601,10 +4870,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4601
4870
|
}
|
|
4602
4871
|
}
|
|
4603
4872
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4604
|
-
stmts.push(
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4873
|
+
stmts.push(...iterStmts);
|
|
4874
|
+
if (ctx.recovery) {
|
|
4875
|
+
const rrV = v(ctx, "_rr");
|
|
4876
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4877
|
+
stmts.push(
|
|
4878
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4879
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4880
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4881
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4882
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4883
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4884
|
+
`${ind(ctx)} continue`,
|
|
4885
|
+
`${ind(ctx)} }`,
|
|
4886
|
+
`${ind(ctx)} break`,
|
|
4887
|
+
`${ind(ctx)}}`,
|
|
4888
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4889
|
+
);
|
|
4890
|
+
} else {
|
|
4891
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4892
|
+
}
|
|
4608
4893
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4609
4894
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4610
4895
|
ctx.indent--;
|
|
@@ -4626,20 +4911,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4626
4911
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4627
4912
|
const arrV = v(ctx, "_arr");
|
|
4628
4913
|
const curV = v(ctx, "_cur");
|
|
4914
|
+
const rec = !!ctx.recovery;
|
|
4915
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4916
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4917
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4918
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4629
4919
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4630
4920
|
const stmts = [
|
|
4631
4921
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4632
4922
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4633
|
-
...
|
|
4634
|
-
|
|
4923
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4924
|
+
...firstStmts
|
|
4635
4925
|
];
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
)
|
|
4642
|
-
|
|
4926
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4927
|
+
if (!rec) return [originalFail];
|
|
4928
|
+
const rr = v(ctx, "_rr");
|
|
4929
|
+
return [
|
|
4930
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
4931
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
4932
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
4933
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
4934
|
+
`${ind(ctx)} }`,
|
|
4935
|
+
`${ind(ctx)} ${rb}break`,
|
|
4936
|
+
`${ind(ctx)}}`
|
|
4937
|
+
];
|
|
4938
|
+
};
|
|
4939
|
+
if (rec) {
|
|
4940
|
+
const rr0 = v(ctx, "_rr0");
|
|
4941
|
+
const didV = v(ctx, "_did");
|
|
4942
|
+
stmts.push(
|
|
4943
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
4944
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
4945
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
4946
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
4947
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
4948
|
+
`${ind(ctx)}}`,
|
|
4949
|
+
`${ind(ctx)}if (${didV}) {`
|
|
4950
|
+
);
|
|
4951
|
+
ctx.indent++;
|
|
4952
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
4953
|
+
ctx.indent++;
|
|
4954
|
+
} else {
|
|
4955
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
4956
|
+
ctx.indent++;
|
|
4957
|
+
stmts.push(
|
|
4958
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
4959
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
4960
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
4961
|
+
);
|
|
4962
|
+
ctx.indent++;
|
|
4963
|
+
}
|
|
4643
4964
|
let sepAtPos = curV;
|
|
4644
4965
|
if (ctx.activeTrivia) {
|
|
4645
4966
|
if (ctx.capturing) {
|
|
@@ -4665,8 +4986,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4665
4986
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4666
4987
|
stmts.push(
|
|
4667
4988
|
...nextStmts,
|
|
4668
|
-
|
|
4669
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
4989
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4670
4990
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4671
4991
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4672
4992
|
);
|
|
@@ -4682,7 +5002,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4682
5002
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4683
5003
|
stmts.push(
|
|
4684
5004
|
...nextStmts,
|
|
4685
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
5005
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4686
5006
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4687
5007
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4688
5008
|
);
|
|
@@ -4702,7 +5022,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4702
5022
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4703
5023
|
stmts.push(
|
|
4704
5024
|
...nextStmts,
|
|
4705
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
5025
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4706
5026
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4707
5027
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4708
5028
|
);
|
|
@@ -4959,7 +5279,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4959
5279
|
stmts.push(
|
|
4960
5280
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4961
5281
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4962
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === '
|
|
5282
|
+
`${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} } })`
|
|
4963
5283
|
);
|
|
4964
5284
|
return { stmts, valueVar: ndV, endVar };
|
|
4965
5285
|
}
|
|
@@ -5049,6 +5369,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5049
5369
|
`${ind0}if (!${okVar}) {`,
|
|
5050
5370
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5051
5371
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5372
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5373
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5374
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5375
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5052
5376
|
`${ind0} ${valVar} = ${errV}`,
|
|
5053
5377
|
`${ind0} ${endVar} = ${pos}`,
|
|
5054
5378
|
`${ind0} ${okVar} = true`,
|
|
@@ -5215,7 +5539,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5215
5539
|
case "guard": {
|
|
5216
5540
|
const fnIdx = ctx.mapFns.length;
|
|
5217
5541
|
ctx.mapFns.push(def.predicate);
|
|
5218
|
-
ctx.mapFnSrcs.push(null);
|
|
5542
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5219
5543
|
const vv = v(ctx);
|
|
5220
5544
|
return {
|
|
5221
5545
|
stmts: [
|
|
@@ -5230,7 +5554,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5230
5554
|
const evIdx = ctx.mapFns.length;
|
|
5231
5555
|
const extra = def.extra;
|
|
5232
5556
|
ctx.mapFns.push((() => extra));
|
|
5233
|
-
ctx.mapFnSrcs.push(null);
|
|
5557
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5234
5558
|
const innerParser = def.parser;
|
|
5235
5559
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5236
5560
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5474,7 +5798,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5474
5798
|
}
|
|
5475
5799
|
return deps;
|
|
5476
5800
|
}
|
|
5477
|
-
function compile(combinator, mapFnSources) {
|
|
5801
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5478
5802
|
markUnusedValues(combinator);
|
|
5479
5803
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5480
5804
|
const ctx = {
|
|
@@ -5495,6 +5819,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5495
5819
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5496
5820
|
namedFnDecls: [],
|
|
5497
5821
|
capturing: hasNodeDef(combinator),
|
|
5822
|
+
recovery: opts?.recovery ?? false,
|
|
5498
5823
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5499
5824
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5500
5825
|
};
|
|
@@ -5547,7 +5872,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5547
5872
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5548
5873
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5549
5874
|
},
|
|
5550
|
-
// Note: collects
|
|
5875
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5551
5876
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5552
5877
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5553
5878
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5593,6 +5918,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
5593
5918
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5594
5919
|
namedFnDecls: [],
|
|
5595
5920
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5921
|
+
recovery: opts?.recovery ?? false,
|
|
5596
5922
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5597
5923
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5598
5924
|
};
|
|
@@ -5688,6 +6014,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5688
6014
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5689
6015
|
namedFnDecls: [],
|
|
5690
6016
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
6017
|
+
recovery: opts?.recovery ?? false,
|
|
5691
6018
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5692
6019
|
ns,
|
|
5693
6020
|
deferFirstSetRefs: true,
|
|
@@ -6335,6 +6662,42 @@ function materializePiece(p, trivia2) {
|
|
|
6335
6662
|
return pieces;
|
|
6336
6663
|
}
|
|
6337
6664
|
|
|
6665
|
+
// src/combinators/guard.ts
|
|
6666
|
+
function guard(predicate) {
|
|
6667
|
+
const meta = {
|
|
6668
|
+
firstSet: { kind: "any" },
|
|
6669
|
+
canMatchNewline: false,
|
|
6670
|
+
isTrivia: false
|
|
6671
|
+
};
|
|
6672
|
+
return {
|
|
6673
|
+
_tag: "guard",
|
|
6674
|
+
_meta: meta,
|
|
6675
|
+
_def: { tag: "guard", predicate },
|
|
6676
|
+
parse(_input, pos, ctx) {
|
|
6677
|
+
if (predicate(ctx.state))
|
|
6678
|
+
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
6679
|
+
return { ok: false, expected: ["guard"], span: { start: pos, end: pos } };
|
|
6680
|
+
}
|
|
6681
|
+
};
|
|
6682
|
+
}
|
|
6683
|
+
|
|
6684
|
+
// src/combinators/withCtx.ts
|
|
6685
|
+
function withCtx(extra, combinator) {
|
|
6686
|
+
const meta = {
|
|
6687
|
+
firstSet: combinator._meta.firstSet,
|
|
6688
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
6689
|
+
isTrivia: false
|
|
6690
|
+
};
|
|
6691
|
+
return {
|
|
6692
|
+
_tag: "withCtx",
|
|
6693
|
+
_meta: meta,
|
|
6694
|
+
_def: { tag: "withCtx", extra, parser: combinator },
|
|
6695
|
+
parse(input, pos, ctx) {
|
|
6696
|
+
return combinator.parse(input, pos, { ...ctx, state: extra });
|
|
6697
|
+
}
|
|
6698
|
+
};
|
|
6699
|
+
}
|
|
6700
|
+
|
|
6338
6701
|
// src/cst/offset-model.ts
|
|
6339
6702
|
var { isFinite } = Number;
|
|
6340
6703
|
|
|
@@ -6366,6 +6729,35 @@ var SUPPORTED = {
|
|
|
6366
6729
|
function isScopeEntry(v2) {
|
|
6367
6730
|
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
6368
6731
|
}
|
|
6732
|
+
function propName(p) {
|
|
6733
|
+
if (p.computed) return null;
|
|
6734
|
+
const key = p.key;
|
|
6735
|
+
return key.type === "Identifier" ? key.name ?? null : key.type === "Literal" ? String(key.value) : null;
|
|
6736
|
+
}
|
|
6737
|
+
function isGatedArmExpr(e) {
|
|
6738
|
+
if (e.type !== "ObjectExpression") return false;
|
|
6739
|
+
let hasGate = false, hasCombinator = false;
|
|
6740
|
+
for (const prop of e.properties) {
|
|
6741
|
+
if (prop.type !== "Property") continue;
|
|
6742
|
+
const name = propName(prop);
|
|
6743
|
+
if (name === "gate") hasGate = true;
|
|
6744
|
+
else if (name === "combinator") hasCombinator = true;
|
|
6745
|
+
}
|
|
6746
|
+
return hasGate && hasCombinator;
|
|
6747
|
+
}
|
|
6748
|
+
function gatedArmParts(e) {
|
|
6749
|
+
let gate;
|
|
6750
|
+
let combinator;
|
|
6751
|
+
for (const prop of e.properties) {
|
|
6752
|
+
if (prop.type !== "Property") return null;
|
|
6753
|
+
const op = prop;
|
|
6754
|
+
const name = propName(op);
|
|
6755
|
+
if (name === "gate") gate = op.value;
|
|
6756
|
+
else if (name === "combinator") combinator = op.value;
|
|
6757
|
+
else return null;
|
|
6758
|
+
}
|
|
6759
|
+
return gate && combinator ? { gate, combinator } : null;
|
|
6760
|
+
}
|
|
6369
6761
|
function isCombinator(v2) {
|
|
6370
6762
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
6371
6763
|
}
|
|
@@ -6547,6 +6939,72 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
6547
6939
|
return null;
|
|
6548
6940
|
}
|
|
6549
6941
|
}
|
|
6942
|
+
if (callee.name === "guard") {
|
|
6943
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6944
|
+
const [predArg] = node2.arguments;
|
|
6945
|
+
if (!predArg || predArg.type === "SpreadElement") return null;
|
|
6946
|
+
const predSrc = code.slice(predArg.start, predArg.end);
|
|
6947
|
+
mfs.push(predSrc);
|
|
6948
|
+
try {
|
|
6949
|
+
const combi = guard(() => true);
|
|
6950
|
+
if (combi._def.tag !== "guard") return null;
|
|
6951
|
+
combi._def.predSrc = predSrc;
|
|
6952
|
+
return combi;
|
|
6953
|
+
} catch {
|
|
6954
|
+
return null;
|
|
6955
|
+
}
|
|
6956
|
+
}
|
|
6957
|
+
if (callee.name === "withCtx") {
|
|
6958
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6959
|
+
const [extraArg, innerArg] = node2.arguments;
|
|
6960
|
+
if (!extraArg || !innerArg || extraArg.type === "SpreadElement" || innerArg.type === "SpreadElement") return null;
|
|
6961
|
+
const extraSrc = code.slice(extraArg.start, extraArg.end);
|
|
6962
|
+
mfs.push(extraSrc);
|
|
6963
|
+
const inner = anyValue(innerArg, scope, code, mfs);
|
|
6964
|
+
if (!isCombinator(inner)) return null;
|
|
6965
|
+
try {
|
|
6966
|
+
const combi = withCtx({}, inner);
|
|
6967
|
+
if (combi._def.tag !== "withCtx") return null;
|
|
6968
|
+
combi._def.extraSrc = extraSrc;
|
|
6969
|
+
return combi;
|
|
6970
|
+
} catch {
|
|
6971
|
+
return null;
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6974
|
+
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
6975
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6976
|
+
const arms = [];
|
|
6977
|
+
const gateSrcs = [];
|
|
6978
|
+
for (const argNode of node2.arguments) {
|
|
6979
|
+
if (argNode.type === "SpreadElement") return null;
|
|
6980
|
+
if (isGatedArmExpr(argNode)) {
|
|
6981
|
+
const parts = gatedArmParts(argNode);
|
|
6982
|
+
if (!parts) return null;
|
|
6983
|
+
const gateSrc = code.slice(parts.gate.start, parts.gate.end);
|
|
6984
|
+
mfs.push(gateSrc);
|
|
6985
|
+
const combi = anyValue(parts.combinator, scope, code, mfs);
|
|
6986
|
+
if (!isCombinator(combi)) return null;
|
|
6987
|
+
arms.push({ gate: () => true, combinator: combi });
|
|
6988
|
+
gateSrcs.push(gateSrc);
|
|
6989
|
+
} else {
|
|
6990
|
+
const combi = anyValue(argNode, scope, code, mfs);
|
|
6991
|
+
if (!isCombinator(combi)) return null;
|
|
6992
|
+
arms.push(combi);
|
|
6993
|
+
gateSrcs.push(null);
|
|
6994
|
+
}
|
|
6995
|
+
}
|
|
6996
|
+
try {
|
|
6997
|
+
const combi = choice(...arms);
|
|
6998
|
+
if (combi._def.tag !== "choice") return null;
|
|
6999
|
+
combi._def.gateSrcs = gateSrcs;
|
|
7000
|
+
for (let i = 0; i < combi._def.gates.length; i++) {
|
|
7001
|
+
if (combi._def.gates[i] !== null !== (gateSrcs[i] !== null)) return null;
|
|
7002
|
+
}
|
|
7003
|
+
return combi;
|
|
7004
|
+
} catch {
|
|
7005
|
+
return null;
|
|
7006
|
+
}
|
|
7007
|
+
}
|
|
6550
7008
|
const factory = SUPPORTED[callee.name];
|
|
6551
7009
|
if (!factory) return null;
|
|
6552
7010
|
const args = node2.arguments.map((arg) => {
|
|
@@ -6609,9 +7067,9 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
6609
7067
|
if (typeof key !== "string" && typeof key !== "number") return null;
|
|
6610
7068
|
return obj[key] ?? null;
|
|
6611
7069
|
}
|
|
6612
|
-
const
|
|
6613
|
-
if (!
|
|
6614
|
-
return obj[
|
|
7070
|
+
const propName2 = mem.property.name;
|
|
7071
|
+
if (!propName2) return null;
|
|
7072
|
+
return obj[propName2] ?? null;
|
|
6615
7073
|
}
|
|
6616
7074
|
if (node2.type === "CallExpression") {
|
|
6617
7075
|
const callee = node2.callee;
|
|
@@ -6856,7 +7314,7 @@ var plugin_default = (0, import_unplugin.createUnplugin)((opts = {}) => ({
|
|
|
6856
7314
|
if (!code.includes("parseman")) return null;
|
|
6857
7315
|
if (!code.includes("macro")) return null;
|
|
6858
7316
|
const moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE, ...opts.moduleAliases ?? []]);
|
|
6859
|
-
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true);
|
|
7317
|
+
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true);
|
|
6860
7318
|
if (result?.warnings.length) {
|
|
6861
7319
|
for (const w of result.warnings) {
|
|
6862
7320
|
if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
|
|
@@ -6960,7 +7418,7 @@ function extractImportBindings(body) {
|
|
|
6960
7418
|
}
|
|
6961
7419
|
return out;
|
|
6962
7420
|
}
|
|
6963
|
-
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false) {
|
|
7421
|
+
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false) {
|
|
6964
7422
|
let result;
|
|
6965
7423
|
try {
|
|
6966
7424
|
result = (0, import_oxc_parser.parseSync)(id, code);
|
|
@@ -7031,7 +7489,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7031
7489
|
(p) => p.key?.name === "trivia"
|
|
7032
7490
|
)?.value : void 0;
|
|
7033
7491
|
const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
|
|
7034
|
-
const compiled = compileRuleMap([...ruleMap], gTrivia ? { trivia: gTrivia } :
|
|
7492
|
+
const compiled = compileRuleMap([...ruleMap], { ...gTrivia ? { trivia: gTrivia } : {}, recovery });
|
|
7035
7493
|
if (!compiled) {
|
|
7036
7494
|
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
7037
7495
|
return null;
|
|
@@ -7129,7 +7587,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7129
7587
|
const ns = nsFor(label2);
|
|
7130
7588
|
const ir = serializeRuleMap(entries);
|
|
7131
7589
|
if (ir) return { carried: [{ ns, ir }] };
|
|
7132
|
-
const p = compileLinkable(entries, ns, composing ? { trivia: composing } :
|
|
7590
|
+
const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, recovery });
|
|
7133
7591
|
return p ? { carried: [p] } : null;
|
|
7134
7592
|
};
|
|
7135
7593
|
const argPieces = (arg, label2, composing) => {
|
|
@@ -7305,7 +7763,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7305
7763
|
const refEntry = scope.get(varName);
|
|
7306
7764
|
const refCombi = refEntry?.combi ?? null;
|
|
7307
7765
|
if (refCombi) {
|
|
7308
|
-
const compiled2 = compile(refCombi);
|
|
7766
|
+
const compiled2 = compile(refCombi, void 0, { recovery });
|
|
7309
7767
|
if (compiled2.inlineExpression === null) {
|
|
7310
7768
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
7311
7769
|
continue;
|
|
@@ -7322,7 +7780,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7322
7780
|
let replacement = compiledRules.replacement;
|
|
7323
7781
|
if (exportPrefix) {
|
|
7324
7782
|
const ns = nsFor(varName);
|
|
7325
|
-
const pieces = compileLinkable([...compiledRules.ruleMap], ns);
|
|
7783
|
+
const pieces = compileLinkable([...compiledRules.ruleMap], ns, { recovery });
|
|
7326
7784
|
if (pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
|
|
7327
7785
|
const ir = serializeRuleMap([...compiledRules.ruleMap]);
|
|
7328
7786
|
replacement = withCarriedPieces(replacement, [ir ? { ns, ir } : pieces]);
|
|
@@ -7358,7 +7816,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7358
7816
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
7359
7817
|
continue;
|
|
7360
7818
|
}
|
|
7361
|
-
const compiled = compile(parser2);
|
|
7819
|
+
const compiled = compile(parser2, void 0, { recovery });
|
|
7362
7820
|
if (compiled.inlineExpression === null) {
|
|
7363
7821
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
7364
7822
|
continue;
|