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/plugin/index.js
CHANGED
|
@@ -85,6 +85,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
85
85
|
return d.parsers.every(me);
|
|
86
86
|
case "choice":
|
|
87
87
|
return d.parsers.some(me);
|
|
88
|
+
case "dispatch":
|
|
89
|
+
return me(d.selector);
|
|
88
90
|
case "transform":
|
|
89
91
|
case "label":
|
|
90
92
|
case "trivia":
|
|
@@ -158,6 +160,8 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
158
160
|
case "keywords":
|
|
159
161
|
return p._meta.firstSet;
|
|
160
162
|
// terminals: no refs, cached set is exact
|
|
163
|
+
case "dispatch":
|
|
164
|
+
return fs2(d.selector);
|
|
161
165
|
case "lazy":
|
|
162
166
|
try {
|
|
163
167
|
return fs2(d.thunk());
|
|
@@ -1106,6 +1110,8 @@ function derive(c, seen) {
|
|
|
1106
1110
|
return [def.label];
|
|
1107
1111
|
case "choice":
|
|
1108
1112
|
return def.parsers.flatMap(deriveExpected2);
|
|
1113
|
+
case "dispatch":
|
|
1114
|
+
return deriveExpected2(def.selector);
|
|
1109
1115
|
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1110
1116
|
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1111
1117
|
// able to fail first — deriving from term 0 alone named a token the parse
|
|
@@ -1244,6 +1250,7 @@ function choice(...args) {
|
|
|
1244
1250
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
1245
1251
|
if (result.ok) return result;
|
|
1246
1252
|
expected.push(...result.expected);
|
|
1253
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1247
1254
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1248
1255
|
}
|
|
1249
1256
|
return {
|
|
@@ -1284,6 +1291,7 @@ function choice(...args) {
|
|
|
1284
1291
|
rollbackCstCapture(ctx, mark);
|
|
1285
1292
|
if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
|
|
1286
1293
|
expected.push(...result.expected);
|
|
1294
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1287
1295
|
continue;
|
|
1288
1296
|
}
|
|
1289
1297
|
const checks = autoNot[i];
|
|
@@ -1963,6 +1971,75 @@ function sequence(...parsers) {
|
|
|
1963
1971
|
};
|
|
1964
1972
|
}
|
|
1965
1973
|
|
|
1974
|
+
// src/combinators/dispatch.ts
|
|
1975
|
+
function when(key, parser2) {
|
|
1976
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
1977
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
1978
|
+
for (const item of keys) {
|
|
1979
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
1980
|
+
}
|
|
1981
|
+
return { kind: "when", keys, parser: parser2 };
|
|
1982
|
+
}
|
|
1983
|
+
function otherwise(parser2) {
|
|
1984
|
+
return { kind: "otherwise", parser: parser2 };
|
|
1985
|
+
}
|
|
1986
|
+
function dispatch(selector, ...arms) {
|
|
1987
|
+
let fallback;
|
|
1988
|
+
const cases = [];
|
|
1989
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1990
|
+
for (let i = 0; i < arms.length; i++) {
|
|
1991
|
+
const arm = arms[i];
|
|
1992
|
+
if (arm.kind === "otherwise") {
|
|
1993
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
1994
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
1995
|
+
fallback = arm.parser;
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
for (const key of arm.keys) {
|
|
1999
|
+
if (seen.has(key)) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2000
|
+
seen.add(key);
|
|
2001
|
+
}
|
|
2002
|
+
cases.push({ keys: arm.keys, parser: arm.parser });
|
|
2003
|
+
}
|
|
2004
|
+
const meta = {
|
|
2005
|
+
firstSet: selector._meta.firstSet,
|
|
2006
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2007
|
+
isTrivia: false
|
|
2008
|
+
};
|
|
2009
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2010
|
+
for (const entry of cases) for (const key of entry.keys) byKey.set(key, entry.parser);
|
|
2011
|
+
return {
|
|
2012
|
+
_tag: "dispatch",
|
|
2013
|
+
_meta: meta,
|
|
2014
|
+
_def: {
|
|
2015
|
+
tag: "dispatch",
|
|
2016
|
+
selector,
|
|
2017
|
+
cases,
|
|
2018
|
+
...fallback === void 0 ? {} : { otherwise: fallback }
|
|
2019
|
+
},
|
|
2020
|
+
parse(input, pos, ctx) {
|
|
2021
|
+
const selected = selector.parse(input, pos, ctx);
|
|
2022
|
+
if (!selected.ok) return selected;
|
|
2023
|
+
const tail = byKey.get(selected.value) ?? fallback;
|
|
2024
|
+
if (tail === void 0) {
|
|
2025
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2026
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2027
|
+
}
|
|
2028
|
+
const mark = saveTriviaMark(ctx);
|
|
2029
|
+
const result = tail.parse(input, selected.span.end, ctx);
|
|
2030
|
+
if (!result.ok) {
|
|
2031
|
+
rollbackTrivia(ctx, mark);
|
|
2032
|
+
return { ...result, committed: true };
|
|
2033
|
+
}
|
|
2034
|
+
return {
|
|
2035
|
+
ok: true,
|
|
2036
|
+
value: [selected.value, result.value],
|
|
2037
|
+
span: { start: pos, end: result.span.end }
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
|
|
1966
2043
|
// src/combinators/attempt.ts
|
|
1967
2044
|
function attempt(parser2) {
|
|
1968
2045
|
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
@@ -1985,6 +2062,7 @@ function attempt(parser2) {
|
|
|
1985
2062
|
if (result.ok) return result;
|
|
1986
2063
|
rollbackCstCapture(ctx, mark);
|
|
1987
2064
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
2065
|
+
if (result.committed) return result;
|
|
1988
2066
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
1989
2067
|
}
|
|
1990
2068
|
};
|
|
@@ -2014,6 +2092,7 @@ function repItem(combinator, input, cur, ctx, guardable) {
|
|
|
2014
2092
|
const result = combinator.parse(input, pos, ctx);
|
|
2015
2093
|
if (!result.ok) {
|
|
2016
2094
|
rollbackTrivia(ctx, mark);
|
|
2095
|
+
if (result.committed) return { fail: result, failPos: pos };
|
|
2017
2096
|
return { fail: result, failPos: pos };
|
|
2018
2097
|
}
|
|
2019
2098
|
if (result.span.end === pos) {
|
|
@@ -2057,6 +2136,7 @@ function many(combinator, opts = {}) {
|
|
|
2057
2136
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2058
2137
|
if (item === "stop") break;
|
|
2059
2138
|
if ("fail" in item) {
|
|
2139
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2060
2140
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2061
2141
|
if (sync === void 0) break;
|
|
2062
2142
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2101,6 +2181,7 @@ function atLeast(combinator, min, max) {
|
|
|
2101
2181
|
while (count < min) {
|
|
2102
2182
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2103
2183
|
if (item === "stop" || "fail" in item) {
|
|
2184
|
+
if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
|
|
2104
2185
|
expected ??= deriveExpected(combinator);
|
|
2105
2186
|
return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
|
|
2106
2187
|
}
|
|
@@ -2113,6 +2194,7 @@ function atLeast(combinator, min, max) {
|
|
|
2113
2194
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2114
2195
|
if (item === "stop") break;
|
|
2115
2196
|
if ("fail" in item) {
|
|
2197
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2116
2198
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2117
2199
|
if (sync === void 0) break;
|
|
2118
2200
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2151,6 +2233,7 @@ function optional(combinator) {
|
|
|
2151
2233
|
const result = combinator.parse(input, pos, ctx);
|
|
2152
2234
|
if (result.ok) return result;
|
|
2153
2235
|
rollbackTrivia(ctx, mark);
|
|
2236
|
+
if (result.committed) return result;
|
|
2154
2237
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
2155
2238
|
}
|
|
2156
2239
|
};
|
|
@@ -2190,6 +2273,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2190
2273
|
values.push(first.value);
|
|
2191
2274
|
cur = first.span.end;
|
|
2192
2275
|
} else {
|
|
2276
|
+
if (first.committed) return first;
|
|
2193
2277
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2194
2278
|
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
2195
2279
|
if (min >= 1) return failAt2(pos);
|
|
@@ -2217,6 +2301,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2217
2301
|
const sep2 = separator.parse(input, sepPos, ctx);
|
|
2218
2302
|
if (!sep2.ok) {
|
|
2219
2303
|
rollbackTrivia(ctx, loopMark);
|
|
2304
|
+
if (sep2.committed) return sep2;
|
|
2220
2305
|
break;
|
|
2221
2306
|
}
|
|
2222
2307
|
const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
|
|
@@ -2232,6 +2317,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2232
2317
|
}
|
|
2233
2318
|
const next = combinator.parse(input, nextPos, ctx);
|
|
2234
2319
|
if (!next.ok) {
|
|
2320
|
+
if (next.committed) return next;
|
|
2235
2321
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2236
2322
|
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2237
2323
|
expected ??= deriveExpected(combinator);
|
|
@@ -2287,6 +2373,11 @@ function markUnusedValues(root) {
|
|
|
2287
2373
|
case "choice":
|
|
2288
2374
|
for (const p of def.parsers) visit(p, consumed);
|
|
2289
2375
|
return;
|
|
2376
|
+
case "dispatch":
|
|
2377
|
+
visit(def.selector, consumed);
|
|
2378
|
+
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2379
|
+
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2380
|
+
return;
|
|
2290
2381
|
case "node":
|
|
2291
2382
|
visit(def.parser, false);
|
|
2292
2383
|
return;
|
|
@@ -2562,6 +2653,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2562
2653
|
case "sequence":
|
|
2563
2654
|
case "choice":
|
|
2564
2655
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2656
|
+
case "dispatch":
|
|
2657
|
+
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2565
2658
|
case "sepBy":
|
|
2566
2659
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2567
2660
|
case "skip":
|
|
@@ -2629,6 +2722,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2629
2722
|
return parserHasTriviaSite(d.parser, seen);
|
|
2630
2723
|
case "choice":
|
|
2631
2724
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2725
|
+
case "dispatch":
|
|
2726
|
+
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2632
2727
|
case "grammar":
|
|
2633
2728
|
return parserHasTriviaSite(d.parser, seen);
|
|
2634
2729
|
case "lazy": {
|
|
@@ -2654,6 +2749,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2654
2749
|
case "sequence":
|
|
2655
2750
|
case "choice":
|
|
2656
2751
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2752
|
+
case "dispatch":
|
|
2753
|
+
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2657
2754
|
case "sepBy":
|
|
2658
2755
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2659
2756
|
case "skip":
|
|
@@ -3028,7 +3125,7 @@ function leaf(root, fn) {
|
|
|
3028
3125
|
}
|
|
3029
3126
|
|
|
3030
3127
|
// src/version.ts
|
|
3031
|
-
var PARSEMAN_VERSION = "0.
|
|
3128
|
+
var PARSEMAN_VERSION = "0.39.0";
|
|
3032
3129
|
|
|
3033
3130
|
// src/cst/host-mode.ts
|
|
3034
3131
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3184,6 +3281,8 @@ function classifyBroadArm(arm, resolve2) {
|
|
|
3184
3281
|
}
|
|
3185
3282
|
return null;
|
|
3186
3283
|
}
|
|
3284
|
+
case "dispatch":
|
|
3285
|
+
return walk2(d.selector);
|
|
3187
3286
|
default:
|
|
3188
3287
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3189
3288
|
}
|
|
@@ -3283,6 +3382,11 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3283
3382
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3284
3383
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3285
3384
|
if (rec[k]) kids.push(rec[k]);
|
|
3385
|
+
if (d.tag === "dispatch") {
|
|
3386
|
+
kids.push(d.selector);
|
|
3387
|
+
for (const c of d.cases) kids.push(c.parser);
|
|
3388
|
+
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3389
|
+
}
|
|
3286
3390
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3287
3391
|
if (d.tag === "lazy") {
|
|
3288
3392
|
try {
|
|
@@ -3389,6 +3493,12 @@ function childrenOf(d) {
|
|
|
3389
3493
|
case "sequence":
|
|
3390
3494
|
case "choice":
|
|
3391
3495
|
return d.parsers;
|
|
3496
|
+
case "dispatch":
|
|
3497
|
+
return [
|
|
3498
|
+
d.selector,
|
|
3499
|
+
...d.cases.map((c) => c.parser),
|
|
3500
|
+
...d.otherwise === void 0 ? [] : [d.otherwise]
|
|
3501
|
+
];
|
|
3392
3502
|
case "skip":
|
|
3393
3503
|
return [d.main, d.skipped];
|
|
3394
3504
|
case "sepBy":
|
|
@@ -3445,6 +3555,8 @@ function payloadKey(p, d) {
|
|
|
3445
3555
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3446
3556
|
case "sepBy":
|
|
3447
3557
|
return `sepBy\0${d.min}\0${d.max ?? ""}\0${d.trailing ?? ""}`;
|
|
3558
|
+
case "dispatch":
|
|
3559
|
+
return `dispatch\0${d.cases.map((c) => JSON.stringify(c.keys)).join("")}\0${d.otherwise !== void 0}`;
|
|
3448
3560
|
case "expect":
|
|
3449
3561
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3450
3562
|
case "scanTo":
|
|
@@ -3516,6 +3628,11 @@ function render(p, depth = 3) {
|
|
|
3516
3628
|
return `sequence(${kids.join(", ")})`;
|
|
3517
3629
|
case "choice":
|
|
3518
3630
|
return `choice(${kids.join(", ")})`;
|
|
3631
|
+
case "dispatch": {
|
|
3632
|
+
const arms = d.cases.map((c, i) => `when([${c.keys.map((k) => JSON.stringify(k)).join(", ")}], ${kids[i + 1] ?? ""})`);
|
|
3633
|
+
if (d.otherwise !== void 0) arms.push(`otherwise(${kids[kids.length - 1] ?? ""})`);
|
|
3634
|
+
return `dispatch(${kids[0] ?? ""}, ${arms.join(", ")})`;
|
|
3635
|
+
}
|
|
3519
3636
|
case "node":
|
|
3520
3637
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3521
3638
|
case "label":
|
|
@@ -3539,6 +3656,10 @@ function segment(d, index) {
|
|
|
3539
3656
|
return `seq[${index}]`;
|
|
3540
3657
|
case "choice":
|
|
3541
3658
|
return `choice[${index}]`;
|
|
3659
|
+
case "dispatch":
|
|
3660
|
+
if (index === 0) return "dispatch.selector";
|
|
3661
|
+
if (index <= d.cases.length) return `dispatch.when[${index - 1}]`;
|
|
3662
|
+
return "dispatch.otherwise";
|
|
3542
3663
|
case "node":
|
|
3543
3664
|
return `node(${d.type ?? ""})`;
|
|
3544
3665
|
case "label":
|
|
@@ -4792,6 +4913,8 @@ function children(def, winners) {
|
|
|
4792
4913
|
case "sequence":
|
|
4793
4914
|
case "choice":
|
|
4794
4915
|
return def.parsers;
|
|
4916
|
+
case "dispatch":
|
|
4917
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
4795
4918
|
case "many":
|
|
4796
4919
|
case "oneOrMore":
|
|
4797
4920
|
case "optional":
|
|
@@ -6256,6 +6379,8 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6256
6379
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6257
6380
|
return { alts };
|
|
6258
6381
|
}
|
|
6382
|
+
case "dispatch":
|
|
6383
|
+
return rec(d.selector);
|
|
6259
6384
|
case "sequence": {
|
|
6260
6385
|
const chain = [];
|
|
6261
6386
|
for (const term of d.parsers) {
|
|
@@ -6338,6 +6463,9 @@ function failReturn(expected, posExpr) {
|
|
|
6338
6463
|
function failReturnArr(expectedArr, posExpr) {
|
|
6339
6464
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6340
6465
|
}
|
|
6466
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6467
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6468
|
+
}
|
|
6341
6469
|
function hoistExpected(ctx, constArrSource) {
|
|
6342
6470
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6343
6471
|
if (name === void 0) {
|
|
@@ -6374,15 +6502,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6374
6502
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6375
6503
|
}
|
|
6376
6504
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6377
|
-
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
6505
|
+
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
|
|
6506
|
+
}
|
|
6507
|
+
function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
|
|
6508
|
+
if (ctx.failLabel) {
|
|
6509
|
+
if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
|
|
6510
|
+
return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
|
|
6511
|
+
}
|
|
6512
|
+
return committedReturnArr(expectedArr, posExpr);
|
|
6378
6513
|
}
|
|
6379
6514
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6380
6515
|
if (srcCtx !== "_ctx") {
|
|
6381
6516
|
if (ctx.failLabel) {
|
|
6382
6517
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6383
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; break ${ctx.failLabel} }`;
|
|
6518
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
|
|
6384
6519
|
}
|
|
6385
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; ${resultFromRecorded()} }`;
|
|
6520
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
|
|
6386
6521
|
}
|
|
6387
6522
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6388
6523
|
return resultFromRecorded();
|
|
@@ -6595,6 +6730,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6595
6730
|
// nothing committed remains.
|
|
6596
6731
|
case "choice":
|
|
6597
6732
|
return false;
|
|
6733
|
+
case "dispatch":
|
|
6734
|
+
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);
|
|
6598
6735
|
case "attempt":
|
|
6599
6736
|
return false;
|
|
6600
6737
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6639,6 +6776,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6639
6776
|
return true;
|
|
6640
6777
|
}
|
|
6641
6778
|
}
|
|
6779
|
+
function mayCommitFailure(p, seen = /* @__PURE__ */ new Set()) {
|
|
6780
|
+
if (seen.has(p)) return false;
|
|
6781
|
+
seen.add(p);
|
|
6782
|
+
const d = p._def;
|
|
6783
|
+
switch (d.tag) {
|
|
6784
|
+
case "dispatch":
|
|
6785
|
+
return true;
|
|
6786
|
+
case "choice":
|
|
6787
|
+
case "sequence":
|
|
6788
|
+
return d.parsers.some((x) => mayCommitFailure(x, seen));
|
|
6789
|
+
case "many":
|
|
6790
|
+
case "oneOrMore":
|
|
6791
|
+
case "optional":
|
|
6792
|
+
case "attempt":
|
|
6793
|
+
case "transform":
|
|
6794
|
+
case "label":
|
|
6795
|
+
case "field":
|
|
6796
|
+
case "grammar":
|
|
6797
|
+
case "node":
|
|
6798
|
+
return mayCommitFailure(d.parser, seen);
|
|
6799
|
+
case "sepBy":
|
|
6800
|
+
return mayCommitFailure(d.parser, seen) || mayCommitFailure(d.separator, seen);
|
|
6801
|
+
case "skip":
|
|
6802
|
+
return mayCommitFailure(d.main, seen) || mayCommitFailure(d.skipped, seen);
|
|
6803
|
+
case "token":
|
|
6804
|
+
case "leaf":
|
|
6805
|
+
return mayCommitFailure(d.parser, seen);
|
|
6806
|
+
case "withCtx":
|
|
6807
|
+
return mayCommitFailure(d.parser, seen);
|
|
6808
|
+
case "scanTo":
|
|
6809
|
+
return mayCommitFailure(d.sentinel, seen) || d.skip.some((x) => mayCommitFailure(x, seen));
|
|
6810
|
+
case "lazy": {
|
|
6811
|
+
try {
|
|
6812
|
+
return mayCommitFailure(d.thunk(), seen);
|
|
6813
|
+
} catch {
|
|
6814
|
+
return true;
|
|
6815
|
+
}
|
|
6816
|
+
}
|
|
6817
|
+
case "unknown":
|
|
6818
|
+
return true;
|
|
6819
|
+
default:
|
|
6820
|
+
return false;
|
|
6821
|
+
}
|
|
6822
|
+
}
|
|
6642
6823
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6643
6824
|
if (seen.has(p)) return false;
|
|
6644
6825
|
seen.add(p);
|
|
@@ -6660,6 +6841,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6660
6841
|
case "sequence":
|
|
6661
6842
|
case "choice":
|
|
6662
6843
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6844
|
+
case "dispatch":
|
|
6845
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
6663
6846
|
case "sepBy":
|
|
6664
6847
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6665
6848
|
case "many":
|
|
@@ -6706,6 +6889,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6706
6889
|
ctx.recordFail = savedRecord;
|
|
6707
6890
|
const ind0 = ind(ctx);
|
|
6708
6891
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
6892
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6709
6893
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6710
6894
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6711
6895
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6719,6 +6903,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6719
6903
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6720
6904
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6721
6905
|
] : [],
|
|
6906
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6722
6907
|
`${ind0}${lbl}: {`,
|
|
6723
6908
|
...r.stmts,
|
|
6724
6909
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6727,7 +6912,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6727
6912
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6728
6913
|
] : []
|
|
6729
6914
|
];
|
|
6730
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
6915
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6731
6916
|
}
|
|
6732
6917
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6733
6918
|
function emitLit(def, ctx, pos) {
|
|
@@ -7104,6 +7289,118 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7104
7289
|
}
|
|
7105
7290
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7106
7291
|
}
|
|
7292
|
+
function emitTailFallible(parser2, ctx, pos) {
|
|
7293
|
+
const savedRecord = ctx.recordFail;
|
|
7294
|
+
ctx.recordFail = true;
|
|
7295
|
+
const out = emitFallible(parser2, ctx, pos);
|
|
7296
|
+
ctx.recordFail = savedRecord;
|
|
7297
|
+
return out;
|
|
7298
|
+
}
|
|
7299
|
+
function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
7300
|
+
if (seen.has(p)) return false;
|
|
7301
|
+
seen.add(p);
|
|
7302
|
+
const d = p._def;
|
|
7303
|
+
switch (d.tag) {
|
|
7304
|
+
case "expect":
|
|
7305
|
+
case "recover":
|
|
7306
|
+
return true;
|
|
7307
|
+
case "many":
|
|
7308
|
+
case "oneOrMore":
|
|
7309
|
+
case "sepBy":
|
|
7310
|
+
return recovery || mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7311
|
+
case "choice":
|
|
7312
|
+
case "sequence": {
|
|
7313
|
+
for (const item of d.parsers) {
|
|
7314
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7315
|
+
}
|
|
7316
|
+
return false;
|
|
7317
|
+
}
|
|
7318
|
+
case "dispatch": {
|
|
7319
|
+
if (mayRecordRecoveryError(d.selector, recovery, seen)) return true;
|
|
7320
|
+
for (const item of d.cases) {
|
|
7321
|
+
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7322
|
+
}
|
|
7323
|
+
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7324
|
+
}
|
|
7325
|
+
case "attempt":
|
|
7326
|
+
case "transform":
|
|
7327
|
+
case "label":
|
|
7328
|
+
case "field":
|
|
7329
|
+
case "grammar":
|
|
7330
|
+
case "node":
|
|
7331
|
+
case "token":
|
|
7332
|
+
case "leaf":
|
|
7333
|
+
case "withCtx":
|
|
7334
|
+
case "optional":
|
|
7335
|
+
return mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7336
|
+
case "skip":
|
|
7337
|
+
return mayRecordRecoveryError(d.main, recovery, seen) || mayRecordRecoveryError(d.skipped, recovery, seen);
|
|
7338
|
+
case "scanTo":
|
|
7339
|
+
if (mayRecordRecoveryError(d.sentinel, recovery, seen)) return true;
|
|
7340
|
+
for (const item of d.skip) {
|
|
7341
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7342
|
+
}
|
|
7343
|
+
return false;
|
|
7344
|
+
case "lazy": {
|
|
7345
|
+
try {
|
|
7346
|
+
return mayRecordRecoveryError(d.thunk(), recovery, seen);
|
|
7347
|
+
} catch {
|
|
7348
|
+
return true;
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
7351
|
+
case "unknown":
|
|
7352
|
+
return true;
|
|
7353
|
+
default:
|
|
7354
|
+
return false;
|
|
7355
|
+
}
|
|
7356
|
+
}
|
|
7357
|
+
function emitDispatchCombinator(def, ctx, pos) {
|
|
7358
|
+
const selector = emit(def.selector, ctx, pos);
|
|
7359
|
+
const outV = v(ctx, "_dval");
|
|
7360
|
+
const outE = v(ctx, "_dend");
|
|
7361
|
+
const keyV = v(ctx, "_dkey");
|
|
7362
|
+
const stmts = [
|
|
7363
|
+
...selector.stmts,
|
|
7364
|
+
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7365
|
+
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7366
|
+
];
|
|
7367
|
+
let wroteBranch = false;
|
|
7368
|
+
const emitSelectedTail = (parser2, keyword, condition) => {
|
|
7369
|
+
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7370
|
+
stmts.push(head);
|
|
7371
|
+
ctx.indent++;
|
|
7372
|
+
const mayError = mayRecordRecoveryError(parser2, !!ctx.recovery);
|
|
7373
|
+
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7374
|
+
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7375
|
+
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7376
|
+
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7377
|
+
const tail = emitTailFallible(parser2, ctx, selector.endVar);
|
|
7378
|
+
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7379
|
+
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7380
|
+
stmts.push(
|
|
7381
|
+
...tail.stmts,
|
|
7382
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7383
|
+
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7384
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`
|
|
7385
|
+
);
|
|
7386
|
+
ctx.indent--;
|
|
7387
|
+
stmts.push(`${ind(ctx)}}`);
|
|
7388
|
+
};
|
|
7389
|
+
for (const entry of def.cases) {
|
|
7390
|
+
const condition = entry.keys.map((key) => `${keyV} === ${JSON.stringify(key)}`).join(" || ");
|
|
7391
|
+
emitSelectedTail(entry.parser, wroteBranch ? "else if" : "if", condition);
|
|
7392
|
+
wroteBranch = true;
|
|
7393
|
+
}
|
|
7394
|
+
if (def.otherwise) {
|
|
7395
|
+
if (wroteBranch) emitSelectedTail(def.otherwise, "else");
|
|
7396
|
+
else emitSelectedTail(def.otherwise, "if", "true");
|
|
7397
|
+
} else {
|
|
7398
|
+
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7399
|
+
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7400
|
+
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7401
|
+
}
|
|
7402
|
+
return { stmts, valueVar: outV, endVar: outE };
|
|
7403
|
+
}
|
|
7107
7404
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7108
7405
|
const superParser = def.parsers[superIndex];
|
|
7109
7406
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7225,12 +7522,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7225
7522
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7226
7523
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7227
7524
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7525
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7228
7526
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7229
7527
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7230
7528
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7231
7529
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7232
7530
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7233
|
-
const
|
|
7531
|
+
const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
|
|
7532
|
+
const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
7533
|
+
const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
|
|
7534
|
+
const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
|
|
7234
7535
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7235
7536
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7236
7537
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7245,7 +7546,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7245
7546
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7246
7547
|
);
|
|
7247
7548
|
}
|
|
7248
|
-
|
|
7549
|
+
if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
|
|
7550
|
+
const arm = emitFallible(p, ctx, pos, atStart);
|
|
7551
|
+
const { stmts: armStmts, okVar, valVar, endVar } = arm;
|
|
7249
7552
|
stmts.push(...armStmts);
|
|
7250
7553
|
if (autoNot && autoNot.length > 0) {
|
|
7251
7554
|
const anCode = v(ctx, "_anc");
|
|
@@ -7269,10 +7572,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7269
7572
|
stmts.push(`${ind(ctx)}}`);
|
|
7270
7573
|
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} });`} }`);
|
|
7271
7574
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7575
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7272
7576
|
} else {
|
|
7273
7577
|
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} }) }`;
|
|
7274
7578
|
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} })`} }`);
|
|
7275
7579
|
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} })`} }`);
|
|
7580
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7276
7581
|
}
|
|
7277
7582
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7278
7583
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7429,7 +7734,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7429
7734
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7430
7735
|
);
|
|
7431
7736
|
}
|
|
7432
|
-
const
|
|
7737
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
7738
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7433
7739
|
stmts.push(...iterStmts);
|
|
7434
7740
|
if (ctx.recovery) {
|
|
7435
7741
|
const rrV = v(ctx, "_rr");
|
|
@@ -7448,7 +7754,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7448
7754
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7449
7755
|
);
|
|
7450
7756
|
} else {
|
|
7451
|
-
stmts.push(`${ind(ctx)}if (!${iterOk}
|
|
7757
|
+
stmts.push(`${ind(ctx)}if (!${iterOk}) { ${rollback}${iter.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7758
|
+
stmts.push(`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
7452
7759
|
}
|
|
7453
7760
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7454
7761
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7460,10 +7767,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7460
7767
|
function emitOptional(def, ctx, pos) {
|
|
7461
7768
|
const valV = v(ctx, "_opt");
|
|
7462
7769
|
const endV = v(ctx, "_opte");
|
|
7463
|
-
const
|
|
7770
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
7771
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7464
7772
|
const ind0 = ind(ctx);
|
|
7465
7773
|
const stmts = [
|
|
7466
7774
|
...lblStmts,
|
|
7775
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7467
7776
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7468
7777
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7469
7778
|
];
|
|
@@ -7495,7 +7804,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7495
7804
|
...preGuard,
|
|
7496
7805
|
`${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`,
|
|
7497
7806
|
...inner.stmts,
|
|
7498
|
-
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7807
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7499
7808
|
],
|
|
7500
7809
|
valueVar: inner.valVar,
|
|
7501
7810
|
endVar: inner.endVar
|
|
@@ -7509,18 +7818,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7509
7818
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7510
7819
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7511
7820
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7512
|
-
const
|
|
7821
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
7822
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7513
7823
|
const stmts = [
|
|
7514
7824
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7515
7825
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7516
7826
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7517
7827
|
...firstStmts
|
|
7518
7828
|
];
|
|
7519
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7520
|
-
if (
|
|
7829
|
+
const failItem = (nextOkVar, nextMayCommit, itemPosVar, breakStmt) => {
|
|
7830
|
+
const commit = nextMayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : "";
|
|
7831
|
+
if (!rec) return [`${ind(ctx)}if (!${nextOkVar}) { ${commit}${breakStmt} }`];
|
|
7521
7832
|
const rr = v(ctx, "_rr");
|
|
7522
7833
|
return [
|
|
7523
7834
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
7835
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7524
7836
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7525
7837
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7526
7838
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7549,6 +7861,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7549
7861
|
stmts.push(
|
|
7550
7862
|
`${ind(ctx)}let ${didV} = false`,
|
|
7551
7863
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
7864
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7552
7865
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7553
7866
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7554
7867
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7559,6 +7872,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7559
7872
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7560
7873
|
ctx.indent++;
|
|
7561
7874
|
} else {
|
|
7875
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7562
7876
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7563
7877
|
ctx.indent++;
|
|
7564
7878
|
stmts.push(
|
|
@@ -7587,16 +7901,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7587
7901
|
);
|
|
7588
7902
|
sepAtPos = spV;
|
|
7589
7903
|
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}; `;
|
|
7590
|
-
const
|
|
7591
|
-
stmts
|
|
7904
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7905
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
7906
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7592
7907
|
const post = postSepMarks();
|
|
7593
7908
|
stmts.push(...post.decl);
|
|
7594
7909
|
const npV = v(ctx, "_np");
|
|
7595
7910
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7596
|
-
const
|
|
7911
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7912
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7597
7913
|
stmts.push(
|
|
7598
7914
|
...nextStmts,
|
|
7599
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7915
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7600
7916
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7601
7917
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7602
7918
|
);
|
|
@@ -7605,14 +7921,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7605
7921
|
const spV = v(ctx, "_sp");
|
|
7606
7922
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7607
7923
|
sepAtPos = spV;
|
|
7608
|
-
const
|
|
7609
|
-
stmts
|
|
7924
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7925
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
7926
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7610
7927
|
const npV = v(ctx, "_np");
|
|
7611
7928
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7612
|
-
const
|
|
7929
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7930
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7613
7931
|
stmts.push(
|
|
7614
7932
|
...nextStmts,
|
|
7615
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
7933
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7616
7934
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7617
7935
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7618
7936
|
);
|
|
@@ -7626,15 +7944,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7626
7944
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7627
7945
|
);
|
|
7628
7946
|
}
|
|
7629
|
-
const
|
|
7630
|
-
stmts
|
|
7947
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7948
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
7949
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7631
7950
|
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}; ` : "";
|
|
7632
7951
|
const post = postSepMarks();
|
|
7633
7952
|
stmts.push(...post.decl);
|
|
7634
|
-
const
|
|
7953
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
7954
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7635
7955
|
stmts.push(
|
|
7636
7956
|
...nextStmts,
|
|
7637
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7957
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7638
7958
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7639
7959
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7640
7960
|
);
|
|
@@ -8015,7 +8335,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
8015
8335
|
const rv = v(ctx, "_rt");
|
|
8016
8336
|
const vv = v(ctx, "_rtv");
|
|
8017
8337
|
const ev = v(ctx, "_rte");
|
|
8018
|
-
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 }`;
|
|
8338
|
+
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 } : {}) }`;
|
|
8019
8339
|
const stmts = [
|
|
8020
8340
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8021
8341
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8096,7 +8416,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8096
8416
|
return { stmts, valueVar: valVar, endVar };
|
|
8097
8417
|
}
|
|
8098
8418
|
function emitExpect(def, ctx, pos) {
|
|
8099
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8419
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8100
8420
|
const ind0 = ind(ctx);
|
|
8101
8421
|
const errV = v(ctx, "_err");
|
|
8102
8422
|
const stmts = [
|
|
@@ -8108,6 +8428,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8108
8428
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8109
8429
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8110
8430
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8431
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8111
8432
|
`${ind0} ${valVar} = ${errV}`,
|
|
8112
8433
|
`${ind0} ${endVar} = ${pos}`,
|
|
8113
8434
|
`${ind0} ${okVar} = true`,
|
|
@@ -8118,7 +8439,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8118
8439
|
function emit(p, ctx, pos) {
|
|
8119
8440
|
const replay = ctx.replayPrefix?.get(p);
|
|
8120
8441
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8121
|
-
const
|
|
8442
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8122
8443
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8123
8444
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8124
8445
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8158,14 +8479,14 @@ function emit(p, ctx, pos) {
|
|
|
8158
8479
|
ctx.indent = 1;
|
|
8159
8480
|
ctx.failLabel = "_pfail";
|
|
8160
8481
|
ctx.recordFail = true;
|
|
8161
|
-
const r =
|
|
8482
|
+
const r = dispatch2("_pos");
|
|
8162
8483
|
ctx.indent = savedIndent;
|
|
8163
8484
|
ctx.failLabel = savedFailLabel;
|
|
8164
8485
|
ctx.recordFail = savedRecord;
|
|
8165
8486
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8166
8487
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8167
8488
|
}
|
|
8168
|
-
return instrument(
|
|
8489
|
+
return instrument(dispatch2());
|
|
8169
8490
|
}
|
|
8170
8491
|
function emitDispatch(p, ctx, pos) {
|
|
8171
8492
|
const bal = p._balancedAmbient;
|
|
@@ -8198,6 +8519,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8198
8519
|
return emitSeq(def, ctx, pos);
|
|
8199
8520
|
case "choice":
|
|
8200
8521
|
return emitChoice(p, def, ctx, pos);
|
|
8522
|
+
case "dispatch":
|
|
8523
|
+
return emitDispatchCombinator(def, ctx, pos);
|
|
8201
8524
|
case "attempt":
|
|
8202
8525
|
return emitAttempt(p, def, ctx, pos);
|
|
8203
8526
|
case "many":
|
|
@@ -8418,6 +8741,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8418
8741
|
case "sequence":
|
|
8419
8742
|
case "choice":
|
|
8420
8743
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8744
|
+
case "dispatch":
|
|
8745
|
+
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
8421
8746
|
case "sepBy":
|
|
8422
8747
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8423
8748
|
case "scanTo":
|
|
@@ -8451,6 +8776,8 @@ function childrenOf2(def) {
|
|
|
8451
8776
|
case "sequence":
|
|
8452
8777
|
case "choice":
|
|
8453
8778
|
return def.parsers;
|
|
8779
|
+
case "dispatch":
|
|
8780
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
8454
8781
|
case "many":
|
|
8455
8782
|
case "attempt":
|
|
8456
8783
|
case "optional":
|
|
@@ -8494,6 +8821,7 @@ function childrenOf2(def) {
|
|
|
8494
8821
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8495
8822
|
"sequence",
|
|
8496
8823
|
"choice",
|
|
8824
|
+
"dispatch",
|
|
8497
8825
|
"many",
|
|
8498
8826
|
"oneOrMore",
|
|
8499
8827
|
"optional",
|
|
@@ -9318,6 +9646,8 @@ function childrenOf3(def) {
|
|
|
9318
9646
|
case "sequence":
|
|
9319
9647
|
case "choice":
|
|
9320
9648
|
return def.parsers;
|
|
9649
|
+
case "dispatch":
|
|
9650
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9321
9651
|
case "many":
|
|
9322
9652
|
case "oneOrMore":
|
|
9323
9653
|
case "optional":
|
|
@@ -9467,6 +9797,9 @@ function evalRuleMapIR(ir) {
|
|
|
9467
9797
|
"keywords",
|
|
9468
9798
|
"sequence",
|
|
9469
9799
|
"choice",
|
|
9800
|
+
"dispatch",
|
|
9801
|
+
"when",
|
|
9802
|
+
"otherwise",
|
|
9470
9803
|
"attempt",
|
|
9471
9804
|
"many",
|
|
9472
9805
|
"oneOrMore",
|
|
@@ -9500,6 +9833,9 @@ function evalRuleMapIR(ir) {
|
|
|
9500
9833
|
keywords,
|
|
9501
9834
|
sequence,
|
|
9502
9835
|
choice,
|
|
9836
|
+
dispatch,
|
|
9837
|
+
when,
|
|
9838
|
+
otherwise,
|
|
9503
9839
|
attempt,
|
|
9504
9840
|
many,
|
|
9505
9841
|
oneOrMore,
|
|
@@ -9685,6 +10021,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9685
10021
|
});
|
|
9686
10022
|
return `_gch([${items.join(", ")}])`;
|
|
9687
10023
|
}
|
|
10024
|
+
case "dispatch": {
|
|
10025
|
+
const arms = def.cases.map(
|
|
10026
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
10027
|
+
);
|
|
10028
|
+
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10029
|
+
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10030
|
+
}
|
|
9688
10031
|
case "many":
|
|
9689
10032
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9690
10033
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -10170,6 +10513,9 @@ function stripTsFromSource(node2, code) {
|
|
|
10170
10513
|
function isWordFactory(v2) {
|
|
10171
10514
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
10172
10515
|
}
|
|
10516
|
+
function isStaticValueEntry(v2) {
|
|
10517
|
+
return !!v2 && typeof v2 === "object" && "value" in v2 && "mfSrcs" in v2;
|
|
10518
|
+
}
|
|
10173
10519
|
function wordFactoryFromArgs(args, scope, code, mfs) {
|
|
10174
10520
|
const [boundaryOrOptsArg, optsArg] = args;
|
|
10175
10521
|
if (boundaryOrOptsArg?.type === "SpreadElement" || optsArg?.type === "SpreadElement") return null;
|
|
@@ -10239,9 +10585,41 @@ function gatedArmParts(e) {
|
|
|
10239
10585
|
}
|
|
10240
10586
|
return gate2 && combinator ? { gate: gate2, combinator } : null;
|
|
10241
10587
|
}
|
|
10588
|
+
function dispatchArmValue(node2, scope, code, mfs) {
|
|
10589
|
+
if (node2.type === "Identifier") {
|
|
10590
|
+
const value = anyValue(node2, scope, code, mfs);
|
|
10591
|
+
return isDispatchArm(value) ? value : null;
|
|
10592
|
+
}
|
|
10593
|
+
if (node2.type !== "CallExpression") return null;
|
|
10594
|
+
const callee = node2.callee;
|
|
10595
|
+
if (callee.type !== "Identifier") return null;
|
|
10596
|
+
if (callee.name === "otherwise") {
|
|
10597
|
+
const [parserArg] = node2.arguments;
|
|
10598
|
+
if (!parserArg || parserArg.type === "SpreadElement") return null;
|
|
10599
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
10600
|
+
if (!isCombinator(parserValue)) return null;
|
|
10601
|
+
return otherwise(parserValue);
|
|
10602
|
+
}
|
|
10603
|
+
if (callee.name === "when") {
|
|
10604
|
+
const [keyArg, parserArg] = node2.arguments;
|
|
10605
|
+
if (!keyArg || !parserArg || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
10606
|
+
const key = anyValue(keyArg, scope, code, mfs);
|
|
10607
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
10608
|
+
if (!isCombinator(parserValue)) return null;
|
|
10609
|
+
if (typeof key === "string") return when(key, parserValue);
|
|
10610
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue);
|
|
10611
|
+
}
|
|
10612
|
+
return null;
|
|
10613
|
+
}
|
|
10242
10614
|
function isCombinator(v2) {
|
|
10243
10615
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
10244
10616
|
}
|
|
10617
|
+
function isDispatchArm(v2) {
|
|
10618
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
10619
|
+
const rec = v2;
|
|
10620
|
+
if (rec.kind === "otherwise") return isCombinator(rec.parser);
|
|
10621
|
+
return rec.kind === "when" && Array.isArray(rec.keys) && rec.keys.every((key) => typeof key === "string") && isCombinator(rec.parser);
|
|
10622
|
+
}
|
|
10245
10623
|
function scopeGet(scope, name, mfs) {
|
|
10246
10624
|
const entry = scope.get(name);
|
|
10247
10625
|
if (!entry) return null;
|
|
@@ -10498,6 +10876,25 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10498
10876
|
return null;
|
|
10499
10877
|
}
|
|
10500
10878
|
}
|
|
10879
|
+
if (callee.name === "dispatch") {
|
|
10880
|
+
const [selectorArg, ...armArgs] = node2.arguments;
|
|
10881
|
+
if (!selectorArg || selectorArg.type === "SpreadElement") return null;
|
|
10882
|
+
const selector = anyValue(selectorArg, scope, code, mfs);
|
|
10883
|
+
if (!isCombinator(selector)) return null;
|
|
10884
|
+
const arms = [];
|
|
10885
|
+
for (const arg of armArgs) {
|
|
10886
|
+
if (arg.type === "SpreadElement") return null;
|
|
10887
|
+
const arm = dispatchArmValue(arg, scope, code, mfs);
|
|
10888
|
+
if (!isDispatchArm(arm)) return null;
|
|
10889
|
+
arms.push(arm);
|
|
10890
|
+
}
|
|
10891
|
+
try {
|
|
10892
|
+
const unsafeDispatch = dispatch;
|
|
10893
|
+
return unsafeDispatch(selector, ...arms);
|
|
10894
|
+
} catch {
|
|
10895
|
+
return null;
|
|
10896
|
+
}
|
|
10897
|
+
}
|
|
10501
10898
|
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
10502
10899
|
if (code === void 0 || mfs === void 0) return null;
|
|
10503
10900
|
const arms = [];
|
|
@@ -10583,6 +10980,10 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10583
10980
|
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
10584
10981
|
return entry.combi;
|
|
10585
10982
|
}
|
|
10983
|
+
if (isStaticValueEntry(entry)) {
|
|
10984
|
+
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
10985
|
+
return entry.value;
|
|
10986
|
+
}
|
|
10586
10987
|
return entry;
|
|
10587
10988
|
}
|
|
10588
10989
|
if (node2.type === "MemberExpression") {
|
|
@@ -10603,6 +11004,9 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10603
11004
|
if (callee.type === "Identifier" && callee.name === "makeWord") {
|
|
10604
11005
|
return wordFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
10605
11006
|
}
|
|
11007
|
+
if (callee.type === "Identifier" && (callee.name === "when" || callee.name === "otherwise")) {
|
|
11008
|
+
return dispatchArmValue(node2, scope, code, mfs);
|
|
11009
|
+
}
|
|
10606
11010
|
return exprToCombi(node2, scope, code, mfs);
|
|
10607
11011
|
}
|
|
10608
11012
|
return null;
|
|
@@ -10661,6 +11065,7 @@ function evalBodyStatements(statements, scope, code) {
|
|
|
10661
11065
|
if (val === null) return false;
|
|
10662
11066
|
const thisDeclMfSrcs = bodyMfs.slice(before);
|
|
10663
11067
|
if (isCombinator(val)) scope.set(name, { combi: val, mfSrcs: thisDeclMfSrcs });
|
|
11068
|
+
else if (isDispatchArm(val)) scope.set(name, { value: val, mfSrcs: thisDeclMfSrcs });
|
|
10664
11069
|
else scope.set(name, val);
|
|
10665
11070
|
}
|
|
10666
11071
|
}
|