parseman 0.37.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/keywords.d.ts +9 -8
- package/dist/combinators/keywords.d.ts.map +1 -1
- package/dist/combinators/parser.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 +432 -53
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +432 -53
- 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 +2 -1
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +517 -67
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.js +517 -67
- package/dist/plugin/index.js.map +4 -4
- package/dist/spec/index.cjs +133 -6
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +133 -6
- 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.cjs
CHANGED
|
@@ -120,6 +120,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
120
120
|
return d.parsers.every(me);
|
|
121
121
|
case "choice":
|
|
122
122
|
return d.parsers.some(me);
|
|
123
|
+
case "dispatch":
|
|
124
|
+
return me(d.selector);
|
|
123
125
|
case "transform":
|
|
124
126
|
case "label":
|
|
125
127
|
case "trivia":
|
|
@@ -193,6 +195,8 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
193
195
|
case "keywords":
|
|
194
196
|
return p._meta.firstSet;
|
|
195
197
|
// terminals: no refs, cached set is exact
|
|
198
|
+
case "dispatch":
|
|
199
|
+
return fs2(d.selector);
|
|
196
200
|
case "lazy":
|
|
197
201
|
try {
|
|
198
202
|
return fs2(d.thunk());
|
|
@@ -1141,6 +1145,8 @@ function derive(c, seen) {
|
|
|
1141
1145
|
return [def.label];
|
|
1142
1146
|
case "choice":
|
|
1143
1147
|
return def.parsers.flatMap(deriveExpected2);
|
|
1148
|
+
case "dispatch":
|
|
1149
|
+
return deriveExpected2(def.selector);
|
|
1144
1150
|
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1145
1151
|
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1146
1152
|
// able to fail first — deriving from term 0 alone named a token the parse
|
|
@@ -1279,6 +1285,7 @@ function choice(...args) {
|
|
|
1279
1285
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
1280
1286
|
if (result.ok) return result;
|
|
1281
1287
|
expected.push(...result.expected);
|
|
1288
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1282
1289
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1283
1290
|
}
|
|
1284
1291
|
return {
|
|
@@ -1319,6 +1326,7 @@ function choice(...args) {
|
|
|
1319
1326
|
rollbackCstCapture(ctx, mark);
|
|
1320
1327
|
if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
|
|
1321
1328
|
expected.push(...result.expected);
|
|
1329
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1322
1330
|
continue;
|
|
1323
1331
|
}
|
|
1324
1332
|
const checks = autoNot[i];
|
|
@@ -1998,6 +2006,75 @@ function sequence(...parsers) {
|
|
|
1998
2006
|
};
|
|
1999
2007
|
}
|
|
2000
2008
|
|
|
2009
|
+
// src/combinators/dispatch.ts
|
|
2010
|
+
function when(key, parser2) {
|
|
2011
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2012
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2013
|
+
for (const item of keys) {
|
|
2014
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2015
|
+
}
|
|
2016
|
+
return { kind: "when", keys, parser: parser2 };
|
|
2017
|
+
}
|
|
2018
|
+
function otherwise(parser2) {
|
|
2019
|
+
return { kind: "otherwise", parser: parser2 };
|
|
2020
|
+
}
|
|
2021
|
+
function dispatch(selector, ...arms) {
|
|
2022
|
+
let fallback;
|
|
2023
|
+
const cases = [];
|
|
2024
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2025
|
+
for (let i = 0; i < arms.length; i++) {
|
|
2026
|
+
const arm = arms[i];
|
|
2027
|
+
if (arm.kind === "otherwise") {
|
|
2028
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2029
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2030
|
+
fallback = arm.parser;
|
|
2031
|
+
continue;
|
|
2032
|
+
}
|
|
2033
|
+
for (const key of arm.keys) {
|
|
2034
|
+
if (seen.has(key)) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2035
|
+
seen.add(key);
|
|
2036
|
+
}
|
|
2037
|
+
cases.push({ keys: arm.keys, parser: arm.parser });
|
|
2038
|
+
}
|
|
2039
|
+
const meta = {
|
|
2040
|
+
firstSet: selector._meta.firstSet,
|
|
2041
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2042
|
+
isTrivia: false
|
|
2043
|
+
};
|
|
2044
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2045
|
+
for (const entry of cases) for (const key of entry.keys) byKey.set(key, entry.parser);
|
|
2046
|
+
return {
|
|
2047
|
+
_tag: "dispatch",
|
|
2048
|
+
_meta: meta,
|
|
2049
|
+
_def: {
|
|
2050
|
+
tag: "dispatch",
|
|
2051
|
+
selector,
|
|
2052
|
+
cases,
|
|
2053
|
+
...fallback === void 0 ? {} : { otherwise: fallback }
|
|
2054
|
+
},
|
|
2055
|
+
parse(input, pos, ctx) {
|
|
2056
|
+
const selected = selector.parse(input, pos, ctx);
|
|
2057
|
+
if (!selected.ok) return selected;
|
|
2058
|
+
const tail = byKey.get(selected.value) ?? fallback;
|
|
2059
|
+
if (tail === void 0) {
|
|
2060
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2061
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2062
|
+
}
|
|
2063
|
+
const mark = saveTriviaMark(ctx);
|
|
2064
|
+
const result = tail.parse(input, selected.span.end, ctx);
|
|
2065
|
+
if (!result.ok) {
|
|
2066
|
+
rollbackTrivia(ctx, mark);
|
|
2067
|
+
return { ...result, committed: true };
|
|
2068
|
+
}
|
|
2069
|
+
return {
|
|
2070
|
+
ok: true,
|
|
2071
|
+
value: [selected.value, result.value],
|
|
2072
|
+
span: { start: pos, end: result.span.end }
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2001
2078
|
// src/combinators/attempt.ts
|
|
2002
2079
|
function attempt(parser2) {
|
|
2003
2080
|
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
@@ -2020,6 +2097,7 @@ function attempt(parser2) {
|
|
|
2020
2097
|
if (result.ok) return result;
|
|
2021
2098
|
rollbackCstCapture(ctx, mark);
|
|
2022
2099
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
2100
|
+
if (result.committed) return result;
|
|
2023
2101
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
2024
2102
|
}
|
|
2025
2103
|
};
|
|
@@ -2049,6 +2127,7 @@ function repItem(combinator, input, cur, ctx, guardable) {
|
|
|
2049
2127
|
const result = combinator.parse(input, pos, ctx);
|
|
2050
2128
|
if (!result.ok) {
|
|
2051
2129
|
rollbackTrivia(ctx, mark);
|
|
2130
|
+
if (result.committed) return { fail: result, failPos: pos };
|
|
2052
2131
|
return { fail: result, failPos: pos };
|
|
2053
2132
|
}
|
|
2054
2133
|
if (result.span.end === pos) {
|
|
@@ -2092,6 +2171,7 @@ function many(combinator, opts = {}) {
|
|
|
2092
2171
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2093
2172
|
if (item === "stop") break;
|
|
2094
2173
|
if ("fail" in item) {
|
|
2174
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2095
2175
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2096
2176
|
if (sync === void 0) break;
|
|
2097
2177
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2136,6 +2216,7 @@ function atLeast(combinator, min, max) {
|
|
|
2136
2216
|
while (count < min) {
|
|
2137
2217
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2138
2218
|
if (item === "stop" || "fail" in item) {
|
|
2219
|
+
if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
|
|
2139
2220
|
expected ??= deriveExpected(combinator);
|
|
2140
2221
|
return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
|
|
2141
2222
|
}
|
|
@@ -2148,6 +2229,7 @@ function atLeast(combinator, min, max) {
|
|
|
2148
2229
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2149
2230
|
if (item === "stop") break;
|
|
2150
2231
|
if ("fail" in item) {
|
|
2232
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2151
2233
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2152
2234
|
if (sync === void 0) break;
|
|
2153
2235
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2186,6 +2268,7 @@ function optional(combinator) {
|
|
|
2186
2268
|
const result = combinator.parse(input, pos, ctx);
|
|
2187
2269
|
if (result.ok) return result;
|
|
2188
2270
|
rollbackTrivia(ctx, mark);
|
|
2271
|
+
if (result.committed) return result;
|
|
2189
2272
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
2190
2273
|
}
|
|
2191
2274
|
};
|
|
@@ -2225,6 +2308,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2225
2308
|
values.push(first.value);
|
|
2226
2309
|
cur = first.span.end;
|
|
2227
2310
|
} else {
|
|
2311
|
+
if (first.committed) return first;
|
|
2228
2312
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2229
2313
|
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
2230
2314
|
if (min >= 1) return failAt2(pos);
|
|
@@ -2252,6 +2336,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2252
2336
|
const sep2 = separator.parse(input, sepPos, ctx);
|
|
2253
2337
|
if (!sep2.ok) {
|
|
2254
2338
|
rollbackTrivia(ctx, loopMark);
|
|
2339
|
+
if (sep2.committed) return sep2;
|
|
2255
2340
|
break;
|
|
2256
2341
|
}
|
|
2257
2342
|
const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
|
|
@@ -2267,6 +2352,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2267
2352
|
}
|
|
2268
2353
|
const next = combinator.parse(input, nextPos, ctx);
|
|
2269
2354
|
if (!next.ok) {
|
|
2355
|
+
if (next.committed) return next;
|
|
2270
2356
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2271
2357
|
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2272
2358
|
expected ??= deriveExpected(combinator);
|
|
@@ -2322,6 +2408,11 @@ function markUnusedValues(root) {
|
|
|
2322
2408
|
case "choice":
|
|
2323
2409
|
for (const p of def.parsers) visit(p, consumed);
|
|
2324
2410
|
return;
|
|
2411
|
+
case "dispatch":
|
|
2412
|
+
visit(def.selector, consumed);
|
|
2413
|
+
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2414
|
+
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2415
|
+
return;
|
|
2325
2416
|
case "node":
|
|
2326
2417
|
visit(def.parser, false);
|
|
2327
2418
|
return;
|
|
@@ -2393,6 +2484,16 @@ function tagRule(r, key) {
|
|
|
2393
2484
|
r._ruleName = key;
|
|
2394
2485
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
2395
2486
|
}
|
|
2487
|
+
function isDefinableRef(v2) {
|
|
2488
|
+
return !!v2 && typeof v2 === "object" && "_def" in v2 && v2._def.tag === "lazy" && typeof v2.define === "function";
|
|
2489
|
+
}
|
|
2490
|
+
function ruleNameOf(r) {
|
|
2491
|
+
return r._ruleName;
|
|
2492
|
+
}
|
|
2493
|
+
function isNamedRuleRefForAnotherRule(r, key) {
|
|
2494
|
+
const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
|
|
2495
|
+
return name !== void 0 && name !== key;
|
|
2496
|
+
}
|
|
2396
2497
|
function rules(a, b) {
|
|
2397
2498
|
const factory = typeof a === "function" ? a : b;
|
|
2398
2499
|
const options = typeof a === "function" ? b : a;
|
|
@@ -2413,11 +2514,21 @@ function rules(a, b) {
|
|
|
2413
2514
|
for (const key of Object.keys(definitions)) {
|
|
2414
2515
|
const placeholder = cache[key];
|
|
2415
2516
|
const parser2 = definitions[key];
|
|
2416
|
-
if (placeholder
|
|
2417
|
-
|
|
2517
|
+
if (placeholder === parser2) {
|
|
2518
|
+
throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
|
|
2519
|
+
}
|
|
2520
|
+
if (isDefinableRef(placeholder)) {
|
|
2521
|
+
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
2418
2522
|
placeholder.define(parser2);
|
|
2419
2523
|
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
2420
2524
|
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
2525
|
+
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
2526
|
+
const alias = ref();
|
|
2527
|
+
tagRule(alias, key);
|
|
2528
|
+
alias.define(parser2);
|
|
2529
|
+
alias._meta.firstSet = parser2._meta.firstSet;
|
|
2530
|
+
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
2531
|
+
cache[key] = alias;
|
|
2421
2532
|
} else {
|
|
2422
2533
|
tagRule(parser2, key);
|
|
2423
2534
|
cache[key] = parser2;
|
|
@@ -2577,6 +2688,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2577
2688
|
case "sequence":
|
|
2578
2689
|
case "choice":
|
|
2579
2690
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2691
|
+
case "dispatch":
|
|
2692
|
+
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2580
2693
|
case "sepBy":
|
|
2581
2694
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2582
2695
|
case "skip":
|
|
@@ -2644,6 +2757,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2644
2757
|
return parserHasTriviaSite(d.parser, seen);
|
|
2645
2758
|
case "choice":
|
|
2646
2759
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2760
|
+
case "dispatch":
|
|
2761
|
+
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2647
2762
|
case "grammar":
|
|
2648
2763
|
return parserHasTriviaSite(d.parser, seen);
|
|
2649
2764
|
case "lazy": {
|
|
@@ -2669,6 +2784,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2669
2784
|
case "sequence":
|
|
2670
2785
|
case "choice":
|
|
2671
2786
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2787
|
+
case "dispatch":
|
|
2788
|
+
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2672
2789
|
case "sepBy":
|
|
2673
2790
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2674
2791
|
case "skip":
|
|
@@ -3043,7 +3160,7 @@ function leaf(root, fn) {
|
|
|
3043
3160
|
}
|
|
3044
3161
|
|
|
3045
3162
|
// src/version.ts
|
|
3046
|
-
var PARSEMAN_VERSION = "0.
|
|
3163
|
+
var PARSEMAN_VERSION = "0.39.0";
|
|
3047
3164
|
|
|
3048
3165
|
// src/cst/host-mode.ts
|
|
3049
3166
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3097,7 +3214,7 @@ function firstSetToString(fs2) {
|
|
|
3097
3214
|
if (fs2.kind === "empty") return "(empty)";
|
|
3098
3215
|
return fs2.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
|
|
3099
3216
|
}
|
|
3100
|
-
var
|
|
3217
|
+
var ruleNameOf2 = (p) => p._ruleName;
|
|
3101
3218
|
var SUGGESTIONS = {
|
|
3102
3219
|
"broad-recognizer": "if this arm leads with a keyword regex, use word('kw', boundary) / keywords([...]) \u2014 they expose an EXACT, gating first-set and lower to the same charCodeAt scan. A genuine scanTo fallback is fine; accept it in the gating snapshot if intentional.",
|
|
3103
3220
|
"leading-not": "let the arm lead with its actual consuming terminal (first-sets gate it automatically); keep not(...) only as a TRAILING boundary. Do not hand-roll not(not(...)) to fake gating \u2014 use peek(X), which is zero-width AND carries X first-set.",
|
|
@@ -3199,6 +3316,8 @@ function classifyBroadArm(arm, resolve2) {
|
|
|
3199
3316
|
}
|
|
3200
3317
|
return null;
|
|
3201
3318
|
}
|
|
3319
|
+
case "dispatch":
|
|
3320
|
+
return walk2(d.selector);
|
|
3202
3321
|
default:
|
|
3203
3322
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3204
3323
|
}
|
|
@@ -3255,7 +3374,7 @@ function detectAntiPatterns(rule, arms) {
|
|
|
3255
3374
|
return out;
|
|
3256
3375
|
}
|
|
3257
3376
|
function analyzeGating(entry, opts) {
|
|
3258
|
-
return analyzeGatingRules([[
|
|
3377
|
+
return analyzeGatingRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3259
3378
|
}
|
|
3260
3379
|
function analyzeGatingRules(ruleMap, opts) {
|
|
3261
3380
|
const raw = [];
|
|
@@ -3288,7 +3407,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3288
3407
|
return;
|
|
3289
3408
|
}
|
|
3290
3409
|
const d = def;
|
|
3291
|
-
const rule =
|
|
3410
|
+
const rule = ruleNameOf2(p) ?? enclosingRule;
|
|
3292
3411
|
if (d.tag === "choice") {
|
|
3293
3412
|
raw.push({ g: analyzeChoice(p, d, rule, opts?.resolveRef), rule });
|
|
3294
3413
|
antiPatterns.push(...detectAntiPatterns(rule, d.parsers));
|
|
@@ -3298,6 +3417,11 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3298
3417
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3299
3418
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3300
3419
|
if (rec[k]) kids.push(rec[k]);
|
|
3420
|
+
if (d.tag === "dispatch") {
|
|
3421
|
+
kids.push(d.selector);
|
|
3422
|
+
for (const c of d.cases) kids.push(c.parser);
|
|
3423
|
+
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3424
|
+
}
|
|
3301
3425
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3302
3426
|
if (d.tag === "lazy") {
|
|
3303
3427
|
try {
|
|
@@ -3307,7 +3431,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3307
3431
|
}
|
|
3308
3432
|
for (const k of kids) visit(k, rule);
|
|
3309
3433
|
};
|
|
3310
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
3434
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name);
|
|
3311
3435
|
const perRule = /* @__PURE__ */ new Map();
|
|
3312
3436
|
for (const r of raw) perRule.set(r.rule, (perRule.get(r.rule) ?? 0) + 1);
|
|
3313
3437
|
const seenInRule = /* @__PURE__ */ new Map();
|
|
@@ -3404,6 +3528,12 @@ function childrenOf(d) {
|
|
|
3404
3528
|
case "sequence":
|
|
3405
3529
|
case "choice":
|
|
3406
3530
|
return d.parsers;
|
|
3531
|
+
case "dispatch":
|
|
3532
|
+
return [
|
|
3533
|
+
d.selector,
|
|
3534
|
+
...d.cases.map((c) => c.parser),
|
|
3535
|
+
...d.otherwise === void 0 ? [] : [d.otherwise]
|
|
3536
|
+
];
|
|
3407
3537
|
case "skip":
|
|
3408
3538
|
return [d.main, d.skipped];
|
|
3409
3539
|
case "sepBy":
|
|
@@ -3431,7 +3561,7 @@ function childrenOf(d) {
|
|
|
3431
3561
|
}
|
|
3432
3562
|
}
|
|
3433
3563
|
}
|
|
3434
|
-
var
|
|
3564
|
+
var ruleNameOf3 = (p) => p._ruleName;
|
|
3435
3565
|
var fnKey = (src, fn) => src ?? (typeof fn === "function" ? String(fn) : "");
|
|
3436
3566
|
function payloadKey(p, d) {
|
|
3437
3567
|
switch (d.tag) {
|
|
@@ -3442,7 +3572,7 @@ function payloadKey(p, d) {
|
|
|
3442
3572
|
case "keywords":
|
|
3443
3573
|
return `keywords\0${[...d.words].join("")}\0${d.caseInsensitive}\0${d.boundary ?? ""}`;
|
|
3444
3574
|
case "lazy": {
|
|
3445
|
-
const n =
|
|
3575
|
+
const n = ruleNameOf3(p);
|
|
3446
3576
|
return n === void 0 ? `ref\0#${anonId(p)}` : `ref\0${n}`;
|
|
3447
3577
|
}
|
|
3448
3578
|
case "label":
|
|
@@ -3460,6 +3590,8 @@ function payloadKey(p, d) {
|
|
|
3460
3590
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3461
3591
|
case "sepBy":
|
|
3462
3592
|
return `sepBy\0${d.min}\0${d.max ?? ""}\0${d.trailing ?? ""}`;
|
|
3593
|
+
case "dispatch":
|
|
3594
|
+
return `dispatch\0${d.cases.map((c) => JSON.stringify(c.keys)).join("")}\0${d.otherwise !== void 0}`;
|
|
3463
3595
|
case "expect":
|
|
3464
3596
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3465
3597
|
case "scanTo":
|
|
@@ -3509,7 +3641,7 @@ var Interner = class {
|
|
|
3509
3641
|
var MAX_RENDER = 160;
|
|
3510
3642
|
function render(p, depth = 3) {
|
|
3511
3643
|
const d = p._def;
|
|
3512
|
-
const name =
|
|
3644
|
+
const name = ruleNameOf3(p);
|
|
3513
3645
|
switch (d.tag) {
|
|
3514
3646
|
case "literal":
|
|
3515
3647
|
return `literal('${d.value}')`;
|
|
@@ -3531,6 +3663,11 @@ function render(p, depth = 3) {
|
|
|
3531
3663
|
return `sequence(${kids.join(", ")})`;
|
|
3532
3664
|
case "choice":
|
|
3533
3665
|
return `choice(${kids.join(", ")})`;
|
|
3666
|
+
case "dispatch": {
|
|
3667
|
+
const arms = d.cases.map((c, i) => `when([${c.keys.map((k) => JSON.stringify(k)).join(", ")}], ${kids[i + 1] ?? ""})`);
|
|
3668
|
+
if (d.otherwise !== void 0) arms.push(`otherwise(${kids[kids.length - 1] ?? ""})`);
|
|
3669
|
+
return `dispatch(${kids[0] ?? ""}, ${arms.join(", ")})`;
|
|
3670
|
+
}
|
|
3534
3671
|
case "node":
|
|
3535
3672
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3536
3673
|
case "label":
|
|
@@ -3554,6 +3691,10 @@ function segment(d, index) {
|
|
|
3554
3691
|
return `seq[${index}]`;
|
|
3555
3692
|
case "choice":
|
|
3556
3693
|
return `choice[${index}]`;
|
|
3694
|
+
case "dispatch":
|
|
3695
|
+
if (index === 0) return "dispatch.selector";
|
|
3696
|
+
if (index <= d.cases.length) return `dispatch.when[${index - 1}]`;
|
|
3697
|
+
return "dispatch.otherwise";
|
|
3557
3698
|
case "node":
|
|
3558
3699
|
return `node(${d.type ?? ""})`;
|
|
3559
3700
|
case "label":
|
|
@@ -3688,7 +3829,7 @@ function keywordAlternationHazards(words, boundary) {
|
|
|
3688
3829
|
return out;
|
|
3689
3830
|
}
|
|
3690
3831
|
function analyzeDuplication(entry, opts) {
|
|
3691
|
-
return analyzeDuplicationRules([[
|
|
3832
|
+
return analyzeDuplicationRules([[ruleNameOf3(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3692
3833
|
}
|
|
3693
3834
|
function assertAnalyzable(ruleMap) {
|
|
3694
3835
|
for (const [name, rule] of ruleMap) {
|
|
@@ -3729,7 +3870,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
3729
3870
|
const visit = (p, rule, path2, enclosingNode, enclosingReducer) => {
|
|
3730
3871
|
if (visited.has(p)) return;
|
|
3731
3872
|
const d = p._def;
|
|
3732
|
-
const own =
|
|
3873
|
+
const own = ruleNameOf3(p);
|
|
3733
3874
|
const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path: path2 };
|
|
3734
3875
|
visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
|
|
3735
3876
|
const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
|
|
@@ -3742,12 +3883,12 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
3742
3883
|
if (d.tag === "lazy") {
|
|
3743
3884
|
try {
|
|
3744
3885
|
const target = d.thunk();
|
|
3745
|
-
visit(target,
|
|
3886
|
+
visit(target, ruleNameOf3(target) ?? ruleNameOf3(p) ?? here.rule, "", null, false);
|
|
3746
3887
|
} catch {
|
|
3747
3888
|
}
|
|
3748
3889
|
}
|
|
3749
3890
|
};
|
|
3750
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
3891
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf3(root) ?? name, "", null, false);
|
|
3751
3892
|
const accept = new Set(opts?.accept ?? []);
|
|
3752
3893
|
const used = /* @__PURE__ */ new Set();
|
|
3753
3894
|
const keep = (f) => {
|
|
@@ -4807,6 +4948,8 @@ function children(def, winners) {
|
|
|
4807
4948
|
case "sequence":
|
|
4808
4949
|
case "choice":
|
|
4809
4950
|
return def.parsers;
|
|
4951
|
+
case "dispatch":
|
|
4952
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
4810
4953
|
case "many":
|
|
4811
4954
|
case "oneOrMore":
|
|
4812
4955
|
case "optional":
|
|
@@ -6271,6 +6414,8 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6271
6414
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6272
6415
|
return { alts };
|
|
6273
6416
|
}
|
|
6417
|
+
case "dispatch":
|
|
6418
|
+
return rec(d.selector);
|
|
6274
6419
|
case "sequence": {
|
|
6275
6420
|
const chain = [];
|
|
6276
6421
|
for (const term of d.parsers) {
|
|
@@ -6353,6 +6498,9 @@ function failReturn(expected, posExpr) {
|
|
|
6353
6498
|
function failReturnArr(expectedArr, posExpr) {
|
|
6354
6499
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6355
6500
|
}
|
|
6501
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6502
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6503
|
+
}
|
|
6356
6504
|
function hoistExpected(ctx, constArrSource) {
|
|
6357
6505
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6358
6506
|
if (name === void 0) {
|
|
@@ -6389,15 +6537,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6389
6537
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6390
6538
|
}
|
|
6391
6539
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6392
|
-
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
6540
|
+
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
|
|
6541
|
+
}
|
|
6542
|
+
function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
|
|
6543
|
+
if (ctx.failLabel) {
|
|
6544
|
+
if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
|
|
6545
|
+
return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
|
|
6546
|
+
}
|
|
6547
|
+
return committedReturnArr(expectedArr, posExpr);
|
|
6393
6548
|
}
|
|
6394
6549
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6395
6550
|
if (srcCtx !== "_ctx") {
|
|
6396
6551
|
if (ctx.failLabel) {
|
|
6397
6552
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6398
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; break ${ctx.failLabel} }`;
|
|
6553
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
|
|
6399
6554
|
}
|
|
6400
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; ${resultFromRecorded()} }`;
|
|
6555
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
|
|
6401
6556
|
}
|
|
6402
6557
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6403
6558
|
return resultFromRecorded();
|
|
@@ -6610,6 +6765,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6610
6765
|
// nothing committed remains.
|
|
6611
6766
|
case "choice":
|
|
6612
6767
|
return false;
|
|
6768
|
+
case "dispatch":
|
|
6769
|
+
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);
|
|
6613
6770
|
case "attempt":
|
|
6614
6771
|
return false;
|
|
6615
6772
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6654,6 +6811,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6654
6811
|
return true;
|
|
6655
6812
|
}
|
|
6656
6813
|
}
|
|
6814
|
+
function mayCommitFailure(p, seen = /* @__PURE__ */ new Set()) {
|
|
6815
|
+
if (seen.has(p)) return false;
|
|
6816
|
+
seen.add(p);
|
|
6817
|
+
const d = p._def;
|
|
6818
|
+
switch (d.tag) {
|
|
6819
|
+
case "dispatch":
|
|
6820
|
+
return true;
|
|
6821
|
+
case "choice":
|
|
6822
|
+
case "sequence":
|
|
6823
|
+
return d.parsers.some((x) => mayCommitFailure(x, seen));
|
|
6824
|
+
case "many":
|
|
6825
|
+
case "oneOrMore":
|
|
6826
|
+
case "optional":
|
|
6827
|
+
case "attempt":
|
|
6828
|
+
case "transform":
|
|
6829
|
+
case "label":
|
|
6830
|
+
case "field":
|
|
6831
|
+
case "grammar":
|
|
6832
|
+
case "node":
|
|
6833
|
+
return mayCommitFailure(d.parser, seen);
|
|
6834
|
+
case "sepBy":
|
|
6835
|
+
return mayCommitFailure(d.parser, seen) || mayCommitFailure(d.separator, seen);
|
|
6836
|
+
case "skip":
|
|
6837
|
+
return mayCommitFailure(d.main, seen) || mayCommitFailure(d.skipped, seen);
|
|
6838
|
+
case "token":
|
|
6839
|
+
case "leaf":
|
|
6840
|
+
return mayCommitFailure(d.parser, seen);
|
|
6841
|
+
case "withCtx":
|
|
6842
|
+
return mayCommitFailure(d.parser, seen);
|
|
6843
|
+
case "scanTo":
|
|
6844
|
+
return mayCommitFailure(d.sentinel, seen) || d.skip.some((x) => mayCommitFailure(x, seen));
|
|
6845
|
+
case "lazy": {
|
|
6846
|
+
try {
|
|
6847
|
+
return mayCommitFailure(d.thunk(), seen);
|
|
6848
|
+
} catch {
|
|
6849
|
+
return true;
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
case "unknown":
|
|
6853
|
+
return true;
|
|
6854
|
+
default:
|
|
6855
|
+
return false;
|
|
6856
|
+
}
|
|
6857
|
+
}
|
|
6657
6858
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6658
6859
|
if (seen.has(p)) return false;
|
|
6659
6860
|
seen.add(p);
|
|
@@ -6675,6 +6876,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6675
6876
|
case "sequence":
|
|
6676
6877
|
case "choice":
|
|
6677
6878
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6879
|
+
case "dispatch":
|
|
6880
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
6678
6881
|
case "sepBy":
|
|
6679
6882
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6680
6883
|
case "many":
|
|
@@ -6721,6 +6924,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6721
6924
|
ctx.recordFail = savedRecord;
|
|
6722
6925
|
const ind0 = ind(ctx);
|
|
6723
6926
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
6927
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6724
6928
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6725
6929
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6726
6930
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6734,6 +6938,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6734
6938
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6735
6939
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6736
6940
|
] : [],
|
|
6941
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6737
6942
|
`${ind0}${lbl}: {`,
|
|
6738
6943
|
...r.stmts,
|
|
6739
6944
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6742,7 +6947,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6742
6947
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6743
6948
|
] : []
|
|
6744
6949
|
];
|
|
6745
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
6950
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6746
6951
|
}
|
|
6747
6952
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6748
6953
|
function emitLit(def, ctx, pos) {
|
|
@@ -7119,6 +7324,118 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7119
7324
|
}
|
|
7120
7325
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7121
7326
|
}
|
|
7327
|
+
function emitTailFallible(parser2, ctx, pos) {
|
|
7328
|
+
const savedRecord = ctx.recordFail;
|
|
7329
|
+
ctx.recordFail = true;
|
|
7330
|
+
const out = emitFallible(parser2, ctx, pos);
|
|
7331
|
+
ctx.recordFail = savedRecord;
|
|
7332
|
+
return out;
|
|
7333
|
+
}
|
|
7334
|
+
function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
7335
|
+
if (seen.has(p)) return false;
|
|
7336
|
+
seen.add(p);
|
|
7337
|
+
const d = p._def;
|
|
7338
|
+
switch (d.tag) {
|
|
7339
|
+
case "expect":
|
|
7340
|
+
case "recover":
|
|
7341
|
+
return true;
|
|
7342
|
+
case "many":
|
|
7343
|
+
case "oneOrMore":
|
|
7344
|
+
case "sepBy":
|
|
7345
|
+
return recovery || mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7346
|
+
case "choice":
|
|
7347
|
+
case "sequence": {
|
|
7348
|
+
for (const item of d.parsers) {
|
|
7349
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7350
|
+
}
|
|
7351
|
+
return false;
|
|
7352
|
+
}
|
|
7353
|
+
case "dispatch": {
|
|
7354
|
+
if (mayRecordRecoveryError(d.selector, recovery, seen)) return true;
|
|
7355
|
+
for (const item of d.cases) {
|
|
7356
|
+
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7357
|
+
}
|
|
7358
|
+
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7359
|
+
}
|
|
7360
|
+
case "attempt":
|
|
7361
|
+
case "transform":
|
|
7362
|
+
case "label":
|
|
7363
|
+
case "field":
|
|
7364
|
+
case "grammar":
|
|
7365
|
+
case "node":
|
|
7366
|
+
case "token":
|
|
7367
|
+
case "leaf":
|
|
7368
|
+
case "withCtx":
|
|
7369
|
+
case "optional":
|
|
7370
|
+
return mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7371
|
+
case "skip":
|
|
7372
|
+
return mayRecordRecoveryError(d.main, recovery, seen) || mayRecordRecoveryError(d.skipped, recovery, seen);
|
|
7373
|
+
case "scanTo":
|
|
7374
|
+
if (mayRecordRecoveryError(d.sentinel, recovery, seen)) return true;
|
|
7375
|
+
for (const item of d.skip) {
|
|
7376
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7377
|
+
}
|
|
7378
|
+
return false;
|
|
7379
|
+
case "lazy": {
|
|
7380
|
+
try {
|
|
7381
|
+
return mayRecordRecoveryError(d.thunk(), recovery, seen);
|
|
7382
|
+
} catch {
|
|
7383
|
+
return true;
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7386
|
+
case "unknown":
|
|
7387
|
+
return true;
|
|
7388
|
+
default:
|
|
7389
|
+
return false;
|
|
7390
|
+
}
|
|
7391
|
+
}
|
|
7392
|
+
function emitDispatchCombinator(def, ctx, pos) {
|
|
7393
|
+
const selector = emit(def.selector, ctx, pos);
|
|
7394
|
+
const outV = v(ctx, "_dval");
|
|
7395
|
+
const outE = v(ctx, "_dend");
|
|
7396
|
+
const keyV = v(ctx, "_dkey");
|
|
7397
|
+
const stmts = [
|
|
7398
|
+
...selector.stmts,
|
|
7399
|
+
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7400
|
+
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7401
|
+
];
|
|
7402
|
+
let wroteBranch = false;
|
|
7403
|
+
const emitSelectedTail = (parser2, keyword, condition) => {
|
|
7404
|
+
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7405
|
+
stmts.push(head);
|
|
7406
|
+
ctx.indent++;
|
|
7407
|
+
const mayError = mayRecordRecoveryError(parser2, !!ctx.recovery);
|
|
7408
|
+
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7409
|
+
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7410
|
+
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7411
|
+
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7412
|
+
const tail = emitTailFallible(parser2, ctx, selector.endVar);
|
|
7413
|
+
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7414
|
+
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7415
|
+
stmts.push(
|
|
7416
|
+
...tail.stmts,
|
|
7417
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7418
|
+
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7419
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`
|
|
7420
|
+
);
|
|
7421
|
+
ctx.indent--;
|
|
7422
|
+
stmts.push(`${ind(ctx)}}`);
|
|
7423
|
+
};
|
|
7424
|
+
for (const entry of def.cases) {
|
|
7425
|
+
const condition = entry.keys.map((key) => `${keyV} === ${JSON.stringify(key)}`).join(" || ");
|
|
7426
|
+
emitSelectedTail(entry.parser, wroteBranch ? "else if" : "if", condition);
|
|
7427
|
+
wroteBranch = true;
|
|
7428
|
+
}
|
|
7429
|
+
if (def.otherwise) {
|
|
7430
|
+
if (wroteBranch) emitSelectedTail(def.otherwise, "else");
|
|
7431
|
+
else emitSelectedTail(def.otherwise, "if", "true");
|
|
7432
|
+
} else {
|
|
7433
|
+
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7434
|
+
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7435
|
+
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7436
|
+
}
|
|
7437
|
+
return { stmts, valueVar: outV, endVar: outE };
|
|
7438
|
+
}
|
|
7122
7439
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7123
7440
|
const superParser = def.parsers[superIndex];
|
|
7124
7441
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7240,12 +7557,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7240
7557
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7241
7558
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7242
7559
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7560
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7243
7561
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7244
7562
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7245
7563
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7246
7564
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7247
7565
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7248
|
-
const
|
|
7566
|
+
const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
|
|
7567
|
+
const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
7568
|
+
const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
|
|
7569
|
+
const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
|
|
7249
7570
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7250
7571
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7251
7572
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7260,7 +7581,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7260
7581
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7261
7582
|
);
|
|
7262
7583
|
}
|
|
7263
|
-
|
|
7584
|
+
if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
|
|
7585
|
+
const arm = emitFallible(p, ctx, pos, atStart);
|
|
7586
|
+
const { stmts: armStmts, okVar, valVar, endVar } = arm;
|
|
7264
7587
|
stmts.push(...armStmts);
|
|
7265
7588
|
if (autoNot && autoNot.length > 0) {
|
|
7266
7589
|
const anCode = v(ctx, "_anc");
|
|
@@ -7284,10 +7607,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7284
7607
|
stmts.push(`${ind(ctx)}}`);
|
|
7285
7608
|
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} });`} }`);
|
|
7286
7609
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7610
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7287
7611
|
} else {
|
|
7288
7612
|
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} }) }`;
|
|
7289
7613
|
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} })`} }`);
|
|
7290
7614
|
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} })`} }`);
|
|
7615
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7291
7616
|
}
|
|
7292
7617
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7293
7618
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7444,7 +7769,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7444
7769
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7445
7770
|
);
|
|
7446
7771
|
}
|
|
7447
|
-
const
|
|
7772
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
7773
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7448
7774
|
stmts.push(...iterStmts);
|
|
7449
7775
|
if (ctx.recovery) {
|
|
7450
7776
|
const rrV = v(ctx, "_rr");
|
|
@@ -7463,7 +7789,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7463
7789
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7464
7790
|
);
|
|
7465
7791
|
} else {
|
|
7466
|
-
stmts.push(`${ind(ctx)}if (!${iterOk}
|
|
7792
|
+
stmts.push(`${ind(ctx)}if (!${iterOk}) { ${rollback}${iter.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7793
|
+
stmts.push(`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
7467
7794
|
}
|
|
7468
7795
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7469
7796
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7475,10 +7802,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7475
7802
|
function emitOptional(def, ctx, pos) {
|
|
7476
7803
|
const valV = v(ctx, "_opt");
|
|
7477
7804
|
const endV = v(ctx, "_opte");
|
|
7478
|
-
const
|
|
7805
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
7806
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7479
7807
|
const ind0 = ind(ctx);
|
|
7480
7808
|
const stmts = [
|
|
7481
7809
|
...lblStmts,
|
|
7810
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7482
7811
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7483
7812
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7484
7813
|
];
|
|
@@ -7510,7 +7839,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7510
7839
|
...preGuard,
|
|
7511
7840
|
`${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`,
|
|
7512
7841
|
...inner.stmts,
|
|
7513
|
-
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7842
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7514
7843
|
],
|
|
7515
7844
|
valueVar: inner.valVar,
|
|
7516
7845
|
endVar: inner.endVar
|
|
@@ -7524,18 +7853,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7524
7853
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7525
7854
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7526
7855
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7527
|
-
const
|
|
7856
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
7857
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7528
7858
|
const stmts = [
|
|
7529
7859
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7530
7860
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7531
7861
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7532
7862
|
...firstStmts
|
|
7533
7863
|
];
|
|
7534
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7535
|
-
if (
|
|
7864
|
+
const failItem = (nextOkVar, nextMayCommit, itemPosVar, breakStmt) => {
|
|
7865
|
+
const commit = nextMayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : "";
|
|
7866
|
+
if (!rec) return [`${ind(ctx)}if (!${nextOkVar}) { ${commit}${breakStmt} }`];
|
|
7536
7867
|
const rr = v(ctx, "_rr");
|
|
7537
7868
|
return [
|
|
7538
7869
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
7870
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7539
7871
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7540
7872
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7541
7873
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7564,6 +7896,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7564
7896
|
stmts.push(
|
|
7565
7897
|
`${ind(ctx)}let ${didV} = false`,
|
|
7566
7898
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
7899
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7567
7900
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7568
7901
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7569
7902
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7574,6 +7907,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7574
7907
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7575
7908
|
ctx.indent++;
|
|
7576
7909
|
} else {
|
|
7910
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7577
7911
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7578
7912
|
ctx.indent++;
|
|
7579
7913
|
stmts.push(
|
|
@@ -7602,16 +7936,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7602
7936
|
);
|
|
7603
7937
|
sepAtPos = spV;
|
|
7604
7938
|
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}; `;
|
|
7605
|
-
const
|
|
7606
|
-
stmts
|
|
7939
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7940
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
7941
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7607
7942
|
const post = postSepMarks();
|
|
7608
7943
|
stmts.push(...post.decl);
|
|
7609
7944
|
const npV = v(ctx, "_np");
|
|
7610
7945
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7611
|
-
const
|
|
7946
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7947
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7612
7948
|
stmts.push(
|
|
7613
7949
|
...nextStmts,
|
|
7614
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7950
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7615
7951
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7616
7952
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7617
7953
|
);
|
|
@@ -7620,14 +7956,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7620
7956
|
const spV = v(ctx, "_sp");
|
|
7621
7957
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7622
7958
|
sepAtPos = spV;
|
|
7623
|
-
const
|
|
7624
|
-
stmts
|
|
7959
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7960
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
7961
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7625
7962
|
const npV = v(ctx, "_np");
|
|
7626
7963
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7627
|
-
const
|
|
7964
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7965
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7628
7966
|
stmts.push(
|
|
7629
7967
|
...nextStmts,
|
|
7630
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
7968
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7631
7969
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7632
7970
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7633
7971
|
);
|
|
@@ -7641,15 +7979,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7641
7979
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7642
7980
|
);
|
|
7643
7981
|
}
|
|
7644
|
-
const
|
|
7645
|
-
stmts
|
|
7982
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7983
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
7984
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7646
7985
|
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}; ` : "";
|
|
7647
7986
|
const post = postSepMarks();
|
|
7648
7987
|
stmts.push(...post.decl);
|
|
7649
|
-
const
|
|
7988
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
7989
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7650
7990
|
stmts.push(
|
|
7651
7991
|
...nextStmts,
|
|
7652
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7992
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7653
7993
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7654
7994
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7655
7995
|
);
|
|
@@ -8030,7 +8370,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
8030
8370
|
const rv = v(ctx, "_rt");
|
|
8031
8371
|
const vv = v(ctx, "_rtv");
|
|
8032
8372
|
const ev = v(ctx, "_rte");
|
|
8033
|
-
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 }`;
|
|
8373
|
+
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 } : {}) }`;
|
|
8034
8374
|
const stmts = [
|
|
8035
8375
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8036
8376
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8111,7 +8451,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8111
8451
|
return { stmts, valueVar: valVar, endVar };
|
|
8112
8452
|
}
|
|
8113
8453
|
function emitExpect(def, ctx, pos) {
|
|
8114
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8454
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8115
8455
|
const ind0 = ind(ctx);
|
|
8116
8456
|
const errV = v(ctx, "_err");
|
|
8117
8457
|
const stmts = [
|
|
@@ -8123,6 +8463,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8123
8463
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8124
8464
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8125
8465
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8466
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8126
8467
|
`${ind0} ${valVar} = ${errV}`,
|
|
8127
8468
|
`${ind0} ${endVar} = ${pos}`,
|
|
8128
8469
|
`${ind0} ${okVar} = true`,
|
|
@@ -8133,7 +8474,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8133
8474
|
function emit(p, ctx, pos) {
|
|
8134
8475
|
const replay = ctx.replayPrefix?.get(p);
|
|
8135
8476
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8136
|
-
const
|
|
8477
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8137
8478
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8138
8479
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8139
8480
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8173,14 +8514,14 @@ function emit(p, ctx, pos) {
|
|
|
8173
8514
|
ctx.indent = 1;
|
|
8174
8515
|
ctx.failLabel = "_pfail";
|
|
8175
8516
|
ctx.recordFail = true;
|
|
8176
|
-
const r =
|
|
8517
|
+
const r = dispatch2("_pos");
|
|
8177
8518
|
ctx.indent = savedIndent;
|
|
8178
8519
|
ctx.failLabel = savedFailLabel;
|
|
8179
8520
|
ctx.recordFail = savedRecord;
|
|
8180
8521
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8181
8522
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8182
8523
|
}
|
|
8183
|
-
return instrument(
|
|
8524
|
+
return instrument(dispatch2());
|
|
8184
8525
|
}
|
|
8185
8526
|
function emitDispatch(p, ctx, pos) {
|
|
8186
8527
|
const bal = p._balancedAmbient;
|
|
@@ -8213,6 +8554,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8213
8554
|
return emitSeq(def, ctx, pos);
|
|
8214
8555
|
case "choice":
|
|
8215
8556
|
return emitChoice(p, def, ctx, pos);
|
|
8557
|
+
case "dispatch":
|
|
8558
|
+
return emitDispatchCombinator(def, ctx, pos);
|
|
8216
8559
|
case "attempt":
|
|
8217
8560
|
return emitAttempt(p, def, ctx, pos);
|
|
8218
8561
|
case "many":
|
|
@@ -8433,6 +8776,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8433
8776
|
case "sequence":
|
|
8434
8777
|
case "choice":
|
|
8435
8778
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8779
|
+
case "dispatch":
|
|
8780
|
+
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
8436
8781
|
case "sepBy":
|
|
8437
8782
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8438
8783
|
case "scanTo":
|
|
@@ -8466,6 +8811,8 @@ function childrenOf2(def) {
|
|
|
8466
8811
|
case "sequence":
|
|
8467
8812
|
case "choice":
|
|
8468
8813
|
return def.parsers;
|
|
8814
|
+
case "dispatch":
|
|
8815
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
8469
8816
|
case "many":
|
|
8470
8817
|
case "attempt":
|
|
8471
8818
|
case "optional":
|
|
@@ -8509,6 +8856,7 @@ function childrenOf2(def) {
|
|
|
8509
8856
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8510
8857
|
"sequence",
|
|
8511
8858
|
"choice",
|
|
8859
|
+
"dispatch",
|
|
8512
8860
|
"many",
|
|
8513
8861
|
"oneOrMore",
|
|
8514
8862
|
"optional",
|
|
@@ -8602,7 +8950,7 @@ function ruleDependencies(ruleMap) {
|
|
|
8602
8950
|
const seen = /* @__PURE__ */ new Set();
|
|
8603
8951
|
const walk2 = (p, isRoot) => {
|
|
8604
8952
|
const def = p._def;
|
|
8605
|
-
const boundary = def.tag === "lazy" ?
|
|
8953
|
+
const boundary = def.tag === "lazy" ? nameOf.get(p) ?? p._ruleName : nameOf.get(p);
|
|
8606
8954
|
if (!isRoot && boundary !== void 0) {
|
|
8607
8955
|
found.add(boundary);
|
|
8608
8956
|
return;
|
|
@@ -9333,6 +9681,8 @@ function childrenOf3(def) {
|
|
|
9333
9681
|
case "sequence":
|
|
9334
9682
|
case "choice":
|
|
9335
9683
|
return def.parsers;
|
|
9684
|
+
case "dispatch":
|
|
9685
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9336
9686
|
case "many":
|
|
9337
9687
|
case "oneOrMore":
|
|
9338
9688
|
case "optional":
|
|
@@ -9367,7 +9717,7 @@ function childrenOf3(def) {
|
|
|
9367
9717
|
return [];
|
|
9368
9718
|
}
|
|
9369
9719
|
}
|
|
9370
|
-
var
|
|
9720
|
+
var ruleNameOf4 = (c) => c._ruleName;
|
|
9371
9721
|
function lazyTarget(c) {
|
|
9372
9722
|
if (c._def.tag !== "lazy") return null;
|
|
9373
9723
|
try {
|
|
@@ -9482,6 +9832,9 @@ function evalRuleMapIR(ir) {
|
|
|
9482
9832
|
"keywords",
|
|
9483
9833
|
"sequence",
|
|
9484
9834
|
"choice",
|
|
9835
|
+
"dispatch",
|
|
9836
|
+
"when",
|
|
9837
|
+
"otherwise",
|
|
9485
9838
|
"attempt",
|
|
9486
9839
|
"many",
|
|
9487
9840
|
"oneOrMore",
|
|
@@ -9515,6 +9868,9 @@ function evalRuleMapIR(ir) {
|
|
|
9515
9868
|
keywords,
|
|
9516
9869
|
sequence,
|
|
9517
9870
|
choice,
|
|
9871
|
+
dispatch,
|
|
9872
|
+
when,
|
|
9873
|
+
otherwise,
|
|
9518
9874
|
attempt,
|
|
9519
9875
|
many,
|
|
9520
9876
|
oneOrMore,
|
|
@@ -9549,12 +9905,16 @@ var Serializer = class {
|
|
|
9549
9905
|
emitted = /* @__PURE__ */ new Set();
|
|
9550
9906
|
decls = [];
|
|
9551
9907
|
ruleValues = /* @__PURE__ */ new Set();
|
|
9908
|
+
localRuleNames = /* @__PURE__ */ new Map();
|
|
9552
9909
|
ruleMap;
|
|
9553
9910
|
scanSkip;
|
|
9554
9911
|
constructor(ruleMap, scanSkip = []) {
|
|
9555
9912
|
this.ruleMap = ruleMap;
|
|
9556
9913
|
this.scanSkip = scanSkip;
|
|
9557
|
-
for (const [, c] of ruleMap)
|
|
9914
|
+
for (const [name, c] of ruleMap) {
|
|
9915
|
+
this.localRuleNames.set(c, name);
|
|
9916
|
+
this.ruleValues.add(this.body(c));
|
|
9917
|
+
}
|
|
9558
9918
|
}
|
|
9559
9919
|
/** A grammar-level `scanSkip` unit is an opaque TERMINAL (a string, a balanced
|
|
9560
9920
|
* bracket) — it must not reach a grammar-rule ref (`g[name]`), because the
|
|
@@ -9565,7 +9925,7 @@ var Serializer = class {
|
|
|
9565
9925
|
if (seen.has(c)) return;
|
|
9566
9926
|
seen.add(c);
|
|
9567
9927
|
if (c._def.tag === "lazy") {
|
|
9568
|
-
if (
|
|
9928
|
+
if (ruleNameOf4(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
|
|
9569
9929
|
const target = lazyTarget(c);
|
|
9570
9930
|
if (target) this.assertNoRuleRef(target, seen);
|
|
9571
9931
|
return;
|
|
@@ -9576,7 +9936,7 @@ var Serializer = class {
|
|
|
9576
9936
|
* its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
|
|
9577
9937
|
* `g[name]` ref — only the top-level entry is unwrapped. */
|
|
9578
9938
|
body(c) {
|
|
9579
|
-
return c._def.tag === "lazy" &&
|
|
9939
|
+
return c._def.tag === "lazy" && ruleNameOf4(c) !== void 0 ? lazyTarget(c) ?? c : c;
|
|
9580
9940
|
}
|
|
9581
9941
|
run() {
|
|
9582
9942
|
for (const [, c] of this.ruleMap) this.analyze(this.body(c), /* @__PURE__ */ new Set());
|
|
@@ -9618,7 +9978,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9618
9978
|
analyze(c, active) {
|
|
9619
9979
|
const def = c._def;
|
|
9620
9980
|
if (def.tag === "lazy") {
|
|
9621
|
-
if (
|
|
9981
|
+
if (ruleNameOf4(c) !== void 0) return;
|
|
9622
9982
|
const target = lazyTarget(c);
|
|
9623
9983
|
if (!target) throw new Unserializable("unresolved unnamed ref");
|
|
9624
9984
|
if (active.has(target)) {
|
|
@@ -9670,7 +10030,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9670
10030
|
const kid = (x) => this.ref(x, selfOf);
|
|
9671
10031
|
switch (def.tag) {
|
|
9672
10032
|
case "lazy": {
|
|
9673
|
-
|
|
10033
|
+
const name = this.localRuleNames.get(c) ?? ruleNameOf4(c);
|
|
10034
|
+
if (name !== void 0) return `g[${JSON.stringify(name)}]`;
|
|
9674
10035
|
const target = lazyTarget(c);
|
|
9675
10036
|
if (selfOf && target === selfOf.comb) return selfOf.var;
|
|
9676
10037
|
return this.ref(target, selfOf);
|
|
@@ -9695,6 +10056,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9695
10056
|
});
|
|
9696
10057
|
return `_gch([${items.join(", ")}])`;
|
|
9697
10058
|
}
|
|
10059
|
+
case "dispatch": {
|
|
10060
|
+
const arms = def.cases.map(
|
|
10061
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
10062
|
+
);
|
|
10063
|
+
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10064
|
+
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10065
|
+
}
|
|
9698
10066
|
case "many":
|
|
9699
10067
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9700
10068
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -10180,6 +10548,28 @@ function stripTsFromSource(node2, code) {
|
|
|
10180
10548
|
function isWordFactory(v2) {
|
|
10181
10549
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
10182
10550
|
}
|
|
10551
|
+
function isStaticValueEntry(v2) {
|
|
10552
|
+
return !!v2 && typeof v2 === "object" && "value" in v2 && "mfSrcs" in v2;
|
|
10553
|
+
}
|
|
10554
|
+
function wordFactoryFromArgs(args, scope, code, mfs) {
|
|
10555
|
+
const [boundaryOrOptsArg, optsArg] = args;
|
|
10556
|
+
if (boundaryOrOptsArg?.type === "SpreadElement" || optsArg?.type === "SpreadElement") return null;
|
|
10557
|
+
const rawBoundaryOrOpts = boundaryOrOptsArg === void 0 ? void 0 : anyValue(boundaryOrOptsArg, scope, code, mfs);
|
|
10558
|
+
const boundaryOrOpts = rawBoundaryOrOpts === void 0 ? "_0-9A-Za-z" : rawBoundaryOrOpts;
|
|
10559
|
+
const opts = optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs);
|
|
10560
|
+
if (typeof boundaryOrOpts === "string") {
|
|
10561
|
+
if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) return null;
|
|
10562
|
+
const caseInsensitive2 = typeof opts === "object" && opts !== null && "caseInsensitive" in opts ? opts.caseInsensitive : false;
|
|
10563
|
+
if (typeof caseInsensitive2 !== "boolean") return null;
|
|
10564
|
+
return { tag: "wordFactory", boundary: boundaryOrOpts, caseInsensitive: caseInsensitive2 };
|
|
10565
|
+
}
|
|
10566
|
+
if (typeof boundaryOrOpts !== "object" || boundaryOrOpts === null || Array.isArray(boundaryOrOpts) || opts !== void 0) {
|
|
10567
|
+
return null;
|
|
10568
|
+
}
|
|
10569
|
+
const caseInsensitive = "caseInsensitive" in boundaryOrOpts ? boundaryOrOpts.caseInsensitive : false;
|
|
10570
|
+
if (typeof caseInsensitive !== "boolean") return null;
|
|
10571
|
+
return { tag: "wordFactory", boundary: "_0-9A-Za-z", caseInsensitive };
|
|
10572
|
+
}
|
|
10183
10573
|
var SUPPORTED = {
|
|
10184
10574
|
literal: (...a) => literal(a[0], a[1]),
|
|
10185
10575
|
regex: (...a) => regex(a[0], a[1]),
|
|
@@ -10230,9 +10620,41 @@ function gatedArmParts(e) {
|
|
|
10230
10620
|
}
|
|
10231
10621
|
return gate2 && combinator ? { gate: gate2, combinator } : null;
|
|
10232
10622
|
}
|
|
10623
|
+
function dispatchArmValue(node2, scope, code, mfs) {
|
|
10624
|
+
if (node2.type === "Identifier") {
|
|
10625
|
+
const value = anyValue(node2, scope, code, mfs);
|
|
10626
|
+
return isDispatchArm(value) ? value : null;
|
|
10627
|
+
}
|
|
10628
|
+
if (node2.type !== "CallExpression") return null;
|
|
10629
|
+
const callee = node2.callee;
|
|
10630
|
+
if (callee.type !== "Identifier") return null;
|
|
10631
|
+
if (callee.name === "otherwise") {
|
|
10632
|
+
const [parserArg] = node2.arguments;
|
|
10633
|
+
if (!parserArg || parserArg.type === "SpreadElement") return null;
|
|
10634
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
10635
|
+
if (!isCombinator(parserValue)) return null;
|
|
10636
|
+
return otherwise(parserValue);
|
|
10637
|
+
}
|
|
10638
|
+
if (callee.name === "when") {
|
|
10639
|
+
const [keyArg, parserArg] = node2.arguments;
|
|
10640
|
+
if (!keyArg || !parserArg || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
10641
|
+
const key = anyValue(keyArg, scope, code, mfs);
|
|
10642
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
10643
|
+
if (!isCombinator(parserValue)) return null;
|
|
10644
|
+
if (typeof key === "string") return when(key, parserValue);
|
|
10645
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue);
|
|
10646
|
+
}
|
|
10647
|
+
return null;
|
|
10648
|
+
}
|
|
10233
10649
|
function isCombinator(v2) {
|
|
10234
10650
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
10235
10651
|
}
|
|
10652
|
+
function isDispatchArm(v2) {
|
|
10653
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
10654
|
+
const rec = v2;
|
|
10655
|
+
if (rec.kind === "otherwise") return isCombinator(rec.parser);
|
|
10656
|
+
return rec.kind === "when" && Array.isArray(rec.keys) && rec.keys.every((key) => typeof key === "string") && isCombinator(rec.parser);
|
|
10657
|
+
}
|
|
10236
10658
|
function scopeGet(scope, name, mfs) {
|
|
10237
10659
|
const entry = scope.get(name);
|
|
10238
10660
|
if (!entry) return null;
|
|
@@ -10263,14 +10685,13 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10263
10685
|
if (node2.type !== "CallExpression") return null;
|
|
10264
10686
|
const callee = node2.callee;
|
|
10265
10687
|
if (callee.type === "CallExpression" && callee.callee.type === "Identifier" && callee.callee.name === "makeWord") {
|
|
10266
|
-
const boundaryArg = callee.arguments[0];
|
|
10267
10688
|
const strArg = node2.arguments[0];
|
|
10268
10689
|
if (!strArg || strArg.type === "SpreadElement") return null;
|
|
10269
|
-
const
|
|
10690
|
+
const factory2 = wordFactoryFromArgs(callee.arguments, scope, code, mfs);
|
|
10270
10691
|
const str = anyValue(strArg, scope, code, mfs);
|
|
10271
|
-
if (
|
|
10692
|
+
if (factory2 === null || typeof str !== "string") return null;
|
|
10272
10693
|
try {
|
|
10273
|
-
return word(str, boundary);
|
|
10694
|
+
return word(str, factory2.boundary, { caseInsensitive: factory2.caseInsensitive });
|
|
10274
10695
|
} catch {
|
|
10275
10696
|
return null;
|
|
10276
10697
|
}
|
|
@@ -10283,7 +10704,7 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10283
10704
|
const str = anyValue(strArg, scope, code, mfs);
|
|
10284
10705
|
if (typeof str !== "string") return null;
|
|
10285
10706
|
try {
|
|
10286
|
-
return word(str, factory2.boundary);
|
|
10707
|
+
return word(str, factory2.boundary, { caseInsensitive: factory2.caseInsensitive });
|
|
10287
10708
|
} catch {
|
|
10288
10709
|
return null;
|
|
10289
10710
|
}
|
|
@@ -10490,6 +10911,25 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10490
10911
|
return null;
|
|
10491
10912
|
}
|
|
10492
10913
|
}
|
|
10914
|
+
if (callee.name === "dispatch") {
|
|
10915
|
+
const [selectorArg, ...armArgs] = node2.arguments;
|
|
10916
|
+
if (!selectorArg || selectorArg.type === "SpreadElement") return null;
|
|
10917
|
+
const selector = anyValue(selectorArg, scope, code, mfs);
|
|
10918
|
+
if (!isCombinator(selector)) return null;
|
|
10919
|
+
const arms = [];
|
|
10920
|
+
for (const arg of armArgs) {
|
|
10921
|
+
if (arg.type === "SpreadElement") return null;
|
|
10922
|
+
const arm = dispatchArmValue(arg, scope, code, mfs);
|
|
10923
|
+
if (!isDispatchArm(arm)) return null;
|
|
10924
|
+
arms.push(arm);
|
|
10925
|
+
}
|
|
10926
|
+
try {
|
|
10927
|
+
const unsafeDispatch = dispatch;
|
|
10928
|
+
return unsafeDispatch(selector, ...arms);
|
|
10929
|
+
} catch {
|
|
10930
|
+
return null;
|
|
10931
|
+
}
|
|
10932
|
+
}
|
|
10493
10933
|
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
10494
10934
|
if (code === void 0 || mfs === void 0) return null;
|
|
10495
10935
|
const arms = [];
|
|
@@ -10575,6 +11015,10 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10575
11015
|
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
10576
11016
|
return entry.combi;
|
|
10577
11017
|
}
|
|
11018
|
+
if (isStaticValueEntry(entry)) {
|
|
11019
|
+
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
11020
|
+
return entry.value;
|
|
11021
|
+
}
|
|
10578
11022
|
return entry;
|
|
10579
11023
|
}
|
|
10580
11024
|
if (node2.type === "MemberExpression") {
|
|
@@ -10593,10 +11037,10 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10593
11037
|
if (node2.type === "CallExpression") {
|
|
10594
11038
|
const callee = node2.callee;
|
|
10595
11039
|
if (callee.type === "Identifier" && callee.name === "makeWord") {
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
return
|
|
11040
|
+
return wordFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
11041
|
+
}
|
|
11042
|
+
if (callee.type === "Identifier" && (callee.name === "when" || callee.name === "otherwise")) {
|
|
11043
|
+
return dispatchArmValue(node2, scope, code, mfs);
|
|
10600
11044
|
}
|
|
10601
11045
|
return exprToCombi(node2, scope, code, mfs);
|
|
10602
11046
|
}
|
|
@@ -10606,10 +11050,7 @@ function evaluateWordFactory(node2, scope, code) {
|
|
|
10606
11050
|
if (node2.type !== "CallExpression") return null;
|
|
10607
11051
|
const callee = node2.callee;
|
|
10608
11052
|
if (callee.type !== "Identifier" || callee.name !== "makeWord") return null;
|
|
10609
|
-
|
|
10610
|
-
const boundary = boundaryArg && boundaryArg.type !== "SpreadElement" ? anyValue(boundaryArg, scope, code) : "_0-9A-Za-z";
|
|
10611
|
-
if (typeof boundary !== "string") return null;
|
|
10612
|
-
return { tag: "wordFactory", boundary };
|
|
11053
|
+
return wordFactoryFromArgs(node2.arguments, scope, code);
|
|
10613
11054
|
}
|
|
10614
11055
|
function evaluateExpr(node2, scope, code, mapFnSources) {
|
|
10615
11056
|
return exprToCombi(node2, scope, code, mapFnSources);
|
|
@@ -10659,6 +11100,7 @@ function evalBodyStatements(statements, scope, code) {
|
|
|
10659
11100
|
if (val === null) return false;
|
|
10660
11101
|
const thisDeclMfSrcs = bodyMfs.slice(before);
|
|
10661
11102
|
if (isCombinator(val)) scope.set(name, { combi: val, mfSrcs: thisDeclMfSrcs });
|
|
11103
|
+
else if (isDispatchArm(val)) scope.set(name, { value: val, mfSrcs: thisDeclMfSrcs });
|
|
10662
11104
|
else scope.set(name, val);
|
|
10663
11105
|
}
|
|
10664
11106
|
}
|
|
@@ -10704,6 +11146,11 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
10704
11146
|
r._ruleName = name;
|
|
10705
11147
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = name;
|
|
10706
11148
|
};
|
|
11149
|
+
const ruleNameOf5 = (r) => r._ruleName;
|
|
11150
|
+
const isNamedRuleRefForAnotherRule2 = (r, key) => {
|
|
11151
|
+
const name = r._def.tag === "lazy" ? ruleNameOf5(r) : void 0;
|
|
11152
|
+
return name !== void 0 && name !== key;
|
|
11153
|
+
};
|
|
10707
11154
|
for (const key of keys) {
|
|
10708
11155
|
if (!ruleRefs.has(key)) {
|
|
10709
11156
|
const r = ref();
|
|
@@ -10734,12 +11181,15 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
10734
11181
|
for (const [key, e] of finalByKey) {
|
|
10735
11182
|
const val = anyValue(e.value, e.scope, e.code, mapFnSources);
|
|
10736
11183
|
if (!isCombinator(val)) return null;
|
|
10737
|
-
|
|
11184
|
+
if (val === ruleRefs.get(key)) return null;
|
|
11185
|
+
if (!isNamedRuleRefForAnotherRule2(val, key)) {
|
|
11186
|
+
tagRef(val, key);
|
|
11187
|
+
}
|
|
10738
11188
|
ruleRefs.get(key).define(val);
|
|
10739
11189
|
}
|
|
10740
11190
|
return ruleRefs;
|
|
10741
11191
|
}
|
|
10742
|
-
function
|
|
11192
|
+
function isDefinableRef2(v2) {
|
|
10743
11193
|
return isCombinator(v2) && typeof v2.define === "function" && v2._def.tag === "lazy";
|
|
10744
11194
|
}
|
|
10745
11195
|
function evaluateRefDeclaration(init, name, scope) {
|
|
@@ -10761,7 +11211,7 @@ function applyDefineStatement(callExpr, scope, code) {
|
|
|
10761
11211
|
if (mem.object.type !== "Identifier" || !mem.object.name) return false;
|
|
10762
11212
|
const target = scope.get(mem.object.name);
|
|
10763
11213
|
const refCombi = isScopeEntry(target) ? target.combi : isCombinator(target) ? target : null;
|
|
10764
|
-
if (!refCombi || !
|
|
11214
|
+
if (!refCombi || !isDefinableRef2(refCombi)) return false;
|
|
10765
11215
|
const args = callExpr.arguments;
|
|
10766
11216
|
if (args.length !== 1 || args[0].type === "SpreadElement") return false;
|
|
10767
11217
|
const inner = anyValue(args[0], scope, code, []);
|