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/index.js
CHANGED
|
@@ -77,6 +77,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
77
77
|
return d.parsers.every(me);
|
|
78
78
|
case "choice":
|
|
79
79
|
return d.parsers.some(me);
|
|
80
|
+
case "dispatch":
|
|
81
|
+
return me(d.selector);
|
|
80
82
|
case "transform":
|
|
81
83
|
case "label":
|
|
82
84
|
case "trivia":
|
|
@@ -150,6 +152,8 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
150
152
|
case "keywords":
|
|
151
153
|
return p._meta.firstSet;
|
|
152
154
|
// terminals: no refs, cached set is exact
|
|
155
|
+
case "dispatch":
|
|
156
|
+
return fs(d.selector);
|
|
153
157
|
case "lazy":
|
|
154
158
|
try {
|
|
155
159
|
return fs(d.thunk());
|
|
@@ -919,8 +923,10 @@ function word(str, boundaryOrOpts, opts) {
|
|
|
919
923
|
const rest = typeof boundaryOrOpts === "object" && boundaryOrOpts !== null ? boundaryOrOpts : opts;
|
|
920
924
|
return keywords([str], { ...rest, boundary });
|
|
921
925
|
}
|
|
922
|
-
function makeWord(
|
|
923
|
-
|
|
926
|
+
function makeWord(boundaryOrOpts = "_0-9A-Za-z", opts) {
|
|
927
|
+
const boundary = typeof boundaryOrOpts === "string" ? boundaryOrOpts : "_0-9A-Za-z";
|
|
928
|
+
const rest = typeof boundaryOrOpts === "object" && boundaryOrOpts !== null ? boundaryOrOpts : opts;
|
|
929
|
+
return (str) => keywords([str], { ...rest, boundary });
|
|
924
930
|
}
|
|
925
931
|
function escapeRe(s) {
|
|
926
932
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -1065,6 +1071,8 @@ function derive(c, seen) {
|
|
|
1065
1071
|
return [def.label];
|
|
1066
1072
|
case "choice":
|
|
1067
1073
|
return def.parsers.flatMap(deriveExpected2);
|
|
1074
|
+
case "dispatch":
|
|
1075
|
+
return deriveExpected2(def.selector);
|
|
1068
1076
|
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1069
1077
|
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1070
1078
|
// able to fail first — deriving from term 0 alone named a token the parse
|
|
@@ -1206,6 +1214,7 @@ function choice(...args) {
|
|
|
1206
1214
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
1207
1215
|
if (result.ok) return result;
|
|
1208
1216
|
expected.push(...result.expected);
|
|
1217
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1209
1218
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1210
1219
|
}
|
|
1211
1220
|
return {
|
|
@@ -1246,6 +1255,7 @@ function choice(...args) {
|
|
|
1246
1255
|
rollbackCstCapture(ctx, mark);
|
|
1247
1256
|
if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
|
|
1248
1257
|
expected.push(...result.expected);
|
|
1258
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1249
1259
|
continue;
|
|
1250
1260
|
}
|
|
1251
1261
|
const checks = autoNot[i];
|
|
@@ -1925,6 +1935,75 @@ function sequence(...parsers) {
|
|
|
1925
1935
|
};
|
|
1926
1936
|
}
|
|
1927
1937
|
|
|
1938
|
+
// src/combinators/dispatch.ts
|
|
1939
|
+
function when(key, parser2) {
|
|
1940
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
1941
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
1942
|
+
for (const item of keys) {
|
|
1943
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
1944
|
+
}
|
|
1945
|
+
return { kind: "when", keys, parser: parser2 };
|
|
1946
|
+
}
|
|
1947
|
+
function otherwise(parser2) {
|
|
1948
|
+
return { kind: "otherwise", parser: parser2 };
|
|
1949
|
+
}
|
|
1950
|
+
function dispatch(selector, ...arms) {
|
|
1951
|
+
let fallback;
|
|
1952
|
+
const cases = [];
|
|
1953
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1954
|
+
for (let i = 0; i < arms.length; i++) {
|
|
1955
|
+
const arm = arms[i];
|
|
1956
|
+
if (arm.kind === "otherwise") {
|
|
1957
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
1958
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
1959
|
+
fallback = arm.parser;
|
|
1960
|
+
continue;
|
|
1961
|
+
}
|
|
1962
|
+
for (const key of arm.keys) {
|
|
1963
|
+
if (seen.has(key)) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
1964
|
+
seen.add(key);
|
|
1965
|
+
}
|
|
1966
|
+
cases.push({ keys: arm.keys, parser: arm.parser });
|
|
1967
|
+
}
|
|
1968
|
+
const meta = {
|
|
1969
|
+
firstSet: selector._meta.firstSet,
|
|
1970
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
1971
|
+
isTrivia: false
|
|
1972
|
+
};
|
|
1973
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1974
|
+
for (const entry of cases) for (const key of entry.keys) byKey.set(key, entry.parser);
|
|
1975
|
+
return {
|
|
1976
|
+
_tag: "dispatch",
|
|
1977
|
+
_meta: meta,
|
|
1978
|
+
_def: {
|
|
1979
|
+
tag: "dispatch",
|
|
1980
|
+
selector,
|
|
1981
|
+
cases,
|
|
1982
|
+
...fallback === void 0 ? {} : { otherwise: fallback }
|
|
1983
|
+
},
|
|
1984
|
+
parse(input, pos, ctx) {
|
|
1985
|
+
const selected = selector.parse(input, pos, ctx);
|
|
1986
|
+
if (!selected.ok) return selected;
|
|
1987
|
+
const tail = byKey.get(selected.value) ?? fallback;
|
|
1988
|
+
if (tail === void 0) {
|
|
1989
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
1990
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
1991
|
+
}
|
|
1992
|
+
const mark = saveTriviaMark(ctx);
|
|
1993
|
+
const result = tail.parse(input, selected.span.end, ctx);
|
|
1994
|
+
if (!result.ok) {
|
|
1995
|
+
rollbackTrivia(ctx, mark);
|
|
1996
|
+
return { ...result, committed: true };
|
|
1997
|
+
}
|
|
1998
|
+
return {
|
|
1999
|
+
ok: true,
|
|
2000
|
+
value: [selected.value, result.value],
|
|
2001
|
+
span: { start: pos, end: result.span.end }
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1928
2007
|
// src/combinators/attempt.ts
|
|
1929
2008
|
function attempt(parser2) {
|
|
1930
2009
|
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
@@ -1947,6 +2026,7 @@ function attempt(parser2) {
|
|
|
1947
2026
|
if (result.ok) return result;
|
|
1948
2027
|
rollbackCstCapture(ctx, mark);
|
|
1949
2028
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
2029
|
+
if (result.committed) return result;
|
|
1950
2030
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
1951
2031
|
}
|
|
1952
2032
|
};
|
|
@@ -1976,6 +2056,7 @@ function repItem(combinator, input, cur, ctx, guardable) {
|
|
|
1976
2056
|
const result = combinator.parse(input, pos, ctx);
|
|
1977
2057
|
if (!result.ok) {
|
|
1978
2058
|
rollbackTrivia(ctx, mark);
|
|
2059
|
+
if (result.committed) return { fail: result, failPos: pos };
|
|
1979
2060
|
return { fail: result, failPos: pos };
|
|
1980
2061
|
}
|
|
1981
2062
|
if (result.span.end === pos) {
|
|
@@ -2019,6 +2100,7 @@ function many(combinator, opts = {}) {
|
|
|
2019
2100
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2020
2101
|
if (item === "stop") break;
|
|
2021
2102
|
if ("fail" in item) {
|
|
2103
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2022
2104
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2023
2105
|
if (sync === void 0) break;
|
|
2024
2106
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2063,6 +2145,7 @@ function atLeast(combinator, min, max) {
|
|
|
2063
2145
|
while (count < min) {
|
|
2064
2146
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2065
2147
|
if (item === "stop" || "fail" in item) {
|
|
2148
|
+
if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
|
|
2066
2149
|
expected ??= deriveExpected(combinator);
|
|
2067
2150
|
return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
|
|
2068
2151
|
}
|
|
@@ -2075,6 +2158,7 @@ function atLeast(combinator, min, max) {
|
|
|
2075
2158
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2076
2159
|
if (item === "stop") break;
|
|
2077
2160
|
if ("fail" in item) {
|
|
2161
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2078
2162
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2079
2163
|
if (sync === void 0) break;
|
|
2080
2164
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2113,6 +2197,7 @@ function optional(combinator) {
|
|
|
2113
2197
|
const result = combinator.parse(input, pos, ctx);
|
|
2114
2198
|
if (result.ok) return result;
|
|
2115
2199
|
rollbackTrivia(ctx, mark);
|
|
2200
|
+
if (result.committed) return result;
|
|
2116
2201
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
2117
2202
|
}
|
|
2118
2203
|
};
|
|
@@ -2152,6 +2237,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2152
2237
|
values.push(first.value);
|
|
2153
2238
|
cur = first.span.end;
|
|
2154
2239
|
} else {
|
|
2240
|
+
if (first.committed) return first;
|
|
2155
2241
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2156
2242
|
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
2157
2243
|
if (min >= 1) return failAt2(pos);
|
|
@@ -2179,6 +2265,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2179
2265
|
const sep = separator.parse(input, sepPos, ctx);
|
|
2180
2266
|
if (!sep.ok) {
|
|
2181
2267
|
rollbackTrivia(ctx, loopMark);
|
|
2268
|
+
if (sep.committed) return sep;
|
|
2182
2269
|
break;
|
|
2183
2270
|
}
|
|
2184
2271
|
const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
|
|
@@ -2194,6 +2281,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2194
2281
|
}
|
|
2195
2282
|
const next = combinator.parse(input, nextPos, ctx);
|
|
2196
2283
|
if (!next.ok) {
|
|
2284
|
+
if (next.committed) return next;
|
|
2197
2285
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2198
2286
|
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2199
2287
|
expected ??= deriveExpected(combinator);
|
|
@@ -2286,6 +2374,11 @@ function markUnusedValues(root) {
|
|
|
2286
2374
|
case "choice":
|
|
2287
2375
|
for (const p of def.parsers) visit(p, consumed);
|
|
2288
2376
|
return;
|
|
2377
|
+
case "dispatch":
|
|
2378
|
+
visit(def.selector, consumed);
|
|
2379
|
+
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2380
|
+
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2381
|
+
return;
|
|
2289
2382
|
case "node":
|
|
2290
2383
|
visit(def.parser, false);
|
|
2291
2384
|
return;
|
|
@@ -2357,6 +2450,16 @@ function tagRule(r, key) {
|
|
|
2357
2450
|
r._ruleName = key;
|
|
2358
2451
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
2359
2452
|
}
|
|
2453
|
+
function isDefinableRef(v2) {
|
|
2454
|
+
return !!v2 && typeof v2 === "object" && "_def" in v2 && v2._def.tag === "lazy" && typeof v2.define === "function";
|
|
2455
|
+
}
|
|
2456
|
+
function ruleNameOf(r) {
|
|
2457
|
+
return r._ruleName;
|
|
2458
|
+
}
|
|
2459
|
+
function isNamedRuleRefForAnotherRule(r, key) {
|
|
2460
|
+
const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
|
|
2461
|
+
return name !== void 0 && name !== key;
|
|
2462
|
+
}
|
|
2360
2463
|
function rules(a, b) {
|
|
2361
2464
|
const factory = typeof a === "function" ? a : b;
|
|
2362
2465
|
const options = typeof a === "function" ? b : a;
|
|
@@ -2377,11 +2480,21 @@ function rules(a, b) {
|
|
|
2377
2480
|
for (const key of Object.keys(definitions)) {
|
|
2378
2481
|
const placeholder = cache[key];
|
|
2379
2482
|
const parser2 = definitions[key];
|
|
2380
|
-
if (placeholder
|
|
2381
|
-
|
|
2483
|
+
if (placeholder === parser2) {
|
|
2484
|
+
throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
|
|
2485
|
+
}
|
|
2486
|
+
if (isDefinableRef(placeholder)) {
|
|
2487
|
+
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
2382
2488
|
placeholder.define(parser2);
|
|
2383
2489
|
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
2384
2490
|
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
2491
|
+
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
2492
|
+
const alias = ref();
|
|
2493
|
+
tagRule(alias, key);
|
|
2494
|
+
alias.define(parser2);
|
|
2495
|
+
alias._meta.firstSet = parser2._meta.firstSet;
|
|
2496
|
+
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
2497
|
+
cache[key] = alias;
|
|
2385
2498
|
} else {
|
|
2386
2499
|
tagRule(parser2, key);
|
|
2387
2500
|
cache[key] = parser2;
|
|
@@ -2541,6 +2654,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2541
2654
|
case "sequence":
|
|
2542
2655
|
case "choice":
|
|
2543
2656
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2657
|
+
case "dispatch":
|
|
2658
|
+
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2544
2659
|
case "sepBy":
|
|
2545
2660
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2546
2661
|
case "skip":
|
|
@@ -2608,6 +2723,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2608
2723
|
return parserHasTriviaSite(d.parser, seen);
|
|
2609
2724
|
case "choice":
|
|
2610
2725
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2726
|
+
case "dispatch":
|
|
2727
|
+
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2611
2728
|
case "grammar":
|
|
2612
2729
|
return parserHasTriviaSite(d.parser, seen);
|
|
2613
2730
|
case "lazy": {
|
|
@@ -2633,6 +2750,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2633
2750
|
case "sequence":
|
|
2634
2751
|
case "choice":
|
|
2635
2752
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2753
|
+
case "dispatch":
|
|
2754
|
+
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2636
2755
|
case "sepBy":
|
|
2637
2756
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2638
2757
|
case "skip":
|
|
@@ -3034,7 +3153,7 @@ function leaf(root, fn) {
|
|
|
3034
3153
|
}
|
|
3035
3154
|
|
|
3036
3155
|
// src/version.ts
|
|
3037
|
-
var PARSEMAN_VERSION = "0.
|
|
3156
|
+
var PARSEMAN_VERSION = "0.39.0";
|
|
3038
3157
|
|
|
3039
3158
|
// src/cst/host-mode.ts
|
|
3040
3159
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3088,7 +3207,7 @@ function firstSetToString(fs) {
|
|
|
3088
3207
|
if (fs.kind === "empty") return "(empty)";
|
|
3089
3208
|
return fs.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
|
|
3090
3209
|
}
|
|
3091
|
-
var
|
|
3210
|
+
var ruleNameOf2 = (p) => p._ruleName;
|
|
3092
3211
|
var SUGGESTIONS = {
|
|
3093
3212
|
"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.",
|
|
3094
3213
|
"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.",
|
|
@@ -3190,6 +3309,8 @@ function classifyBroadArm(arm, resolve) {
|
|
|
3190
3309
|
}
|
|
3191
3310
|
return null;
|
|
3192
3311
|
}
|
|
3312
|
+
case "dispatch":
|
|
3313
|
+
return walk2(d.selector);
|
|
3193
3314
|
default:
|
|
3194
3315
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3195
3316
|
}
|
|
@@ -3246,7 +3367,7 @@ function detectAntiPatterns(rule, arms) {
|
|
|
3246
3367
|
return out;
|
|
3247
3368
|
}
|
|
3248
3369
|
function analyzeGating(entry, opts) {
|
|
3249
|
-
return analyzeGatingRules([[
|
|
3370
|
+
return analyzeGatingRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3250
3371
|
}
|
|
3251
3372
|
function analyzeGatingRules(ruleMap, opts) {
|
|
3252
3373
|
const raw = [];
|
|
@@ -3279,7 +3400,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3279
3400
|
return;
|
|
3280
3401
|
}
|
|
3281
3402
|
const d = def;
|
|
3282
|
-
const rule =
|
|
3403
|
+
const rule = ruleNameOf2(p) ?? enclosingRule;
|
|
3283
3404
|
if (d.tag === "choice") {
|
|
3284
3405
|
raw.push({ g: analyzeChoice(p, d, rule, opts?.resolveRef), rule });
|
|
3285
3406
|
antiPatterns.push(...detectAntiPatterns(rule, d.parsers));
|
|
@@ -3289,6 +3410,11 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3289
3410
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3290
3411
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3291
3412
|
if (rec[k]) kids.push(rec[k]);
|
|
3413
|
+
if (d.tag === "dispatch") {
|
|
3414
|
+
kids.push(d.selector);
|
|
3415
|
+
for (const c of d.cases) kids.push(c.parser);
|
|
3416
|
+
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3417
|
+
}
|
|
3292
3418
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3293
3419
|
if (d.tag === "lazy") {
|
|
3294
3420
|
try {
|
|
@@ -3298,7 +3424,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3298
3424
|
}
|
|
3299
3425
|
for (const k of kids) visit(k, rule);
|
|
3300
3426
|
};
|
|
3301
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
3427
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name);
|
|
3302
3428
|
const perRule = /* @__PURE__ */ new Map();
|
|
3303
3429
|
for (const r of raw) perRule.set(r.rule, (perRule.get(r.rule) ?? 0) + 1);
|
|
3304
3430
|
const seenInRule = /* @__PURE__ */ new Map();
|
|
@@ -3395,6 +3521,12 @@ function childrenOf(d) {
|
|
|
3395
3521
|
case "sequence":
|
|
3396
3522
|
case "choice":
|
|
3397
3523
|
return d.parsers;
|
|
3524
|
+
case "dispatch":
|
|
3525
|
+
return [
|
|
3526
|
+
d.selector,
|
|
3527
|
+
...d.cases.map((c) => c.parser),
|
|
3528
|
+
...d.otherwise === void 0 ? [] : [d.otherwise]
|
|
3529
|
+
];
|
|
3398
3530
|
case "skip":
|
|
3399
3531
|
return [d.main, d.skipped];
|
|
3400
3532
|
case "sepBy":
|
|
@@ -3422,7 +3554,7 @@ function childrenOf(d) {
|
|
|
3422
3554
|
}
|
|
3423
3555
|
}
|
|
3424
3556
|
}
|
|
3425
|
-
var
|
|
3557
|
+
var ruleNameOf3 = (p) => p._ruleName;
|
|
3426
3558
|
var fnKey = (src, fn) => src ?? (typeof fn === "function" ? String(fn) : "");
|
|
3427
3559
|
function payloadKey(p, d) {
|
|
3428
3560
|
switch (d.tag) {
|
|
@@ -3433,7 +3565,7 @@ function payloadKey(p, d) {
|
|
|
3433
3565
|
case "keywords":
|
|
3434
3566
|
return `keywords\0${[...d.words].join("")}\0${d.caseInsensitive}\0${d.boundary ?? ""}`;
|
|
3435
3567
|
case "lazy": {
|
|
3436
|
-
const n =
|
|
3568
|
+
const n = ruleNameOf3(p);
|
|
3437
3569
|
return n === void 0 ? `ref\0#${anonId(p)}` : `ref\0${n}`;
|
|
3438
3570
|
}
|
|
3439
3571
|
case "label":
|
|
@@ -3451,6 +3583,8 @@ function payloadKey(p, d) {
|
|
|
3451
3583
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3452
3584
|
case "sepBy":
|
|
3453
3585
|
return `sepBy\0${d.min}\0${d.max ?? ""}\0${d.trailing ?? ""}`;
|
|
3586
|
+
case "dispatch":
|
|
3587
|
+
return `dispatch\0${d.cases.map((c) => JSON.stringify(c.keys)).join("")}\0${d.otherwise !== void 0}`;
|
|
3454
3588
|
case "expect":
|
|
3455
3589
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3456
3590
|
case "scanTo":
|
|
@@ -3500,7 +3634,7 @@ var Interner = class {
|
|
|
3500
3634
|
var MAX_RENDER = 160;
|
|
3501
3635
|
function render(p, depth = 3) {
|
|
3502
3636
|
const d = p._def;
|
|
3503
|
-
const name =
|
|
3637
|
+
const name = ruleNameOf3(p);
|
|
3504
3638
|
switch (d.tag) {
|
|
3505
3639
|
case "literal":
|
|
3506
3640
|
return `literal('${d.value}')`;
|
|
@@ -3522,6 +3656,11 @@ function render(p, depth = 3) {
|
|
|
3522
3656
|
return `sequence(${kids.join(", ")})`;
|
|
3523
3657
|
case "choice":
|
|
3524
3658
|
return `choice(${kids.join(", ")})`;
|
|
3659
|
+
case "dispatch": {
|
|
3660
|
+
const arms = d.cases.map((c, i) => `when([${c.keys.map((k) => JSON.stringify(k)).join(", ")}], ${kids[i + 1] ?? ""})`);
|
|
3661
|
+
if (d.otherwise !== void 0) arms.push(`otherwise(${kids[kids.length - 1] ?? ""})`);
|
|
3662
|
+
return `dispatch(${kids[0] ?? ""}, ${arms.join(", ")})`;
|
|
3663
|
+
}
|
|
3525
3664
|
case "node":
|
|
3526
3665
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3527
3666
|
case "label":
|
|
@@ -3545,6 +3684,10 @@ function segment(d, index) {
|
|
|
3545
3684
|
return `seq[${index}]`;
|
|
3546
3685
|
case "choice":
|
|
3547
3686
|
return `choice[${index}]`;
|
|
3687
|
+
case "dispatch":
|
|
3688
|
+
if (index === 0) return "dispatch.selector";
|
|
3689
|
+
if (index <= d.cases.length) return `dispatch.when[${index - 1}]`;
|
|
3690
|
+
return "dispatch.otherwise";
|
|
3548
3691
|
case "node":
|
|
3549
3692
|
return `node(${d.type ?? ""})`;
|
|
3550
3693
|
case "label":
|
|
@@ -3679,7 +3822,7 @@ function keywordAlternationHazards(words, boundary) {
|
|
|
3679
3822
|
return out;
|
|
3680
3823
|
}
|
|
3681
3824
|
function analyzeDuplication(entry, opts) {
|
|
3682
|
-
return analyzeDuplicationRules([[
|
|
3825
|
+
return analyzeDuplicationRules([[ruleNameOf3(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3683
3826
|
}
|
|
3684
3827
|
function assertAnalyzable(ruleMap) {
|
|
3685
3828
|
for (const [name, rule] of ruleMap) {
|
|
@@ -3720,7 +3863,7 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
3720
3863
|
const visit = (p, rule, path, enclosingNode, enclosingReducer) => {
|
|
3721
3864
|
if (visited.has(p)) return;
|
|
3722
3865
|
const d = p._def;
|
|
3723
|
-
const own =
|
|
3866
|
+
const own = ruleNameOf3(p);
|
|
3724
3867
|
const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path };
|
|
3725
3868
|
visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
|
|
3726
3869
|
const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
|
|
@@ -3733,12 +3876,12 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
3733
3876
|
if (d.tag === "lazy") {
|
|
3734
3877
|
try {
|
|
3735
3878
|
const target = d.thunk();
|
|
3736
|
-
visit(target,
|
|
3879
|
+
visit(target, ruleNameOf3(target) ?? ruleNameOf3(p) ?? here.rule, "", null, false);
|
|
3737
3880
|
} catch {
|
|
3738
3881
|
}
|
|
3739
3882
|
}
|
|
3740
3883
|
};
|
|
3741
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
3884
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf3(root) ?? name, "", null, false);
|
|
3742
3885
|
const accept = new Set(opts?.accept ?? []);
|
|
3743
3886
|
const used = /* @__PURE__ */ new Set();
|
|
3744
3887
|
const keep = (f) => {
|
|
@@ -4798,6 +4941,8 @@ function children(def, winners) {
|
|
|
4798
4941
|
case "sequence":
|
|
4799
4942
|
case "choice":
|
|
4800
4943
|
return def.parsers;
|
|
4944
|
+
case "dispatch":
|
|
4945
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
4801
4946
|
case "many":
|
|
4802
4947
|
case "oneOrMore":
|
|
4803
4948
|
case "optional":
|
|
@@ -6262,6 +6407,8 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6262
6407
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6263
6408
|
return { alts };
|
|
6264
6409
|
}
|
|
6410
|
+
case "dispatch":
|
|
6411
|
+
return rec(d.selector);
|
|
6265
6412
|
case "sequence": {
|
|
6266
6413
|
const chain = [];
|
|
6267
6414
|
for (const term of d.parsers) {
|
|
@@ -6336,6 +6483,9 @@ function failReturn(expected, posExpr) {
|
|
|
6336
6483
|
function failReturnArr(expectedArr, posExpr) {
|
|
6337
6484
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6338
6485
|
}
|
|
6486
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6487
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6488
|
+
}
|
|
6339
6489
|
function hoistExpected(ctx, constArrSource) {
|
|
6340
6490
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6341
6491
|
if (name === void 0) {
|
|
@@ -6372,15 +6522,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6372
6522
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6373
6523
|
}
|
|
6374
6524
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6375
|
-
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
6525
|
+
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
|
|
6526
|
+
}
|
|
6527
|
+
function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
|
|
6528
|
+
if (ctx.failLabel) {
|
|
6529
|
+
if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
|
|
6530
|
+
return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
|
|
6531
|
+
}
|
|
6532
|
+
return committedReturnArr(expectedArr, posExpr);
|
|
6376
6533
|
}
|
|
6377
6534
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6378
6535
|
if (srcCtx !== "_ctx") {
|
|
6379
6536
|
if (ctx.failLabel) {
|
|
6380
6537
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6381
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; break ${ctx.failLabel} }`;
|
|
6538
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
|
|
6382
6539
|
}
|
|
6383
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; ${resultFromRecorded()} }`;
|
|
6540
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
|
|
6384
6541
|
}
|
|
6385
6542
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6386
6543
|
return resultFromRecorded();
|
|
@@ -6593,6 +6750,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6593
6750
|
// nothing committed remains.
|
|
6594
6751
|
case "choice":
|
|
6595
6752
|
return false;
|
|
6753
|
+
case "dispatch":
|
|
6754
|
+
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);
|
|
6596
6755
|
case "attempt":
|
|
6597
6756
|
return false;
|
|
6598
6757
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6637,6 +6796,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6637
6796
|
return true;
|
|
6638
6797
|
}
|
|
6639
6798
|
}
|
|
6799
|
+
function mayCommitFailure(p, seen = /* @__PURE__ */ new Set()) {
|
|
6800
|
+
if (seen.has(p)) return false;
|
|
6801
|
+
seen.add(p);
|
|
6802
|
+
const d = p._def;
|
|
6803
|
+
switch (d.tag) {
|
|
6804
|
+
case "dispatch":
|
|
6805
|
+
return true;
|
|
6806
|
+
case "choice":
|
|
6807
|
+
case "sequence":
|
|
6808
|
+
return d.parsers.some((x) => mayCommitFailure(x, seen));
|
|
6809
|
+
case "many":
|
|
6810
|
+
case "oneOrMore":
|
|
6811
|
+
case "optional":
|
|
6812
|
+
case "attempt":
|
|
6813
|
+
case "transform":
|
|
6814
|
+
case "label":
|
|
6815
|
+
case "field":
|
|
6816
|
+
case "grammar":
|
|
6817
|
+
case "node":
|
|
6818
|
+
return mayCommitFailure(d.parser, seen);
|
|
6819
|
+
case "sepBy":
|
|
6820
|
+
return mayCommitFailure(d.parser, seen) || mayCommitFailure(d.separator, seen);
|
|
6821
|
+
case "skip":
|
|
6822
|
+
return mayCommitFailure(d.main, seen) || mayCommitFailure(d.skipped, seen);
|
|
6823
|
+
case "token":
|
|
6824
|
+
case "leaf":
|
|
6825
|
+
return mayCommitFailure(d.parser, seen);
|
|
6826
|
+
case "withCtx":
|
|
6827
|
+
return mayCommitFailure(d.parser, seen);
|
|
6828
|
+
case "scanTo":
|
|
6829
|
+
return mayCommitFailure(d.sentinel, seen) || d.skip.some((x) => mayCommitFailure(x, seen));
|
|
6830
|
+
case "lazy": {
|
|
6831
|
+
try {
|
|
6832
|
+
return mayCommitFailure(d.thunk(), seen);
|
|
6833
|
+
} catch {
|
|
6834
|
+
return true;
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
case "unknown":
|
|
6838
|
+
return true;
|
|
6839
|
+
default:
|
|
6840
|
+
return false;
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6640
6843
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6641
6844
|
if (seen.has(p)) return false;
|
|
6642
6845
|
seen.add(p);
|
|
@@ -6658,6 +6861,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6658
6861
|
case "sequence":
|
|
6659
6862
|
case "choice":
|
|
6660
6863
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6864
|
+
case "dispatch":
|
|
6865
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
6661
6866
|
case "sepBy":
|
|
6662
6867
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6663
6868
|
case "many":
|
|
@@ -6704,6 +6909,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6704
6909
|
ctx.recordFail = savedRecord;
|
|
6705
6910
|
const ind0 = ind(ctx);
|
|
6706
6911
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
6912
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6707
6913
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6708
6914
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6709
6915
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6717,6 +6923,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6717
6923
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6718
6924
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6719
6925
|
] : [],
|
|
6926
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6720
6927
|
`${ind0}${lbl}: {`,
|
|
6721
6928
|
...r.stmts,
|
|
6722
6929
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6725,7 +6932,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6725
6932
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6726
6933
|
] : []
|
|
6727
6934
|
];
|
|
6728
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
6935
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6729
6936
|
}
|
|
6730
6937
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6731
6938
|
function emitLit(def, ctx, pos) {
|
|
@@ -7102,6 +7309,118 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7102
7309
|
}
|
|
7103
7310
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7104
7311
|
}
|
|
7312
|
+
function emitTailFallible(parser2, ctx, pos) {
|
|
7313
|
+
const savedRecord = ctx.recordFail;
|
|
7314
|
+
ctx.recordFail = true;
|
|
7315
|
+
const out = emitFallible(parser2, ctx, pos);
|
|
7316
|
+
ctx.recordFail = savedRecord;
|
|
7317
|
+
return out;
|
|
7318
|
+
}
|
|
7319
|
+
function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
7320
|
+
if (seen.has(p)) return false;
|
|
7321
|
+
seen.add(p);
|
|
7322
|
+
const d = p._def;
|
|
7323
|
+
switch (d.tag) {
|
|
7324
|
+
case "expect":
|
|
7325
|
+
case "recover":
|
|
7326
|
+
return true;
|
|
7327
|
+
case "many":
|
|
7328
|
+
case "oneOrMore":
|
|
7329
|
+
case "sepBy":
|
|
7330
|
+
return recovery || mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7331
|
+
case "choice":
|
|
7332
|
+
case "sequence": {
|
|
7333
|
+
for (const item of d.parsers) {
|
|
7334
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7335
|
+
}
|
|
7336
|
+
return false;
|
|
7337
|
+
}
|
|
7338
|
+
case "dispatch": {
|
|
7339
|
+
if (mayRecordRecoveryError(d.selector, recovery, seen)) return true;
|
|
7340
|
+
for (const item of d.cases) {
|
|
7341
|
+
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7342
|
+
}
|
|
7343
|
+
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7344
|
+
}
|
|
7345
|
+
case "attempt":
|
|
7346
|
+
case "transform":
|
|
7347
|
+
case "label":
|
|
7348
|
+
case "field":
|
|
7349
|
+
case "grammar":
|
|
7350
|
+
case "node":
|
|
7351
|
+
case "token":
|
|
7352
|
+
case "leaf":
|
|
7353
|
+
case "withCtx":
|
|
7354
|
+
case "optional":
|
|
7355
|
+
return mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7356
|
+
case "skip":
|
|
7357
|
+
return mayRecordRecoveryError(d.main, recovery, seen) || mayRecordRecoveryError(d.skipped, recovery, seen);
|
|
7358
|
+
case "scanTo":
|
|
7359
|
+
if (mayRecordRecoveryError(d.sentinel, recovery, seen)) return true;
|
|
7360
|
+
for (const item of d.skip) {
|
|
7361
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7362
|
+
}
|
|
7363
|
+
return false;
|
|
7364
|
+
case "lazy": {
|
|
7365
|
+
try {
|
|
7366
|
+
return mayRecordRecoveryError(d.thunk(), recovery, seen);
|
|
7367
|
+
} catch {
|
|
7368
|
+
return true;
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7371
|
+
case "unknown":
|
|
7372
|
+
return true;
|
|
7373
|
+
default:
|
|
7374
|
+
return false;
|
|
7375
|
+
}
|
|
7376
|
+
}
|
|
7377
|
+
function emitDispatchCombinator(def, ctx, pos) {
|
|
7378
|
+
const selector = emit(def.selector, ctx, pos);
|
|
7379
|
+
const outV = v(ctx, "_dval");
|
|
7380
|
+
const outE = v(ctx, "_dend");
|
|
7381
|
+
const keyV = v(ctx, "_dkey");
|
|
7382
|
+
const stmts = [
|
|
7383
|
+
...selector.stmts,
|
|
7384
|
+
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7385
|
+
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7386
|
+
];
|
|
7387
|
+
let wroteBranch = false;
|
|
7388
|
+
const emitSelectedTail = (parser2, keyword, condition) => {
|
|
7389
|
+
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7390
|
+
stmts.push(head);
|
|
7391
|
+
ctx.indent++;
|
|
7392
|
+
const mayError = mayRecordRecoveryError(parser2, !!ctx.recovery);
|
|
7393
|
+
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7394
|
+
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7395
|
+
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7396
|
+
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7397
|
+
const tail = emitTailFallible(parser2, ctx, selector.endVar);
|
|
7398
|
+
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7399
|
+
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7400
|
+
stmts.push(
|
|
7401
|
+
...tail.stmts,
|
|
7402
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7403
|
+
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7404
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`
|
|
7405
|
+
);
|
|
7406
|
+
ctx.indent--;
|
|
7407
|
+
stmts.push(`${ind(ctx)}}`);
|
|
7408
|
+
};
|
|
7409
|
+
for (const entry of def.cases) {
|
|
7410
|
+
const condition = entry.keys.map((key) => `${keyV} === ${JSON.stringify(key)}`).join(" || ");
|
|
7411
|
+
emitSelectedTail(entry.parser, wroteBranch ? "else if" : "if", condition);
|
|
7412
|
+
wroteBranch = true;
|
|
7413
|
+
}
|
|
7414
|
+
if (def.otherwise) {
|
|
7415
|
+
if (wroteBranch) emitSelectedTail(def.otherwise, "else");
|
|
7416
|
+
else emitSelectedTail(def.otherwise, "if", "true");
|
|
7417
|
+
} else {
|
|
7418
|
+
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7419
|
+
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7420
|
+
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7421
|
+
}
|
|
7422
|
+
return { stmts, valueVar: outV, endVar: outE };
|
|
7423
|
+
}
|
|
7105
7424
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7106
7425
|
const superParser = def.parsers[superIndex];
|
|
7107
7426
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7223,12 +7542,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7223
7542
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7224
7543
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7225
7544
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7545
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7226
7546
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7227
7547
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7228
7548
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7229
7549
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7230
7550
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7231
|
-
const
|
|
7551
|
+
const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
|
|
7552
|
+
const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
7553
|
+
const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
|
|
7554
|
+
const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
|
|
7232
7555
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7233
7556
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7234
7557
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7243,7 +7566,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7243
7566
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7244
7567
|
);
|
|
7245
7568
|
}
|
|
7246
|
-
|
|
7569
|
+
if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
|
|
7570
|
+
const arm = emitFallible(p, ctx, pos, atStart);
|
|
7571
|
+
const { stmts: armStmts, okVar, valVar, endVar } = arm;
|
|
7247
7572
|
stmts.push(...armStmts);
|
|
7248
7573
|
if (autoNot && autoNot.length > 0) {
|
|
7249
7574
|
const anCode = v(ctx, "_anc");
|
|
@@ -7267,10 +7592,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7267
7592
|
stmts.push(`${ind(ctx)}}`);
|
|
7268
7593
|
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} });`} }`);
|
|
7269
7594
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7595
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7270
7596
|
} else {
|
|
7271
7597
|
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} }) }`;
|
|
7272
7598
|
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} })`} }`);
|
|
7273
7599
|
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} })`} }`);
|
|
7600
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7274
7601
|
}
|
|
7275
7602
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7276
7603
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7427,7 +7754,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7427
7754
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7428
7755
|
);
|
|
7429
7756
|
}
|
|
7430
|
-
const
|
|
7757
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
7758
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7431
7759
|
stmts.push(...iterStmts);
|
|
7432
7760
|
if (ctx.recovery) {
|
|
7433
7761
|
const rrV = v(ctx, "_rr");
|
|
@@ -7446,7 +7774,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7446
7774
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7447
7775
|
);
|
|
7448
7776
|
} else {
|
|
7449
|
-
stmts.push(`${ind(ctx)}if (!${iterOk}
|
|
7777
|
+
stmts.push(`${ind(ctx)}if (!${iterOk}) { ${rollback}${iter.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7778
|
+
stmts.push(`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
7450
7779
|
}
|
|
7451
7780
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7452
7781
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7458,10 +7787,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7458
7787
|
function emitOptional(def, ctx, pos) {
|
|
7459
7788
|
const valV = v(ctx, "_opt");
|
|
7460
7789
|
const endV = v(ctx, "_opte");
|
|
7461
|
-
const
|
|
7790
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
7791
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7462
7792
|
const ind0 = ind(ctx);
|
|
7463
7793
|
const stmts = [
|
|
7464
7794
|
...lblStmts,
|
|
7795
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7465
7796
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7466
7797
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7467
7798
|
];
|
|
@@ -7493,7 +7824,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7493
7824
|
...preGuard,
|
|
7494
7825
|
`${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`,
|
|
7495
7826
|
...inner.stmts,
|
|
7496
|
-
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7827
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7497
7828
|
],
|
|
7498
7829
|
valueVar: inner.valVar,
|
|
7499
7830
|
endVar: inner.endVar
|
|
@@ -7507,18 +7838,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7507
7838
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7508
7839
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7509
7840
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7510
|
-
const
|
|
7841
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
7842
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7511
7843
|
const stmts = [
|
|
7512
7844
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7513
7845
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7514
7846
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7515
7847
|
...firstStmts
|
|
7516
7848
|
];
|
|
7517
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7518
|
-
if (
|
|
7849
|
+
const failItem = (nextOkVar, nextMayCommit, itemPosVar, breakStmt) => {
|
|
7850
|
+
const commit = nextMayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : "";
|
|
7851
|
+
if (!rec) return [`${ind(ctx)}if (!${nextOkVar}) { ${commit}${breakStmt} }`];
|
|
7519
7852
|
const rr = v(ctx, "_rr");
|
|
7520
7853
|
return [
|
|
7521
7854
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
7855
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7522
7856
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7523
7857
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7524
7858
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7547,6 +7881,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7547
7881
|
stmts.push(
|
|
7548
7882
|
`${ind(ctx)}let ${didV} = false`,
|
|
7549
7883
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
7884
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7550
7885
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7551
7886
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7552
7887
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7557,6 +7892,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7557
7892
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7558
7893
|
ctx.indent++;
|
|
7559
7894
|
} else {
|
|
7895
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7560
7896
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7561
7897
|
ctx.indent++;
|
|
7562
7898
|
stmts.push(
|
|
@@ -7585,16 +7921,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7585
7921
|
);
|
|
7586
7922
|
sepAtPos = spV;
|
|
7587
7923
|
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}; `;
|
|
7588
|
-
const
|
|
7589
|
-
stmts
|
|
7924
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7925
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
7926
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7590
7927
|
const post = postSepMarks();
|
|
7591
7928
|
stmts.push(...post.decl);
|
|
7592
7929
|
const npV = v(ctx, "_np");
|
|
7593
7930
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7594
|
-
const
|
|
7931
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7932
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7595
7933
|
stmts.push(
|
|
7596
7934
|
...nextStmts,
|
|
7597
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7935
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7598
7936
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7599
7937
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7600
7938
|
);
|
|
@@ -7603,14 +7941,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7603
7941
|
const spV = v(ctx, "_sp");
|
|
7604
7942
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7605
7943
|
sepAtPos = spV;
|
|
7606
|
-
const
|
|
7607
|
-
stmts
|
|
7944
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7945
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
7946
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7608
7947
|
const npV = v(ctx, "_np");
|
|
7609
7948
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7610
|
-
const
|
|
7949
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
7950
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7611
7951
|
stmts.push(
|
|
7612
7952
|
...nextStmts,
|
|
7613
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
7953
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7614
7954
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7615
7955
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7616
7956
|
);
|
|
@@ -7624,15 +7964,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7624
7964
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7625
7965
|
);
|
|
7626
7966
|
}
|
|
7627
|
-
const
|
|
7628
|
-
stmts
|
|
7967
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
7968
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
7969
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7629
7970
|
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}; ` : "";
|
|
7630
7971
|
const post = postSepMarks();
|
|
7631
7972
|
stmts.push(...post.decl);
|
|
7632
|
-
const
|
|
7973
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
7974
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7633
7975
|
stmts.push(
|
|
7634
7976
|
...nextStmts,
|
|
7635
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7977
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7636
7978
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7637
7979
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7638
7980
|
);
|
|
@@ -8013,7 +8355,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
8013
8355
|
const rv = v(ctx, "_rt");
|
|
8014
8356
|
const vv = v(ctx, "_rtv");
|
|
8015
8357
|
const ev = v(ctx, "_rte");
|
|
8016
|
-
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 }`;
|
|
8358
|
+
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 } : {}) }`;
|
|
8017
8359
|
const stmts = [
|
|
8018
8360
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8019
8361
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8094,7 +8436,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8094
8436
|
return { stmts, valueVar: valVar, endVar };
|
|
8095
8437
|
}
|
|
8096
8438
|
function emitExpect(def, ctx, pos) {
|
|
8097
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8439
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8098
8440
|
const ind0 = ind(ctx);
|
|
8099
8441
|
const errV = v(ctx, "_err");
|
|
8100
8442
|
const stmts = [
|
|
@@ -8106,6 +8448,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8106
8448
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8107
8449
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8108
8450
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8451
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8109
8452
|
`${ind0} ${valVar} = ${errV}`,
|
|
8110
8453
|
`${ind0} ${endVar} = ${pos}`,
|
|
8111
8454
|
`${ind0} ${okVar} = true`,
|
|
@@ -8116,7 +8459,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8116
8459
|
function emit(p, ctx, pos) {
|
|
8117
8460
|
const replay = ctx.replayPrefix?.get(p);
|
|
8118
8461
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8119
|
-
const
|
|
8462
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8120
8463
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8121
8464
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8122
8465
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8156,14 +8499,14 @@ function emit(p, ctx, pos) {
|
|
|
8156
8499
|
ctx.indent = 1;
|
|
8157
8500
|
ctx.failLabel = "_pfail";
|
|
8158
8501
|
ctx.recordFail = true;
|
|
8159
|
-
const r =
|
|
8502
|
+
const r = dispatch2("_pos");
|
|
8160
8503
|
ctx.indent = savedIndent;
|
|
8161
8504
|
ctx.failLabel = savedFailLabel;
|
|
8162
8505
|
ctx.recordFail = savedRecord;
|
|
8163
8506
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8164
8507
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8165
8508
|
}
|
|
8166
|
-
return instrument(
|
|
8509
|
+
return instrument(dispatch2());
|
|
8167
8510
|
}
|
|
8168
8511
|
function emitDispatch(p, ctx, pos) {
|
|
8169
8512
|
const bal = p._balancedAmbient;
|
|
@@ -8196,6 +8539,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8196
8539
|
return emitSeq(def, ctx, pos);
|
|
8197
8540
|
case "choice":
|
|
8198
8541
|
return emitChoice(p, def, ctx, pos);
|
|
8542
|
+
case "dispatch":
|
|
8543
|
+
return emitDispatchCombinator(def, ctx, pos);
|
|
8199
8544
|
case "attempt":
|
|
8200
8545
|
return emitAttempt(p, def, ctx, pos);
|
|
8201
8546
|
case "many":
|
|
@@ -8416,6 +8761,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8416
8761
|
case "sequence":
|
|
8417
8762
|
case "choice":
|
|
8418
8763
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8764
|
+
case "dispatch":
|
|
8765
|
+
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
8419
8766
|
case "sepBy":
|
|
8420
8767
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8421
8768
|
case "scanTo":
|
|
@@ -8449,6 +8796,8 @@ function childrenOf2(def) {
|
|
|
8449
8796
|
case "sequence":
|
|
8450
8797
|
case "choice":
|
|
8451
8798
|
return def.parsers;
|
|
8799
|
+
case "dispatch":
|
|
8800
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
8452
8801
|
case "many":
|
|
8453
8802
|
case "attempt":
|
|
8454
8803
|
case "optional":
|
|
@@ -8492,6 +8841,7 @@ function childrenOf2(def) {
|
|
|
8492
8841
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8493
8842
|
"sequence",
|
|
8494
8843
|
"choice",
|
|
8844
|
+
"dispatch",
|
|
8495
8845
|
"many",
|
|
8496
8846
|
"oneOrMore",
|
|
8497
8847
|
"optional",
|
|
@@ -8585,7 +8935,7 @@ function ruleDependencies(ruleMap) {
|
|
|
8585
8935
|
const seen = /* @__PURE__ */ new Set();
|
|
8586
8936
|
const walk2 = (p, isRoot) => {
|
|
8587
8937
|
const def = p._def;
|
|
8588
|
-
const boundary = def.tag === "lazy" ?
|
|
8938
|
+
const boundary = def.tag === "lazy" ? nameOf.get(p) ?? p._ruleName : nameOf.get(p);
|
|
8589
8939
|
if (!isRoot && boundary !== void 0) {
|
|
8590
8940
|
found.add(boundary);
|
|
8591
8941
|
return;
|
|
@@ -9190,6 +9540,8 @@ function childrenOf3(def) {
|
|
|
9190
9540
|
case "sequence":
|
|
9191
9541
|
case "choice":
|
|
9192
9542
|
return def.parsers;
|
|
9543
|
+
case "dispatch":
|
|
9544
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9193
9545
|
case "many":
|
|
9194
9546
|
case "oneOrMore":
|
|
9195
9547
|
case "optional":
|
|
@@ -9224,7 +9576,7 @@ function childrenOf3(def) {
|
|
|
9224
9576
|
return [];
|
|
9225
9577
|
}
|
|
9226
9578
|
}
|
|
9227
|
-
var
|
|
9579
|
+
var ruleNameOf4 = (c) => c._ruleName;
|
|
9228
9580
|
function lazyTarget(c) {
|
|
9229
9581
|
if (c._def.tag !== "lazy") return null;
|
|
9230
9582
|
try {
|
|
@@ -9339,6 +9691,9 @@ function evalRuleMapIR(ir) {
|
|
|
9339
9691
|
"keywords",
|
|
9340
9692
|
"sequence",
|
|
9341
9693
|
"choice",
|
|
9694
|
+
"dispatch",
|
|
9695
|
+
"when",
|
|
9696
|
+
"otherwise",
|
|
9342
9697
|
"attempt",
|
|
9343
9698
|
"many",
|
|
9344
9699
|
"oneOrMore",
|
|
@@ -9372,6 +9727,9 @@ function evalRuleMapIR(ir) {
|
|
|
9372
9727
|
keywords,
|
|
9373
9728
|
sequence,
|
|
9374
9729
|
choice,
|
|
9730
|
+
dispatch,
|
|
9731
|
+
when,
|
|
9732
|
+
otherwise,
|
|
9375
9733
|
attempt,
|
|
9376
9734
|
many,
|
|
9377
9735
|
oneOrMore,
|
|
@@ -9406,12 +9764,16 @@ var Serializer = class {
|
|
|
9406
9764
|
emitted = /* @__PURE__ */ new Set();
|
|
9407
9765
|
decls = [];
|
|
9408
9766
|
ruleValues = /* @__PURE__ */ new Set();
|
|
9767
|
+
localRuleNames = /* @__PURE__ */ new Map();
|
|
9409
9768
|
ruleMap;
|
|
9410
9769
|
scanSkip;
|
|
9411
9770
|
constructor(ruleMap, scanSkip = []) {
|
|
9412
9771
|
this.ruleMap = ruleMap;
|
|
9413
9772
|
this.scanSkip = scanSkip;
|
|
9414
|
-
for (const [, c] of ruleMap)
|
|
9773
|
+
for (const [name, c] of ruleMap) {
|
|
9774
|
+
this.localRuleNames.set(c, name);
|
|
9775
|
+
this.ruleValues.add(this.body(c));
|
|
9776
|
+
}
|
|
9415
9777
|
}
|
|
9416
9778
|
/** A grammar-level `scanSkip` unit is an opaque TERMINAL (a string, a balanced
|
|
9417
9779
|
* bracket) — it must not reach a grammar-rule ref (`g[name]`), because the
|
|
@@ -9422,7 +9784,7 @@ var Serializer = class {
|
|
|
9422
9784
|
if (seen.has(c)) return;
|
|
9423
9785
|
seen.add(c);
|
|
9424
9786
|
if (c._def.tag === "lazy") {
|
|
9425
|
-
if (
|
|
9787
|
+
if (ruleNameOf4(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
|
|
9426
9788
|
const target = lazyTarget(c);
|
|
9427
9789
|
if (target) this.assertNoRuleRef(target, seen);
|
|
9428
9790
|
return;
|
|
@@ -9433,7 +9795,7 @@ var Serializer = class {
|
|
|
9433
9795
|
* its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
|
|
9434
9796
|
* `g[name]` ref — only the top-level entry is unwrapped. */
|
|
9435
9797
|
body(c) {
|
|
9436
|
-
return c._def.tag === "lazy" &&
|
|
9798
|
+
return c._def.tag === "lazy" && ruleNameOf4(c) !== void 0 ? lazyTarget(c) ?? c : c;
|
|
9437
9799
|
}
|
|
9438
9800
|
run() {
|
|
9439
9801
|
for (const [, c] of this.ruleMap) this.analyze(this.body(c), /* @__PURE__ */ new Set());
|
|
@@ -9475,7 +9837,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9475
9837
|
analyze(c, active) {
|
|
9476
9838
|
const def = c._def;
|
|
9477
9839
|
if (def.tag === "lazy") {
|
|
9478
|
-
if (
|
|
9840
|
+
if (ruleNameOf4(c) !== void 0) return;
|
|
9479
9841
|
const target = lazyTarget(c);
|
|
9480
9842
|
if (!target) throw new Unserializable("unresolved unnamed ref");
|
|
9481
9843
|
if (active.has(target)) {
|
|
@@ -9527,7 +9889,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9527
9889
|
const kid = (x) => this.ref(x, selfOf);
|
|
9528
9890
|
switch (def.tag) {
|
|
9529
9891
|
case "lazy": {
|
|
9530
|
-
|
|
9892
|
+
const name = this.localRuleNames.get(c) ?? ruleNameOf4(c);
|
|
9893
|
+
if (name !== void 0) return `g[${JSON.stringify(name)}]`;
|
|
9531
9894
|
const target = lazyTarget(c);
|
|
9532
9895
|
if (selfOf && target === selfOf.comb) return selfOf.var;
|
|
9533
9896
|
return this.ref(target, selfOf);
|
|
@@ -9552,6 +9915,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9552
9915
|
});
|
|
9553
9916
|
return `_gch([${items.join(", ")}])`;
|
|
9554
9917
|
}
|
|
9918
|
+
case "dispatch": {
|
|
9919
|
+
const arms = def.cases.map(
|
|
9920
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
9921
|
+
);
|
|
9922
|
+
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
9923
|
+
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
9924
|
+
}
|
|
9555
9925
|
case "many":
|
|
9556
9926
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9557
9927
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -10771,6 +11141,12 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
10771
11141
|
const unsafeSequence = sequence;
|
|
10772
11142
|
return unsafeSequence(...def.parsers.map(build));
|
|
10773
11143
|
}
|
|
11144
|
+
case "dispatch": {
|
|
11145
|
+
const arms = def.cases.map((entry2) => when(entry2.keys, build(entry2.parser)));
|
|
11146
|
+
if (def.otherwise) arms.push(otherwise(build(def.otherwise)));
|
|
11147
|
+
const unsafeDispatch = dispatch;
|
|
11148
|
+
return unsafeDispatch(build(def.selector), ...arms);
|
|
11149
|
+
}
|
|
10774
11150
|
case "many":
|
|
10775
11151
|
return many(build(def.parser));
|
|
10776
11152
|
case "oneOrMore":
|
|
@@ -11215,6 +11591,7 @@ export {
|
|
|
11215
11591
|
createGrammarTraceSink,
|
|
11216
11592
|
createVisitor,
|
|
11217
11593
|
cstBuildHost,
|
|
11594
|
+
dispatch,
|
|
11218
11595
|
duplicationFindingCount,
|
|
11219
11596
|
expect,
|
|
11220
11597
|
extractCharClasses,
|
|
@@ -11247,6 +11624,7 @@ export {
|
|
|
11247
11624
|
oneOrMore,
|
|
11248
11625
|
oneOrMoreSep,
|
|
11249
11626
|
optional,
|
|
11627
|
+
otherwise,
|
|
11250
11628
|
parse,
|
|
11251
11629
|
parseDoc,
|
|
11252
11630
|
parser,
|
|
@@ -11270,6 +11648,7 @@ export {
|
|
|
11270
11648
|
triviaEntries,
|
|
11271
11649
|
triviaKindMask,
|
|
11272
11650
|
walk,
|
|
11651
|
+
when,
|
|
11273
11652
|
withCtx,
|
|
11274
11653
|
word
|
|
11275
11654
|
};
|