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.js
CHANGED
|
@@ -297,7 +297,13 @@ function saveCstMark(ctx) {
|
|
|
297
297
|
raw: cstRawLen(ctx),
|
|
298
298
|
tlog: cstTlLen(ctx),
|
|
299
299
|
leaves: cstLeavesLen(ctx),
|
|
300
|
-
fields: ctx._fields?.length ?? 0
|
|
300
|
+
fields: ctx._fields?.length ?? 0,
|
|
301
|
+
// Speculative rollback must truncate the flat recovery-error sink in lockstep
|
|
302
|
+
// with the CST leaves: a branch that recovered (pushing a ParseError to
|
|
303
|
+
// ctx._errors AND embedding it as a CST child via captureError) then failed
|
|
304
|
+
// must remove BOTH, or the flat error survives as a GHOST that a tree walk
|
|
305
|
+
// can't see (flat run().errors would disagree with the embedded set).
|
|
306
|
+
errors: ctx._errors?.length ?? 0
|
|
301
307
|
};
|
|
302
308
|
}
|
|
303
309
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -313,6 +319,7 @@ function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
|
313
319
|
if (len === 0) b[keySingle] = void 0;
|
|
314
320
|
}
|
|
315
321
|
function rollbackCstCapture(ctx, mark) {
|
|
322
|
+
if (ctx._errors && mark.errors !== void 0) ctx._errors.length = mark.errors;
|
|
316
323
|
const b = ctx._cstBuf;
|
|
317
324
|
if (b) {
|
|
318
325
|
rollbackBufList(b, "raw", "rawSingle", mark.raw);
|
|
@@ -870,12 +877,159 @@ function keywords(words, opts = {}) {
|
|
|
870
877
|
};
|
|
871
878
|
}
|
|
872
879
|
|
|
880
|
+
// src/recovery/scan.ts
|
|
881
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
882
|
+
const s = {
|
|
883
|
+
_probe: ctx._probe,
|
|
884
|
+
_errors: ctx._errors,
|
|
885
|
+
_cstLeaves: ctx._cstLeaves,
|
|
886
|
+
_cstChildren: ctx._cstChildren,
|
|
887
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
888
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
889
|
+
_triviaLog: ctx._triviaLog,
|
|
890
|
+
_fields: ctx._fields,
|
|
891
|
+
_cstBuf: ctx._cstBuf,
|
|
892
|
+
_tolerant: ctx._tolerant,
|
|
893
|
+
_sync: ctx._sync
|
|
894
|
+
};
|
|
895
|
+
ctx._probe = void 0;
|
|
896
|
+
ctx._errors = void 0;
|
|
897
|
+
ctx._cstLeaves = void 0;
|
|
898
|
+
ctx._cstChildren = void 0;
|
|
899
|
+
ctx._cstRawChildren = void 0;
|
|
900
|
+
ctx._cstTriviaLog = void 0;
|
|
901
|
+
ctx._triviaLog = void 0;
|
|
902
|
+
ctx._fields = void 0;
|
|
903
|
+
ctx._cstBuf = void 0;
|
|
904
|
+
ctx._tolerant = void 0;
|
|
905
|
+
ctx._sync = void 0;
|
|
906
|
+
try {
|
|
907
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
908
|
+
} finally {
|
|
909
|
+
ctx._probe = s._probe;
|
|
910
|
+
ctx._errors = s._errors;
|
|
911
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
912
|
+
ctx._cstChildren = s._cstChildren;
|
|
913
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
914
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
915
|
+
ctx._triviaLog = s._triviaLog;
|
|
916
|
+
ctx._fields = s._fields;
|
|
917
|
+
ctx._cstBuf = s._cstBuf;
|
|
918
|
+
ctx._tolerant = s._tolerant;
|
|
919
|
+
ctx._sync = s._sync;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function orSentinel(a, b) {
|
|
923
|
+
if (b === void 0) return a;
|
|
924
|
+
return {
|
|
925
|
+
_tag: "orSentinel",
|
|
926
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
927
|
+
_def: { tag: "unknown" },
|
|
928
|
+
parse(input, pos, ctx) {
|
|
929
|
+
const ra = a.parse(input, pos, ctx);
|
|
930
|
+
if (ra.ok) return ra;
|
|
931
|
+
return b.parse(input, pos, ctx);
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
function firstSetSentinel(fs2) {
|
|
936
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
937
|
+
const ranges = fs2.ranges;
|
|
938
|
+
return {
|
|
939
|
+
_tag: "firstSetSentinel",
|
|
940
|
+
_meta: { firstSet: fs2, canMatchNewline: false, isTrivia: false },
|
|
941
|
+
_def: { tag: "unknown" },
|
|
942
|
+
parse(input, pos) {
|
|
943
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
944
|
+
if (code !== void 0) {
|
|
945
|
+
for (const r of ranges) {
|
|
946
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
954
|
+
let scanPos = from;
|
|
955
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
956
|
+
const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
|
|
957
|
+
ctx._errors?.push(error);
|
|
958
|
+
return { error, end: scanPos };
|
|
959
|
+
}
|
|
960
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
961
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
962
|
+
}
|
|
963
|
+
function captureError(ctx, error) {
|
|
964
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/combinators/expect.ts
|
|
968
|
+
function deriveExpected(c) {
|
|
969
|
+
const def = c._def;
|
|
970
|
+
switch (def.tag) {
|
|
971
|
+
case "literal":
|
|
972
|
+
return [JSON.stringify(def.value)];
|
|
973
|
+
case "regex":
|
|
974
|
+
return [`/${def.source}/`];
|
|
975
|
+
case "keywords":
|
|
976
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
977
|
+
case "label":
|
|
978
|
+
return [def.label];
|
|
979
|
+
case "choice":
|
|
980
|
+
return def.parsers.flatMap(deriveExpected);
|
|
981
|
+
case "sequence":
|
|
982
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
983
|
+
case "node":
|
|
984
|
+
case "grammar":
|
|
985
|
+
case "trivia":
|
|
986
|
+
case "token":
|
|
987
|
+
case "optional":
|
|
988
|
+
case "many":
|
|
989
|
+
case "oneOrMore":
|
|
990
|
+
case "transform":
|
|
991
|
+
case "not":
|
|
992
|
+
return deriveExpected(def.parser);
|
|
993
|
+
case "lazy": {
|
|
994
|
+
const name = c._ruleName;
|
|
995
|
+
try {
|
|
996
|
+
return deriveExpected(def.thunk());
|
|
997
|
+
} catch {
|
|
998
|
+
return name ? [name] : [];
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
default:
|
|
1002
|
+
return [];
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
function expect(combinator, label2) {
|
|
1006
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1007
|
+
const meta = {
|
|
1008
|
+
firstSet: combinator._meta.firstSet,
|
|
1009
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1010
|
+
isTrivia: false
|
|
1011
|
+
};
|
|
1012
|
+
return {
|
|
1013
|
+
_tag: "expect",
|
|
1014
|
+
_meta: meta,
|
|
1015
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1016
|
+
parse(input, pos, ctx) {
|
|
1017
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1018
|
+
if (result.ok) return result;
|
|
1019
|
+
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
1020
|
+
ctx._errors?.push(error);
|
|
1021
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1022
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
|
|
873
1027
|
// src/combinators/choice.ts
|
|
874
1028
|
function choice(...args) {
|
|
875
1029
|
const parsers = args.map((a) => "gate" in a ? a.combinator : a);
|
|
876
1030
|
const gates = args.map((a) => "gate" in a ? a.gate : null);
|
|
877
1031
|
const hasGates = gates.some((g) => g !== null);
|
|
878
|
-
const disjoint =
|
|
1032
|
+
const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
|
|
879
1033
|
let combined = { kind: "empty" };
|
|
880
1034
|
for (const p of parsers) combined = union(combined, p._meta.firstSet);
|
|
881
1035
|
const meta = {
|
|
@@ -914,17 +1068,21 @@ function choice(...args) {
|
|
|
914
1068
|
const expected = [];
|
|
915
1069
|
if (disjoint && pos < input.length) {
|
|
916
1070
|
const code = input.codePointAt(pos);
|
|
917
|
-
let
|
|
918
|
-
if (
|
|
919
|
-
for (
|
|
920
|
-
if (inFirstSet(code,
|
|
921
|
-
|
|
1071
|
+
let idx = code < 128 ? asciiDispatch[code] : -1;
|
|
1072
|
+
if (idx < 0) {
|
|
1073
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1074
|
+
if (inFirstSet(code, parsers[i]._meta.firstSet)) {
|
|
1075
|
+
idx = i;
|
|
922
1076
|
break;
|
|
923
1077
|
}
|
|
924
1078
|
}
|
|
925
1079
|
}
|
|
926
|
-
if (
|
|
927
|
-
const
|
|
1080
|
+
if (idx >= 0) {
|
|
1081
|
+
const gate = gates[idx];
|
|
1082
|
+
if (gate && !gate(ctx.state)) {
|
|
1083
|
+
return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
|
|
1084
|
+
}
|
|
1085
|
+
const result = parsers[idx].parse(input, pos, ctx);
|
|
928
1086
|
if (result.ok) return result;
|
|
929
1087
|
expected.push(...result.expected);
|
|
930
1088
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
@@ -1105,13 +1263,13 @@ function areDisjoint(sets) {
|
|
|
1105
1263
|
return true;
|
|
1106
1264
|
}
|
|
1107
1265
|
function buildAsciiDispatch(parsers) {
|
|
1108
|
-
const table = Array(128).fill(
|
|
1109
|
-
for (
|
|
1110
|
-
const fs2 =
|
|
1266
|
+
const table = Array(128).fill(-1);
|
|
1267
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1268
|
+
const fs2 = parsers[i]._meta.firstSet;
|
|
1111
1269
|
if (fs2.kind !== "ranges") continue;
|
|
1112
1270
|
for (const { lo, hi } of fs2.ranges) {
|
|
1113
1271
|
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1114
|
-
table[code] =
|
|
1272
|
+
table[code] = i;
|
|
1115
1273
|
}
|
|
1116
1274
|
}
|
|
1117
1275
|
}
|
|
@@ -1256,10 +1414,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1256
1414
|
}
|
|
1257
1415
|
function saveTriviaMark(ctx) {
|
|
1258
1416
|
const m = saveCstMark(ctx);
|
|
1259
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1417
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1260
1418
|
}
|
|
1261
1419
|
function rollbackTrivia(ctx, mark) {
|
|
1262
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1420
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1263
1421
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1264
1422
|
}
|
|
1265
1423
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1503,11 +1661,59 @@ function sequence(...parsers) {
|
|
|
1503
1661
|
isTrivia: false
|
|
1504
1662
|
};
|
|
1505
1663
|
const def = { tag: "sequence", parsers };
|
|
1664
|
+
let followSentinels;
|
|
1665
|
+
function parseTolerant(input, pos, ctx) {
|
|
1666
|
+
followSentinels ??= parsers.map((_, i) => {
|
|
1667
|
+
const fs2 = parsers.slice(i + 1).reduce(
|
|
1668
|
+
(acc, p) => union(acc, firstSetOf(p)),
|
|
1669
|
+
{ kind: "empty" }
|
|
1670
|
+
);
|
|
1671
|
+
return firstSetSentinel(fs2);
|
|
1672
|
+
});
|
|
1673
|
+
const values = def.valueUnused ? void 0 : [];
|
|
1674
|
+
let cur = pos;
|
|
1675
|
+
const inheritedSync = ctx._sync;
|
|
1676
|
+
try {
|
|
1677
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1678
|
+
ctx._sync = followSentinels[i] ?? inheritedSync;
|
|
1679
|
+
if (ctx.trivia && i > 0) {
|
|
1680
|
+
const mark = saveTriviaMark(ctx);
|
|
1681
|
+
let scanEnd;
|
|
1682
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
1683
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1684
|
+
scan.commit();
|
|
1685
|
+
scanEnd = scan.end;
|
|
1686
|
+
} else {
|
|
1687
|
+
scanEnd = advanceTrivia(input, cur, ctx);
|
|
1688
|
+
}
|
|
1689
|
+
const result2 = parsers[i].parse(input, scanEnd, ctx);
|
|
1690
|
+
if (!result2.ok) return result2;
|
|
1691
|
+
if (result2.span.end > scanEnd) cur = result2.span.end;
|
|
1692
|
+
else rollbackTrivia(ctx, mark);
|
|
1693
|
+
if (values !== void 0) values.push(result2.value);
|
|
1694
|
+
continue;
|
|
1695
|
+
}
|
|
1696
|
+
const result = parsers[i].parse(input, cur, ctx);
|
|
1697
|
+
if (!result.ok) return result;
|
|
1698
|
+
if (values !== void 0) values.push(result.value);
|
|
1699
|
+
cur = result.span.end;
|
|
1700
|
+
}
|
|
1701
|
+
} finally {
|
|
1702
|
+
ctx._sync = inheritedSync;
|
|
1703
|
+
}
|
|
1704
|
+
return {
|
|
1705
|
+
ok: true,
|
|
1706
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1707
|
+
value: values ?? void 0,
|
|
1708
|
+
span: { start: pos, end: cur }
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1506
1711
|
return {
|
|
1507
1712
|
_tag: "sequence",
|
|
1508
1713
|
_meta: meta,
|
|
1509
1714
|
_def: def,
|
|
1510
1715
|
parse(input, pos, ctx) {
|
|
1716
|
+
if (ctx._tolerant) return parseTolerant(input, pos, ctx);
|
|
1511
1717
|
const values = def.valueUnused ? void 0 : [];
|
|
1512
1718
|
let cur = pos;
|
|
1513
1719
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -1566,7 +1772,7 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1566
1772
|
const result = combinator.parse(input, pos, ctx);
|
|
1567
1773
|
if (!result.ok) {
|
|
1568
1774
|
rollbackTrivia(ctx, mark);
|
|
1569
|
-
return { fail: result };
|
|
1775
|
+
return { fail: result, failPos: pos };
|
|
1570
1776
|
}
|
|
1571
1777
|
if (result.span.end === pos) {
|
|
1572
1778
|
rollbackTrivia(ctx, mark);
|
|
@@ -1581,6 +1787,7 @@ function many(combinator) {
|
|
|
1581
1787
|
isTrivia: false
|
|
1582
1788
|
};
|
|
1583
1789
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1790
|
+
let expected;
|
|
1584
1791
|
return {
|
|
1585
1792
|
_tag: "many",
|
|
1586
1793
|
_meta: meta,
|
|
@@ -1590,7 +1797,18 @@ function many(combinator) {
|
|
|
1590
1797
|
let cur = pos;
|
|
1591
1798
|
while (cur < input.length) {
|
|
1592
1799
|
const item = repItem(combinator, input, cur, ctx);
|
|
1593
|
-
if (item === "stop"
|
|
1800
|
+
if (item === "stop") break;
|
|
1801
|
+
if ("fail" in item) {
|
|
1802
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1803
|
+
if (sync === void 0) break;
|
|
1804
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1805
|
+
expected ??= deriveExpected(combinator);
|
|
1806
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1807
|
+
if (values !== void 0) values.push(error);
|
|
1808
|
+
captureError(ctx, error);
|
|
1809
|
+
cur = end;
|
|
1810
|
+
continue;
|
|
1811
|
+
}
|
|
1594
1812
|
if (values !== void 0) values.push(item.value);
|
|
1595
1813
|
cur = item.end;
|
|
1596
1814
|
}
|
|
@@ -1605,6 +1823,7 @@ function oneOrMore(combinator) {
|
|
|
1605
1823
|
isTrivia: false
|
|
1606
1824
|
};
|
|
1607
1825
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1826
|
+
let expected;
|
|
1608
1827
|
return {
|
|
1609
1828
|
_tag: "oneOrMore",
|
|
1610
1829
|
_meta: meta,
|
|
@@ -1616,7 +1835,18 @@ function oneOrMore(combinator) {
|
|
|
1616
1835
|
let cur = first.span.end;
|
|
1617
1836
|
while (cur < input.length) {
|
|
1618
1837
|
const item = repItem(combinator, input, cur, ctx);
|
|
1619
|
-
if (item === "stop"
|
|
1838
|
+
if (item === "stop") break;
|
|
1839
|
+
if ("fail" in item) {
|
|
1840
|
+
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
1841
|
+
if (sync === void 0) break;
|
|
1842
|
+
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
1843
|
+
expected ??= deriveExpected(combinator);
|
|
1844
|
+
const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
|
|
1845
|
+
if (values !== void 0) values.push(error);
|
|
1846
|
+
captureError(ctx, error);
|
|
1847
|
+
cur = end;
|
|
1848
|
+
continue;
|
|
1849
|
+
}
|
|
1620
1850
|
if (values !== void 0) values.push(item.value);
|
|
1621
1851
|
cur = item.end;
|
|
1622
1852
|
}
|
|
@@ -1662,15 +1892,29 @@ function sepBy(combinator, separator) {
|
|
|
1662
1892
|
canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
|
|
1663
1893
|
isTrivia: false
|
|
1664
1894
|
};
|
|
1895
|
+
let expected;
|
|
1665
1896
|
return {
|
|
1666
1897
|
_tag: "sepBy",
|
|
1667
1898
|
_meta: meta,
|
|
1668
1899
|
_def: { tag: "sepBy", parser: combinator, separator },
|
|
1669
1900
|
parse(input, pos, ctx) {
|
|
1670
1901
|
const first = combinator.parse(input, pos, ctx);
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1902
|
+
const values = [];
|
|
1903
|
+
let cur;
|
|
1904
|
+
if (first.ok) {
|
|
1905
|
+
values.push(first.value);
|
|
1906
|
+
cur = first.span.end;
|
|
1907
|
+
} else {
|
|
1908
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1909
|
+
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
1910
|
+
return { ok: true, value: [], span: { start: pos, end: pos } };
|
|
1911
|
+
}
|
|
1912
|
+
expected ??= deriveExpected(combinator);
|
|
1913
|
+
const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
|
|
1914
|
+
values.push(rec.error);
|
|
1915
|
+
captureError(ctx, rec.error);
|
|
1916
|
+
cur = rec.end;
|
|
1917
|
+
}
|
|
1674
1918
|
while (cur < input.length) {
|
|
1675
1919
|
const loopMark = saveTriviaMark(ctx);
|
|
1676
1920
|
let sepPos = cur;
|
|
@@ -1700,6 +1944,15 @@ function sepBy(combinator, separator) {
|
|
|
1700
1944
|
}
|
|
1701
1945
|
const next = combinator.parse(input, nextPos, ctx);
|
|
1702
1946
|
if (!next.ok) {
|
|
1947
|
+
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
1948
|
+
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
1949
|
+
expected ??= deriveExpected(combinator);
|
|
1950
|
+
const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
|
|
1951
|
+
values.push(rec.error);
|
|
1952
|
+
captureError(ctx, rec.error);
|
|
1953
|
+
cur = rec.end;
|
|
1954
|
+
continue;
|
|
1955
|
+
}
|
|
1703
1956
|
rollbackTrivia(ctx, loopMark);
|
|
1704
1957
|
break;
|
|
1705
1958
|
}
|
|
@@ -1836,7 +2089,7 @@ function rules(a, b) {
|
|
|
1836
2089
|
cache[key] = parser2;
|
|
1837
2090
|
}
|
|
1838
2091
|
}
|
|
1839
|
-
if (options?.trivia
|
|
2092
|
+
if (options?.trivia != null) {
|
|
1840
2093
|
for (const key of Object.keys(definitions)) {
|
|
1841
2094
|
const rule = cache[key];
|
|
1842
2095
|
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
@@ -1866,7 +2119,9 @@ function not(combinator) {
|
|
|
1866
2119
|
_meta: meta,
|
|
1867
2120
|
_def: { tag: "not", parser: combinator },
|
|
1868
2121
|
parse(input, pos, ctx) {
|
|
2122
|
+
const mark = saveCstMark(ctx);
|
|
1869
2123
|
const result = combinator.parse(input, pos, ctx);
|
|
2124
|
+
rollbackCstCapture(ctx, mark);
|
|
1870
2125
|
if (result.ok) {
|
|
1871
2126
|
return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
|
|
1872
2127
|
}
|
|
@@ -1980,7 +2235,7 @@ function unwrapChild(child) {
|
|
|
1980
2235
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1981
2236
|
}
|
|
1982
2237
|
function isCstChild(value) {
|
|
1983
|
-
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "
|
|
2238
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
|
|
1984
2239
|
}
|
|
1985
2240
|
function missingInferredType() {
|
|
1986
2241
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -2233,65 +2488,6 @@ function token(root) {
|
|
|
2233
2488
|
};
|
|
2234
2489
|
}
|
|
2235
2490
|
|
|
2236
|
-
// src/combinators/expect.ts
|
|
2237
|
-
function deriveExpected(c) {
|
|
2238
|
-
const def = c._def;
|
|
2239
|
-
switch (def.tag) {
|
|
2240
|
-
case "literal":
|
|
2241
|
-
return [JSON.stringify(def.value)];
|
|
2242
|
-
case "regex":
|
|
2243
|
-
return [`/${def.source}/`];
|
|
2244
|
-
case "keywords":
|
|
2245
|
-
return def.words.map((w) => JSON.stringify(w));
|
|
2246
|
-
case "label":
|
|
2247
|
-
return [def.label];
|
|
2248
|
-
case "choice":
|
|
2249
|
-
return def.parsers.flatMap(deriveExpected);
|
|
2250
|
-
case "sequence":
|
|
2251
|
-
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
2252
|
-
case "node":
|
|
2253
|
-
case "grammar":
|
|
2254
|
-
case "trivia":
|
|
2255
|
-
case "token":
|
|
2256
|
-
case "optional":
|
|
2257
|
-
case "many":
|
|
2258
|
-
case "oneOrMore":
|
|
2259
|
-
case "transform":
|
|
2260
|
-
case "not":
|
|
2261
|
-
return deriveExpected(def.parser);
|
|
2262
|
-
case "lazy": {
|
|
2263
|
-
const name = c._ruleName;
|
|
2264
|
-
try {
|
|
2265
|
-
return deriveExpected(def.thunk());
|
|
2266
|
-
} catch {
|
|
2267
|
-
return name ? [name] : [];
|
|
2268
|
-
}
|
|
2269
|
-
}
|
|
2270
|
-
default:
|
|
2271
|
-
return [];
|
|
2272
|
-
}
|
|
2273
|
-
}
|
|
2274
|
-
function expect(combinator, label2) {
|
|
2275
|
-
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2276
|
-
const meta = {
|
|
2277
|
-
firstSet: combinator._meta.firstSet,
|
|
2278
|
-
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2279
|
-
isTrivia: false
|
|
2280
|
-
};
|
|
2281
|
-
return {
|
|
2282
|
-
_tag: "expect",
|
|
2283
|
-
_meta: meta,
|
|
2284
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
2285
|
-
parse(input, pos, ctx) {
|
|
2286
|
-
const result = combinator.parse(input, pos, ctx);
|
|
2287
|
-
if (result.ok) return result;
|
|
2288
|
-
const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
|
|
2289
|
-
ctx._errors?.push(error);
|
|
2290
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
2291
|
-
}
|
|
2292
|
-
};
|
|
2293
|
-
}
|
|
2294
|
-
|
|
2295
2491
|
// src/compiler/scannable-run.ts
|
|
2296
2492
|
var BACKSLASH = 92;
|
|
2297
2493
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
@@ -2363,20 +2559,39 @@ function parseSeqParts(source) {
|
|
|
2363
2559
|
lit = [];
|
|
2364
2560
|
}
|
|
2365
2561
|
};
|
|
2366
|
-
const
|
|
2562
|
+
const braceQuant = (at) => {
|
|
2563
|
+
const close = source.indexOf("}", at);
|
|
2564
|
+
if (close === -1) return null;
|
|
2565
|
+
const body = source.slice(at + 1, close);
|
|
2566
|
+
const m = /^(\d+)(,(\d*)?)?$/.exec(body);
|
|
2567
|
+
if (!m) return null;
|
|
2568
|
+
const min = Number(m[1]);
|
|
2569
|
+
const max = m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity;
|
|
2570
|
+
if (max < 1 || min > max) return null;
|
|
2571
|
+
return { min, max, len: close - at + 1 };
|
|
2572
|
+
};
|
|
2573
|
+
const runFrom = (ranges, negated, at) => {
|
|
2574
|
+
const q = source[at];
|
|
2367
2575
|
if (q === "+") {
|
|
2368
|
-
parts.push({ part: "run", ranges, negated, min: 1,
|
|
2576
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: Infinity });
|
|
2369
2577
|
return 1;
|
|
2370
2578
|
}
|
|
2371
2579
|
if (q === "*") {
|
|
2372
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2580
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: Infinity });
|
|
2373
2581
|
return 1;
|
|
2374
2582
|
}
|
|
2375
2583
|
if (q === "?") {
|
|
2376
|
-
parts.push({ part: "run", ranges, negated, min: 0,
|
|
2584
|
+
parts.push({ part: "run", ranges, negated, min: 0, max: 1 });
|
|
2377
2585
|
return 1;
|
|
2378
2586
|
}
|
|
2379
|
-
|
|
2587
|
+
if (q === "{") {
|
|
2588
|
+
const b = braceQuant(at);
|
|
2589
|
+
if (b) {
|
|
2590
|
+
parts.push({ part: "run", ranges, negated, min: b.min, max: b.max });
|
|
2591
|
+
return b.len;
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
parts.push({ part: "run", ranges, negated, min: 1, max: 1 });
|
|
2380
2595
|
return 0;
|
|
2381
2596
|
};
|
|
2382
2597
|
let i = 0;
|
|
@@ -2401,7 +2616,7 @@ function parseSeqParts(source) {
|
|
|
2401
2616
|
if (!ranges) return null;
|
|
2402
2617
|
flush();
|
|
2403
2618
|
i = k + 1;
|
|
2404
|
-
i += runFrom(ranges, neg,
|
|
2619
|
+
i += runFrom(ranges, neg, i);
|
|
2405
2620
|
continue;
|
|
2406
2621
|
}
|
|
2407
2622
|
if (ch === "\\") {
|
|
@@ -2409,7 +2624,7 @@ function parseSeqParts(source) {
|
|
|
2409
2624
|
if (e === "d" || e === "w" || e === "s") {
|
|
2410
2625
|
flush();
|
|
2411
2626
|
i += 2;
|
|
2412
|
-
i += runFrom(shorthandRanges(e), false,
|
|
2627
|
+
i += runFrom(shorthandRanges(e), false, i);
|
|
2413
2628
|
continue;
|
|
2414
2629
|
}
|
|
2415
2630
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2498,7 +2713,7 @@ function seqIsUnambiguous(parts) {
|
|
|
2498
2713
|
let hasMandatory = false;
|
|
2499
2714
|
for (let k = 0; k < parts.length; k++) {
|
|
2500
2715
|
const p = parts[k];
|
|
2501
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2716
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2502
2717
|
if (mandatory) hasMandatory = true;
|
|
2503
2718
|
if (p.part === "group") {
|
|
2504
2719
|
const exposure = groupPartExposure(p);
|
|
@@ -2509,9 +2724,8 @@ function seqIsUnambiguous(parts) {
|
|
|
2509
2724
|
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
2510
2725
|
}
|
|
2511
2726
|
}
|
|
2512
|
-
const
|
|
2513
|
-
|
|
2514
|
-
if (skippableSingle || isUnboundedRepeat) {
|
|
2727
|
+
const needsDisjoint = p.part === "lit" ? p.optional : p.part === "run" ? p.max > p.min : p.unbounded || p.min === 0;
|
|
2728
|
+
if (needsDisjoint) {
|
|
2515
2729
|
const rest = seqFirstAccept(parts.slice(k + 1));
|
|
2516
2730
|
if (!firstSetsDisjoint(partFirstAccept(p), rest)) return false;
|
|
2517
2731
|
}
|
|
@@ -2568,8 +2782,8 @@ function fixedClassSeq(shape) {
|
|
|
2568
2782
|
if (p.part === "lit") {
|
|
2569
2783
|
if (p.optional) return null;
|
|
2570
2784
|
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
2571
|
-
} else if (p.part === "run" &&
|
|
2572
|
-
out.push({ ranges: p.ranges, negated: p.negated });
|
|
2785
|
+
} else if (p.part === "run" && p.max === p.min && Number.isFinite(p.max)) {
|
|
2786
|
+
for (let c = 0; c < p.max; c++) out.push({ ranges: p.ranges, negated: p.negated });
|
|
2573
2787
|
} else {
|
|
2574
2788
|
return null;
|
|
2575
2789
|
}
|
|
@@ -2621,7 +2835,7 @@ function trailingBacktrackClass(shape) {
|
|
|
2621
2835
|
const last = shape.parts[shape.parts.length - 1];
|
|
2622
2836
|
if (last.part === "lit") return null;
|
|
2623
2837
|
if (last.part === "run") {
|
|
2624
|
-
if (last.
|
|
2838
|
+
if (last.max > last.min) return { ranges: last.ranges, negated: last.negated };
|
|
2625
2839
|
return null;
|
|
2626
2840
|
}
|
|
2627
2841
|
return groupPartExposure(last);
|
|
@@ -2758,7 +2972,7 @@ function partFirstAccept(part) {
|
|
|
2758
2972
|
function seqFirstAccept(parts) {
|
|
2759
2973
|
const sets = [];
|
|
2760
2974
|
for (const p of parts) {
|
|
2761
|
-
const mandatory = p.part === "lit" ? !p.optional : p.min
|
|
2975
|
+
const mandatory = p.part === "lit" ? !p.optional : p.min >= 1;
|
|
2762
2976
|
sets.push(partFirstAccept(p));
|
|
2763
2977
|
if (mandatory) break;
|
|
2764
2978
|
}
|
|
@@ -3173,7 +3387,13 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3173
3387
|
lines.push(`${ind2} if (!(${endV2} + ${L} <= input.length && (${cond}))) break`);
|
|
3174
3388
|
lines.push(`${ind2} ${endV2} += ${L}`);
|
|
3175
3389
|
}
|
|
3176
|
-
} else if (p.part === "run" &&
|
|
3390
|
+
} else if (p.part === "run" && p.max === Infinity) {
|
|
3391
|
+
const s = mint("_s");
|
|
3392
|
+
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3393
|
+
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3394
|
+
if (p.min === 1) lines.push(`${ind2} if (${endV2} === ${s}) break`);
|
|
3395
|
+
else if (p.min > 1) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3396
|
+
} else if (p.part === "run" && p.max === 1) {
|
|
3177
3397
|
if (p.min === 1) {
|
|
3178
3398
|
lines.push(`${ind2} if (!(${endV2} < input.length && ${runCond(p, endV2)})) break`);
|
|
3179
3399
|
lines.push(`${ind2} ${endV2}++`);
|
|
@@ -3183,8 +3403,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
3183
3403
|
} else if (p.part === "run") {
|
|
3184
3404
|
const s = mint("_s");
|
|
3185
3405
|
lines.push(`${ind2} const ${s} = ${endV2}`);
|
|
3186
|
-
lines.push(`${ind2} while (${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3187
|
-
if (p.min
|
|
3406
|
+
lines.push(`${ind2} while (${endV2} - ${s} < ${p.max} && ${endV2} < input.length && ${runCond(p, endV2)}) ${endV2}++`);
|
|
3407
|
+
if (p.min > 0) lines.push(`${ind2} if (${endV2} - ${s} < ${p.min}) break`);
|
|
3188
3408
|
} else {
|
|
3189
3409
|
const inner = emitShapeMatch(p.inner, endV2, mint, `${ind2} `, first ? firstChar : void 0);
|
|
3190
3410
|
if (!p.unbounded) {
|
|
@@ -3651,21 +3871,29 @@ function hoistExpected(ctx, constArrSource) {
|
|
|
3651
3871
|
}
|
|
3652
3872
|
return name;
|
|
3653
3873
|
}
|
|
3874
|
+
function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
3875
|
+
if (!ctx.recovery) return "";
|
|
3876
|
+
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3877
|
+
const pb = v(ctx, "_pb");
|
|
3878
|
+
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} } } } `;
|
|
3879
|
+
}
|
|
3654
3880
|
function failBody(ctx, expected, posExpr) {
|
|
3881
|
+
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
3655
3882
|
if (ctx.failLabel) {
|
|
3656
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3657
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3883
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3884
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
3658
3885
|
}
|
|
3659
|
-
return failReturn(expected, posExpr);
|
|
3886
|
+
return probe + failReturn(expected, posExpr);
|
|
3660
3887
|
}
|
|
3661
3888
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3889
|
+
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
3662
3890
|
if (ctx.failLabel) {
|
|
3663
|
-
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
3891
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3664
3892
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3665
|
-
return `{ _ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3893
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
3666
3894
|
}
|
|
3667
|
-
if (!constant) return
|
|
3668
|
-
return failReturnArr(expectedArr, posExpr);
|
|
3895
|
+
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3896
|
+
return probe + failReturnArr(expectedArr, posExpr);
|
|
3669
3897
|
}
|
|
3670
3898
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3671
3899
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4165,6 +4393,10 @@ function emitRegex(def, ctx, pos) {
|
|
|
4165
4393
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
4166
4394
|
return { stmts, valueVar: vv, endVar };
|
|
4167
4395
|
}
|
|
4396
|
+
function syncSentinelExpr(fs2) {
|
|
4397
|
+
if (fs2.kind !== "ranges" || fs2.ranges.length === 0) return null;
|
|
4398
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs2.ranges)} })`;
|
|
4399
|
+
}
|
|
4168
4400
|
function emitSeqValues(def, ctx, pos) {
|
|
4169
4401
|
const startV = v(ctx, "_start");
|
|
4170
4402
|
const curV = v(ctx, "_cur");
|
|
@@ -4173,7 +4405,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4173
4405
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4174
4406
|
];
|
|
4175
4407
|
const valueVars = [];
|
|
4408
|
+
const syncInV = ctx.recovery ? v(ctx, "_syncIn") : "";
|
|
4409
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
4410
|
+
const publishSync = (i) => {
|
|
4411
|
+
if (!ctx.recovery) return "";
|
|
4412
|
+
const fs2 = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
4413
|
+
const ref2 = syncSentinelExpr(fs2);
|
|
4414
|
+
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
4415
|
+
};
|
|
4176
4416
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4417
|
+
const syncPub = publishSync(i);
|
|
4418
|
+
if (syncPub) stmts.push(syncPub);
|
|
4177
4419
|
if (i > 0 && ctx.activeTrivia) {
|
|
4178
4420
|
if (ctx.capturing) {
|
|
4179
4421
|
const capFn = ensureTriviaCaptureFn(ctx);
|
|
@@ -4198,7 +4440,17 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
4198
4440
|
continue;
|
|
4199
4441
|
} else {
|
|
4200
4442
|
const trivFn = ensureTriviaFn(ctx);
|
|
4201
|
-
|
|
4443
|
+
const scanEndV = v(ctx, "_sne");
|
|
4444
|
+
stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
4445
|
+
const r2 = emit(def.parsers[i], ctx, scanEndV);
|
|
4446
|
+
stmts.push(...r2.stmts);
|
|
4447
|
+
const endAfterV = v(ctx, "_sea");
|
|
4448
|
+
stmts.push(
|
|
4449
|
+
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
4450
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
|
|
4451
|
+
);
|
|
4452
|
+
valueVars.push(r2.valueVar);
|
|
4453
|
+
continue;
|
|
4202
4454
|
}
|
|
4203
4455
|
}
|
|
4204
4456
|
const r = emit(def.parsers[i], ctx, curV);
|
|
@@ -4276,6 +4528,21 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
|
|
|
4276
4528
|
`${ind(ctx)}${endV} = ${endVar}`
|
|
4277
4529
|
];
|
|
4278
4530
|
}
|
|
4531
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4532
|
+
const p = def.parsers[i];
|
|
4533
|
+
const gate = def.gates[i];
|
|
4534
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4535
|
+
const gateIdx = ctx.mapFns.length;
|
|
4536
|
+
ctx.mapFns.push(gate);
|
|
4537
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4538
|
+
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4539
|
+
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4540
|
+
ctx.indent++;
|
|
4541
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4542
|
+
ctx.indent--;
|
|
4543
|
+
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4544
|
+
return stmts;
|
|
4545
|
+
}
|
|
4279
4546
|
function emitChoice(def, ctx, pos) {
|
|
4280
4547
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4281
4548
|
if (def.disjoint) {
|
|
@@ -4291,12 +4558,11 @@ function emitChoice(def, ctx, pos) {
|
|
|
4291
4558
|
stmts.push(`${ind(ctx)}switch (${codeV}) {`);
|
|
4292
4559
|
ctx.indent++;
|
|
4293
4560
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
4294
|
-
const p = def.parsers[i];
|
|
4295
4561
|
for (const cp of plan.cases[i]) stmts.push(`${ind(ctx)}case ${cp}:`);
|
|
4296
4562
|
stmts.push(`${ind(ctx)}{`);
|
|
4297
4563
|
ctx.indent++;
|
|
4298
4564
|
stmts.push(
|
|
4299
|
-
...
|
|
4565
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
4300
4566
|
`${ind(ctx)}break`
|
|
4301
4567
|
);
|
|
4302
4568
|
ctx.indent--;
|
|
@@ -4308,13 +4574,14 @@ function emitChoice(def, ctx, pos) {
|
|
|
4308
4574
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4309
4575
|
}
|
|
4310
4576
|
let first = true;
|
|
4311
|
-
for (
|
|
4577
|
+
for (let i = 0; i < def.parsers.length; i++) {
|
|
4578
|
+
const p = def.parsers[i];
|
|
4312
4579
|
const cond = firstSetCond(codeV, p._meta.firstSet);
|
|
4313
4580
|
const kw = first ? "if" : "else if";
|
|
4314
4581
|
first = false;
|
|
4315
4582
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4316
4583
|
ctx.indent++;
|
|
4317
|
-
stmts.push(...
|
|
4584
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
4318
4585
|
ctx.indent--;
|
|
4319
4586
|
stmts.push(`${ind(ctx)}}`);
|
|
4320
4587
|
}
|
|
@@ -4428,7 +4695,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4428
4695
|
if (gate) {
|
|
4429
4696
|
const gateIdx = ctx.mapFns.length;
|
|
4430
4697
|
ctx.mapFns.push(gate);
|
|
4431
|
-
ctx.mapFnSrcs.push(null);
|
|
4698
|
+
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4432
4699
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4433
4700
|
}
|
|
4434
4701
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -4533,6 +4800,8 @@ function emitMany(def, ctx, pos) {
|
|
|
4533
4800
|
...wantValue ? [`${ind(ctx)}const ${arrV} = []`] : [],
|
|
4534
4801
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
4535
4802
|
];
|
|
4803
|
+
const mySyncV = ctx.recovery ? v(ctx, "_mysy") : "";
|
|
4804
|
+
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${mySyncV} = _ctx._sync`);
|
|
4536
4805
|
if (def.min === 1) {
|
|
4537
4806
|
const firstR = emit(def.parser, ctx, curV);
|
|
4538
4807
|
stmts.push(...firstR.stmts);
|
|
@@ -4566,10 +4835,26 @@ function emitMany(def, ctx, pos) {
|
|
|
4566
4835
|
}
|
|
4567
4836
|
}
|
|
4568
4837
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
4569
|
-
stmts.push(
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4838
|
+
stmts.push(...iterStmts);
|
|
4839
|
+
if (ctx.recovery) {
|
|
4840
|
+
const rrV = v(ctx, "_rr");
|
|
4841
|
+
const exp = hoistExpected(ctx, deriveExpectedArr([def.parser]));
|
|
4842
|
+
stmts.push(
|
|
4843
|
+
`${ind(ctx)}if (!${iterOk}) {`,
|
|
4844
|
+
`${ind(ctx)} ${rollback}if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPos}, _ctx)) {`,
|
|
4845
|
+
`${ind(ctx)} const ${rrV} = _ctx._rec.scan(input, ${itemPos}, _ctx, ${mySyncV}, ${exp})`,
|
|
4846
|
+
...wantValue ? [`${ind(ctx)} ${arrV}.push(${rrV}.error)`] : [],
|
|
4847
|
+
`${ind(ctx)} _ctx._rec.capture(_ctx, ${rrV}.error)`,
|
|
4848
|
+
`${ind(ctx)} ${curV} = ${rrV}.end`,
|
|
4849
|
+
`${ind(ctx)} continue`,
|
|
4850
|
+
`${ind(ctx)} }`,
|
|
4851
|
+
`${ind(ctx)} break`,
|
|
4852
|
+
`${ind(ctx)}}`,
|
|
4853
|
+
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
4854
|
+
);
|
|
4855
|
+
} else {
|
|
4856
|
+
stmts.push(`${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
4857
|
+
}
|
|
4573
4858
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
4574
4859
|
stmts.push(`${ind(ctx)}${curV} = ${iterEnd}`);
|
|
4575
4860
|
ctx.indent--;
|
|
@@ -4591,20 +4876,56 @@ function emitOptional(def, ctx, pos) {
|
|
|
4591
4876
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4592
4877
|
const arrV = v(ctx, "_arr");
|
|
4593
4878
|
const curV = v(ctx, "_cur");
|
|
4879
|
+
const rec = !!ctx.recovery;
|
|
4880
|
+
const mySyncV = rec ? v(ctx, "_mysy") : "";
|
|
4881
|
+
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
4882
|
+
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
4883
|
+
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
4594
4884
|
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos, true);
|
|
4595
4885
|
const stmts = [
|
|
4596
4886
|
`${ind(ctx)}const ${arrV} = []`,
|
|
4597
4887
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
4598
|
-
...
|
|
4599
|
-
|
|
4888
|
+
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
4889
|
+
...firstStmts
|
|
4600
4890
|
];
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
)
|
|
4607
|
-
|
|
4891
|
+
const failItem = (nextOkVar, itemPosVar, rb, originalFail) => {
|
|
4892
|
+
if (!rec) return [originalFail];
|
|
4893
|
+
const rr = v(ctx, "_rr");
|
|
4894
|
+
return [
|
|
4895
|
+
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
4896
|
+
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
4897
|
+
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
4898
|
+
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
4899
|
+
`${ind(ctx)} }`,
|
|
4900
|
+
`${ind(ctx)} ${rb}break`,
|
|
4901
|
+
`${ind(ctx)}}`
|
|
4902
|
+
];
|
|
4903
|
+
};
|
|
4904
|
+
if (rec) {
|
|
4905
|
+
const rr0 = v(ctx, "_rr0");
|
|
4906
|
+
const didV = v(ctx, "_did");
|
|
4907
|
+
stmts.push(
|
|
4908
|
+
`${ind(ctx)}let ${didV} = false`,
|
|
4909
|
+
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
4910
|
+
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
4911
|
+
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
4912
|
+
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
4913
|
+
`${ind(ctx)}}`,
|
|
4914
|
+
`${ind(ctx)}if (${didV}) {`
|
|
4915
|
+
);
|
|
4916
|
+
ctx.indent++;
|
|
4917
|
+
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
4918
|
+
ctx.indent++;
|
|
4919
|
+
} else {
|
|
4920
|
+
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
4921
|
+
ctx.indent++;
|
|
4922
|
+
stmts.push(
|
|
4923
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
4924
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
4925
|
+
`${ind(ctx)}while (${curV} < input.length) {`
|
|
4926
|
+
);
|
|
4927
|
+
ctx.indent++;
|
|
4928
|
+
}
|
|
4608
4929
|
let sepAtPos = curV;
|
|
4609
4930
|
if (ctx.activeTrivia) {
|
|
4610
4931
|
if (ctx.capturing) {
|
|
@@ -4630,8 +4951,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4630
4951
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4631
4952
|
stmts.push(
|
|
4632
4953
|
...nextStmts,
|
|
4633
|
-
|
|
4634
|
-
`${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`,
|
|
4954
|
+
...failItem(nextOk, npV, rollbackToSep, `${ind(ctx)}if (!${nextOk}) { ${rollbackToSep}break }`),
|
|
4635
4955
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4636
4956
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4637
4957
|
);
|
|
@@ -4647,7 +4967,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4647
4967
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV, true);
|
|
4648
4968
|
stmts.push(
|
|
4649
4969
|
...nextStmts,
|
|
4650
|
-
`${ind(ctx)}if (!${nextOk}) break
|
|
4970
|
+
...failItem(nextOk, npV, "", `${ind(ctx)}if (!${nextOk}) break`),
|
|
4651
4971
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4652
4972
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4653
4973
|
);
|
|
@@ -4667,7 +4987,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
4667
4987
|
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd, true);
|
|
4668
4988
|
stmts.push(
|
|
4669
4989
|
...nextStmts,
|
|
4670
|
-
`${ind(ctx)}if (!${nextOk}) { ${nextRb}break }
|
|
4990
|
+
...failItem(nextOk, sepEnd, nextRb, `${ind(ctx)}if (!${nextOk}) { ${nextRb}break }`),
|
|
4671
4991
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
4672
4992
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
4673
4993
|
);
|
|
@@ -4924,7 +5244,7 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4924
5244
|
stmts.push(
|
|
4925
5245
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4926
5246
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4927
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === '
|
|
5247
|
+
`${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} } })`
|
|
4928
5248
|
);
|
|
4929
5249
|
return { stmts, valueVar: ndV, endVar };
|
|
4930
5250
|
}
|
|
@@ -5014,6 +5334,10 @@ function emitExpect(def, ctx, pos) {
|
|
|
5014
5334
|
`${ind0}if (!${okVar}) {`,
|
|
5015
5335
|
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${pos} }, expected: ${JSON.stringify(def.expected)} }`,
|
|
5016
5336
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
5337
|
+
// Embed the missing-token error as a `parseError` CST child, mirroring the
|
|
5338
|
+
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
5339
|
+
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
5340
|
+
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
5017
5341
|
`${ind0} ${valVar} = ${errV}`,
|
|
5018
5342
|
`${ind0} ${endVar} = ${pos}`,
|
|
5019
5343
|
`${ind0} ${okVar} = true`,
|
|
@@ -5180,7 +5504,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5180
5504
|
case "guard": {
|
|
5181
5505
|
const fnIdx = ctx.mapFns.length;
|
|
5182
5506
|
ctx.mapFns.push(def.predicate);
|
|
5183
|
-
ctx.mapFnSrcs.push(null);
|
|
5507
|
+
ctx.mapFnSrcs.push(def.predSrc ?? null);
|
|
5184
5508
|
const vv = v(ctx);
|
|
5185
5509
|
return {
|
|
5186
5510
|
stmts: [
|
|
@@ -5195,7 +5519,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5195
5519
|
const evIdx = ctx.mapFns.length;
|
|
5196
5520
|
const extra = def.extra;
|
|
5197
5521
|
ctx.mapFns.push((() => extra));
|
|
5198
|
-
ctx.mapFnSrcs.push(null);
|
|
5522
|
+
ctx.mapFnSrcs.push(def.extraSrc !== void 0 ? `() => (${def.extraSrc})` : null);
|
|
5199
5523
|
const innerParser = def.parser;
|
|
5200
5524
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
5201
5525
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -5439,7 +5763,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5439
5763
|
}
|
|
5440
5764
|
return deps;
|
|
5441
5765
|
}
|
|
5442
|
-
function compile(combinator, mapFnSources) {
|
|
5766
|
+
function compile(combinator, mapFnSources, opts) {
|
|
5443
5767
|
markUnusedValues(combinator);
|
|
5444
5768
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5445
5769
|
const ctx = {
|
|
@@ -5460,6 +5784,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5460
5784
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5461
5785
|
namedFnDecls: [],
|
|
5462
5786
|
capturing: hasNodeDef(combinator),
|
|
5787
|
+
recovery: opts?.recovery ?? false,
|
|
5463
5788
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5464
5789
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5465
5790
|
};
|
|
@@ -5512,7 +5837,7 @@ function compile(combinator, mapFnSources) {
|
|
|
5512
5837
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
5513
5838
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
|
|
5514
5839
|
},
|
|
5515
|
-
// Note: collects
|
|
5840
|
+
// Note: collects expect() errors via _errors. Unlike interpreter
|
|
5516
5841
|
// parse({recover:true}) it does NOT populate furthestFail — the compiled path
|
|
5517
5842
|
// inlines failures for throughput and deliberately skips _probe bookkeeping.
|
|
5518
5843
|
// Callers wanting a furthest-position diagnostic detect unconsumed input
|
|
@@ -5558,6 +5883,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
5558
5883
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5559
5884
|
namedFnDecls: [],
|
|
5560
5885
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5886
|
+
recovery: opts?.recovery ?? false,
|
|
5561
5887
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5562
5888
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5563
5889
|
};
|
|
@@ -5653,6 +5979,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5653
5979
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5654
5980
|
namedFnDecls: [],
|
|
5655
5981
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5982
|
+
recovery: opts?.recovery ?? false,
|
|
5656
5983
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5657
5984
|
ns,
|
|
5658
5985
|
deferFirstSetRefs: true,
|
|
@@ -6300,6 +6627,42 @@ function materializePiece(p, trivia2) {
|
|
|
6300
6627
|
return pieces;
|
|
6301
6628
|
}
|
|
6302
6629
|
|
|
6630
|
+
// src/combinators/guard.ts
|
|
6631
|
+
function guard(predicate) {
|
|
6632
|
+
const meta = {
|
|
6633
|
+
firstSet: { kind: "any" },
|
|
6634
|
+
canMatchNewline: false,
|
|
6635
|
+
isTrivia: false
|
|
6636
|
+
};
|
|
6637
|
+
return {
|
|
6638
|
+
_tag: "guard",
|
|
6639
|
+
_meta: meta,
|
|
6640
|
+
_def: { tag: "guard", predicate },
|
|
6641
|
+
parse(_input, pos, ctx) {
|
|
6642
|
+
if (predicate(ctx.state))
|
|
6643
|
+
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
6644
|
+
return { ok: false, expected: ["guard"], span: { start: pos, end: pos } };
|
|
6645
|
+
}
|
|
6646
|
+
};
|
|
6647
|
+
}
|
|
6648
|
+
|
|
6649
|
+
// src/combinators/withCtx.ts
|
|
6650
|
+
function withCtx(extra, combinator) {
|
|
6651
|
+
const meta = {
|
|
6652
|
+
firstSet: combinator._meta.firstSet,
|
|
6653
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
6654
|
+
isTrivia: false
|
|
6655
|
+
};
|
|
6656
|
+
return {
|
|
6657
|
+
_tag: "withCtx",
|
|
6658
|
+
_meta: meta,
|
|
6659
|
+
_def: { tag: "withCtx", extra, parser: combinator },
|
|
6660
|
+
parse(input, pos, ctx) {
|
|
6661
|
+
return combinator.parse(input, pos, { ...ctx, state: extra });
|
|
6662
|
+
}
|
|
6663
|
+
};
|
|
6664
|
+
}
|
|
6665
|
+
|
|
6303
6666
|
// src/cst/offset-model.ts
|
|
6304
6667
|
var { isFinite } = Number;
|
|
6305
6668
|
|
|
@@ -6331,6 +6694,35 @@ var SUPPORTED = {
|
|
|
6331
6694
|
function isScopeEntry(v2) {
|
|
6332
6695
|
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
6333
6696
|
}
|
|
6697
|
+
function propName(p) {
|
|
6698
|
+
if (p.computed) return null;
|
|
6699
|
+
const key = p.key;
|
|
6700
|
+
return key.type === "Identifier" ? key.name ?? null : key.type === "Literal" ? String(key.value) : null;
|
|
6701
|
+
}
|
|
6702
|
+
function isGatedArmExpr(e) {
|
|
6703
|
+
if (e.type !== "ObjectExpression") return false;
|
|
6704
|
+
let hasGate = false, hasCombinator = false;
|
|
6705
|
+
for (const prop of e.properties) {
|
|
6706
|
+
if (prop.type !== "Property") continue;
|
|
6707
|
+
const name = propName(prop);
|
|
6708
|
+
if (name === "gate") hasGate = true;
|
|
6709
|
+
else if (name === "combinator") hasCombinator = true;
|
|
6710
|
+
}
|
|
6711
|
+
return hasGate && hasCombinator;
|
|
6712
|
+
}
|
|
6713
|
+
function gatedArmParts(e) {
|
|
6714
|
+
let gate;
|
|
6715
|
+
let combinator;
|
|
6716
|
+
for (const prop of e.properties) {
|
|
6717
|
+
if (prop.type !== "Property") return null;
|
|
6718
|
+
const op = prop;
|
|
6719
|
+
const name = propName(op);
|
|
6720
|
+
if (name === "gate") gate = op.value;
|
|
6721
|
+
else if (name === "combinator") combinator = op.value;
|
|
6722
|
+
else return null;
|
|
6723
|
+
}
|
|
6724
|
+
return gate && combinator ? { gate, combinator } : null;
|
|
6725
|
+
}
|
|
6334
6726
|
function isCombinator(v2) {
|
|
6335
6727
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
6336
6728
|
}
|
|
@@ -6512,6 +6904,72 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
6512
6904
|
return null;
|
|
6513
6905
|
}
|
|
6514
6906
|
}
|
|
6907
|
+
if (callee.name === "guard") {
|
|
6908
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6909
|
+
const [predArg] = node2.arguments;
|
|
6910
|
+
if (!predArg || predArg.type === "SpreadElement") return null;
|
|
6911
|
+
const predSrc = code.slice(predArg.start, predArg.end);
|
|
6912
|
+
mfs.push(predSrc);
|
|
6913
|
+
try {
|
|
6914
|
+
const combi = guard(() => true);
|
|
6915
|
+
if (combi._def.tag !== "guard") return null;
|
|
6916
|
+
combi._def.predSrc = predSrc;
|
|
6917
|
+
return combi;
|
|
6918
|
+
} catch {
|
|
6919
|
+
return null;
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
if (callee.name === "withCtx") {
|
|
6923
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6924
|
+
const [extraArg, innerArg] = node2.arguments;
|
|
6925
|
+
if (!extraArg || !innerArg || extraArg.type === "SpreadElement" || innerArg.type === "SpreadElement") return null;
|
|
6926
|
+
const extraSrc = code.slice(extraArg.start, extraArg.end);
|
|
6927
|
+
mfs.push(extraSrc);
|
|
6928
|
+
const inner = anyValue(innerArg, scope, code, mfs);
|
|
6929
|
+
if (!isCombinator(inner)) return null;
|
|
6930
|
+
try {
|
|
6931
|
+
const combi = withCtx({}, inner);
|
|
6932
|
+
if (combi._def.tag !== "withCtx") return null;
|
|
6933
|
+
combi._def.extraSrc = extraSrc;
|
|
6934
|
+
return combi;
|
|
6935
|
+
} catch {
|
|
6936
|
+
return null;
|
|
6937
|
+
}
|
|
6938
|
+
}
|
|
6939
|
+
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
6940
|
+
if (code === void 0 || mfs === void 0) return null;
|
|
6941
|
+
const arms = [];
|
|
6942
|
+
const gateSrcs = [];
|
|
6943
|
+
for (const argNode of node2.arguments) {
|
|
6944
|
+
if (argNode.type === "SpreadElement") return null;
|
|
6945
|
+
if (isGatedArmExpr(argNode)) {
|
|
6946
|
+
const parts = gatedArmParts(argNode);
|
|
6947
|
+
if (!parts) return null;
|
|
6948
|
+
const gateSrc = code.slice(parts.gate.start, parts.gate.end);
|
|
6949
|
+
mfs.push(gateSrc);
|
|
6950
|
+
const combi = anyValue(parts.combinator, scope, code, mfs);
|
|
6951
|
+
if (!isCombinator(combi)) return null;
|
|
6952
|
+
arms.push({ gate: () => true, combinator: combi });
|
|
6953
|
+
gateSrcs.push(gateSrc);
|
|
6954
|
+
} else {
|
|
6955
|
+
const combi = anyValue(argNode, scope, code, mfs);
|
|
6956
|
+
if (!isCombinator(combi)) return null;
|
|
6957
|
+
arms.push(combi);
|
|
6958
|
+
gateSrcs.push(null);
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6961
|
+
try {
|
|
6962
|
+
const combi = choice(...arms);
|
|
6963
|
+
if (combi._def.tag !== "choice") return null;
|
|
6964
|
+
combi._def.gateSrcs = gateSrcs;
|
|
6965
|
+
for (let i = 0; i < combi._def.gates.length; i++) {
|
|
6966
|
+
if (combi._def.gates[i] !== null !== (gateSrcs[i] !== null)) return null;
|
|
6967
|
+
}
|
|
6968
|
+
return combi;
|
|
6969
|
+
} catch {
|
|
6970
|
+
return null;
|
|
6971
|
+
}
|
|
6972
|
+
}
|
|
6515
6973
|
const factory = SUPPORTED[callee.name];
|
|
6516
6974
|
if (!factory) return null;
|
|
6517
6975
|
const args = node2.arguments.map((arg) => {
|
|
@@ -6574,9 +7032,9 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
6574
7032
|
if (typeof key !== "string" && typeof key !== "number") return null;
|
|
6575
7033
|
return obj[key] ?? null;
|
|
6576
7034
|
}
|
|
6577
|
-
const
|
|
6578
|
-
if (!
|
|
6579
|
-
return obj[
|
|
7035
|
+
const propName2 = mem.property.name;
|
|
7036
|
+
if (!propName2) return null;
|
|
7037
|
+
return obj[propName2] ?? null;
|
|
6580
7038
|
}
|
|
6581
7039
|
if (node2.type === "CallExpression") {
|
|
6582
7040
|
const callee = node2.callee;
|
|
@@ -6821,7 +7279,7 @@ var plugin_default = createUnplugin((opts = {}) => ({
|
|
|
6821
7279
|
if (!code.includes("parseman")) return null;
|
|
6822
7280
|
if (!code.includes("macro")) return null;
|
|
6823
7281
|
const moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE, ...opts.moduleAliases ?? []]);
|
|
6824
|
-
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true);
|
|
7282
|
+
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true);
|
|
6825
7283
|
if (result?.warnings.length) {
|
|
6826
7284
|
for (const w of result.warnings) {
|
|
6827
7285
|
if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
|
|
@@ -6925,7 +7383,7 @@ function extractImportBindings(body) {
|
|
|
6925
7383
|
}
|
|
6926
7384
|
return out;
|
|
6927
7385
|
}
|
|
6928
|
-
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false) {
|
|
7386
|
+
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false) {
|
|
6929
7387
|
let result;
|
|
6930
7388
|
try {
|
|
6931
7389
|
result = parseSync(id, code);
|
|
@@ -6996,7 +7454,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
6996
7454
|
(p) => p.key?.name === "trivia"
|
|
6997
7455
|
)?.value : void 0;
|
|
6998
7456
|
const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
|
|
6999
|
-
const compiled = compileRuleMap([...ruleMap], gTrivia ? { trivia: gTrivia } :
|
|
7457
|
+
const compiled = compileRuleMap([...ruleMap], { ...gTrivia ? { trivia: gTrivia } : {}, recovery });
|
|
7000
7458
|
if (!compiled) {
|
|
7001
7459
|
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
7002
7460
|
return null;
|
|
@@ -7094,7 +7552,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7094
7552
|
const ns = nsFor(label2);
|
|
7095
7553
|
const ir = serializeRuleMap(entries);
|
|
7096
7554
|
if (ir) return { carried: [{ ns, ir }] };
|
|
7097
|
-
const p = compileLinkable(entries, ns, composing ? { trivia: composing } :
|
|
7555
|
+
const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, recovery });
|
|
7098
7556
|
return p ? { carried: [p] } : null;
|
|
7099
7557
|
};
|
|
7100
7558
|
const argPieces = (arg, label2, composing) => {
|
|
@@ -7270,7 +7728,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7270
7728
|
const refEntry = scope.get(varName);
|
|
7271
7729
|
const refCombi = refEntry?.combi ?? null;
|
|
7272
7730
|
if (refCombi) {
|
|
7273
|
-
const compiled2 = compile(refCombi);
|
|
7731
|
+
const compiled2 = compile(refCombi, void 0, { recovery });
|
|
7274
7732
|
if (compiled2.inlineExpression === null) {
|
|
7275
7733
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
7276
7734
|
continue;
|
|
@@ -7287,7 +7745,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7287
7745
|
let replacement = compiledRules.replacement;
|
|
7288
7746
|
if (exportPrefix) {
|
|
7289
7747
|
const ns = nsFor(varName);
|
|
7290
|
-
const pieces = compileLinkable([...compiledRules.ruleMap], ns);
|
|
7748
|
+
const pieces = compileLinkable([...compiledRules.ruleMap], ns, { recovery });
|
|
7291
7749
|
if (pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
|
|
7292
7750
|
const ir = serializeRuleMap([...compiledRules.ruleMap]);
|
|
7293
7751
|
replacement = withCarriedPieces(replacement, [ir ? { ns, ir } : pieces]);
|
|
@@ -7323,7 +7781,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7323
7781
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
7324
7782
|
continue;
|
|
7325
7783
|
}
|
|
7326
|
-
const compiled = compile(parser2);
|
|
7784
|
+
const compiled = compile(parser2, void 0, { recovery });
|
|
7327
7785
|
if (compiled.inlineExpression === null) {
|
|
7328
7786
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
7329
7787
|
continue;
|