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.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;
|
|
@@ -2358,6 +2449,16 @@ function tagRule(r, key) {
|
|
|
2358
2449
|
r._ruleName = key;
|
|
2359
2450
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
2360
2451
|
}
|
|
2452
|
+
function isDefinableRef(v2) {
|
|
2453
|
+
return !!v2 && typeof v2 === "object" && "_def" in v2 && v2._def.tag === "lazy" && typeof v2.define === "function";
|
|
2454
|
+
}
|
|
2455
|
+
function ruleNameOf(r) {
|
|
2456
|
+
return r._ruleName;
|
|
2457
|
+
}
|
|
2458
|
+
function isNamedRuleRefForAnotherRule(r, key) {
|
|
2459
|
+
const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
|
|
2460
|
+
return name !== void 0 && name !== key;
|
|
2461
|
+
}
|
|
2361
2462
|
function rules(a, b) {
|
|
2362
2463
|
const factory = typeof a === "function" ? a : b;
|
|
2363
2464
|
const options = typeof a === "function" ? b : a;
|
|
@@ -2378,11 +2479,21 @@ function rules(a, b) {
|
|
|
2378
2479
|
for (const key of Object.keys(definitions)) {
|
|
2379
2480
|
const placeholder = cache[key];
|
|
2380
2481
|
const parser2 = definitions[key];
|
|
2381
|
-
if (placeholder
|
|
2382
|
-
|
|
2482
|
+
if (placeholder === parser2) {
|
|
2483
|
+
throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
|
|
2484
|
+
}
|
|
2485
|
+
if (isDefinableRef(placeholder)) {
|
|
2486
|
+
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
2383
2487
|
placeholder.define(parser2);
|
|
2384
2488
|
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
2385
2489
|
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
2490
|
+
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
2491
|
+
const alias = ref();
|
|
2492
|
+
tagRule(alias, key);
|
|
2493
|
+
alias.define(parser2);
|
|
2494
|
+
alias._meta.firstSet = parser2._meta.firstSet;
|
|
2495
|
+
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
2496
|
+
cache[key] = alias;
|
|
2386
2497
|
} else {
|
|
2387
2498
|
tagRule(parser2, key);
|
|
2388
2499
|
cache[key] = parser2;
|
|
@@ -2542,6 +2653,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2542
2653
|
case "sequence":
|
|
2543
2654
|
case "choice":
|
|
2544
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);
|
|
2545
2658
|
case "sepBy":
|
|
2546
2659
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2547
2660
|
case "skip":
|
|
@@ -2609,6 +2722,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2609
2722
|
return parserHasTriviaSite(d.parser, seen);
|
|
2610
2723
|
case "choice":
|
|
2611
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);
|
|
2612
2727
|
case "grammar":
|
|
2613
2728
|
return parserHasTriviaSite(d.parser, seen);
|
|
2614
2729
|
case "lazy": {
|
|
@@ -2634,6 +2749,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2634
2749
|
case "sequence":
|
|
2635
2750
|
case "choice":
|
|
2636
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);
|
|
2637
2754
|
case "sepBy":
|
|
2638
2755
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2639
2756
|
case "skip":
|
|
@@ -3008,7 +3125,7 @@ function leaf(root, fn) {
|
|
|
3008
3125
|
}
|
|
3009
3126
|
|
|
3010
3127
|
// src/version.ts
|
|
3011
|
-
var PARSEMAN_VERSION = "0.
|
|
3128
|
+
var PARSEMAN_VERSION = "0.39.0";
|
|
3012
3129
|
|
|
3013
3130
|
// src/cst/host-mode.ts
|
|
3014
3131
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3062,7 +3179,7 @@ function firstSetToString(fs2) {
|
|
|
3062
3179
|
if (fs2.kind === "empty") return "(empty)";
|
|
3063
3180
|
return fs2.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
|
|
3064
3181
|
}
|
|
3065
|
-
var
|
|
3182
|
+
var ruleNameOf2 = (p) => p._ruleName;
|
|
3066
3183
|
var SUGGESTIONS = {
|
|
3067
3184
|
"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.",
|
|
3068
3185
|
"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.",
|
|
@@ -3164,6 +3281,8 @@ function classifyBroadArm(arm, resolve2) {
|
|
|
3164
3281
|
}
|
|
3165
3282
|
return null;
|
|
3166
3283
|
}
|
|
3284
|
+
case "dispatch":
|
|
3285
|
+
return walk2(d.selector);
|
|
3167
3286
|
default:
|
|
3168
3287
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3169
3288
|
}
|
|
@@ -3220,7 +3339,7 @@ function detectAntiPatterns(rule, arms) {
|
|
|
3220
3339
|
return out;
|
|
3221
3340
|
}
|
|
3222
3341
|
function analyzeGating(entry, opts) {
|
|
3223
|
-
return analyzeGatingRules([[
|
|
3342
|
+
return analyzeGatingRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3224
3343
|
}
|
|
3225
3344
|
function analyzeGatingRules(ruleMap, opts) {
|
|
3226
3345
|
const raw = [];
|
|
@@ -3253,7 +3372,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3253
3372
|
return;
|
|
3254
3373
|
}
|
|
3255
3374
|
const d = def;
|
|
3256
|
-
const rule =
|
|
3375
|
+
const rule = ruleNameOf2(p) ?? enclosingRule;
|
|
3257
3376
|
if (d.tag === "choice") {
|
|
3258
3377
|
raw.push({ g: analyzeChoice(p, d, rule, opts?.resolveRef), rule });
|
|
3259
3378
|
antiPatterns.push(...detectAntiPatterns(rule, d.parsers));
|
|
@@ -3263,6 +3382,11 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3263
3382
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3264
3383
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3265
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
|
+
}
|
|
3266
3390
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3267
3391
|
if (d.tag === "lazy") {
|
|
3268
3392
|
try {
|
|
@@ -3272,7 +3396,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3272
3396
|
}
|
|
3273
3397
|
for (const k of kids) visit(k, rule);
|
|
3274
3398
|
};
|
|
3275
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
3399
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name);
|
|
3276
3400
|
const perRule = /* @__PURE__ */ new Map();
|
|
3277
3401
|
for (const r of raw) perRule.set(r.rule, (perRule.get(r.rule) ?? 0) + 1);
|
|
3278
3402
|
const seenInRule = /* @__PURE__ */ new Map();
|
|
@@ -3369,6 +3493,12 @@ function childrenOf(d) {
|
|
|
3369
3493
|
case "sequence":
|
|
3370
3494
|
case "choice":
|
|
3371
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
|
+
];
|
|
3372
3502
|
case "skip":
|
|
3373
3503
|
return [d.main, d.skipped];
|
|
3374
3504
|
case "sepBy":
|
|
@@ -3396,7 +3526,7 @@ function childrenOf(d) {
|
|
|
3396
3526
|
}
|
|
3397
3527
|
}
|
|
3398
3528
|
}
|
|
3399
|
-
var
|
|
3529
|
+
var ruleNameOf3 = (p) => p._ruleName;
|
|
3400
3530
|
var fnKey = (src, fn) => src ?? (typeof fn === "function" ? String(fn) : "");
|
|
3401
3531
|
function payloadKey(p, d) {
|
|
3402
3532
|
switch (d.tag) {
|
|
@@ -3407,7 +3537,7 @@ function payloadKey(p, d) {
|
|
|
3407
3537
|
case "keywords":
|
|
3408
3538
|
return `keywords\0${[...d.words].join("")}\0${d.caseInsensitive}\0${d.boundary ?? ""}`;
|
|
3409
3539
|
case "lazy": {
|
|
3410
|
-
const n =
|
|
3540
|
+
const n = ruleNameOf3(p);
|
|
3411
3541
|
return n === void 0 ? `ref\0#${anonId(p)}` : `ref\0${n}`;
|
|
3412
3542
|
}
|
|
3413
3543
|
case "label":
|
|
@@ -3425,6 +3555,8 @@ function payloadKey(p, d) {
|
|
|
3425
3555
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3426
3556
|
case "sepBy":
|
|
3427
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}`;
|
|
3428
3560
|
case "expect":
|
|
3429
3561
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3430
3562
|
case "scanTo":
|
|
@@ -3474,7 +3606,7 @@ var Interner = class {
|
|
|
3474
3606
|
var MAX_RENDER = 160;
|
|
3475
3607
|
function render(p, depth = 3) {
|
|
3476
3608
|
const d = p._def;
|
|
3477
|
-
const name =
|
|
3609
|
+
const name = ruleNameOf3(p);
|
|
3478
3610
|
switch (d.tag) {
|
|
3479
3611
|
case "literal":
|
|
3480
3612
|
return `literal('${d.value}')`;
|
|
@@ -3496,6 +3628,11 @@ function render(p, depth = 3) {
|
|
|
3496
3628
|
return `sequence(${kids.join(", ")})`;
|
|
3497
3629
|
case "choice":
|
|
3498
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
|
+
}
|
|
3499
3636
|
case "node":
|
|
3500
3637
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3501
3638
|
case "label":
|
|
@@ -3519,6 +3656,10 @@ function segment(d, index) {
|
|
|
3519
3656
|
return `seq[${index}]`;
|
|
3520
3657
|
case "choice":
|
|
3521
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";
|
|
3522
3663
|
case "node":
|
|
3523
3664
|
return `node(${d.type ?? ""})`;
|
|
3524
3665
|
case "label":
|
|
@@ -3653,7 +3794,7 @@ function keywordAlternationHazards(words, boundary) {
|
|
|
3653
3794
|
return out;
|
|
3654
3795
|
}
|
|
3655
3796
|
function analyzeDuplication(entry, opts) {
|
|
3656
|
-
return analyzeDuplicationRules([[
|
|
3797
|
+
return analyzeDuplicationRules([[ruleNameOf3(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3657
3798
|
}
|
|
3658
3799
|
function assertAnalyzable(ruleMap) {
|
|
3659
3800
|
for (const [name, rule] of ruleMap) {
|
|
@@ -3694,7 +3835,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
3694
3835
|
const visit = (p, rule, path2, enclosingNode, enclosingReducer) => {
|
|
3695
3836
|
if (visited.has(p)) return;
|
|
3696
3837
|
const d = p._def;
|
|
3697
|
-
const own =
|
|
3838
|
+
const own = ruleNameOf3(p);
|
|
3698
3839
|
const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path: path2 };
|
|
3699
3840
|
visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
|
|
3700
3841
|
const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
|
|
@@ -3707,12 +3848,12 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
3707
3848
|
if (d.tag === "lazy") {
|
|
3708
3849
|
try {
|
|
3709
3850
|
const target = d.thunk();
|
|
3710
|
-
visit(target,
|
|
3851
|
+
visit(target, ruleNameOf3(target) ?? ruleNameOf3(p) ?? here.rule, "", null, false);
|
|
3711
3852
|
} catch {
|
|
3712
3853
|
}
|
|
3713
3854
|
}
|
|
3714
3855
|
};
|
|
3715
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
3856
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf3(root) ?? name, "", null, false);
|
|
3716
3857
|
const accept = new Set(opts?.accept ?? []);
|
|
3717
3858
|
const used = /* @__PURE__ */ new Set();
|
|
3718
3859
|
const keep = (f) => {
|
|
@@ -4772,6 +4913,8 @@ function children(def, winners) {
|
|
|
4772
4913
|
case "sequence":
|
|
4773
4914
|
case "choice":
|
|
4774
4915
|
return def.parsers;
|
|
4916
|
+
case "dispatch":
|
|
4917
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
4775
4918
|
case "many":
|
|
4776
4919
|
case "oneOrMore":
|
|
4777
4920
|
case "optional":
|
|
@@ -6236,6 +6379,8 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6236
6379
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6237
6380
|
return { alts };
|
|
6238
6381
|
}
|
|
6382
|
+
case "dispatch":
|
|
6383
|
+
return rec(d.selector);
|
|
6239
6384
|
case "sequence": {
|
|
6240
6385
|
const chain = [];
|
|
6241
6386
|
for (const term of d.parsers) {
|
|
@@ -6318,6 +6463,9 @@ function failReturn(expected, posExpr) {
|
|
|
6318
6463
|
function failReturnArr(expectedArr, posExpr) {
|
|
6319
6464
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6320
6465
|
}
|
|
6466
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6467
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6468
|
+
}
|
|
6321
6469
|
function hoistExpected(ctx, constArrSource) {
|
|
6322
6470
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6323
6471
|
if (name === void 0) {
|
|
@@ -6354,15 +6502,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6354
6502
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6355
6503
|
}
|
|
6356
6504
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6357
|
-
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);
|
|
6358
6513
|
}
|
|
6359
6514
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6360
6515
|
if (srcCtx !== "_ctx") {
|
|
6361
6516
|
if (ctx.failLabel) {
|
|
6362
6517
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6363
|
-
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} }`;
|
|
6364
6519
|
}
|
|
6365
|
-
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()} }`;
|
|
6366
6521
|
}
|
|
6367
6522
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6368
6523
|
return resultFromRecorded();
|
|
@@ -6575,6 +6730,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6575
6730
|
// nothing committed remains.
|
|
6576
6731
|
case "choice":
|
|
6577
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);
|
|
6578
6735
|
case "attempt":
|
|
6579
6736
|
return false;
|
|
6580
6737
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6619,6 +6776,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6619
6776
|
return true;
|
|
6620
6777
|
}
|
|
6621
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
|
+
}
|
|
6622
6823
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6623
6824
|
if (seen.has(p)) return false;
|
|
6624
6825
|
seen.add(p);
|
|
@@ -6640,6 +6841,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6640
6841
|
case "sequence":
|
|
6641
6842
|
case "choice":
|
|
6642
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);
|
|
6643
6846
|
case "sepBy":
|
|
6644
6847
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6645
6848
|
case "many":
|
|
@@ -6686,6 +6889,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6686
6889
|
ctx.recordFail = savedRecord;
|
|
6687
6890
|
const ind0 = ind(ctx);
|
|
6688
6891
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
6892
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6689
6893
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6690
6894
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6691
6895
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6699,6 +6903,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6699
6903
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6700
6904
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6701
6905
|
] : [],
|
|
6906
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6702
6907
|
`${ind0}${lbl}: {`,
|
|
6703
6908
|
...r.stmts,
|
|
6704
6909
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6707,7 +6912,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6707
6912
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6708
6913
|
] : []
|
|
6709
6914
|
];
|
|
6710
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
6915
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6711
6916
|
}
|
|
6712
6917
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6713
6918
|
function emitLit(def, ctx, pos) {
|
|
@@ -7084,6 +7289,118 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7084
7289
|
}
|
|
7085
7290
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7086
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
|
+
}
|
|
7087
7404
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7088
7405
|
const superParser = def.parsers[superIndex];
|
|
7089
7406
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7205,12 +7522,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7205
7522
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7206
7523
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7207
7524
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7525
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7208
7526
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7209
7527
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7210
7528
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7211
7529
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7212
7530
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7213
|
-
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("; ");
|
|
7214
7535
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7215
7536
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7216
7537
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7225,7 +7546,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7225
7546
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7226
7547
|
);
|
|
7227
7548
|
}
|
|
7228
|
-
|
|
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;
|
|
7229
7552
|
stmts.push(...armStmts);
|
|
7230
7553
|
if (autoNot && autoNot.length > 0) {
|
|
7231
7554
|
const anCode = v(ctx, "_anc");
|
|
@@ -7249,10 +7572,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7249
7572
|
stmts.push(`${ind(ctx)}}`);
|
|
7250
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} });`} }`);
|
|
7251
7574
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7575
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7252
7576
|
} else {
|
|
7253
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} }) }`;
|
|
7254
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} })`} }`);
|
|
7255
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)}`);
|
|
7256
7581
|
}
|
|
7257
7582
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7258
7583
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7409,7 +7734,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7409
7734
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7410
7735
|
);
|
|
7411
7736
|
}
|
|
7412
|
-
const
|
|
7737
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
7738
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7413
7739
|
stmts.push(...iterStmts);
|
|
7414
7740
|
if (ctx.recovery) {
|
|
7415
7741
|
const rrV = v(ctx, "_rr");
|
|
@@ -7428,7 +7754,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7428
7754
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7429
7755
|
);
|
|
7430
7756
|
} else {
|
|
7431
|
-
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 }`);
|
|
7432
7759
|
}
|
|
7433
7760
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7434
7761
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7440,10 +7767,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7440
7767
|
function emitOptional(def, ctx, pos) {
|
|
7441
7768
|
const valV = v(ctx, "_opt");
|
|
7442
7769
|
const endV = v(ctx, "_opte");
|
|
7443
|
-
const
|
|
7770
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
7771
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7444
7772
|
const ind0 = ind(ctx);
|
|
7445
7773
|
const stmts = [
|
|
7446
7774
|
...lblStmts,
|
|
7775
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7447
7776
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7448
7777
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7449
7778
|
];
|
|
@@ -7475,7 +7804,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7475
7804
|
...preGuard,
|
|
7476
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`,
|
|
7477
7806
|
...inner.stmts,
|
|
7478
|
-
...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)} }`)
|
|
7479
7808
|
],
|
|
7480
7809
|
valueVar: inner.valVar,
|
|
7481
7810
|
endVar: inner.endVar
|
|
@@ -7489,18 +7818,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7489
7818
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7490
7819
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7491
7820
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7492
|
-
const
|
|
7821
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
7822
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7493
7823
|
const stmts = [
|
|
7494
7824
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7495
7825
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7496
7826
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7497
7827
|
...firstStmts
|
|
7498
7828
|
];
|
|
7499
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7500
|
-
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} }`];
|
|
7501
7832
|
const rr = v(ctx, "_rr");
|
|
7502
7833
|
return [
|
|
7503
7834
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
7835
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7504
7836
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7505
7837
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7506
7838
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7529,6 +7861,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7529
7861
|
stmts.push(
|
|
7530
7862
|
`${ind(ctx)}let ${didV} = false`,
|
|
7531
7863
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
7864
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7532
7865
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7533
7866
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7534
7867
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7539,6 +7872,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7539
7872
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7540
7873
|
ctx.indent++;
|
|
7541
7874
|
} else {
|
|
7875
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7542
7876
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7543
7877
|
ctx.indent++;
|
|
7544
7878
|
stmts.push(
|
|
@@ -7567,16 +7901,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7567
7901
|
);
|
|
7568
7902
|
sepAtPos = spV;
|
|
7569
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}; `;
|
|
7570
|
-
const
|
|
7571
|
-
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 }`);
|
|
7572
7907
|
const post = postSepMarks();
|
|
7573
7908
|
stmts.push(...post.decl);
|
|
7574
7909
|
const npV = v(ctx, "_np");
|
|
7575
7910
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7576
|
-
const
|
|
7911
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7912
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7577
7913
|
stmts.push(
|
|
7578
7914
|
...nextStmts,
|
|
7579
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7915
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7580
7916
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7581
7917
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7582
7918
|
);
|
|
@@ -7585,14 +7921,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7585
7921
|
const spV = v(ctx, "_sp");
|
|
7586
7922
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7587
7923
|
sepAtPos = spV;
|
|
7588
|
-
const
|
|
7589
|
-
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 }`);
|
|
7590
7927
|
const npV = v(ctx, "_np");
|
|
7591
7928
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7592
|
-
const
|
|
7929
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7930
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7593
7931
|
stmts.push(
|
|
7594
7932
|
...nextStmts,
|
|
7595
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
7933
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7596
7934
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7597
7935
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7598
7936
|
);
|
|
@@ -7606,15 +7944,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7606
7944
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7607
7945
|
);
|
|
7608
7946
|
}
|
|
7609
|
-
const
|
|
7610
|
-
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 }`);
|
|
7611
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}; ` : "";
|
|
7612
7951
|
const post = postSepMarks();
|
|
7613
7952
|
stmts.push(...post.decl);
|
|
7614
|
-
const
|
|
7953
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
7954
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7615
7955
|
stmts.push(
|
|
7616
7956
|
...nextStmts,
|
|
7617
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7957
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7618
7958
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7619
7959
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7620
7960
|
);
|
|
@@ -7995,7 +8335,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
7995
8335
|
const rv = v(ctx, "_rt");
|
|
7996
8336
|
const vv = v(ctx, "_rtv");
|
|
7997
8337
|
const ev = v(ctx, "_rte");
|
|
7998
|
-
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 } : {}) }`;
|
|
7999
8339
|
const stmts = [
|
|
8000
8340
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8001
8341
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8076,7 +8416,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8076
8416
|
return { stmts, valueVar: valVar, endVar };
|
|
8077
8417
|
}
|
|
8078
8418
|
function emitExpect(def, ctx, pos) {
|
|
8079
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8419
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8080
8420
|
const ind0 = ind(ctx);
|
|
8081
8421
|
const errV = v(ctx, "_err");
|
|
8082
8422
|
const stmts = [
|
|
@@ -8088,6 +8428,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8088
8428
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8089
8429
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8090
8430
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8431
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8091
8432
|
`${ind0} ${valVar} = ${errV}`,
|
|
8092
8433
|
`${ind0} ${endVar} = ${pos}`,
|
|
8093
8434
|
`${ind0} ${okVar} = true`,
|
|
@@ -8098,7 +8439,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8098
8439
|
function emit(p, ctx, pos) {
|
|
8099
8440
|
const replay = ctx.replayPrefix?.get(p);
|
|
8100
8441
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8101
|
-
const
|
|
8442
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8102
8443
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8103
8444
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8104
8445
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8138,14 +8479,14 @@ function emit(p, ctx, pos) {
|
|
|
8138
8479
|
ctx.indent = 1;
|
|
8139
8480
|
ctx.failLabel = "_pfail";
|
|
8140
8481
|
ctx.recordFail = true;
|
|
8141
|
-
const r =
|
|
8482
|
+
const r = dispatch2("_pos");
|
|
8142
8483
|
ctx.indent = savedIndent;
|
|
8143
8484
|
ctx.failLabel = savedFailLabel;
|
|
8144
8485
|
ctx.recordFail = savedRecord;
|
|
8145
8486
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8146
8487
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8147
8488
|
}
|
|
8148
|
-
return instrument(
|
|
8489
|
+
return instrument(dispatch2());
|
|
8149
8490
|
}
|
|
8150
8491
|
function emitDispatch(p, ctx, pos) {
|
|
8151
8492
|
const bal = p._balancedAmbient;
|
|
@@ -8178,6 +8519,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8178
8519
|
return emitSeq(def, ctx, pos);
|
|
8179
8520
|
case "choice":
|
|
8180
8521
|
return emitChoice(p, def, ctx, pos);
|
|
8522
|
+
case "dispatch":
|
|
8523
|
+
return emitDispatchCombinator(def, ctx, pos);
|
|
8181
8524
|
case "attempt":
|
|
8182
8525
|
return emitAttempt(p, def, ctx, pos);
|
|
8183
8526
|
case "many":
|
|
@@ -8398,6 +8741,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8398
8741
|
case "sequence":
|
|
8399
8742
|
case "choice":
|
|
8400
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);
|
|
8401
8746
|
case "sepBy":
|
|
8402
8747
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8403
8748
|
case "scanTo":
|
|
@@ -8431,6 +8776,8 @@ function childrenOf2(def) {
|
|
|
8431
8776
|
case "sequence":
|
|
8432
8777
|
case "choice":
|
|
8433
8778
|
return def.parsers;
|
|
8779
|
+
case "dispatch":
|
|
8780
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
8434
8781
|
case "many":
|
|
8435
8782
|
case "attempt":
|
|
8436
8783
|
case "optional":
|
|
@@ -8474,6 +8821,7 @@ function childrenOf2(def) {
|
|
|
8474
8821
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8475
8822
|
"sequence",
|
|
8476
8823
|
"choice",
|
|
8824
|
+
"dispatch",
|
|
8477
8825
|
"many",
|
|
8478
8826
|
"oneOrMore",
|
|
8479
8827
|
"optional",
|
|
@@ -8567,7 +8915,7 @@ function ruleDependencies(ruleMap) {
|
|
|
8567
8915
|
const seen = /* @__PURE__ */ new Set();
|
|
8568
8916
|
const walk2 = (p, isRoot) => {
|
|
8569
8917
|
const def = p._def;
|
|
8570
|
-
const boundary = def.tag === "lazy" ?
|
|
8918
|
+
const boundary = def.tag === "lazy" ? nameOf.get(p) ?? p._ruleName : nameOf.get(p);
|
|
8571
8919
|
if (!isRoot && boundary !== void 0) {
|
|
8572
8920
|
found.add(boundary);
|
|
8573
8921
|
return;
|
|
@@ -9298,6 +9646,8 @@ function childrenOf3(def) {
|
|
|
9298
9646
|
case "sequence":
|
|
9299
9647
|
case "choice":
|
|
9300
9648
|
return def.parsers;
|
|
9649
|
+
case "dispatch":
|
|
9650
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9301
9651
|
case "many":
|
|
9302
9652
|
case "oneOrMore":
|
|
9303
9653
|
case "optional":
|
|
@@ -9332,7 +9682,7 @@ function childrenOf3(def) {
|
|
|
9332
9682
|
return [];
|
|
9333
9683
|
}
|
|
9334
9684
|
}
|
|
9335
|
-
var
|
|
9685
|
+
var ruleNameOf4 = (c) => c._ruleName;
|
|
9336
9686
|
function lazyTarget(c) {
|
|
9337
9687
|
if (c._def.tag !== "lazy") return null;
|
|
9338
9688
|
try {
|
|
@@ -9447,6 +9797,9 @@ function evalRuleMapIR(ir) {
|
|
|
9447
9797
|
"keywords",
|
|
9448
9798
|
"sequence",
|
|
9449
9799
|
"choice",
|
|
9800
|
+
"dispatch",
|
|
9801
|
+
"when",
|
|
9802
|
+
"otherwise",
|
|
9450
9803
|
"attempt",
|
|
9451
9804
|
"many",
|
|
9452
9805
|
"oneOrMore",
|
|
@@ -9480,6 +9833,9 @@ function evalRuleMapIR(ir) {
|
|
|
9480
9833
|
keywords,
|
|
9481
9834
|
sequence,
|
|
9482
9835
|
choice,
|
|
9836
|
+
dispatch,
|
|
9837
|
+
when,
|
|
9838
|
+
otherwise,
|
|
9483
9839
|
attempt,
|
|
9484
9840
|
many,
|
|
9485
9841
|
oneOrMore,
|
|
@@ -9514,12 +9870,16 @@ var Serializer = class {
|
|
|
9514
9870
|
emitted = /* @__PURE__ */ new Set();
|
|
9515
9871
|
decls = [];
|
|
9516
9872
|
ruleValues = /* @__PURE__ */ new Set();
|
|
9873
|
+
localRuleNames = /* @__PURE__ */ new Map();
|
|
9517
9874
|
ruleMap;
|
|
9518
9875
|
scanSkip;
|
|
9519
9876
|
constructor(ruleMap, scanSkip = []) {
|
|
9520
9877
|
this.ruleMap = ruleMap;
|
|
9521
9878
|
this.scanSkip = scanSkip;
|
|
9522
|
-
for (const [, c] of ruleMap)
|
|
9879
|
+
for (const [name, c] of ruleMap) {
|
|
9880
|
+
this.localRuleNames.set(c, name);
|
|
9881
|
+
this.ruleValues.add(this.body(c));
|
|
9882
|
+
}
|
|
9523
9883
|
}
|
|
9524
9884
|
/** A grammar-level `scanSkip` unit is an opaque TERMINAL (a string, a balanced
|
|
9525
9885
|
* bracket) — it must not reach a grammar-rule ref (`g[name]`), because the
|
|
@@ -9530,7 +9890,7 @@ var Serializer = class {
|
|
|
9530
9890
|
if (seen.has(c)) return;
|
|
9531
9891
|
seen.add(c);
|
|
9532
9892
|
if (c._def.tag === "lazy") {
|
|
9533
|
-
if (
|
|
9893
|
+
if (ruleNameOf4(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
|
|
9534
9894
|
const target = lazyTarget(c);
|
|
9535
9895
|
if (target) this.assertNoRuleRef(target, seen);
|
|
9536
9896
|
return;
|
|
@@ -9541,7 +9901,7 @@ var Serializer = class {
|
|
|
9541
9901
|
* its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
|
|
9542
9902
|
* `g[name]` ref — only the top-level entry is unwrapped. */
|
|
9543
9903
|
body(c) {
|
|
9544
|
-
return c._def.tag === "lazy" &&
|
|
9904
|
+
return c._def.tag === "lazy" && ruleNameOf4(c) !== void 0 ? lazyTarget(c) ?? c : c;
|
|
9545
9905
|
}
|
|
9546
9906
|
run() {
|
|
9547
9907
|
for (const [, c] of this.ruleMap) this.analyze(this.body(c), /* @__PURE__ */ new Set());
|
|
@@ -9583,7 +9943,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9583
9943
|
analyze(c, active) {
|
|
9584
9944
|
const def = c._def;
|
|
9585
9945
|
if (def.tag === "lazy") {
|
|
9586
|
-
if (
|
|
9946
|
+
if (ruleNameOf4(c) !== void 0) return;
|
|
9587
9947
|
const target = lazyTarget(c);
|
|
9588
9948
|
if (!target) throw new Unserializable("unresolved unnamed ref");
|
|
9589
9949
|
if (active.has(target)) {
|
|
@@ -9635,7 +9995,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9635
9995
|
const kid = (x) => this.ref(x, selfOf);
|
|
9636
9996
|
switch (def.tag) {
|
|
9637
9997
|
case "lazy": {
|
|
9638
|
-
|
|
9998
|
+
const name = this.localRuleNames.get(c) ?? ruleNameOf4(c);
|
|
9999
|
+
if (name !== void 0) return `g[${JSON.stringify(name)}]`;
|
|
9639
10000
|
const target = lazyTarget(c);
|
|
9640
10001
|
if (selfOf && target === selfOf.comb) return selfOf.var;
|
|
9641
10002
|
return this.ref(target, selfOf);
|
|
@@ -9660,6 +10021,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9660
10021
|
});
|
|
9661
10022
|
return `_gch([${items.join(", ")}])`;
|
|
9662
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
|
+
}
|
|
9663
10031
|
case "many":
|
|
9664
10032
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9665
10033
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -10145,6 +10513,28 @@ function stripTsFromSource(node2, code) {
|
|
|
10145
10513
|
function isWordFactory(v2) {
|
|
10146
10514
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
10147
10515
|
}
|
|
10516
|
+
function isStaticValueEntry(v2) {
|
|
10517
|
+
return !!v2 && typeof v2 === "object" && "value" in v2 && "mfSrcs" in v2;
|
|
10518
|
+
}
|
|
10519
|
+
function wordFactoryFromArgs(args, scope, code, mfs) {
|
|
10520
|
+
const [boundaryOrOptsArg, optsArg] = args;
|
|
10521
|
+
if (boundaryOrOptsArg?.type === "SpreadElement" || optsArg?.type === "SpreadElement") return null;
|
|
10522
|
+
const rawBoundaryOrOpts = boundaryOrOptsArg === void 0 ? void 0 : anyValue(boundaryOrOptsArg, scope, code, mfs);
|
|
10523
|
+
const boundaryOrOpts = rawBoundaryOrOpts === void 0 ? "_0-9A-Za-z" : rawBoundaryOrOpts;
|
|
10524
|
+
const opts = optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs);
|
|
10525
|
+
if (typeof boundaryOrOpts === "string") {
|
|
10526
|
+
if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) return null;
|
|
10527
|
+
const caseInsensitive2 = typeof opts === "object" && opts !== null && "caseInsensitive" in opts ? opts.caseInsensitive : false;
|
|
10528
|
+
if (typeof caseInsensitive2 !== "boolean") return null;
|
|
10529
|
+
return { tag: "wordFactory", boundary: boundaryOrOpts, caseInsensitive: caseInsensitive2 };
|
|
10530
|
+
}
|
|
10531
|
+
if (typeof boundaryOrOpts !== "object" || boundaryOrOpts === null || Array.isArray(boundaryOrOpts) || opts !== void 0) {
|
|
10532
|
+
return null;
|
|
10533
|
+
}
|
|
10534
|
+
const caseInsensitive = "caseInsensitive" in boundaryOrOpts ? boundaryOrOpts.caseInsensitive : false;
|
|
10535
|
+
if (typeof caseInsensitive !== "boolean") return null;
|
|
10536
|
+
return { tag: "wordFactory", boundary: "_0-9A-Za-z", caseInsensitive };
|
|
10537
|
+
}
|
|
10148
10538
|
var SUPPORTED = {
|
|
10149
10539
|
literal: (...a) => literal(a[0], a[1]),
|
|
10150
10540
|
regex: (...a) => regex(a[0], a[1]),
|
|
@@ -10195,9 +10585,41 @@ function gatedArmParts(e) {
|
|
|
10195
10585
|
}
|
|
10196
10586
|
return gate2 && combinator ? { gate: gate2, combinator } : null;
|
|
10197
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
|
+
}
|
|
10198
10614
|
function isCombinator(v2) {
|
|
10199
10615
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
10200
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
|
+
}
|
|
10201
10623
|
function scopeGet(scope, name, mfs) {
|
|
10202
10624
|
const entry = scope.get(name);
|
|
10203
10625
|
if (!entry) return null;
|
|
@@ -10228,14 +10650,13 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10228
10650
|
if (node2.type !== "CallExpression") return null;
|
|
10229
10651
|
const callee = node2.callee;
|
|
10230
10652
|
if (callee.type === "CallExpression" && callee.callee.type === "Identifier" && callee.callee.name === "makeWord") {
|
|
10231
|
-
const boundaryArg = callee.arguments[0];
|
|
10232
10653
|
const strArg = node2.arguments[0];
|
|
10233
10654
|
if (!strArg || strArg.type === "SpreadElement") return null;
|
|
10234
|
-
const
|
|
10655
|
+
const factory2 = wordFactoryFromArgs(callee.arguments, scope, code, mfs);
|
|
10235
10656
|
const str = anyValue(strArg, scope, code, mfs);
|
|
10236
|
-
if (
|
|
10657
|
+
if (factory2 === null || typeof str !== "string") return null;
|
|
10237
10658
|
try {
|
|
10238
|
-
return word(str, boundary);
|
|
10659
|
+
return word(str, factory2.boundary, { caseInsensitive: factory2.caseInsensitive });
|
|
10239
10660
|
} catch {
|
|
10240
10661
|
return null;
|
|
10241
10662
|
}
|
|
@@ -10248,7 +10669,7 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10248
10669
|
const str = anyValue(strArg, scope, code, mfs);
|
|
10249
10670
|
if (typeof str !== "string") return null;
|
|
10250
10671
|
try {
|
|
10251
|
-
return word(str, factory2.boundary);
|
|
10672
|
+
return word(str, factory2.boundary, { caseInsensitive: factory2.caseInsensitive });
|
|
10252
10673
|
} catch {
|
|
10253
10674
|
return null;
|
|
10254
10675
|
}
|
|
@@ -10455,6 +10876,25 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10455
10876
|
return null;
|
|
10456
10877
|
}
|
|
10457
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
|
+
}
|
|
10458
10898
|
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
10459
10899
|
if (code === void 0 || mfs === void 0) return null;
|
|
10460
10900
|
const arms = [];
|
|
@@ -10540,6 +10980,10 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10540
10980
|
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
10541
10981
|
return entry.combi;
|
|
10542
10982
|
}
|
|
10983
|
+
if (isStaticValueEntry(entry)) {
|
|
10984
|
+
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
10985
|
+
return entry.value;
|
|
10986
|
+
}
|
|
10543
10987
|
return entry;
|
|
10544
10988
|
}
|
|
10545
10989
|
if (node2.type === "MemberExpression") {
|
|
@@ -10558,10 +11002,10 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10558
11002
|
if (node2.type === "CallExpression") {
|
|
10559
11003
|
const callee = node2.callee;
|
|
10560
11004
|
if (callee.type === "Identifier" && callee.name === "makeWord") {
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
return
|
|
11005
|
+
return wordFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
11006
|
+
}
|
|
11007
|
+
if (callee.type === "Identifier" && (callee.name === "when" || callee.name === "otherwise")) {
|
|
11008
|
+
return dispatchArmValue(node2, scope, code, mfs);
|
|
10565
11009
|
}
|
|
10566
11010
|
return exprToCombi(node2, scope, code, mfs);
|
|
10567
11011
|
}
|
|
@@ -10571,10 +11015,7 @@ function evaluateWordFactory(node2, scope, code) {
|
|
|
10571
11015
|
if (node2.type !== "CallExpression") return null;
|
|
10572
11016
|
const callee = node2.callee;
|
|
10573
11017
|
if (callee.type !== "Identifier" || callee.name !== "makeWord") return null;
|
|
10574
|
-
|
|
10575
|
-
const boundary = boundaryArg && boundaryArg.type !== "SpreadElement" ? anyValue(boundaryArg, scope, code) : "_0-9A-Za-z";
|
|
10576
|
-
if (typeof boundary !== "string") return null;
|
|
10577
|
-
return { tag: "wordFactory", boundary };
|
|
11018
|
+
return wordFactoryFromArgs(node2.arguments, scope, code);
|
|
10578
11019
|
}
|
|
10579
11020
|
function evaluateExpr(node2, scope, code, mapFnSources) {
|
|
10580
11021
|
return exprToCombi(node2, scope, code, mapFnSources);
|
|
@@ -10624,6 +11065,7 @@ function evalBodyStatements(statements, scope, code) {
|
|
|
10624
11065
|
if (val === null) return false;
|
|
10625
11066
|
const thisDeclMfSrcs = bodyMfs.slice(before);
|
|
10626
11067
|
if (isCombinator(val)) scope.set(name, { combi: val, mfSrcs: thisDeclMfSrcs });
|
|
11068
|
+
else if (isDispatchArm(val)) scope.set(name, { value: val, mfSrcs: thisDeclMfSrcs });
|
|
10627
11069
|
else scope.set(name, val);
|
|
10628
11070
|
}
|
|
10629
11071
|
}
|
|
@@ -10669,6 +11111,11 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
10669
11111
|
r._ruleName = name;
|
|
10670
11112
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = name;
|
|
10671
11113
|
};
|
|
11114
|
+
const ruleNameOf5 = (r) => r._ruleName;
|
|
11115
|
+
const isNamedRuleRefForAnotherRule2 = (r, key) => {
|
|
11116
|
+
const name = r._def.tag === "lazy" ? ruleNameOf5(r) : void 0;
|
|
11117
|
+
return name !== void 0 && name !== key;
|
|
11118
|
+
};
|
|
10672
11119
|
for (const key of keys) {
|
|
10673
11120
|
if (!ruleRefs.has(key)) {
|
|
10674
11121
|
const r = ref();
|
|
@@ -10699,12 +11146,15 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
10699
11146
|
for (const [key, e] of finalByKey) {
|
|
10700
11147
|
const val = anyValue(e.value, e.scope, e.code, mapFnSources);
|
|
10701
11148
|
if (!isCombinator(val)) return null;
|
|
10702
|
-
|
|
11149
|
+
if (val === ruleRefs.get(key)) return null;
|
|
11150
|
+
if (!isNamedRuleRefForAnotherRule2(val, key)) {
|
|
11151
|
+
tagRef(val, key);
|
|
11152
|
+
}
|
|
10703
11153
|
ruleRefs.get(key).define(val);
|
|
10704
11154
|
}
|
|
10705
11155
|
return ruleRefs;
|
|
10706
11156
|
}
|
|
10707
|
-
function
|
|
11157
|
+
function isDefinableRef2(v2) {
|
|
10708
11158
|
return isCombinator(v2) && typeof v2.define === "function" && v2._def.tag === "lazy";
|
|
10709
11159
|
}
|
|
10710
11160
|
function evaluateRefDeclaration(init, name, scope) {
|
|
@@ -10726,7 +11176,7 @@ function applyDefineStatement(callExpr, scope, code) {
|
|
|
10726
11176
|
if (mem.object.type !== "Identifier" || !mem.object.name) return false;
|
|
10727
11177
|
const target = scope.get(mem.object.name);
|
|
10728
11178
|
const refCombi = isScopeEntry(target) ? target.combi : isCombinator(target) ? target : null;
|
|
10729
|
-
if (!refCombi || !
|
|
11179
|
+
if (!refCombi || !isDefinableRef2(refCombi)) return false;
|
|
10730
11180
|
const args = callExpr.arguments;
|
|
10731
11181
|
if (args.length !== 1 || args[0].type === "SpreadElement") return false;
|
|
10732
11182
|
const inner = anyValue(args[0], scope, code, []);
|