parseman 0.38.0 → 0.39.1
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 +53 -0
- package/dist/combinators/dispatch.d.ts.map +1 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts +2 -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 +772 -33
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +772 -33
- 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 +6 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +840 -33
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +840 -33
- package/dist/plugin/index.js.map +4 -4
- package/dist/spec/index.cjs +294 -1
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +294 -1
- package/dist/spec/index.js.map +4 -4
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -94,6 +94,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
94
94
|
return d.value.length === 0;
|
|
95
95
|
case "keywords":
|
|
96
96
|
return false;
|
|
97
|
+
case "routed":
|
|
98
|
+
return false;
|
|
97
99
|
case "regex":
|
|
98
100
|
try {
|
|
99
101
|
const m = new RegExp(d.source).exec("");
|
|
@@ -120,6 +122,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
120
122
|
return d.parsers.every(me);
|
|
121
123
|
case "choice":
|
|
122
124
|
return d.parsers.some(me);
|
|
125
|
+
case "dispatch":
|
|
126
|
+
return me(d.selector);
|
|
123
127
|
case "transform":
|
|
124
128
|
case "label":
|
|
125
129
|
case "trivia":
|
|
@@ -193,6 +197,8 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
193
197
|
case "keywords":
|
|
194
198
|
return p._meta.firstSet;
|
|
195
199
|
// terminals: no refs, cached set is exact
|
|
200
|
+
case "dispatch":
|
|
201
|
+
return fs2(d.selector);
|
|
196
202
|
case "lazy":
|
|
197
203
|
try {
|
|
198
204
|
return fs2(d.thunk());
|
|
@@ -1141,6 +1147,8 @@ function derive(c, seen) {
|
|
|
1141
1147
|
return [def.label];
|
|
1142
1148
|
case "choice":
|
|
1143
1149
|
return def.parsers.flatMap(deriveExpected2);
|
|
1150
|
+
case "dispatch":
|
|
1151
|
+
return deriveExpected2(def.selector);
|
|
1144
1152
|
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1145
1153
|
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1146
1154
|
// able to fail first — deriving from term 0 alone named a token the parse
|
|
@@ -1180,6 +1188,8 @@ function derive(c, seen) {
|
|
|
1180
1188
|
case "not":
|
|
1181
1189
|
case "peek":
|
|
1182
1190
|
return deriveExpected2(def.parser);
|
|
1191
|
+
case "routed":
|
|
1192
|
+
return ["routed()"];
|
|
1183
1193
|
case "lazy": {
|
|
1184
1194
|
const name = c._ruleName;
|
|
1185
1195
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -1279,6 +1289,7 @@ function choice(...args) {
|
|
|
1279
1289
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
1280
1290
|
if (result.ok) return result;
|
|
1281
1291
|
expected.push(...result.expected);
|
|
1292
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1282
1293
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1283
1294
|
}
|
|
1284
1295
|
return {
|
|
@@ -1319,6 +1330,7 @@ function choice(...args) {
|
|
|
1319
1330
|
rollbackCstCapture(ctx, mark);
|
|
1320
1331
|
if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
|
|
1321
1332
|
expected.push(...result.expected);
|
|
1333
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1322
1334
|
continue;
|
|
1323
1335
|
}
|
|
1324
1336
|
const checks = autoNot[i];
|
|
@@ -1998,6 +2010,245 @@ function sequence(...parsers) {
|
|
|
1998
2010
|
};
|
|
1999
2011
|
}
|
|
2000
2012
|
|
|
2013
|
+
// src/combinators/dispatch.ts
|
|
2014
|
+
function parserUsesRouted(parser2, seen = /* @__PURE__ */ new Set()) {
|
|
2015
|
+
if (seen.has(parser2)) return false;
|
|
2016
|
+
seen.add(parser2);
|
|
2017
|
+
const def = parser2._def;
|
|
2018
|
+
switch (def.tag) {
|
|
2019
|
+
case "routed":
|
|
2020
|
+
return true;
|
|
2021
|
+
case "sequence":
|
|
2022
|
+
case "choice":
|
|
2023
|
+
return def.parsers.some((entry) => parserUsesRouted(entry, seen));
|
|
2024
|
+
case "dispatch":
|
|
2025
|
+
return false;
|
|
2026
|
+
case "sepBy":
|
|
2027
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.separator, seen);
|
|
2028
|
+
case "skip":
|
|
2029
|
+
return parserUsesRouted(def.main, seen) || parserUsesRouted(def.skipped, seen);
|
|
2030
|
+
case "grammar":
|
|
2031
|
+
return parserUsesRouted(def.parser, seen) || (def.triviaParser ? parserUsesRouted(def.triviaParser, seen) : false);
|
|
2032
|
+
case "scanTo":
|
|
2033
|
+
return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen));
|
|
2034
|
+
case "recover":
|
|
2035
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.sentinel, seen);
|
|
2036
|
+
case "lazy":
|
|
2037
|
+
try {
|
|
2038
|
+
return parserUsesRouted(def.thunk(), seen);
|
|
2039
|
+
} catch {
|
|
2040
|
+
return false;
|
|
2041
|
+
}
|
|
2042
|
+
case "many":
|
|
2043
|
+
case "oneOrMore":
|
|
2044
|
+
case "optional":
|
|
2045
|
+
case "attempt":
|
|
2046
|
+
case "transform":
|
|
2047
|
+
case "trivia":
|
|
2048
|
+
case "token":
|
|
2049
|
+
case "leaf":
|
|
2050
|
+
case "label":
|
|
2051
|
+
case "field":
|
|
2052
|
+
case "not":
|
|
2053
|
+
case "peek":
|
|
2054
|
+
case "node":
|
|
2055
|
+
case "withCtx":
|
|
2056
|
+
case "expect":
|
|
2057
|
+
return parserUsesRouted(def.parser, seen);
|
|
2058
|
+
default:
|
|
2059
|
+
return false;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
function branchUsesRouted(branch) {
|
|
2063
|
+
return branch.usesRouted === true || parserUsesRouted(branch.parser);
|
|
2064
|
+
}
|
|
2065
|
+
function asciiFoldKey(key) {
|
|
2066
|
+
let out = "";
|
|
2067
|
+
for (let i = 0; i < key.length; i++) {
|
|
2068
|
+
const c = key.charCodeAt(i);
|
|
2069
|
+
out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
|
|
2070
|
+
}
|
|
2071
|
+
return out;
|
|
2072
|
+
}
|
|
2073
|
+
function matchesDispatchMatcher(value, matcher) {
|
|
2074
|
+
const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
|
|
2075
|
+
const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
|
|
2076
|
+
switch (matcher.kind) {
|
|
2077
|
+
case "startsWith":
|
|
2078
|
+
return candidate.startsWith(expected);
|
|
2079
|
+
case "endsWith":
|
|
2080
|
+
return candidate.endsWith(expected);
|
|
2081
|
+
case "matches": {
|
|
2082
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
2083
|
+
return new RegExp(matcher.value, flags).test(value);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
function isStringMatcher(value) {
|
|
2088
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2089
|
+
const kind = value.kind;
|
|
2090
|
+
return kind === "startsWith" || kind === "endsWith" || kind === "matches";
|
|
2091
|
+
}
|
|
2092
|
+
function fixedMatcher(kind, value) {
|
|
2093
|
+
if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
|
|
2094
|
+
if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
|
|
2095
|
+
return { kind, value };
|
|
2096
|
+
}
|
|
2097
|
+
function startsWith(prefix) {
|
|
2098
|
+
return fixedMatcher("startsWith", prefix);
|
|
2099
|
+
}
|
|
2100
|
+
function endsWith(suffix) {
|
|
2101
|
+
return fixedMatcher("endsWith", suffix);
|
|
2102
|
+
}
|
|
2103
|
+
function matches(pattern) {
|
|
2104
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
|
|
2105
|
+
if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
|
|
2106
|
+
throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
|
|
2107
|
+
}
|
|
2108
|
+
return { kind: "matches", value: pattern.source, flags: pattern.flags };
|
|
2109
|
+
}
|
|
2110
|
+
function when(key, parser2, opts = {}) {
|
|
2111
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
2112
|
+
if (isStringMatcher(key)) {
|
|
2113
|
+
return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2114
|
+
}
|
|
2115
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2116
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2117
|
+
for (const item of keys) {
|
|
2118
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2119
|
+
}
|
|
2120
|
+
return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2121
|
+
}
|
|
2122
|
+
function otherwise(parser2) {
|
|
2123
|
+
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2124
|
+
}
|
|
2125
|
+
function routed() {
|
|
2126
|
+
return {
|
|
2127
|
+
_tag: "routed",
|
|
2128
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
2129
|
+
_def: { tag: "routed" },
|
|
2130
|
+
parse(_input, pos, ctx) {
|
|
2131
|
+
const item = ctx._routed;
|
|
2132
|
+
if (item === void 0) {
|
|
2133
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2134
|
+
}
|
|
2135
|
+
if (pos !== item.span.start) {
|
|
2136
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2137
|
+
}
|
|
2138
|
+
if (cstCaptureActive(ctx)) {
|
|
2139
|
+
pushCstLeaf(ctx, { _tag: "leaf", value: item.value, span: item.span });
|
|
2140
|
+
}
|
|
2141
|
+
return { ok: true, value: item.value, span: item.span };
|
|
2142
|
+
}
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
function dispatch(selector, ...arms) {
|
|
2146
|
+
if (parserUsesRouted(selector)) {
|
|
2147
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2148
|
+
}
|
|
2149
|
+
let fallback;
|
|
2150
|
+
let fallbackUsesRouted = false;
|
|
2151
|
+
const matchers = [];
|
|
2152
|
+
const cases = [];
|
|
2153
|
+
const seen = [];
|
|
2154
|
+
for (let i = 0; i < arms.length; i++) {
|
|
2155
|
+
const arm = arms[i];
|
|
2156
|
+
if (arm.kind === "otherwise") {
|
|
2157
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2158
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2159
|
+
fallback = arm.parser;
|
|
2160
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
if (arm.kind === "whenMatcher") {
|
|
2164
|
+
const matcher = arm.matcher;
|
|
2165
|
+
matchers.push({
|
|
2166
|
+
kind: matcher.kind,
|
|
2167
|
+
value: matcher.value,
|
|
2168
|
+
...matcher.kind === "matches" ? { flags: matcher.flags } : {},
|
|
2169
|
+
parser: arm.parser,
|
|
2170
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2171
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2172
|
+
});
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
for (const key of arm.keys) {
|
|
2176
|
+
const folded = asciiFoldKey(key);
|
|
2177
|
+
for (const prior of seen) {
|
|
2178
|
+
const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
|
|
2179
|
+
if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2180
|
+
}
|
|
2181
|
+
seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
|
|
2182
|
+
}
|
|
2183
|
+
cases.push({
|
|
2184
|
+
keys: arm.keys,
|
|
2185
|
+
parser: arm.parser,
|
|
2186
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2187
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2190
|
+
const meta = {
|
|
2191
|
+
firstSet: selector._meta.firstSet,
|
|
2192
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2193
|
+
isTrivia: false
|
|
2194
|
+
};
|
|
2195
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2196
|
+
const byFoldedKey = /* @__PURE__ */ new Map();
|
|
2197
|
+
for (const entry of cases) {
|
|
2198
|
+
for (const key of entry.keys) {
|
|
2199
|
+
if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
|
|
2200
|
+
else byKey.set(key, entry);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
return {
|
|
2204
|
+
_tag: "dispatch",
|
|
2205
|
+
_meta: meta,
|
|
2206
|
+
_def: {
|
|
2207
|
+
tag: "dispatch",
|
|
2208
|
+
selector,
|
|
2209
|
+
cases,
|
|
2210
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2211
|
+
...fallback === void 0 ? {} : { otherwise: fallback, ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {} }
|
|
2212
|
+
},
|
|
2213
|
+
parse(input, pos, ctx) {
|
|
2214
|
+
if (parserUsesRouted(selector)) {
|
|
2215
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2216
|
+
}
|
|
2217
|
+
const selectorMark = saveTriviaMark(ctx);
|
|
2218
|
+
const selected = selector.parse(input, pos, ctx);
|
|
2219
|
+
if (!selected.ok) return selected;
|
|
2220
|
+
const branch = byKey.get(selected.value) ?? (byFoldedKey.size === 0 ? void 0 : byFoldedKey.get(asciiFoldKey(selected.value))) ?? matchers.find((matcher) => matchesDispatchMatcher(selected.value, matcher)) ?? (fallback === void 0 ? void 0 : { keys: [], parser: fallback, caseInsensitive: false, usesRouted: fallbackUsesRouted });
|
|
2221
|
+
if (branch === void 0) {
|
|
2222
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2223
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2224
|
+
}
|
|
2225
|
+
const savedRouted = ctx._routed;
|
|
2226
|
+
const usesRouted = branchUsesRouted(branch);
|
|
2227
|
+
let mark = saveTriviaMark(ctx);
|
|
2228
|
+
if (usesRouted) {
|
|
2229
|
+
rollbackTrivia(ctx, selectorMark);
|
|
2230
|
+
mark = saveTriviaMark(ctx);
|
|
2231
|
+
ctx._routed = { value: selected.value, span: selected.span };
|
|
2232
|
+
}
|
|
2233
|
+
let result;
|
|
2234
|
+
try {
|
|
2235
|
+
result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
|
|
2236
|
+
} finally {
|
|
2237
|
+
if (usesRouted) ctx._routed = savedRouted;
|
|
2238
|
+
}
|
|
2239
|
+
if (!result.ok) {
|
|
2240
|
+
rollbackTrivia(ctx, mark);
|
|
2241
|
+
return { ...result, committed: true };
|
|
2242
|
+
}
|
|
2243
|
+
return {
|
|
2244
|
+
ok: true,
|
|
2245
|
+
value: [selected.value, result.value],
|
|
2246
|
+
span: { start: pos, end: result.span.end }
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2001
2252
|
// src/combinators/attempt.ts
|
|
2002
2253
|
function attempt(parser2) {
|
|
2003
2254
|
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
@@ -2020,6 +2271,7 @@ function attempt(parser2) {
|
|
|
2020
2271
|
if (result.ok) return result;
|
|
2021
2272
|
rollbackCstCapture(ctx, mark);
|
|
2022
2273
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
2274
|
+
if (result.committed) return result;
|
|
2023
2275
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
2024
2276
|
}
|
|
2025
2277
|
};
|
|
@@ -2049,6 +2301,7 @@ function repItem(combinator, input, cur, ctx, guardable) {
|
|
|
2049
2301
|
const result = combinator.parse(input, pos, ctx);
|
|
2050
2302
|
if (!result.ok) {
|
|
2051
2303
|
rollbackTrivia(ctx, mark);
|
|
2304
|
+
if (result.committed) return { fail: result, failPos: pos };
|
|
2052
2305
|
return { fail: result, failPos: pos };
|
|
2053
2306
|
}
|
|
2054
2307
|
if (result.span.end === pos) {
|
|
@@ -2092,6 +2345,7 @@ function many(combinator, opts = {}) {
|
|
|
2092
2345
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2093
2346
|
if (item === "stop") break;
|
|
2094
2347
|
if ("fail" in item) {
|
|
2348
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2095
2349
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2096
2350
|
if (sync === void 0) break;
|
|
2097
2351
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2136,6 +2390,7 @@ function atLeast(combinator, min, max) {
|
|
|
2136
2390
|
while (count < min) {
|
|
2137
2391
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2138
2392
|
if (item === "stop" || "fail" in item) {
|
|
2393
|
+
if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
|
|
2139
2394
|
expected ??= deriveExpected(combinator);
|
|
2140
2395
|
return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
|
|
2141
2396
|
}
|
|
@@ -2148,6 +2403,7 @@ function atLeast(combinator, min, max) {
|
|
|
2148
2403
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2149
2404
|
if (item === "stop") break;
|
|
2150
2405
|
if ("fail" in item) {
|
|
2406
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2151
2407
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2152
2408
|
if (sync === void 0) break;
|
|
2153
2409
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2186,6 +2442,7 @@ function optional(combinator) {
|
|
|
2186
2442
|
const result = combinator.parse(input, pos, ctx);
|
|
2187
2443
|
if (result.ok) return result;
|
|
2188
2444
|
rollbackTrivia(ctx, mark);
|
|
2445
|
+
if (result.committed) return result;
|
|
2189
2446
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
2190
2447
|
}
|
|
2191
2448
|
};
|
|
@@ -2225,6 +2482,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2225
2482
|
values.push(first.value);
|
|
2226
2483
|
cur = first.span.end;
|
|
2227
2484
|
} else {
|
|
2485
|
+
if (first.committed) return first;
|
|
2228
2486
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2229
2487
|
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
2230
2488
|
if (min >= 1) return failAt2(pos);
|
|
@@ -2252,6 +2510,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2252
2510
|
const sep2 = separator.parse(input, sepPos, ctx);
|
|
2253
2511
|
if (!sep2.ok) {
|
|
2254
2512
|
rollbackTrivia(ctx, loopMark);
|
|
2513
|
+
if (sep2.committed) return sep2;
|
|
2255
2514
|
break;
|
|
2256
2515
|
}
|
|
2257
2516
|
const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
|
|
@@ -2267,6 +2526,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2267
2526
|
}
|
|
2268
2527
|
const next = combinator.parse(input, nextPos, ctx);
|
|
2269
2528
|
if (!next.ok) {
|
|
2529
|
+
if (next.committed) return next;
|
|
2270
2530
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2271
2531
|
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2272
2532
|
expected ??= deriveExpected(combinator);
|
|
@@ -2322,6 +2582,12 @@ function markUnusedValues(root) {
|
|
|
2322
2582
|
case "choice":
|
|
2323
2583
|
for (const p of def.parsers) visit(p, consumed);
|
|
2324
2584
|
return;
|
|
2585
|
+
case "dispatch":
|
|
2586
|
+
visit(def.selector, consumed);
|
|
2587
|
+
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2588
|
+
if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
|
|
2589
|
+
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2590
|
+
return;
|
|
2325
2591
|
case "node":
|
|
2326
2592
|
visit(def.parser, false);
|
|
2327
2593
|
return;
|
|
@@ -2597,6 +2863,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2597
2863
|
case "sequence":
|
|
2598
2864
|
case "choice":
|
|
2599
2865
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2866
|
+
case "dispatch":
|
|
2867
|
+
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => parserHasOwnFields(entry.parser, seen)) : false) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2600
2868
|
case "sepBy":
|
|
2601
2869
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2602
2870
|
case "skip":
|
|
@@ -2664,6 +2932,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2664
2932
|
return parserHasTriviaSite(d.parser, seen);
|
|
2665
2933
|
case "choice":
|
|
2666
2934
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2935
|
+
case "dispatch":
|
|
2936
|
+
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => parserHasTriviaSite(entry.parser, seen)) : false) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2667
2937
|
case "grammar":
|
|
2668
2938
|
return parserHasTriviaSite(d.parser, seen);
|
|
2669
2939
|
case "lazy": {
|
|
@@ -2689,6 +2959,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2689
2959
|
case "sequence":
|
|
2690
2960
|
case "choice":
|
|
2691
2961
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2962
|
+
case "dispatch":
|
|
2963
|
+
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => parserEnablesTriviaCapture(entry.parser, seen)) : false) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2692
2964
|
case "sepBy":
|
|
2693
2965
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2694
2966
|
case "skip":
|
|
@@ -3063,7 +3335,7 @@ function leaf(root, fn) {
|
|
|
3063
3335
|
}
|
|
3064
3336
|
|
|
3065
3337
|
// src/version.ts
|
|
3066
|
-
var PARSEMAN_VERSION = "0.
|
|
3338
|
+
var PARSEMAN_VERSION = "0.39.1";
|
|
3067
3339
|
|
|
3068
3340
|
// src/cst/host-mode.ts
|
|
3069
3341
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3219,6 +3491,8 @@ function classifyBroadArm(arm, resolve2) {
|
|
|
3219
3491
|
}
|
|
3220
3492
|
return null;
|
|
3221
3493
|
}
|
|
3494
|
+
case "dispatch":
|
|
3495
|
+
return walk2(d.selector);
|
|
3222
3496
|
default:
|
|
3223
3497
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3224
3498
|
}
|
|
@@ -3318,6 +3592,12 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3318
3592
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3319
3593
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3320
3594
|
if (rec[k]) kids.push(rec[k]);
|
|
3595
|
+
if (d.tag === "dispatch") {
|
|
3596
|
+
kids.push(d.selector);
|
|
3597
|
+
for (const c of d.cases) kids.push(c.parser);
|
|
3598
|
+
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3599
|
+
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3600
|
+
}
|
|
3321
3601
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3322
3602
|
if (d.tag === "lazy") {
|
|
3323
3603
|
try {
|
|
@@ -3424,6 +3704,12 @@ function childrenOf(d) {
|
|
|
3424
3704
|
case "sequence":
|
|
3425
3705
|
case "choice":
|
|
3426
3706
|
return d.parsers;
|
|
3707
|
+
case "dispatch":
|
|
3708
|
+
return [
|
|
3709
|
+
d.selector,
|
|
3710
|
+
...d.cases.map((c) => c.parser),
|
|
3711
|
+
...d.otherwise === void 0 ? [] : [d.otherwise]
|
|
3712
|
+
];
|
|
3427
3713
|
case "skip":
|
|
3428
3714
|
return [d.main, d.skipped];
|
|
3429
3715
|
case "sepBy":
|
|
@@ -3480,6 +3766,8 @@ function payloadKey(p, d) {
|
|
|
3480
3766
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3481
3767
|
case "sepBy":
|
|
3482
3768
|
return `sepBy\0${d.min}\0${d.max ?? ""}\0${d.trailing ?? ""}`;
|
|
3769
|
+
case "dispatch":
|
|
3770
|
+
return `dispatch\0${d.cases.map((c) => JSON.stringify(c.keys)).join("")}\0${d.otherwise !== void 0}`;
|
|
3483
3771
|
case "expect":
|
|
3484
3772
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3485
3773
|
case "scanTo":
|
|
@@ -3551,6 +3839,11 @@ function render(p, depth = 3) {
|
|
|
3551
3839
|
return `sequence(${kids.join(", ")})`;
|
|
3552
3840
|
case "choice":
|
|
3553
3841
|
return `choice(${kids.join(", ")})`;
|
|
3842
|
+
case "dispatch": {
|
|
3843
|
+
const arms = d.cases.map((c, i) => `when([${c.keys.map((k) => JSON.stringify(k)).join(", ")}], ${kids[i + 1] ?? ""})`);
|
|
3844
|
+
if (d.otherwise !== void 0) arms.push(`otherwise(${kids[kids.length - 1] ?? ""})`);
|
|
3845
|
+
return `dispatch(${kids[0] ?? ""}, ${arms.join(", ")})`;
|
|
3846
|
+
}
|
|
3554
3847
|
case "node":
|
|
3555
3848
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3556
3849
|
case "label":
|
|
@@ -3574,6 +3867,10 @@ function segment(d, index) {
|
|
|
3574
3867
|
return `seq[${index}]`;
|
|
3575
3868
|
case "choice":
|
|
3576
3869
|
return `choice[${index}]`;
|
|
3870
|
+
case "dispatch":
|
|
3871
|
+
if (index === 0) return "dispatch.selector";
|
|
3872
|
+
if (index <= d.cases.length) return `dispatch.when[${index - 1}]`;
|
|
3873
|
+
return "dispatch.otherwise";
|
|
3577
3874
|
case "node":
|
|
3578
3875
|
return `node(${d.type ?? ""})`;
|
|
3579
3876
|
case "label":
|
|
@@ -4822,11 +5119,25 @@ function escapeClassChar(ch2) {
|
|
|
4822
5119
|
}
|
|
4823
5120
|
|
|
4824
5121
|
// src/compiler/grammar-coverage-ids.ts
|
|
5122
|
+
function idPart(value) {
|
|
5123
|
+
return encodeURIComponent(value);
|
|
5124
|
+
}
|
|
5125
|
+
function dispatchArmIds(def, path2) {
|
|
5126
|
+
const ids = [];
|
|
5127
|
+
for (const entry of def.cases) ids.push(`dispatch:${path2}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5128
|
+
for (const entry of def.matchers ?? []) {
|
|
5129
|
+
ids.push(`dispatch:${path2}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5130
|
+
}
|
|
5131
|
+
if (def.otherwise) ids.push(`dispatch:${path2}/otherwise`);
|
|
5132
|
+
return ids;
|
|
5133
|
+
}
|
|
4825
5134
|
function children(def, winners) {
|
|
4826
5135
|
switch (def.tag) {
|
|
4827
5136
|
case "sequence":
|
|
4828
5137
|
case "choice":
|
|
4829
5138
|
return def.parsers;
|
|
5139
|
+
case "dispatch":
|
|
5140
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
4830
5141
|
case "many":
|
|
4831
5142
|
case "oneOrMore":
|
|
4832
5143
|
case "optional":
|
|
@@ -4869,6 +5180,7 @@ function children(def, winners) {
|
|
|
4869
5180
|
function buildGrammarPlan(entry, winners) {
|
|
4870
5181
|
const definitions = /* @__PURE__ */ new Map();
|
|
4871
5182
|
const choices = /* @__PURE__ */ new WeakMap();
|
|
5183
|
+
const dispatches = /* @__PURE__ */ new WeakMap();
|
|
4872
5184
|
const attempts = /* @__PURE__ */ new WeakMap();
|
|
4873
5185
|
const labels = /* @__PURE__ */ new WeakMap();
|
|
4874
5186
|
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -4899,6 +5211,11 @@ function buildGrammarPlan(entry, winners) {
|
|
|
4899
5211
|
choices.set(parser2, ids);
|
|
4900
5212
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
4901
5213
|
}
|
|
5214
|
+
if (parser2._def.tag === "dispatch") {
|
|
5215
|
+
const ids = dispatchArmIds(parser2._def, path2);
|
|
5216
|
+
dispatches.set(parser2, ids);
|
|
5217
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5218
|
+
}
|
|
4902
5219
|
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path2}`);
|
|
4903
5220
|
if (parser2._def.tag === "label") {
|
|
4904
5221
|
const id = `label:${path2}`;
|
|
@@ -4911,7 +5228,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
4911
5228
|
for (const root of roots) {
|
|
4912
5229
|
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
4913
5230
|
}
|
|
4914
|
-
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
5231
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
|
|
4915
5232
|
}
|
|
4916
5233
|
|
|
4917
5234
|
// src/compiler/scannable-run.ts
|
|
@@ -6285,12 +6602,15 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6285
6602
|
case "literal":
|
|
6286
6603
|
case "regex":
|
|
6287
6604
|
case "keywords":
|
|
6605
|
+
case "routed":
|
|
6288
6606
|
return { alts: [[seg(p._meta.firstSet, matchesEmpty(p))]] };
|
|
6289
6607
|
case "choice": {
|
|
6290
6608
|
const alts = [];
|
|
6291
6609
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6292
6610
|
return { alts };
|
|
6293
6611
|
}
|
|
6612
|
+
case "dispatch":
|
|
6613
|
+
return rec(d.selector);
|
|
6294
6614
|
case "sequence": {
|
|
6295
6615
|
const chain = [];
|
|
6296
6616
|
for (const term of d.parsers) {
|
|
@@ -6373,6 +6693,9 @@ function failReturn(expected, posExpr) {
|
|
|
6373
6693
|
function failReturnArr(expectedArr, posExpr) {
|
|
6374
6694
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6375
6695
|
}
|
|
6696
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6697
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6698
|
+
}
|
|
6376
6699
|
function hoistExpected(ctx, constArrSource) {
|
|
6377
6700
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6378
6701
|
if (name === void 0) {
|
|
@@ -6409,15 +6732,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6409
6732
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6410
6733
|
}
|
|
6411
6734
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6412
|
-
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
6735
|
+
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
|
|
6736
|
+
}
|
|
6737
|
+
function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
|
|
6738
|
+
if (ctx.failLabel) {
|
|
6739
|
+
if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
|
|
6740
|
+
return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
|
|
6741
|
+
}
|
|
6742
|
+
return committedReturnArr(expectedArr, posExpr);
|
|
6413
6743
|
}
|
|
6414
6744
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6415
6745
|
if (srcCtx !== "_ctx") {
|
|
6416
6746
|
if (ctx.failLabel) {
|
|
6417
6747
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6418
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; break ${ctx.failLabel} }`;
|
|
6748
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
|
|
6419
6749
|
}
|
|
6420
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; ${resultFromRecorded()} }`;
|
|
6750
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
|
|
6421
6751
|
}
|
|
6422
6752
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6423
6753
|
return resultFromRecorded();
|
|
@@ -6630,6 +6960,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6630
6960
|
// nothing committed remains.
|
|
6631
6961
|
case "choice":
|
|
6632
6962
|
return false;
|
|
6963
|
+
case "dispatch":
|
|
6964
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => mayLeavePartialCapture(x.parser, seen) || capturesLeaf(x.parser, seen)) || (d.matchers ? d.matchers.some((x) => mayLeavePartialCapture(x.parser, seen) || capturesLeaf(x.parser, seen)) : false) || (d.otherwise ? mayLeavePartialCapture(d.otherwise, seen) || capturesLeaf(d.otherwise, seen) : false);
|
|
6633
6965
|
case "attempt":
|
|
6634
6966
|
return false;
|
|
6635
6967
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6674,6 +7006,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6674
7006
|
return true;
|
|
6675
7007
|
}
|
|
6676
7008
|
}
|
|
7009
|
+
function mayCommitFailure(p, seen = /* @__PURE__ */ new Set()) {
|
|
7010
|
+
if (seen.has(p)) return false;
|
|
7011
|
+
seen.add(p);
|
|
7012
|
+
const d = p._def;
|
|
7013
|
+
switch (d.tag) {
|
|
7014
|
+
case "dispatch":
|
|
7015
|
+
return true;
|
|
7016
|
+
case "choice":
|
|
7017
|
+
case "sequence":
|
|
7018
|
+
return d.parsers.some((x) => mayCommitFailure(x, seen));
|
|
7019
|
+
case "many":
|
|
7020
|
+
case "oneOrMore":
|
|
7021
|
+
case "optional":
|
|
7022
|
+
case "attempt":
|
|
7023
|
+
case "transform":
|
|
7024
|
+
case "label":
|
|
7025
|
+
case "field":
|
|
7026
|
+
case "grammar":
|
|
7027
|
+
case "node":
|
|
7028
|
+
return mayCommitFailure(d.parser, seen);
|
|
7029
|
+
case "sepBy":
|
|
7030
|
+
return mayCommitFailure(d.parser, seen) || mayCommitFailure(d.separator, seen);
|
|
7031
|
+
case "skip":
|
|
7032
|
+
return mayCommitFailure(d.main, seen) || mayCommitFailure(d.skipped, seen);
|
|
7033
|
+
case "token":
|
|
7034
|
+
case "leaf":
|
|
7035
|
+
return mayCommitFailure(d.parser, seen);
|
|
7036
|
+
case "withCtx":
|
|
7037
|
+
return mayCommitFailure(d.parser, seen);
|
|
7038
|
+
case "scanTo":
|
|
7039
|
+
return mayCommitFailure(d.sentinel, seen) || d.skip.some((x) => mayCommitFailure(x, seen));
|
|
7040
|
+
case "lazy": {
|
|
7041
|
+
try {
|
|
7042
|
+
return mayCommitFailure(d.thunk(), seen);
|
|
7043
|
+
} catch {
|
|
7044
|
+
return true;
|
|
7045
|
+
}
|
|
7046
|
+
}
|
|
7047
|
+
case "unknown":
|
|
7048
|
+
return true;
|
|
7049
|
+
default:
|
|
7050
|
+
return false;
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
6677
7053
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6678
7054
|
if (seen.has(p)) return false;
|
|
6679
7055
|
seen.add(p);
|
|
@@ -6684,6 +7060,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6684
7060
|
case "keywords":
|
|
6685
7061
|
case "node":
|
|
6686
7062
|
case "token":
|
|
7063
|
+
case "routed":
|
|
6687
7064
|
case "leaf":
|
|
6688
7065
|
return true;
|
|
6689
7066
|
case "not":
|
|
@@ -6695,6 +7072,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6695
7072
|
case "sequence":
|
|
6696
7073
|
case "choice":
|
|
6697
7074
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
7075
|
+
case "dispatch":
|
|
7076
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => capturesLeaf(entry.parser, seen)) : false) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
6698
7077
|
case "sepBy":
|
|
6699
7078
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6700
7079
|
case "many":
|
|
@@ -6741,6 +7120,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6741
7120
|
ctx.recordFail = savedRecord;
|
|
6742
7121
|
const ind0 = ind(ctx);
|
|
6743
7122
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
7123
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6744
7124
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6745
7125
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6746
7126
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6754,6 +7134,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6754
7134
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6755
7135
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6756
7136
|
] : [],
|
|
7137
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6757
7138
|
`${ind0}${lbl}: {`,
|
|
6758
7139
|
...r.stmts,
|
|
6759
7140
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6762,7 +7143,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6762
7143
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6763
7144
|
] : []
|
|
6764
7145
|
];
|
|
6765
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
7146
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6766
7147
|
}
|
|
6767
7148
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6768
7149
|
function emitLit(def, ctx, pos) {
|
|
@@ -7139,6 +7520,186 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7139
7520
|
}
|
|
7140
7521
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7141
7522
|
}
|
|
7523
|
+
function emitTailFallible(parser2, ctx, pos) {
|
|
7524
|
+
const savedRecord = ctx.recordFail;
|
|
7525
|
+
ctx.recordFail = true;
|
|
7526
|
+
const out = emitFallible(parser2, ctx, pos);
|
|
7527
|
+
ctx.recordFail = savedRecord;
|
|
7528
|
+
return out;
|
|
7529
|
+
}
|
|
7530
|
+
function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
7531
|
+
if (seen.has(p)) return false;
|
|
7532
|
+
seen.add(p);
|
|
7533
|
+
const d = p._def;
|
|
7534
|
+
switch (d.tag) {
|
|
7535
|
+
case "expect":
|
|
7536
|
+
case "recover":
|
|
7537
|
+
return true;
|
|
7538
|
+
case "many":
|
|
7539
|
+
case "oneOrMore":
|
|
7540
|
+
case "sepBy":
|
|
7541
|
+
return recovery || mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7542
|
+
case "choice":
|
|
7543
|
+
case "sequence": {
|
|
7544
|
+
for (const item of d.parsers) {
|
|
7545
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7546
|
+
}
|
|
7547
|
+
return false;
|
|
7548
|
+
}
|
|
7549
|
+
case "dispatch": {
|
|
7550
|
+
if (mayRecordRecoveryError(d.selector, recovery, seen)) return true;
|
|
7551
|
+
for (const item of d.cases) {
|
|
7552
|
+
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7553
|
+
}
|
|
7554
|
+
if (d.matchers?.some((item) => mayRecordRecoveryError(item.parser, recovery, seen))) return true;
|
|
7555
|
+
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7556
|
+
}
|
|
7557
|
+
case "attempt":
|
|
7558
|
+
case "transform":
|
|
7559
|
+
case "label":
|
|
7560
|
+
case "field":
|
|
7561
|
+
case "grammar":
|
|
7562
|
+
case "node":
|
|
7563
|
+
case "token":
|
|
7564
|
+
case "leaf":
|
|
7565
|
+
case "withCtx":
|
|
7566
|
+
case "optional":
|
|
7567
|
+
return mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7568
|
+
case "skip":
|
|
7569
|
+
return mayRecordRecoveryError(d.main, recovery, seen) || mayRecordRecoveryError(d.skipped, recovery, seen);
|
|
7570
|
+
case "scanTo":
|
|
7571
|
+
if (mayRecordRecoveryError(d.sentinel, recovery, seen)) return true;
|
|
7572
|
+
for (const item of d.skip) {
|
|
7573
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7574
|
+
}
|
|
7575
|
+
return false;
|
|
7576
|
+
case "lazy": {
|
|
7577
|
+
try {
|
|
7578
|
+
return mayRecordRecoveryError(d.thunk(), recovery, seen);
|
|
7579
|
+
} catch {
|
|
7580
|
+
return true;
|
|
7581
|
+
}
|
|
7582
|
+
}
|
|
7583
|
+
case "unknown":
|
|
7584
|
+
return true;
|
|
7585
|
+
default:
|
|
7586
|
+
return false;
|
|
7587
|
+
}
|
|
7588
|
+
}
|
|
7589
|
+
function emitDispatchCombinator(parser2, def, ctx, pos) {
|
|
7590
|
+
if (parserUsesRouted2(def.selector)) {
|
|
7591
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
7592
|
+
}
|
|
7593
|
+
const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
|
|
7594
|
+
const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
|
|
7595
|
+
const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
|
|
7596
|
+
const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
|
|
7597
|
+
const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
|
|
7598
|
+
const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
|
|
7599
|
+
const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
|
|
7600
|
+
const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
|
|
7601
|
+
const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
|
|
7602
|
+
const selector = emit(def.selector, ctx, pos);
|
|
7603
|
+
const outV = v(ctx, "_dval");
|
|
7604
|
+
const outE = v(ctx, "_dend");
|
|
7605
|
+
const keyV = v(ctx, "_dkey");
|
|
7606
|
+
const stmts = [
|
|
7607
|
+
...selectorLeafMark ? [
|
|
7608
|
+
`${ind(ctx)}const ${selectorLeafMark} = _ctx._cstLeaves?.length ?? 0`,
|
|
7609
|
+
`${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
|
|
7610
|
+
`${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
7611
|
+
`${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
|
|
7612
|
+
`${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
|
|
7613
|
+
`${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
|
|
7614
|
+
] : [],
|
|
7615
|
+
...selector.stmts,
|
|
7616
|
+
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7617
|
+
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7618
|
+
];
|
|
7619
|
+
let wroteBranch = false;
|
|
7620
|
+
const emitSelectedTail = (entry, keyword, condition, coverageId) => {
|
|
7621
|
+
const parser3 = entry.parser;
|
|
7622
|
+
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7623
|
+
stmts.push(head);
|
|
7624
|
+
ctx.indent++;
|
|
7625
|
+
const usesRouted = branchUsesRouted2(entry);
|
|
7626
|
+
const routedV = usesRouted ? v(ctx, "_drt") : null;
|
|
7627
|
+
const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
|
|
7628
|
+
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7629
|
+
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7630
|
+
if (routedV) {
|
|
7631
|
+
stmts.push(
|
|
7632
|
+
`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
|
|
7633
|
+
...selectorLeafMark ? [
|
|
7634
|
+
`${ind(ctx)}if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${selectorLeafMark}) _ctx._cstLeaves.length = ${selectorLeafMark}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${selectorRawMark}) _ctx._cstRawChildren.length = ${selectorRawMark}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${selectorTriviaMark}) _ctx._cstTriviaLog.length = ${selectorTriviaMark}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${selectorLogMark}) _ctx._triviaLog.length = ${selectorLogMark}; if (_ctx._fields && _ctx._fields.length !== ${selectorFieldMark}) _ctx._fields.length = ${selectorFieldMark}; if (_ctx._errors && _ctx._errors.length !== ${selectorErrorMark}) _ctx._errors.length = ${selectorErrorMark}`
|
|
7635
|
+
] : []
|
|
7636
|
+
);
|
|
7637
|
+
}
|
|
7638
|
+
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7639
|
+
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7640
|
+
const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
|
|
7641
|
+
stmts.push(...coverageAttempt(ctx, coverageId, pos));
|
|
7642
|
+
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7643
|
+
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7644
|
+
const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
|
|
7645
|
+
const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
|
|
7646
|
+
stmts.push(
|
|
7647
|
+
...tail.stmts,
|
|
7648
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
|
|
7649
|
+
...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
|
|
7650
|
+
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7651
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`,
|
|
7652
|
+
...coverageHit(ctx, coverageId, pos, tail.endVar)
|
|
7653
|
+
);
|
|
7654
|
+
ctx.indent--;
|
|
7655
|
+
stmts.push(`${ind(ctx)}}`);
|
|
7656
|
+
};
|
|
7657
|
+
let coverageIndex = 0;
|
|
7658
|
+
for (const entry of def.cases) {
|
|
7659
|
+
const condition = entry.keys.map((key) => emitDispatchKeyCondition(keyV, key, entry.caseInsensitive)).join(" || ");
|
|
7660
|
+
emitSelectedTail(entry, wroteBranch ? "else if" : "if", condition, coverageIds[coverageIndex++]);
|
|
7661
|
+
wroteBranch = true;
|
|
7662
|
+
}
|
|
7663
|
+
const emitMatcherTails = () => {
|
|
7664
|
+
for (const matcher of def.matchers ?? []) {
|
|
7665
|
+
emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
|
|
7666
|
+
wroteBranch = true;
|
|
7667
|
+
}
|
|
7668
|
+
};
|
|
7669
|
+
if (def.otherwise) {
|
|
7670
|
+
emitMatcherTails();
|
|
7671
|
+
const otherwiseEntry = { parser: def.otherwise, usesRouted: def.otherwiseUsesRouted };
|
|
7672
|
+
if (wroteBranch) emitSelectedTail(otherwiseEntry, "else", void 0, coverageIds[coverageIndex++]);
|
|
7673
|
+
else emitSelectedTail(otherwiseEntry, "if", "true", coverageIds[coverageIndex++]);
|
|
7674
|
+
} else {
|
|
7675
|
+
emitMatcherTails();
|
|
7676
|
+
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7677
|
+
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7678
|
+
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7679
|
+
}
|
|
7680
|
+
return { stmts, valueVar: outV, endVar: outE };
|
|
7681
|
+
}
|
|
7682
|
+
function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
|
|
7683
|
+
if (!caseInsensitive) return `${valueVar} === ${JSON.stringify(key)}`;
|
|
7684
|
+
const parts = [`${valueVar}.length === ${key.length}`];
|
|
7685
|
+
for (let i = 0; i < key.length; i++) {
|
|
7686
|
+
parts.push(foldEq(`${valueVar}.charCodeAt(${i})`, key.charCodeAt(i)));
|
|
7687
|
+
}
|
|
7688
|
+
return parts.join(" && ");
|
|
7689
|
+
}
|
|
7690
|
+
function emitDispatchMatcherCondition(valueVar, matcher) {
|
|
7691
|
+
if (matcher.kind === "matches") {
|
|
7692
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
7693
|
+
return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
|
|
7694
|
+
}
|
|
7695
|
+
const text = matcher.value;
|
|
7696
|
+
const parts = [`${valueVar}.length >= ${text.length}`];
|
|
7697
|
+
const offset = matcher.kind === "endsWith" ? `${valueVar}.length - ${text.length}` : "0";
|
|
7698
|
+
for (let i = 0; i < text.length; i++) {
|
|
7699
|
+
parts.push(matcher.caseInsensitive ? foldEq(`${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`})`, text.charCodeAt(i)) : `${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`}) === ${text.charCodeAt(i)}`);
|
|
7700
|
+
}
|
|
7701
|
+
return parts.join(" && ");
|
|
7702
|
+
}
|
|
7142
7703
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7143
7704
|
const superParser = def.parsers[superIndex];
|
|
7144
7705
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7260,12 +7821,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7260
7821
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7261
7822
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7262
7823
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7824
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7263
7825
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7264
7826
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7265
7827
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7266
7828
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7267
7829
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7268
|
-
const
|
|
7830
|
+
const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
|
|
7831
|
+
const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
7832
|
+
const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
|
|
7833
|
+
const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
|
|
7269
7834
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7270
7835
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7271
7836
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7280,7 +7845,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7280
7845
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7281
7846
|
);
|
|
7282
7847
|
}
|
|
7283
|
-
|
|
7848
|
+
if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
|
|
7849
|
+
const arm = emitFallible(p, ctx, pos, atStart);
|
|
7850
|
+
const { stmts: armStmts, okVar, valVar, endVar } = arm;
|
|
7284
7851
|
stmts.push(...armStmts);
|
|
7285
7852
|
if (autoNot && autoNot.length > 0) {
|
|
7286
7853
|
const anCode = v(ctx, "_anc");
|
|
@@ -7304,10 +7871,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7304
7871
|
stmts.push(`${ind(ctx)}}`);
|
|
7305
7872
|
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} });`} }`);
|
|
7306
7873
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7874
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7307
7875
|
} else {
|
|
7308
7876
|
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} }) }`;
|
|
7309
7877
|
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} })`} }`);
|
|
7310
7878
|
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} })`} }`);
|
|
7879
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7311
7880
|
}
|
|
7312
7881
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7313
7882
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7464,7 +8033,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7464
8033
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7465
8034
|
);
|
|
7466
8035
|
}
|
|
7467
|
-
const
|
|
8036
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
8037
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7468
8038
|
stmts.push(...iterStmts);
|
|
7469
8039
|
if (ctx.recovery) {
|
|
7470
8040
|
const rrV = v(ctx, "_rr");
|
|
@@ -7483,7 +8053,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7483
8053
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7484
8054
|
);
|
|
7485
8055
|
} else {
|
|
7486
|
-
stmts.push(`${ind(ctx)}if (!${iterOk}
|
|
8056
|
+
stmts.push(`${ind(ctx)}if (!${iterOk}) { ${rollback}${iter.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
8057
|
+
stmts.push(`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
7487
8058
|
}
|
|
7488
8059
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7489
8060
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7495,10 +8066,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7495
8066
|
function emitOptional(def, ctx, pos) {
|
|
7496
8067
|
const valV = v(ctx, "_opt");
|
|
7497
8068
|
const endV = v(ctx, "_opte");
|
|
7498
|
-
const
|
|
8069
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
8070
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7499
8071
|
const ind0 = ind(ctx);
|
|
7500
8072
|
const stmts = [
|
|
7501
8073
|
...lblStmts,
|
|
8074
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7502
8075
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7503
8076
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7504
8077
|
];
|
|
@@ -7530,7 +8103,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7530
8103
|
...preGuard,
|
|
7531
8104
|
`${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`,
|
|
7532
8105
|
...inner.stmts,
|
|
7533
|
-
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
8106
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7534
8107
|
],
|
|
7535
8108
|
valueVar: inner.valVar,
|
|
7536
8109
|
endVar: inner.endVar
|
|
@@ -7544,18 +8117,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7544
8117
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7545
8118
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7546
8119
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7547
|
-
const
|
|
8120
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
8121
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7548
8122
|
const stmts = [
|
|
7549
8123
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7550
8124
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7551
8125
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7552
8126
|
...firstStmts
|
|
7553
8127
|
];
|
|
7554
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7555
|
-
if (
|
|
8128
|
+
const failItem = (nextOkVar, nextMayCommit, itemPosVar, breakStmt) => {
|
|
8129
|
+
const commit = nextMayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : "";
|
|
8130
|
+
if (!rec) return [`${ind(ctx)}if (!${nextOkVar}) { ${commit}${breakStmt} }`];
|
|
7556
8131
|
const rr = v(ctx, "_rr");
|
|
7557
8132
|
return [
|
|
7558
8133
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
8134
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7559
8135
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7560
8136
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7561
8137
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7584,6 +8160,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7584
8160
|
stmts.push(
|
|
7585
8161
|
`${ind(ctx)}let ${didV} = false`,
|
|
7586
8162
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
8163
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7587
8164
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7588
8165
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7589
8166
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7594,6 +8171,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7594
8171
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7595
8172
|
ctx.indent++;
|
|
7596
8173
|
} else {
|
|
8174
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7597
8175
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7598
8176
|
ctx.indent++;
|
|
7599
8177
|
stmts.push(
|
|
@@ -7622,16 +8200,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7622
8200
|
);
|
|
7623
8201
|
sepAtPos = spV;
|
|
7624
8202
|
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}; `;
|
|
7625
|
-
const
|
|
7626
|
-
stmts
|
|
8203
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8204
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
8205
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7627
8206
|
const post = postSepMarks();
|
|
7628
8207
|
stmts.push(...post.decl);
|
|
7629
8208
|
const npV = v(ctx, "_np");
|
|
7630
8209
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7631
|
-
const
|
|
8210
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8211
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7632
8212
|
stmts.push(
|
|
7633
8213
|
...nextStmts,
|
|
7634
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
8214
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7635
8215
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7636
8216
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7637
8217
|
);
|
|
@@ -7640,14 +8220,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7640
8220
|
const spV = v(ctx, "_sp");
|
|
7641
8221
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7642
8222
|
sepAtPos = spV;
|
|
7643
|
-
const
|
|
7644
|
-
stmts
|
|
8223
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8224
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
8225
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7645
8226
|
const npV = v(ctx, "_np");
|
|
7646
8227
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7647
|
-
const
|
|
8228
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8229
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7648
8230
|
stmts.push(
|
|
7649
8231
|
...nextStmts,
|
|
7650
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
8232
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7651
8233
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7652
8234
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7653
8235
|
);
|
|
@@ -7661,15 +8243,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7661
8243
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7662
8244
|
);
|
|
7663
8245
|
}
|
|
7664
|
-
const
|
|
7665
|
-
stmts
|
|
8246
|
+
const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8247
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
|
|
8248
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7666
8249
|
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}; ` : "";
|
|
7667
8250
|
const post = postSepMarks();
|
|
7668
8251
|
stmts.push(...post.decl);
|
|
7669
|
-
const
|
|
8252
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
8253
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7670
8254
|
stmts.push(
|
|
7671
8255
|
...nextStmts,
|
|
7672
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
8256
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7673
8257
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7674
8258
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7675
8259
|
);
|
|
@@ -7770,6 +8354,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
7770
8354
|
endVar: pos
|
|
7771
8355
|
};
|
|
7772
8356
|
}
|
|
8357
|
+
function emitRouted(ctx, pos) {
|
|
8358
|
+
const item = v(ctx, "_rt");
|
|
8359
|
+
return {
|
|
8360
|
+
stmts: [
|
|
8361
|
+
`${ind(ctx)}const ${item} = _ctx._routed`,
|
|
8362
|
+
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8363
|
+
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8364
|
+
],
|
|
8365
|
+
valueVar: `${item}.value`,
|
|
8366
|
+
endVar: `${item}.span.end`
|
|
8367
|
+
};
|
|
8368
|
+
}
|
|
7773
8369
|
function escapeTokenLiteral(value) {
|
|
7774
8370
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
7775
8371
|
}
|
|
@@ -8050,7 +8646,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
8050
8646
|
const rv = v(ctx, "_rt");
|
|
8051
8647
|
const vv = v(ctx, "_rtv");
|
|
8052
8648
|
const ev = v(ctx, "_rte");
|
|
8053
|
-
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 }`;
|
|
8649
|
+
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 } : {}) }`;
|
|
8054
8650
|
const stmts = [
|
|
8055
8651
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8056
8652
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8131,7 +8727,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8131
8727
|
return { stmts, valueVar: valVar, endVar };
|
|
8132
8728
|
}
|
|
8133
8729
|
function emitExpect(def, ctx, pos) {
|
|
8134
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8730
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8135
8731
|
const ind0 = ind(ctx);
|
|
8136
8732
|
const errV = v(ctx, "_err");
|
|
8137
8733
|
const stmts = [
|
|
@@ -8143,6 +8739,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8143
8739
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8144
8740
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8145
8741
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8742
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8146
8743
|
`${ind0} ${valVar} = ${errV}`,
|
|
8147
8744
|
`${ind0} ${endVar} = ${pos}`,
|
|
8148
8745
|
`${ind0} ${okVar} = true`,
|
|
@@ -8153,7 +8750,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8153
8750
|
function emit(p, ctx, pos) {
|
|
8154
8751
|
const replay = ctx.replayPrefix?.get(p);
|
|
8155
8752
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8156
|
-
const
|
|
8753
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8157
8754
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8158
8755
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8159
8756
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8193,14 +8790,14 @@ function emit(p, ctx, pos) {
|
|
|
8193
8790
|
ctx.indent = 1;
|
|
8194
8791
|
ctx.failLabel = "_pfail";
|
|
8195
8792
|
ctx.recordFail = true;
|
|
8196
|
-
const r =
|
|
8793
|
+
const r = dispatch2("_pos");
|
|
8197
8794
|
ctx.indent = savedIndent;
|
|
8198
8795
|
ctx.failLabel = savedFailLabel;
|
|
8199
8796
|
ctx.recordFail = savedRecord;
|
|
8200
8797
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8201
8798
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8202
8799
|
}
|
|
8203
|
-
return instrument(
|
|
8800
|
+
return instrument(dispatch2());
|
|
8204
8801
|
}
|
|
8205
8802
|
function emitDispatch(p, ctx, pos) {
|
|
8206
8803
|
const bal = p._balancedAmbient;
|
|
@@ -8233,6 +8830,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8233
8830
|
return emitSeq(def, ctx, pos);
|
|
8234
8831
|
case "choice":
|
|
8235
8832
|
return emitChoice(p, def, ctx, pos);
|
|
8833
|
+
case "dispatch":
|
|
8834
|
+
return emitDispatchCombinator(p, def, ctx, pos);
|
|
8236
8835
|
case "attempt":
|
|
8237
8836
|
return emitAttempt(p, def, ctx, pos);
|
|
8238
8837
|
case "many":
|
|
@@ -8357,6 +8956,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8357
8956
|
return emitNot(def, ctx, pos);
|
|
8358
8957
|
case "peek":
|
|
8359
8958
|
return emitPeek(def, ctx, pos);
|
|
8959
|
+
case "routed":
|
|
8960
|
+
return emitRouted(ctx, pos);
|
|
8360
8961
|
case "node":
|
|
8361
8962
|
return emitNode(def, ctx, pos);
|
|
8362
8963
|
case "scanTo":
|
|
@@ -8453,6 +9054,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8453
9054
|
case "sequence":
|
|
8454
9055
|
case "choice":
|
|
8455
9056
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
9057
|
+
case "dispatch":
|
|
9058
|
+
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => hasNodeDef(entry.parser, seen)) : false) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
8456
9059
|
case "sepBy":
|
|
8457
9060
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8458
9061
|
case "scanTo":
|
|
@@ -8467,6 +9070,26 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8467
9070
|
return false;
|
|
8468
9071
|
}
|
|
8469
9072
|
}
|
|
9073
|
+
function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
|
|
9074
|
+
if (seen.has(p)) return false;
|
|
9075
|
+
seen.add(p);
|
|
9076
|
+
const d = p._def;
|
|
9077
|
+
switch (d.tag) {
|
|
9078
|
+
case "routed":
|
|
9079
|
+
return true;
|
|
9080
|
+
case "lazy": {
|
|
9081
|
+
try {
|
|
9082
|
+
return parserUsesRouted2(d.thunk(), seen);
|
|
9083
|
+
} catch {
|
|
9084
|
+
return false;
|
|
9085
|
+
}
|
|
9086
|
+
}
|
|
9087
|
+
case "dispatch":
|
|
9088
|
+
return false;
|
|
9089
|
+
default:
|
|
9090
|
+
return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
|
|
9091
|
+
}
|
|
9092
|
+
}
|
|
8470
9093
|
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
8471
9094
|
if (seen.has(p)) return false;
|
|
8472
9095
|
seen.add(p);
|
|
@@ -8486,6 +9109,8 @@ function childrenOf2(def) {
|
|
|
8486
9109
|
case "sequence":
|
|
8487
9110
|
case "choice":
|
|
8488
9111
|
return def.parsers;
|
|
9112
|
+
case "dispatch":
|
|
9113
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
8489
9114
|
case "many":
|
|
8490
9115
|
case "attempt":
|
|
8491
9116
|
case "optional":
|
|
@@ -8522,6 +9147,7 @@ function childrenOf2(def) {
|
|
|
8522
9147
|
case "regex":
|
|
8523
9148
|
case "keywords":
|
|
8524
9149
|
case "guard":
|
|
9150
|
+
case "routed":
|
|
8525
9151
|
case "unknown":
|
|
8526
9152
|
return [];
|
|
8527
9153
|
}
|
|
@@ -8529,6 +9155,7 @@ function childrenOf2(def) {
|
|
|
8529
9155
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8530
9156
|
"sequence",
|
|
8531
9157
|
"choice",
|
|
9158
|
+
"dispatch",
|
|
8532
9159
|
"many",
|
|
8533
9160
|
"oneOrMore",
|
|
8534
9161
|
"optional",
|
|
@@ -9353,6 +9980,8 @@ function childrenOf3(def) {
|
|
|
9353
9980
|
case "sequence":
|
|
9354
9981
|
case "choice":
|
|
9355
9982
|
return def.parsers;
|
|
9983
|
+
case "dispatch":
|
|
9984
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
9356
9985
|
case "many":
|
|
9357
9986
|
case "oneOrMore":
|
|
9358
9987
|
case "optional":
|
|
@@ -9381,6 +10010,7 @@ function childrenOf3(def) {
|
|
|
9381
10010
|
case "literal":
|
|
9382
10011
|
case "regex":
|
|
9383
10012
|
case "keywords":
|
|
10013
|
+
case "routed":
|
|
9384
10014
|
case "guard":
|
|
9385
10015
|
case "recover":
|
|
9386
10016
|
case "unknown":
|
|
@@ -9405,6 +10035,16 @@ function repeatOpts(min, max, trailing) {
|
|
|
9405
10035
|
if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
|
|
9406
10036
|
return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
|
|
9407
10037
|
}
|
|
10038
|
+
function matcherExpr(entry) {
|
|
10039
|
+
switch (entry.kind) {
|
|
10040
|
+
case "startsWith":
|
|
10041
|
+
return `startsWith(${JSON.stringify(entry.value)})`;
|
|
10042
|
+
case "endsWith":
|
|
10043
|
+
return `endsWith(${JSON.stringify(entry.value)})`;
|
|
10044
|
+
case "matches":
|
|
10045
|
+
return `matches(${new RegExp(entry.value, entry.flags ?? "").toString()})`;
|
|
10046
|
+
}
|
|
10047
|
+
}
|
|
9408
10048
|
function serializeRuleMap(ruleMap, scanSkip) {
|
|
9409
10049
|
try {
|
|
9410
10050
|
return new Serializer(ruleMap, scanSkip ?? []).run();
|
|
@@ -9502,6 +10142,13 @@ function evalRuleMapIR(ir) {
|
|
|
9502
10142
|
"keywords",
|
|
9503
10143
|
"sequence",
|
|
9504
10144
|
"choice",
|
|
10145
|
+
"dispatch",
|
|
10146
|
+
"when",
|
|
10147
|
+
"startsWith",
|
|
10148
|
+
"endsWith",
|
|
10149
|
+
"matches",
|
|
10150
|
+
"otherwise",
|
|
10151
|
+
"routed",
|
|
9505
10152
|
"attempt",
|
|
9506
10153
|
"many",
|
|
9507
10154
|
"oneOrMore",
|
|
@@ -9535,6 +10182,13 @@ function evalRuleMapIR(ir) {
|
|
|
9535
10182
|
keywords,
|
|
9536
10183
|
sequence,
|
|
9537
10184
|
choice,
|
|
10185
|
+
dispatch,
|
|
10186
|
+
when,
|
|
10187
|
+
startsWith,
|
|
10188
|
+
endsWith,
|
|
10189
|
+
matches,
|
|
10190
|
+
otherwise,
|
|
10191
|
+
routed,
|
|
9538
10192
|
attempt,
|
|
9539
10193
|
many,
|
|
9540
10194
|
oneOrMore,
|
|
@@ -9720,6 +10374,18 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9720
10374
|
});
|
|
9721
10375
|
return `_gch([${items.join(", ")}])`;
|
|
9722
10376
|
}
|
|
10377
|
+
case "dispatch": {
|
|
10378
|
+
const arms = def.cases.map(
|
|
10379
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`
|
|
10380
|
+
);
|
|
10381
|
+
if (def.matchers) {
|
|
10382
|
+
for (const entry of def.matchers) {
|
|
10383
|
+
arms.push(`when(${matcherExpr(entry)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`);
|
|
10384
|
+
}
|
|
10385
|
+
}
|
|
10386
|
+
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10387
|
+
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10388
|
+
}
|
|
9723
10389
|
case "many":
|
|
9724
10390
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9725
10391
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -9736,6 +10402,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9736
10402
|
return `not(${kid(def.parser)})`;
|
|
9737
10403
|
case "peek":
|
|
9738
10404
|
return `peek(${kid(def.parser)})`;
|
|
10405
|
+
case "routed":
|
|
10406
|
+
return "routed()";
|
|
9739
10407
|
case "trivia":
|
|
9740
10408
|
return `trivia(${kid(def.parser)})`;
|
|
9741
10409
|
case "token":
|
|
@@ -10205,6 +10873,12 @@ function stripTsFromSource(node2, code) {
|
|
|
10205
10873
|
function isWordFactory(v2) {
|
|
10206
10874
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
10207
10875
|
}
|
|
10876
|
+
function isWhenFactory(v2) {
|
|
10877
|
+
return !!v2 && typeof v2 === "object" && v2.tag === "whenFactory";
|
|
10878
|
+
}
|
|
10879
|
+
function isStaticValueEntry(v2) {
|
|
10880
|
+
return !!v2 && typeof v2 === "object" && "value" in v2 && "mfSrcs" in v2;
|
|
10881
|
+
}
|
|
10208
10882
|
function wordFactoryFromArgs(args, scope, code, mfs) {
|
|
10209
10883
|
const [boundaryOrOptsArg, optsArg] = args;
|
|
10210
10884
|
if (boundaryOrOptsArg?.type === "SpreadElement" || optsArg?.type === "SpreadElement") return null;
|
|
@@ -10224,6 +10898,23 @@ function wordFactoryFromArgs(args, scope, code, mfs) {
|
|
|
10224
10898
|
if (typeof caseInsensitive !== "boolean") return null;
|
|
10225
10899
|
return { tag: "wordFactory", boundary: "_0-9A-Za-z", caseInsensitive };
|
|
10226
10900
|
}
|
|
10901
|
+
function dispatchWhenOptions(v2) {
|
|
10902
|
+
if (v2 === void 0) return {};
|
|
10903
|
+
if (typeof v2 !== "object" || v2 === null || Array.isArray(v2)) return null;
|
|
10904
|
+
for (const key of Object.keys(v2)) {
|
|
10905
|
+
if (key !== "caseInsensitive") return null;
|
|
10906
|
+
}
|
|
10907
|
+
const caseInsensitive = "caseInsensitive" in v2 ? v2.caseInsensitive : false;
|
|
10908
|
+
if (typeof caseInsensitive !== "boolean") return null;
|
|
10909
|
+
return { caseInsensitive };
|
|
10910
|
+
}
|
|
10911
|
+
function whenFactoryFromArgs(args, scope, code, mfs) {
|
|
10912
|
+
const [optsArg, extra] = args;
|
|
10913
|
+
if (optsArg?.type === "SpreadElement" || extra !== void 0) return null;
|
|
10914
|
+
const rawOpts = optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs);
|
|
10915
|
+
const opts = dispatchWhenOptions(rawOpts);
|
|
10916
|
+
return opts === null ? null : { tag: "whenFactory", caseInsensitive: opts.caseInsensitive ?? false };
|
|
10917
|
+
}
|
|
10227
10918
|
var SUPPORTED = {
|
|
10228
10919
|
literal: (...a) => literal(a[0], a[1]),
|
|
10229
10920
|
regex: (...a) => regex(a[0], a[1]),
|
|
@@ -10239,6 +10930,7 @@ var SUPPORTED = {
|
|
|
10239
10930
|
field: (...a) => field(a[0], a[1]),
|
|
10240
10931
|
noTrivia: (...a) => noTrivia(a[0]),
|
|
10241
10932
|
token: (...a) => token(a[0]),
|
|
10933
|
+
routed: () => routed(),
|
|
10242
10934
|
leaf: (...a) => leaf(a[0], a[1]),
|
|
10243
10935
|
expect: (...a) => expect(a[0], a[1])
|
|
10244
10936
|
};
|
|
@@ -10274,9 +10966,65 @@ function gatedArmParts(e) {
|
|
|
10274
10966
|
}
|
|
10275
10967
|
return gate2 && combinator ? { gate: gate2, combinator } : null;
|
|
10276
10968
|
}
|
|
10969
|
+
function dispatchArmValue(node2, scope, code, mfs) {
|
|
10970
|
+
if (node2.type === "Identifier") {
|
|
10971
|
+
const value = anyValue(node2, scope, code, mfs);
|
|
10972
|
+
return isDispatchArm(value) ? value : null;
|
|
10973
|
+
}
|
|
10974
|
+
if (node2.type !== "CallExpression") return null;
|
|
10975
|
+
const callee = node2.callee;
|
|
10976
|
+
if (callee.type !== "Identifier") return null;
|
|
10977
|
+
const factory = scope.get(callee.name);
|
|
10978
|
+
if (isWhenFactory(factory)) {
|
|
10979
|
+
const [keyArg, parserArg, extraArg] = node2.arguments;
|
|
10980
|
+
if (!keyArg || !parserArg || extraArg !== void 0 || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
10981
|
+
const key = anyValue(keyArg, scope, code, mfs);
|
|
10982
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
10983
|
+
if (!isCombinator(parserValue)) return null;
|
|
10984
|
+
const opts = { caseInsensitive: factory.caseInsensitive };
|
|
10985
|
+
if (typeof key === "string") return when(key, parserValue, opts);
|
|
10986
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
|
|
10987
|
+
return null;
|
|
10988
|
+
}
|
|
10989
|
+
if (callee.name === "otherwise") {
|
|
10990
|
+
const [parserArg] = node2.arguments;
|
|
10991
|
+
if (!parserArg || parserArg.type === "SpreadElement") return null;
|
|
10992
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
10993
|
+
if (!isCombinator(parserValue)) return null;
|
|
10994
|
+
return otherwise(parserValue);
|
|
10995
|
+
}
|
|
10996
|
+
if (callee.name === "when") {
|
|
10997
|
+
const [keyArg, parserArg, optsArg] = node2.arguments;
|
|
10998
|
+
if (!keyArg || !parserArg || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement" || optsArg?.type === "SpreadElement") return null;
|
|
10999
|
+
const key = anyValue(keyArg, scope, code, mfs);
|
|
11000
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
11001
|
+
const opts = dispatchWhenOptions(optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs));
|
|
11002
|
+
if (opts === null) return null;
|
|
11003
|
+
if (!isCombinator(parserValue)) return null;
|
|
11004
|
+
if (typeof key === "string") return when(key, parserValue, opts);
|
|
11005
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
|
|
11006
|
+
if (isDispatchMatcher(key)) return when(key, parserValue, opts);
|
|
11007
|
+
}
|
|
11008
|
+
return null;
|
|
11009
|
+
}
|
|
10277
11010
|
function isCombinator(v2) {
|
|
10278
11011
|
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
10279
11012
|
}
|
|
11013
|
+
function isDispatchArm(v2) {
|
|
11014
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
11015
|
+
const rec = v2;
|
|
11016
|
+
if (rec.kind === "otherwise") return isCombinator(rec.parser);
|
|
11017
|
+
if (rec.kind === "whenMatcher") {
|
|
11018
|
+
return isDispatchMatcher(rec.matcher) && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
|
|
11019
|
+
}
|
|
11020
|
+
return rec.kind === "when" && Array.isArray(rec.keys) && rec.keys.every((key) => typeof key === "string") && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
|
|
11021
|
+
}
|
|
11022
|
+
function isDispatchMatcher(v2) {
|
|
11023
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
11024
|
+
const rec = v2;
|
|
11025
|
+
if ((rec.kind === "startsWith" || rec.kind === "endsWith") && typeof rec.value === "string") return true;
|
|
11026
|
+
return rec.kind === "matches" && typeof rec.value === "string" && typeof rec.flags === "string";
|
|
11027
|
+
}
|
|
10280
11028
|
function scopeGet(scope, name, mfs) {
|
|
10281
11029
|
const entry = scope.get(name);
|
|
10282
11030
|
if (!entry) return null;
|
|
@@ -10533,6 +11281,25 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10533
11281
|
return null;
|
|
10534
11282
|
}
|
|
10535
11283
|
}
|
|
11284
|
+
if (callee.name === "dispatch") {
|
|
11285
|
+
const [selectorArg, ...armArgs] = node2.arguments;
|
|
11286
|
+
if (!selectorArg || selectorArg.type === "SpreadElement") return null;
|
|
11287
|
+
const selector = anyValue(selectorArg, scope, code, mfs);
|
|
11288
|
+
if (!isCombinator(selector)) return null;
|
|
11289
|
+
const arms = [];
|
|
11290
|
+
for (const arg of armArgs) {
|
|
11291
|
+
if (arg.type === "SpreadElement") return null;
|
|
11292
|
+
const arm = dispatchArmValue(arg, scope, code, mfs);
|
|
11293
|
+
if (!isDispatchArm(arm)) return null;
|
|
11294
|
+
arms.push(arm);
|
|
11295
|
+
}
|
|
11296
|
+
try {
|
|
11297
|
+
const unsafeDispatch = dispatch;
|
|
11298
|
+
return unsafeDispatch(selector, ...arms);
|
|
11299
|
+
} catch {
|
|
11300
|
+
return null;
|
|
11301
|
+
}
|
|
11302
|
+
}
|
|
10536
11303
|
if (callee.name === "choice" && node2.arguments.some((a) => a.type !== "SpreadElement" && isGatedArmExpr(a))) {
|
|
10537
11304
|
if (code === void 0 || mfs === void 0) return null;
|
|
10538
11305
|
const arms = [];
|
|
@@ -10618,6 +11385,10 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10618
11385
|
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
10619
11386
|
return entry.combi;
|
|
10620
11387
|
}
|
|
11388
|
+
if (isStaticValueEntry(entry)) {
|
|
11389
|
+
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
11390
|
+
return entry.value;
|
|
11391
|
+
}
|
|
10621
11392
|
return entry;
|
|
10622
11393
|
}
|
|
10623
11394
|
if (node2.type === "MemberExpression") {
|
|
@@ -10638,6 +11409,27 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
10638
11409
|
if (callee.type === "Identifier" && callee.name === "makeWord") {
|
|
10639
11410
|
return wordFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
10640
11411
|
}
|
|
11412
|
+
if (callee.type === "Identifier" && callee.name === "makeWhen") {
|
|
11413
|
+
return whenFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
11414
|
+
}
|
|
11415
|
+
if (callee.type === "Identifier" && (callee.name === "startsWith" || callee.name === "endsWith")) {
|
|
11416
|
+
if (node2.arguments.length !== 1 || node2.arguments[0]?.type === "SpreadElement") return null;
|
|
11417
|
+
const value = anyValue(node2.arguments[0], scope, code, mfs);
|
|
11418
|
+
if (typeof value !== "string") return null;
|
|
11419
|
+
return callee.name === "startsWith" ? startsWith(value) : endsWith(value);
|
|
11420
|
+
}
|
|
11421
|
+
if (callee.type === "Identifier" && callee.name === "matches") {
|
|
11422
|
+
if (node2.arguments.length !== 1 || node2.arguments[0]?.type === "SpreadElement") return null;
|
|
11423
|
+
const value = anyValue(node2.arguments[0], scope, code, mfs);
|
|
11424
|
+
if (!(value instanceof RegExp)) return null;
|
|
11425
|
+
return matches(value);
|
|
11426
|
+
}
|
|
11427
|
+
if (callee.type === "Identifier" && (callee.name === "when" || callee.name === "otherwise")) {
|
|
11428
|
+
return dispatchArmValue(node2, scope, code, mfs);
|
|
11429
|
+
}
|
|
11430
|
+
if (callee.type === "Identifier" && isWhenFactory(scope.get(callee.name))) {
|
|
11431
|
+
return dispatchArmValue(node2, scope, code, mfs);
|
|
11432
|
+
}
|
|
10641
11433
|
return exprToCombi(node2, scope, code, mfs);
|
|
10642
11434
|
}
|
|
10643
11435
|
return null;
|
|
@@ -10648,6 +11440,12 @@ function evaluateWordFactory(node2, scope, code) {
|
|
|
10648
11440
|
if (callee.type !== "Identifier" || callee.name !== "makeWord") return null;
|
|
10649
11441
|
return wordFactoryFromArgs(node2.arguments, scope, code);
|
|
10650
11442
|
}
|
|
11443
|
+
function evaluateWhenFactory(node2, scope, code) {
|
|
11444
|
+
if (node2.type !== "CallExpression") return null;
|
|
11445
|
+
const callee = node2.callee;
|
|
11446
|
+
if (callee.type !== "Identifier" || callee.name !== "makeWhen") return null;
|
|
11447
|
+
return whenFactoryFromArgs(node2.arguments, scope, code);
|
|
11448
|
+
}
|
|
10651
11449
|
function evaluateExpr(node2, scope, code, mapFnSources) {
|
|
10652
11450
|
return exprToCombi(node2, scope, code, mapFnSources);
|
|
10653
11451
|
}
|
|
@@ -10696,6 +11494,7 @@ function evalBodyStatements(statements, scope, code) {
|
|
|
10696
11494
|
if (val === null) return false;
|
|
10697
11495
|
const thisDeclMfSrcs = bodyMfs.slice(before);
|
|
10698
11496
|
if (isCombinator(val)) scope.set(name, { combi: val, mfSrcs: thisDeclMfSrcs });
|
|
11497
|
+
else if (isDispatchArm(val)) scope.set(name, { value: val, mfSrcs: thisDeclMfSrcs });
|
|
10699
11498
|
else scope.set(name, val);
|
|
10700
11499
|
}
|
|
10701
11500
|
}
|
|
@@ -11227,7 +12026,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
11227
12026
|
for (const match of source.matchAll(/id:\s*"([^"]+)"/g)) ids.add(match[1]);
|
|
11228
12027
|
return [...ids].sort().map((id2) => ({
|
|
11229
12028
|
id: id2,
|
|
11230
|
-
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : "choice-arm"
|
|
12029
|
+
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : id2.startsWith("dispatch:") ? "dispatch-arm" : "choice-arm"
|
|
11231
12030
|
}));
|
|
11232
12031
|
};
|
|
11233
12032
|
const localComposedCarried = /* @__PURE__ */ new Map();
|
|
@@ -11673,6 +12472,14 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
11673
12472
|
if (wordFactory) {
|
|
11674
12473
|
;
|
|
11675
12474
|
scope.set(varName, wordFactory);
|
|
12475
|
+
replacements.push({ start: init.start, end: init.end, replacement: "undefined" });
|
|
12476
|
+
continue;
|
|
12477
|
+
}
|
|
12478
|
+
const whenFactory = evaluateWhenFactory(init, scope, code);
|
|
12479
|
+
if (whenFactory) {
|
|
12480
|
+
;
|
|
12481
|
+
scope.set(varName, whenFactory);
|
|
12482
|
+
replacements.push({ start: init.start, end: init.end, replacement: "undefined" });
|
|
11676
12483
|
continue;
|
|
11677
12484
|
}
|
|
11678
12485
|
const combiArray = evaluateCombinatorArray(init, scope, code);
|