parseman 0.38.0 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/duplication.d.ts.map +1 -1
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/combinators/attempt.d.ts.map +1 -1
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +20 -0
- package/dist/combinators/dispatch.d.ts.map +1 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/index.cjs +383 -31
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +383 -31
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs.map +2 -2
- package/dist/language-service/index.js.map +2 -2
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +436 -31
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.js +436 -31
- package/dist/plugin/index.js.map +4 -4
- package/dist/spec/index.cjs +107 -0
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +107 -0
- package/dist/spec/index.js.map +4 -4
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -55,6 +55,7 @@ __export(index_exports, {
|
|
|
55
55
|
createGrammarTraceSink: () => createGrammarTraceSink,
|
|
56
56
|
createVisitor: () => createVisitor,
|
|
57
57
|
cstBuildHost: () => cstBuildHost,
|
|
58
|
+
dispatch: () => dispatch,
|
|
58
59
|
duplicationFindingCount: () => duplicationFindingCount,
|
|
59
60
|
expect: () => expect,
|
|
60
61
|
extractCharClasses: () => extractCharClasses,
|
|
@@ -87,6 +88,7 @@ __export(index_exports, {
|
|
|
87
88
|
oneOrMore: () => oneOrMore,
|
|
88
89
|
oneOrMoreSep: () => oneOrMoreSep,
|
|
89
90
|
optional: () => optional,
|
|
91
|
+
otherwise: () => otherwise,
|
|
90
92
|
parse: () => parse,
|
|
91
93
|
parseDoc: () => parseDoc,
|
|
92
94
|
parser: () => parser,
|
|
@@ -110,6 +112,7 @@ __export(index_exports, {
|
|
|
110
112
|
triviaEntries: () => triviaEntries,
|
|
111
113
|
triviaKindMask: () => triviaKindMask,
|
|
112
114
|
walk: () => walk,
|
|
115
|
+
when: () => when,
|
|
113
116
|
withCtx: () => withCtx,
|
|
114
117
|
word: () => word
|
|
115
118
|
});
|
|
@@ -194,6 +197,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
194
197
|
return d.parsers.every(me);
|
|
195
198
|
case "choice":
|
|
196
199
|
return d.parsers.some(me);
|
|
200
|
+
case "dispatch":
|
|
201
|
+
return me(d.selector);
|
|
197
202
|
case "transform":
|
|
198
203
|
case "label":
|
|
199
204
|
case "trivia":
|
|
@@ -267,6 +272,8 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
267
272
|
case "keywords":
|
|
268
273
|
return p._meta.firstSet;
|
|
269
274
|
// terminals: no refs, cached set is exact
|
|
275
|
+
case "dispatch":
|
|
276
|
+
return fs(d.selector);
|
|
270
277
|
case "lazy":
|
|
271
278
|
try {
|
|
272
279
|
return fs(d.thunk());
|
|
@@ -1184,6 +1191,8 @@ function derive(c, seen) {
|
|
|
1184
1191
|
return [def.label];
|
|
1185
1192
|
case "choice":
|
|
1186
1193
|
return def.parsers.flatMap(deriveExpected2);
|
|
1194
|
+
case "dispatch":
|
|
1195
|
+
return deriveExpected2(def.selector);
|
|
1187
1196
|
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1188
1197
|
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1189
1198
|
// able to fail first — deriving from term 0 alone named a token the parse
|
|
@@ -1325,6 +1334,7 @@ function choice(...args) {
|
|
|
1325
1334
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
1326
1335
|
if (result.ok) return result;
|
|
1327
1336
|
expected.push(...result.expected);
|
|
1337
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1328
1338
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1329
1339
|
}
|
|
1330
1340
|
return {
|
|
@@ -1365,6 +1375,7 @@ function choice(...args) {
|
|
|
1365
1375
|
rollbackCstCapture(ctx, mark);
|
|
1366
1376
|
if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
|
|
1367
1377
|
expected.push(...result.expected);
|
|
1378
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1368
1379
|
continue;
|
|
1369
1380
|
}
|
|
1370
1381
|
const checks = autoNot[i];
|
|
@@ -2044,6 +2055,75 @@ function sequence(...parsers) {
|
|
|
2044
2055
|
};
|
|
2045
2056
|
}
|
|
2046
2057
|
|
|
2058
|
+
// src/combinators/dispatch.ts
|
|
2059
|
+
function when(key, parser2) {
|
|
2060
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2061
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2062
|
+
for (const item of keys) {
|
|
2063
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2064
|
+
}
|
|
2065
|
+
return { kind: "when", keys, parser: parser2 };
|
|
2066
|
+
}
|
|
2067
|
+
function otherwise(parser2) {
|
|
2068
|
+
return { kind: "otherwise", parser: parser2 };
|
|
2069
|
+
}
|
|
2070
|
+
function dispatch(selector, ...arms) {
|
|
2071
|
+
let fallback;
|
|
2072
|
+
const cases = [];
|
|
2073
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2074
|
+
for (let i = 0; i < arms.length; i++) {
|
|
2075
|
+
const arm = arms[i];
|
|
2076
|
+
if (arm.kind === "otherwise") {
|
|
2077
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2078
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2079
|
+
fallback = arm.parser;
|
|
2080
|
+
continue;
|
|
2081
|
+
}
|
|
2082
|
+
for (const key of arm.keys) {
|
|
2083
|
+
if (seen.has(key)) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2084
|
+
seen.add(key);
|
|
2085
|
+
}
|
|
2086
|
+
cases.push({ keys: arm.keys, parser: arm.parser });
|
|
2087
|
+
}
|
|
2088
|
+
const meta = {
|
|
2089
|
+
firstSet: selector._meta.firstSet,
|
|
2090
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2091
|
+
isTrivia: false
|
|
2092
|
+
};
|
|
2093
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2094
|
+
for (const entry of cases) for (const key of entry.keys) byKey.set(key, entry.parser);
|
|
2095
|
+
return {
|
|
2096
|
+
_tag: "dispatch",
|
|
2097
|
+
_meta: meta,
|
|
2098
|
+
_def: {
|
|
2099
|
+
tag: "dispatch",
|
|
2100
|
+
selector,
|
|
2101
|
+
cases,
|
|
2102
|
+
...fallback === void 0 ? {} : { otherwise: fallback }
|
|
2103
|
+
},
|
|
2104
|
+
parse(input, pos, ctx) {
|
|
2105
|
+
const selected = selector.parse(input, pos, ctx);
|
|
2106
|
+
if (!selected.ok) return selected;
|
|
2107
|
+
const tail = byKey.get(selected.value) ?? fallback;
|
|
2108
|
+
if (tail === void 0) {
|
|
2109
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2110
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2111
|
+
}
|
|
2112
|
+
const mark = saveTriviaMark(ctx);
|
|
2113
|
+
const result = tail.parse(input, selected.span.end, ctx);
|
|
2114
|
+
if (!result.ok) {
|
|
2115
|
+
rollbackTrivia(ctx, mark);
|
|
2116
|
+
return { ...result, committed: true };
|
|
2117
|
+
}
|
|
2118
|
+
return {
|
|
2119
|
+
ok: true,
|
|
2120
|
+
value: [selected.value, result.value],
|
|
2121
|
+
span: { start: pos, end: result.span.end }
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2047
2127
|
// src/combinators/attempt.ts
|
|
2048
2128
|
function attempt(parser2) {
|
|
2049
2129
|
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
@@ -2066,6 +2146,7 @@ function attempt(parser2) {
|
|
|
2066
2146
|
if (result.ok) return result;
|
|
2067
2147
|
rollbackCstCapture(ctx, mark);
|
|
2068
2148
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
2149
|
+
if (result.committed) return result;
|
|
2069
2150
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
2070
2151
|
}
|
|
2071
2152
|
};
|
|
@@ -2095,6 +2176,7 @@ function repItem(combinator, input, cur, ctx, guardable) {
|
|
|
2095
2176
|
const result = combinator.parse(input, pos, ctx);
|
|
2096
2177
|
if (!result.ok) {
|
|
2097
2178
|
rollbackTrivia(ctx, mark);
|
|
2179
|
+
if (result.committed) return { fail: result, failPos: pos };
|
|
2098
2180
|
return { fail: result, failPos: pos };
|
|
2099
2181
|
}
|
|
2100
2182
|
if (result.span.end === pos) {
|
|
@@ -2138,6 +2220,7 @@ function many(combinator, opts = {}) {
|
|
|
2138
2220
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2139
2221
|
if (item === "stop") break;
|
|
2140
2222
|
if ("fail" in item) {
|
|
2223
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2141
2224
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2142
2225
|
if (sync === void 0) break;
|
|
2143
2226
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2182,6 +2265,7 @@ function atLeast(combinator, min, max) {
|
|
|
2182
2265
|
while (count < min) {
|
|
2183
2266
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2184
2267
|
if (item === "stop" || "fail" in item) {
|
|
2268
|
+
if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
|
|
2185
2269
|
expected ??= deriveExpected(combinator);
|
|
2186
2270
|
return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
|
|
2187
2271
|
}
|
|
@@ -2194,6 +2278,7 @@ function atLeast(combinator, min, max) {
|
|
|
2194
2278
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2195
2279
|
if (item === "stop") break;
|
|
2196
2280
|
if ("fail" in item) {
|
|
2281
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2197
2282
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2198
2283
|
if (sync === void 0) break;
|
|
2199
2284
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2232,6 +2317,7 @@ function optional(combinator) {
|
|
|
2232
2317
|
const result = combinator.parse(input, pos, ctx);
|
|
2233
2318
|
if (result.ok) return result;
|
|
2234
2319
|
rollbackTrivia(ctx, mark);
|
|
2320
|
+
if (result.committed) return result;
|
|
2235
2321
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
2236
2322
|
}
|
|
2237
2323
|
};
|
|
@@ -2271,6 +2357,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2271
2357
|
values.push(first.value);
|
|
2272
2358
|
cur = first.span.end;
|
|
2273
2359
|
} else {
|
|
2360
|
+
if (first.committed) return first;
|
|
2274
2361
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2275
2362
|
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
2276
2363
|
if (min >= 1) return failAt2(pos);
|
|
@@ -2298,6 +2385,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2298
2385
|
const sep = separator.parse(input, sepPos, ctx);
|
|
2299
2386
|
if (!sep.ok) {
|
|
2300
2387
|
rollbackTrivia(ctx, loopMark);
|
|
2388
|
+
if (sep.committed) return sep;
|
|
2301
2389
|
break;
|
|
2302
2390
|
}
|
|
2303
2391
|
const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
|
|
@@ -2313,6 +2401,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2313
2401
|
}
|
|
2314
2402
|
const next = combinator.parse(input, nextPos, ctx);
|
|
2315
2403
|
if (!next.ok) {
|
|
2404
|
+
if (next.committed) return next;
|
|
2316
2405
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2317
2406
|
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2318
2407
|
expected ??= deriveExpected(combinator);
|
|
@@ -2405,6 +2494,11 @@ function markUnusedValues(root) {
|
|
|
2405
2494
|
case "choice":
|
|
2406
2495
|
for (const p of def.parsers) visit(p, consumed);
|
|
2407
2496
|
return;
|
|
2497
|
+
case "dispatch":
|
|
2498
|
+
visit(def.selector, consumed);
|
|
2499
|
+
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2500
|
+
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2501
|
+
return;
|
|
2408
2502
|
case "node":
|
|
2409
2503
|
visit(def.parser, false);
|
|
2410
2504
|
return;
|
|
@@ -2680,6 +2774,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2680
2774
|
case "sequence":
|
|
2681
2775
|
case "choice":
|
|
2682
2776
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2777
|
+
case "dispatch":
|
|
2778
|
+
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2683
2779
|
case "sepBy":
|
|
2684
2780
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2685
2781
|
case "skip":
|
|
@@ -2747,6 +2843,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2747
2843
|
return parserHasTriviaSite(d.parser, seen);
|
|
2748
2844
|
case "choice":
|
|
2749
2845
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2846
|
+
case "dispatch":
|
|
2847
|
+
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2750
2848
|
case "grammar":
|
|
2751
2849
|
return parserHasTriviaSite(d.parser, seen);
|
|
2752
2850
|
case "lazy": {
|
|
@@ -2772,6 +2870,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2772
2870
|
case "sequence":
|
|
2773
2871
|
case "choice":
|
|
2774
2872
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2873
|
+
case "dispatch":
|
|
2874
|
+
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2775
2875
|
case "sepBy":
|
|
2776
2876
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2777
2877
|
case "skip":
|
|
@@ -3173,7 +3273,7 @@ function leaf(root, fn) {
|
|
|
3173
3273
|
}
|
|
3174
3274
|
|
|
3175
3275
|
// src/version.ts
|
|
3176
|
-
var PARSEMAN_VERSION = "0.
|
|
3276
|
+
var PARSEMAN_VERSION = "0.39.0";
|
|
3177
3277
|
|
|
3178
3278
|
// src/cst/host-mode.ts
|
|
3179
3279
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3329,6 +3429,8 @@ function classifyBroadArm(arm, resolve) {
|
|
|
3329
3429
|
}
|
|
3330
3430
|
return null;
|
|
3331
3431
|
}
|
|
3432
|
+
case "dispatch":
|
|
3433
|
+
return walk2(d.selector);
|
|
3332
3434
|
default:
|
|
3333
3435
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3334
3436
|
}
|
|
@@ -3428,6 +3530,11 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3428
3530
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3429
3531
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3430
3532
|
if (rec[k]) kids.push(rec[k]);
|
|
3533
|
+
if (d.tag === "dispatch") {
|
|
3534
|
+
kids.push(d.selector);
|
|
3535
|
+
for (const c of d.cases) kids.push(c.parser);
|
|
3536
|
+
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3537
|
+
}
|
|
3431
3538
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3432
3539
|
if (d.tag === "lazy") {
|
|
3433
3540
|
try {
|
|
@@ -3534,6 +3641,12 @@ function childrenOf(d) {
|
|
|
3534
3641
|
case "sequence":
|
|
3535
3642
|
case "choice":
|
|
3536
3643
|
return d.parsers;
|
|
3644
|
+
case "dispatch":
|
|
3645
|
+
return [
|
|
3646
|
+
d.selector,
|
|
3647
|
+
...d.cases.map((c) => c.parser),
|
|
3648
|
+
...d.otherwise === void 0 ? [] : [d.otherwise]
|
|
3649
|
+
];
|
|
3537
3650
|
case "skip":
|
|
3538
3651
|
return [d.main, d.skipped];
|
|
3539
3652
|
case "sepBy":
|
|
@@ -3590,6 +3703,8 @@ function payloadKey(p, d) {
|
|
|
3590
3703
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3591
3704
|
case "sepBy":
|
|
3592
3705
|
return `sepBy\0${d.min}\0${d.max ?? ""}\0${d.trailing ?? ""}`;
|
|
3706
|
+
case "dispatch":
|
|
3707
|
+
return `dispatch\0${d.cases.map((c) => JSON.stringify(c.keys)).join("")}\0${d.otherwise !== void 0}`;
|
|
3593
3708
|
case "expect":
|
|
3594
3709
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3595
3710
|
case "scanTo":
|
|
@@ -3661,6 +3776,11 @@ function render(p, depth = 3) {
|
|
|
3661
3776
|
return `sequence(${kids.join(", ")})`;
|
|
3662
3777
|
case "choice":
|
|
3663
3778
|
return `choice(${kids.join(", ")})`;
|
|
3779
|
+
case "dispatch": {
|
|
3780
|
+
const arms = d.cases.map((c, i) => `when([${c.keys.map((k) => JSON.stringify(k)).join(", ")}], ${kids[i + 1] ?? ""})`);
|
|
3781
|
+
if (d.otherwise !== void 0) arms.push(`otherwise(${kids[kids.length - 1] ?? ""})`);
|
|
3782
|
+
return `dispatch(${kids[0] ?? ""}, ${arms.join(", ")})`;
|
|
3783
|
+
}
|
|
3664
3784
|
case "node":
|
|
3665
3785
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3666
3786
|
case "label":
|
|
@@ -3684,6 +3804,10 @@ function segment(d, index) {
|
|
|
3684
3804
|
return `seq[${index}]`;
|
|
3685
3805
|
case "choice":
|
|
3686
3806
|
return `choice[${index}]`;
|
|
3807
|
+
case "dispatch":
|
|
3808
|
+
if (index === 0) return "dispatch.selector";
|
|
3809
|
+
if (index <= d.cases.length) return `dispatch.when[${index - 1}]`;
|
|
3810
|
+
return "dispatch.otherwise";
|
|
3687
3811
|
case "node":
|
|
3688
3812
|
return `node(${d.type ?? ""})`;
|
|
3689
3813
|
case "label":
|
|
@@ -4937,6 +5061,8 @@ function children(def, winners) {
|
|
|
4937
5061
|
case "sequence":
|
|
4938
5062
|
case "choice":
|
|
4939
5063
|
return def.parsers;
|
|
5064
|
+
case "dispatch":
|
|
5065
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
4940
5066
|
case "many":
|
|
4941
5067
|
case "oneOrMore":
|
|
4942
5068
|
case "optional":
|
|
@@ -6401,6 +6527,8 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6401
6527
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6402
6528
|
return { alts };
|
|
6403
6529
|
}
|
|
6530
|
+
case "dispatch":
|
|
6531
|
+
return rec(d.selector);
|
|
6404
6532
|
case "sequence": {
|
|
6405
6533
|
const chain = [];
|
|
6406
6534
|
for (const term of d.parsers) {
|
|
@@ -6475,6 +6603,9 @@ function failReturn(expected, posExpr) {
|
|
|
6475
6603
|
function failReturnArr(expectedArr, posExpr) {
|
|
6476
6604
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6477
6605
|
}
|
|
6606
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6607
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6608
|
+
}
|
|
6478
6609
|
function hoistExpected(ctx, constArrSource) {
|
|
6479
6610
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6480
6611
|
if (name === void 0) {
|
|
@@ -6511,15 +6642,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6511
6642
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6512
6643
|
}
|
|
6513
6644
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6514
|
-
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
6645
|
+
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
|
|
6646
|
+
}
|
|
6647
|
+
function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
|
|
6648
|
+
if (ctx.failLabel) {
|
|
6649
|
+
if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
|
|
6650
|
+
return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
|
|
6651
|
+
}
|
|
6652
|
+
return committedReturnArr(expectedArr, posExpr);
|
|
6515
6653
|
}
|
|
6516
6654
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6517
6655
|
if (srcCtx !== "_ctx") {
|
|
6518
6656
|
if (ctx.failLabel) {
|
|
6519
6657
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6520
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; break ${ctx.failLabel} }`;
|
|
6658
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
|
|
6521
6659
|
}
|
|
6522
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; ${resultFromRecorded()} }`;
|
|
6660
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
|
|
6523
6661
|
}
|
|
6524
6662
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6525
6663
|
return resultFromRecorded();
|
|
@@ -6732,6 +6870,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6732
6870
|
// nothing committed remains.
|
|
6733
6871
|
case "choice":
|
|
6734
6872
|
return false;
|
|
6873
|
+
case "dispatch":
|
|
6874
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => mayLeavePartialCapture(x.parser, seen) || capturesLeaf(x.parser, seen)) || (d.otherwise ? mayLeavePartialCapture(d.otherwise, seen) || capturesLeaf(d.otherwise, seen) : false);
|
|
6735
6875
|
case "attempt":
|
|
6736
6876
|
return false;
|
|
6737
6877
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6776,6 +6916,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6776
6916
|
return true;
|
|
6777
6917
|
}
|
|
6778
6918
|
}
|
|
6919
|
+
function mayCommitFailure(p, seen = /* @__PURE__ */ new Set()) {
|
|
6920
|
+
if (seen.has(p)) return false;
|
|
6921
|
+
seen.add(p);
|
|
6922
|
+
const d = p._def;
|
|
6923
|
+
switch (d.tag) {
|
|
6924
|
+
case "dispatch":
|
|
6925
|
+
return true;
|
|
6926
|
+
case "choice":
|
|
6927
|
+
case "sequence":
|
|
6928
|
+
return d.parsers.some((x) => mayCommitFailure(x, seen));
|
|
6929
|
+
case "many":
|
|
6930
|
+
case "oneOrMore":
|
|
6931
|
+
case "optional":
|
|
6932
|
+
case "attempt":
|
|
6933
|
+
case "transform":
|
|
6934
|
+
case "label":
|
|
6935
|
+
case "field":
|
|
6936
|
+
case "grammar":
|
|
6937
|
+
case "node":
|
|
6938
|
+
return mayCommitFailure(d.parser, seen);
|
|
6939
|
+
case "sepBy":
|
|
6940
|
+
return mayCommitFailure(d.parser, seen) || mayCommitFailure(d.separator, seen);
|
|
6941
|
+
case "skip":
|
|
6942
|
+
return mayCommitFailure(d.main, seen) || mayCommitFailure(d.skipped, seen);
|
|
6943
|
+
case "token":
|
|
6944
|
+
case "leaf":
|
|
6945
|
+
return mayCommitFailure(d.parser, seen);
|
|
6946
|
+
case "withCtx":
|
|
6947
|
+
return mayCommitFailure(d.parser, seen);
|
|
6948
|
+
case "scanTo":
|
|
6949
|
+
return mayCommitFailure(d.sentinel, seen) || d.skip.some((x) => mayCommitFailure(x, seen));
|
|
6950
|
+
case "lazy": {
|
|
6951
|
+
try {
|
|
6952
|
+
return mayCommitFailure(d.thunk(), seen);
|
|
6953
|
+
} catch {
|
|
6954
|
+
return true;
|
|
6955
|
+
}
|
|
6956
|
+
}
|
|
6957
|
+
case "unknown":
|
|
6958
|
+
return true;
|
|
6959
|
+
default:
|
|
6960
|
+
return false;
|
|
6961
|
+
}
|
|
6962
|
+
}
|
|
6779
6963
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6780
6964
|
if (seen.has(p)) return false;
|
|
6781
6965
|
seen.add(p);
|
|
@@ -6797,6 +6981,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6797
6981
|
case "sequence":
|
|
6798
6982
|
case "choice":
|
|
6799
6983
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6984
|
+
case "dispatch":
|
|
6985
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
6800
6986
|
case "sepBy":
|
|
6801
6987
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6802
6988
|
case "many":
|
|
@@ -6843,6 +7029,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6843
7029
|
ctx.recordFail = savedRecord;
|
|
6844
7030
|
const ind0 = ind(ctx);
|
|
6845
7031
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
7032
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6846
7033
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6847
7034
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6848
7035
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6856,6 +7043,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6856
7043
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6857
7044
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6858
7045
|
] : [],
|
|
7046
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6859
7047
|
`${ind0}${lbl}: {`,
|
|
6860
7048
|
...r.stmts,
|
|
6861
7049
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6864,7 +7052,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6864
7052
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6865
7053
|
] : []
|
|
6866
7054
|
];
|
|
6867
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
7055
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6868
7056
|
}
|
|
6869
7057
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6870
7058
|
function emitLit(def, ctx, pos) {
|
|
@@ -7241,6 +7429,118 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7241
7429
|
}
|
|
7242
7430
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7243
7431
|
}
|
|
7432
|
+
function emitTailFallible(parser2, ctx, pos) {
|
|
7433
|
+
const savedRecord = ctx.recordFail;
|
|
7434
|
+
ctx.recordFail = true;
|
|
7435
|
+
const out = emitFallible(parser2, ctx, pos);
|
|
7436
|
+
ctx.recordFail = savedRecord;
|
|
7437
|
+
return out;
|
|
7438
|
+
}
|
|
7439
|
+
function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
7440
|
+
if (seen.has(p)) return false;
|
|
7441
|
+
seen.add(p);
|
|
7442
|
+
const d = p._def;
|
|
7443
|
+
switch (d.tag) {
|
|
7444
|
+
case "expect":
|
|
7445
|
+
case "recover":
|
|
7446
|
+
return true;
|
|
7447
|
+
case "many":
|
|
7448
|
+
case "oneOrMore":
|
|
7449
|
+
case "sepBy":
|
|
7450
|
+
return recovery || mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7451
|
+
case "choice":
|
|
7452
|
+
case "sequence": {
|
|
7453
|
+
for (const item of d.parsers) {
|
|
7454
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7455
|
+
}
|
|
7456
|
+
return false;
|
|
7457
|
+
}
|
|
7458
|
+
case "dispatch": {
|
|
7459
|
+
if (mayRecordRecoveryError(d.selector, recovery, seen)) return true;
|
|
7460
|
+
for (const item of d.cases) {
|
|
7461
|
+
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7462
|
+
}
|
|
7463
|
+
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7464
|
+
}
|
|
7465
|
+
case "attempt":
|
|
7466
|
+
case "transform":
|
|
7467
|
+
case "label":
|
|
7468
|
+
case "field":
|
|
7469
|
+
case "grammar":
|
|
7470
|
+
case "node":
|
|
7471
|
+
case "token":
|
|
7472
|
+
case "leaf":
|
|
7473
|
+
case "withCtx":
|
|
7474
|
+
case "optional":
|
|
7475
|
+
return mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7476
|
+
case "skip":
|
|
7477
|
+
return mayRecordRecoveryError(d.main, recovery, seen) || mayRecordRecoveryError(d.skipped, recovery, seen);
|
|
7478
|
+
case "scanTo":
|
|
7479
|
+
if (mayRecordRecoveryError(d.sentinel, recovery, seen)) return true;
|
|
7480
|
+
for (const item of d.skip) {
|
|
7481
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7482
|
+
}
|
|
7483
|
+
return false;
|
|
7484
|
+
case "lazy": {
|
|
7485
|
+
try {
|
|
7486
|
+
return mayRecordRecoveryError(d.thunk(), recovery, seen);
|
|
7487
|
+
} catch {
|
|
7488
|
+
return true;
|
|
7489
|
+
}
|
|
7490
|
+
}
|
|
7491
|
+
case "unknown":
|
|
7492
|
+
return true;
|
|
7493
|
+
default:
|
|
7494
|
+
return false;
|
|
7495
|
+
}
|
|
7496
|
+
}
|
|
7497
|
+
function emitDispatchCombinator(def, ctx, pos) {
|
|
7498
|
+
const selector = emit(def.selector, ctx, pos);
|
|
7499
|
+
const outV = v(ctx, "_dval");
|
|
7500
|
+
const outE = v(ctx, "_dend");
|
|
7501
|
+
const keyV = v(ctx, "_dkey");
|
|
7502
|
+
const stmts = [
|
|
7503
|
+
...selector.stmts,
|
|
7504
|
+
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7505
|
+
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7506
|
+
];
|
|
7507
|
+
let wroteBranch = false;
|
|
7508
|
+
const emitSelectedTail = (parser2, keyword, condition) => {
|
|
7509
|
+
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7510
|
+
stmts.push(head);
|
|
7511
|
+
ctx.indent++;
|
|
7512
|
+
const mayError = mayRecordRecoveryError(parser2, !!ctx.recovery);
|
|
7513
|
+
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7514
|
+
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7515
|
+
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7516
|
+
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7517
|
+
const tail = emitTailFallible(parser2, ctx, selector.endVar);
|
|
7518
|
+
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7519
|
+
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7520
|
+
stmts.push(
|
|
7521
|
+
...tail.stmts,
|
|
7522
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7523
|
+
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7524
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`
|
|
7525
|
+
);
|
|
7526
|
+
ctx.indent--;
|
|
7527
|
+
stmts.push(`${ind(ctx)}}`);
|
|
7528
|
+
};
|
|
7529
|
+
for (const entry of def.cases) {
|
|
7530
|
+
const condition = entry.keys.map((key) => `${keyV} === ${JSON.stringify(key)}`).join(" || ");
|
|
7531
|
+
emitSelectedTail(entry.parser, wroteBranch ? "else if" : "if", condition);
|
|
7532
|
+
wroteBranch = true;
|
|
7533
|
+
}
|
|
7534
|
+
if (def.otherwise) {
|
|
7535
|
+
if (wroteBranch) emitSelectedTail(def.otherwise, "else");
|
|
7536
|
+
else emitSelectedTail(def.otherwise, "if", "true");
|
|
7537
|
+
} else {
|
|
7538
|
+
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7539
|
+
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7540
|
+
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7541
|
+
}
|
|
7542
|
+
return { stmts, valueVar: outV, endVar: outE };
|
|
7543
|
+
}
|
|
7244
7544
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7245
7545
|
const superParser = def.parsers[superIndex];
|
|
7246
7546
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7362,12 +7662,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7362
7662
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7363
7663
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7364
7664
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7665
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7365
7666
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7366
7667
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7367
7668
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7368
7669
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7369
7670
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7370
|
-
const
|
|
7671
|
+
const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
|
|
7672
|
+
const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
7673
|
+
const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
|
|
7674
|
+
const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
|
|
7371
7675
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7372
7676
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7373
7677
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7382,7 +7686,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7382
7686
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7383
7687
|
);
|
|
7384
7688
|
}
|
|
7385
|
-
|
|
7689
|
+
if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
|
|
7690
|
+
const arm = emitFallible(p, ctx, pos, atStart);
|
|
7691
|
+
const { stmts: armStmts, okVar, valVar, endVar } = arm;
|
|
7386
7692
|
stmts.push(...armStmts);
|
|
7387
7693
|
if (autoNot && autoNot.length > 0) {
|
|
7388
7694
|
const anCode = v(ctx, "_anc");
|
|
@@ -7406,10 +7712,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7406
7712
|
stmts.push(`${ind(ctx)}}`);
|
|
7407
7713
|
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}; ${coverageBase === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} });`} }`);
|
|
7408
7714
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7715
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7409
7716
|
} else {
|
|
7410
7717
|
const rejectedFlush = autoRejectedV === void 0 ? "" : `; for (const _rejectedId of ${autoRejectedV}) { _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'failure', offset: ${pos} }); _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'backtrack', offset: ${pos} }) }`;
|
|
7411
7718
|
stmts.push(`${ind(ctx)}if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true${coverageBase === void 0 ? "" : `${rejectedFlush}; _ctx._grammarCoverage?.(${JSON.stringify(`${coverageBase}${i}`)}); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'selected', offset: ${pos}, end: ${endVar} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'success', offset: ${pos}, end: ${endVar} })`} }`);
|
|
7412
7719
|
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}${rollback ? `; ${rollback}` : ""}${coverageBase === void 0 ? "" : `; _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} })`} }`);
|
|
7720
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7413
7721
|
}
|
|
7414
7722
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7415
7723
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7566,7 +7874,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7566
7874
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7567
7875
|
);
|
|
7568
7876
|
}
|
|
7569
|
-
const
|
|
7877
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
7878
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7570
7879
|
stmts.push(...iterStmts);
|
|
7571
7880
|
if (ctx.recovery) {
|
|
7572
7881
|
const rrV = v(ctx, "_rr");
|
|
@@ -7585,7 +7894,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7585
7894
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7586
7895
|
);
|
|
7587
7896
|
} else {
|
|
7588
|
-
stmts.push(`${ind(ctx)}if (!${iterOk}
|
|
7897
|
+
stmts.push(`${ind(ctx)}if (!${iterOk}) { ${rollback}${iter.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7898
|
+
stmts.push(`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
7589
7899
|
}
|
|
7590
7900
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7591
7901
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7597,10 +7907,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7597
7907
|
function emitOptional(def, ctx, pos) {
|
|
7598
7908
|
const valV = v(ctx, "_opt");
|
|
7599
7909
|
const endV = v(ctx, "_opte");
|
|
7600
|
-
const
|
|
7910
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
7911
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7601
7912
|
const ind0 = ind(ctx);
|
|
7602
7913
|
const stmts = [
|
|
7603
7914
|
...lblStmts,
|
|
7915
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7604
7916
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7605
7917
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7606
7918
|
];
|
|
@@ -7632,7 +7944,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7632
7944
|
...preGuard,
|
|
7633
7945
|
`${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${trivia2} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`,
|
|
7634
7946
|
...inner.stmts,
|
|
7635
|
-
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7947
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7636
7948
|
],
|
|
7637
7949
|
valueVar: inner.valVar,
|
|
7638
7950
|
endVar: inner.endVar
|
|
@@ -7646,18 +7958,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7646
7958
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7647
7959
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7648
7960
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7649
|
-
const
|
|
7961
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
7962
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7650
7963
|
const stmts = [
|
|
7651
7964
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7652
7965
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7653
7966
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7654
7967
|
...firstStmts
|
|
7655
7968
|
];
|
|
7656
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7657
|
-
if (
|
|
7969
|
+
const failItem = (nextOkVar, nextMayCommit, itemPosVar, breakStmt) => {
|
|
7970
|
+
const commit = nextMayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : "";
|
|
7971
|
+
if (!rec) return [`${ind(ctx)}if (!${nextOkVar}) { ${commit}${breakStmt} }`];
|
|
7658
7972
|
const rr = v(ctx, "_rr");
|
|
7659
7973
|
return [
|
|
7660
7974
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
7975
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7661
7976
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7662
7977
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7663
7978
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7686,6 +8001,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7686
8001
|
stmts.push(
|
|
7687
8002
|
`${ind(ctx)}let ${didV} = false`,
|
|
7688
8003
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
8004
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7689
8005
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7690
8006
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7691
8007
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7696,6 +8012,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7696
8012
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7697
8013
|
ctx.indent++;
|
|
7698
8014
|
} else {
|
|
8015
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7699
8016
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7700
8017
|
ctx.indent++;
|
|
7701
8018
|
stmts.push(
|
|
@@ -7724,16 +8041,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7724
8041
|
);
|
|
7725
8042
|
sepAtPos = spV;
|
|
7726
8043
|
const rollbackToSep = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markV}) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${markTl}) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}; `;
|
|
7727
|
-
const
|
|
7728
|
-
stmts
|
|
8044
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8045
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8046
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7729
8047
|
const post = postSepMarks();
|
|
7730
8048
|
stmts.push(...post.decl);
|
|
7731
8049
|
const npV = v(ctx, "_np");
|
|
7732
8050
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7733
|
-
const
|
|
8051
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8052
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7734
8053
|
stmts.push(
|
|
7735
8054
|
...nextStmts,
|
|
7736
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
8055
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7737
8056
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7738
8057
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7739
8058
|
);
|
|
@@ -7742,14 +8061,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7742
8061
|
const spV = v(ctx, "_sp");
|
|
7743
8062
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7744
8063
|
sepAtPos = spV;
|
|
7745
|
-
const
|
|
7746
|
-
stmts
|
|
8064
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8065
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8066
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7747
8067
|
const npV = v(ctx, "_np");
|
|
7748
8068
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7749
|
-
const
|
|
8069
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8070
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7750
8071
|
stmts.push(
|
|
7751
8072
|
...nextStmts,
|
|
7752
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
8073
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7753
8074
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7754
8075
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7755
8076
|
);
|
|
@@ -7763,15 +8084,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7763
8084
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7764
8085
|
);
|
|
7765
8086
|
}
|
|
7766
|
-
const
|
|
7767
|
-
stmts
|
|
8087
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8088
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8089
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7768
8090
|
const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; ` : "";
|
|
7769
8091
|
const post = postSepMarks();
|
|
7770
8092
|
stmts.push(...post.decl);
|
|
7771
|
-
const
|
|
8093
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
8094
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7772
8095
|
stmts.push(
|
|
7773
8096
|
...nextStmts,
|
|
7774
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
8097
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7775
8098
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7776
8099
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7777
8100
|
);
|
|
@@ -8152,7 +8475,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
8152
8475
|
const rv = v(ctx, "_rt");
|
|
8153
8476
|
const vv = v(ctx, "_rtv");
|
|
8154
8477
|
const ev = v(ctx, "_rte");
|
|
8155
|
-
const failStmt = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${rv}.span.start; _ctx._fx = ${rv}.expected; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : `return { ok: false, expected: ${rv}.expected, span: ${rv}.span }`;
|
|
8478
|
+
const failStmt = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${rv}.span.start; _ctx._fx = ${rv}.expected; _ctx._fc = ${rv}.committed === true; break ${ctx.failLabel} }` : `{ _ctx._fc = ${rv}.committed === true; break ${ctx.failLabel} }` : `return { ok: false, expected: ${rv}.expected, span: ${rv}.span, ...(${rv}.committed ? { committed: true } : {}) }`;
|
|
8156
8479
|
const stmts = [
|
|
8157
8480
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8158
8481
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8233,7 +8556,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8233
8556
|
return { stmts, valueVar: valVar, endVar };
|
|
8234
8557
|
}
|
|
8235
8558
|
function emitExpect(def, ctx, pos) {
|
|
8236
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8559
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8237
8560
|
const ind0 = ind(ctx);
|
|
8238
8561
|
const errV = v(ctx, "_err");
|
|
8239
8562
|
const stmts = [
|
|
@@ -8245,6 +8568,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8245
8568
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8246
8569
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8247
8570
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8571
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8248
8572
|
`${ind0} ${valVar} = ${errV}`,
|
|
8249
8573
|
`${ind0} ${endVar} = ${pos}`,
|
|
8250
8574
|
`${ind0} ${okVar} = true`,
|
|
@@ -8255,7 +8579,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8255
8579
|
function emit(p, ctx, pos) {
|
|
8256
8580
|
const replay = ctx.replayPrefix?.get(p);
|
|
8257
8581
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8258
|
-
const
|
|
8582
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8259
8583
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8260
8584
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8261
8585
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8295,14 +8619,14 @@ function emit(p, ctx, pos) {
|
|
|
8295
8619
|
ctx.indent = 1;
|
|
8296
8620
|
ctx.failLabel = "_pfail";
|
|
8297
8621
|
ctx.recordFail = true;
|
|
8298
|
-
const r =
|
|
8622
|
+
const r = dispatch2("_pos");
|
|
8299
8623
|
ctx.indent = savedIndent;
|
|
8300
8624
|
ctx.failLabel = savedFailLabel;
|
|
8301
8625
|
ctx.recordFail = savedRecord;
|
|
8302
8626
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8303
8627
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8304
8628
|
}
|
|
8305
|
-
return instrument(
|
|
8629
|
+
return instrument(dispatch2());
|
|
8306
8630
|
}
|
|
8307
8631
|
function emitDispatch(p, ctx, pos) {
|
|
8308
8632
|
const bal = p._balancedAmbient;
|
|
@@ -8335,6 +8659,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8335
8659
|
return emitSeq(def, ctx, pos);
|
|
8336
8660
|
case "choice":
|
|
8337
8661
|
return emitChoice(p, def, ctx, pos);
|
|
8662
|
+
case "dispatch":
|
|
8663
|
+
return emitDispatchCombinator(def, ctx, pos);
|
|
8338
8664
|
case "attempt":
|
|
8339
8665
|
return emitAttempt(p, def, ctx, pos);
|
|
8340
8666
|
case "many":
|
|
@@ -8555,6 +8881,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8555
8881
|
case "sequence":
|
|
8556
8882
|
case "choice":
|
|
8557
8883
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8884
|
+
case "dispatch":
|
|
8885
|
+
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
8558
8886
|
case "sepBy":
|
|
8559
8887
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8560
8888
|
case "scanTo":
|
|
@@ -8588,6 +8916,8 @@ function childrenOf2(def) {
|
|
|
8588
8916
|
case "sequence":
|
|
8589
8917
|
case "choice":
|
|
8590
8918
|
return def.parsers;
|
|
8919
|
+
case "dispatch":
|
|
8920
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
8591
8921
|
case "many":
|
|
8592
8922
|
case "attempt":
|
|
8593
8923
|
case "optional":
|
|
@@ -8631,6 +8961,7 @@ function childrenOf2(def) {
|
|
|
8631
8961
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8632
8962
|
"sequence",
|
|
8633
8963
|
"choice",
|
|
8964
|
+
"dispatch",
|
|
8634
8965
|
"many",
|
|
8635
8966
|
"oneOrMore",
|
|
8636
8967
|
"optional",
|
|
@@ -9329,6 +9660,8 @@ function childrenOf3(def) {
|
|
|
9329
9660
|
case "sequence":
|
|
9330
9661
|
case "choice":
|
|
9331
9662
|
return def.parsers;
|
|
9663
|
+
case "dispatch":
|
|
9664
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9332
9665
|
case "many":
|
|
9333
9666
|
case "oneOrMore":
|
|
9334
9667
|
case "optional":
|
|
@@ -9478,6 +9811,9 @@ function evalRuleMapIR(ir) {
|
|
|
9478
9811
|
"keywords",
|
|
9479
9812
|
"sequence",
|
|
9480
9813
|
"choice",
|
|
9814
|
+
"dispatch",
|
|
9815
|
+
"when",
|
|
9816
|
+
"otherwise",
|
|
9481
9817
|
"attempt",
|
|
9482
9818
|
"many",
|
|
9483
9819
|
"oneOrMore",
|
|
@@ -9511,6 +9847,9 @@ function evalRuleMapIR(ir) {
|
|
|
9511
9847
|
keywords,
|
|
9512
9848
|
sequence,
|
|
9513
9849
|
choice,
|
|
9850
|
+
dispatch,
|
|
9851
|
+
when,
|
|
9852
|
+
otherwise,
|
|
9514
9853
|
attempt,
|
|
9515
9854
|
many,
|
|
9516
9855
|
oneOrMore,
|
|
@@ -9696,6 +10035,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9696
10035
|
});
|
|
9697
10036
|
return `_gch([${items.join(", ")}])`;
|
|
9698
10037
|
}
|
|
10038
|
+
case "dispatch": {
|
|
10039
|
+
const arms = def.cases.map(
|
|
10040
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
10041
|
+
);
|
|
10042
|
+
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10043
|
+
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10044
|
+
}
|
|
9699
10045
|
case "many":
|
|
9700
10046
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9701
10047
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -10915,6 +11261,12 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
10915
11261
|
const unsafeSequence = sequence;
|
|
10916
11262
|
return unsafeSequence(...def.parsers.map(build));
|
|
10917
11263
|
}
|
|
11264
|
+
case "dispatch": {
|
|
11265
|
+
const arms = def.cases.map((entry2) => when(entry2.keys, build(entry2.parser)));
|
|
11266
|
+
if (def.otherwise) arms.push(otherwise(build(def.otherwise)));
|
|
11267
|
+
const unsafeDispatch = dispatch;
|
|
11268
|
+
return unsafeDispatch(build(def.selector), ...arms);
|
|
11269
|
+
}
|
|
10918
11270
|
case "many":
|
|
10919
11271
|
return many(build(def.parser));
|
|
10920
11272
|
case "oneOrMore":
|