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/index.cjs
CHANGED
|
@@ -55,7 +55,9 @@ __export(index_exports, {
|
|
|
55
55
|
createGrammarTraceSink: () => createGrammarTraceSink,
|
|
56
56
|
createVisitor: () => createVisitor,
|
|
57
57
|
cstBuildHost: () => cstBuildHost,
|
|
58
|
+
dispatch: () => dispatch,
|
|
58
59
|
duplicationFindingCount: () => duplicationFindingCount,
|
|
60
|
+
endsWith: () => endsWith,
|
|
59
61
|
expect: () => expect,
|
|
60
62
|
extractCharClasses: () => extractCharClasses,
|
|
61
63
|
field: () => field,
|
|
@@ -78,8 +80,10 @@ __export(index_exports, {
|
|
|
78
80
|
lineBreaksIn: () => lineBreaksIn,
|
|
79
81
|
lineStartWithin: () => lineStartWithin,
|
|
80
82
|
literal: () => literal,
|
|
83
|
+
makeWhen: () => makeWhen,
|
|
81
84
|
makeWord: () => makeWord,
|
|
82
85
|
many: () => many,
|
|
86
|
+
matches: () => matches,
|
|
83
87
|
noTrivia: () => noTrivia,
|
|
84
88
|
node: () => node,
|
|
85
89
|
not: () => not,
|
|
@@ -87,6 +91,7 @@ __export(index_exports, {
|
|
|
87
91
|
oneOrMore: () => oneOrMore,
|
|
88
92
|
oneOrMoreSep: () => oneOrMoreSep,
|
|
89
93
|
optional: () => optional,
|
|
94
|
+
otherwise: () => otherwise,
|
|
90
95
|
parse: () => parse,
|
|
91
96
|
parseDoc: () => parseDoc,
|
|
92
97
|
parser: () => parser,
|
|
@@ -95,6 +100,7 @@ __export(index_exports, {
|
|
|
95
100
|
regex: () => regex,
|
|
96
101
|
relativize: () => relativize,
|
|
97
102
|
relativizeCST: () => relativizeCST,
|
|
103
|
+
routed: () => routed,
|
|
98
104
|
rules: () => rules,
|
|
99
105
|
run: () => run,
|
|
100
106
|
runWithGrammarCoverage: () => runWithGrammarCoverage,
|
|
@@ -104,12 +110,14 @@ __export(index_exports, {
|
|
|
104
110
|
shiftAbsolute: () => shiftAbsolute,
|
|
105
111
|
siteToString: () => siteToString,
|
|
106
112
|
skip: () => skip,
|
|
113
|
+
startsWith: () => startsWith,
|
|
107
114
|
token: () => token,
|
|
108
115
|
transform: () => transform,
|
|
109
116
|
trivia: () => trivia,
|
|
110
117
|
triviaEntries: () => triviaEntries,
|
|
111
118
|
triviaKindMask: () => triviaKindMask,
|
|
112
119
|
walk: () => walk,
|
|
120
|
+
when: () => when,
|
|
113
121
|
withCtx: () => withCtx,
|
|
114
122
|
word: () => word
|
|
115
123
|
});
|
|
@@ -168,6 +176,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
168
176
|
return d.value.length === 0;
|
|
169
177
|
case "keywords":
|
|
170
178
|
return false;
|
|
179
|
+
case "routed":
|
|
180
|
+
return false;
|
|
171
181
|
case "regex":
|
|
172
182
|
try {
|
|
173
183
|
const m = new RegExp(d.source).exec("");
|
|
@@ -194,6 +204,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
194
204
|
return d.parsers.every(me);
|
|
195
205
|
case "choice":
|
|
196
206
|
return d.parsers.some(me);
|
|
207
|
+
case "dispatch":
|
|
208
|
+
return me(d.selector);
|
|
197
209
|
case "transform":
|
|
198
210
|
case "label":
|
|
199
211
|
case "trivia":
|
|
@@ -267,6 +279,8 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
267
279
|
case "keywords":
|
|
268
280
|
return p._meta.firstSet;
|
|
269
281
|
// terminals: no refs, cached set is exact
|
|
282
|
+
case "dispatch":
|
|
283
|
+
return fs(d.selector);
|
|
270
284
|
case "lazy":
|
|
271
285
|
try {
|
|
272
286
|
return fs(d.thunk());
|
|
@@ -1184,6 +1198,8 @@ function derive(c, seen) {
|
|
|
1184
1198
|
return [def.label];
|
|
1185
1199
|
case "choice":
|
|
1186
1200
|
return def.parsers.flatMap(deriveExpected2);
|
|
1201
|
+
case "dispatch":
|
|
1202
|
+
return deriveExpected2(def.selector);
|
|
1187
1203
|
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1188
1204
|
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1189
1205
|
// able to fail first — deriving from term 0 alone named a token the parse
|
|
@@ -1223,6 +1239,8 @@ function derive(c, seen) {
|
|
|
1223
1239
|
case "not":
|
|
1224
1240
|
case "peek":
|
|
1225
1241
|
return deriveExpected2(def.parser);
|
|
1242
|
+
case "routed":
|
|
1243
|
+
return ["routed()"];
|
|
1226
1244
|
case "lazy": {
|
|
1227
1245
|
const name = c._ruleName;
|
|
1228
1246
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -1325,6 +1343,7 @@ function choice(...args) {
|
|
|
1325
1343
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
1326
1344
|
if (result.ok) return result;
|
|
1327
1345
|
expected.push(...result.expected);
|
|
1346
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1328
1347
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1329
1348
|
}
|
|
1330
1349
|
return {
|
|
@@ -1365,6 +1384,7 @@ function choice(...args) {
|
|
|
1365
1384
|
rollbackCstCapture(ctx, mark);
|
|
1366
1385
|
if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
|
|
1367
1386
|
expected.push(...result.expected);
|
|
1387
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1368
1388
|
continue;
|
|
1369
1389
|
}
|
|
1370
1390
|
const checks = autoNot[i];
|
|
@@ -2044,6 +2064,248 @@ function sequence(...parsers) {
|
|
|
2044
2064
|
};
|
|
2045
2065
|
}
|
|
2046
2066
|
|
|
2067
|
+
// src/combinators/dispatch.ts
|
|
2068
|
+
function parserUsesRouted(parser2, seen = /* @__PURE__ */ new Set()) {
|
|
2069
|
+
if (seen.has(parser2)) return false;
|
|
2070
|
+
seen.add(parser2);
|
|
2071
|
+
const def = parser2._def;
|
|
2072
|
+
switch (def.tag) {
|
|
2073
|
+
case "routed":
|
|
2074
|
+
return true;
|
|
2075
|
+
case "sequence":
|
|
2076
|
+
case "choice":
|
|
2077
|
+
return def.parsers.some((entry) => parserUsesRouted(entry, seen));
|
|
2078
|
+
case "dispatch":
|
|
2079
|
+
return false;
|
|
2080
|
+
case "sepBy":
|
|
2081
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.separator, seen);
|
|
2082
|
+
case "skip":
|
|
2083
|
+
return parserUsesRouted(def.main, seen) || parserUsesRouted(def.skipped, seen);
|
|
2084
|
+
case "grammar":
|
|
2085
|
+
return parserUsesRouted(def.parser, seen) || (def.triviaParser ? parserUsesRouted(def.triviaParser, seen) : false);
|
|
2086
|
+
case "scanTo":
|
|
2087
|
+
return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen));
|
|
2088
|
+
case "recover":
|
|
2089
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.sentinel, seen);
|
|
2090
|
+
case "lazy":
|
|
2091
|
+
try {
|
|
2092
|
+
return parserUsesRouted(def.thunk(), seen);
|
|
2093
|
+
} catch {
|
|
2094
|
+
return false;
|
|
2095
|
+
}
|
|
2096
|
+
case "many":
|
|
2097
|
+
case "oneOrMore":
|
|
2098
|
+
case "optional":
|
|
2099
|
+
case "attempt":
|
|
2100
|
+
case "transform":
|
|
2101
|
+
case "trivia":
|
|
2102
|
+
case "token":
|
|
2103
|
+
case "leaf":
|
|
2104
|
+
case "label":
|
|
2105
|
+
case "field":
|
|
2106
|
+
case "not":
|
|
2107
|
+
case "peek":
|
|
2108
|
+
case "node":
|
|
2109
|
+
case "withCtx":
|
|
2110
|
+
case "expect":
|
|
2111
|
+
return parserUsesRouted(def.parser, seen);
|
|
2112
|
+
default:
|
|
2113
|
+
return false;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
function branchUsesRouted(branch) {
|
|
2117
|
+
return branch.usesRouted === true || parserUsesRouted(branch.parser);
|
|
2118
|
+
}
|
|
2119
|
+
function asciiFoldKey(key) {
|
|
2120
|
+
let out = "";
|
|
2121
|
+
for (let i = 0; i < key.length; i++) {
|
|
2122
|
+
const c = key.charCodeAt(i);
|
|
2123
|
+
out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
|
|
2124
|
+
}
|
|
2125
|
+
return out;
|
|
2126
|
+
}
|
|
2127
|
+
function matchesDispatchMatcher(value, matcher) {
|
|
2128
|
+
const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
|
|
2129
|
+
const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
|
|
2130
|
+
switch (matcher.kind) {
|
|
2131
|
+
case "startsWith":
|
|
2132
|
+
return candidate.startsWith(expected);
|
|
2133
|
+
case "endsWith":
|
|
2134
|
+
return candidate.endsWith(expected);
|
|
2135
|
+
case "matches": {
|
|
2136
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
2137
|
+
return new RegExp(matcher.value, flags).test(value);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
function isStringMatcher(value) {
|
|
2142
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2143
|
+
const kind = value.kind;
|
|
2144
|
+
return kind === "startsWith" || kind === "endsWith" || kind === "matches";
|
|
2145
|
+
}
|
|
2146
|
+
function fixedMatcher(kind, value) {
|
|
2147
|
+
if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
|
|
2148
|
+
if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
|
|
2149
|
+
return { kind, value };
|
|
2150
|
+
}
|
|
2151
|
+
function startsWith(prefix) {
|
|
2152
|
+
return fixedMatcher("startsWith", prefix);
|
|
2153
|
+
}
|
|
2154
|
+
function endsWith(suffix) {
|
|
2155
|
+
return fixedMatcher("endsWith", suffix);
|
|
2156
|
+
}
|
|
2157
|
+
function matches(pattern) {
|
|
2158
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
|
|
2159
|
+
if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
|
|
2160
|
+
throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
|
|
2161
|
+
}
|
|
2162
|
+
return { kind: "matches", value: pattern.source, flags: pattern.flags };
|
|
2163
|
+
}
|
|
2164
|
+
function when(key, parser2, opts = {}) {
|
|
2165
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
2166
|
+
if (isStringMatcher(key)) {
|
|
2167
|
+
return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2168
|
+
}
|
|
2169
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2170
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2171
|
+
for (const item of keys) {
|
|
2172
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2173
|
+
}
|
|
2174
|
+
return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2175
|
+
}
|
|
2176
|
+
function makeWhen(opts = {}) {
|
|
2177
|
+
return (key, parser2) => when(key, parser2, opts);
|
|
2178
|
+
}
|
|
2179
|
+
function otherwise(parser2) {
|
|
2180
|
+
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2181
|
+
}
|
|
2182
|
+
function routed() {
|
|
2183
|
+
return {
|
|
2184
|
+
_tag: "routed",
|
|
2185
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
2186
|
+
_def: { tag: "routed" },
|
|
2187
|
+
parse(_input, pos, ctx) {
|
|
2188
|
+
const item = ctx._routed;
|
|
2189
|
+
if (item === void 0) {
|
|
2190
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2191
|
+
}
|
|
2192
|
+
if (pos !== item.span.start) {
|
|
2193
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2194
|
+
}
|
|
2195
|
+
if (cstCaptureActive(ctx)) {
|
|
2196
|
+
pushCstLeaf(ctx, { _tag: "leaf", value: item.value, span: item.span });
|
|
2197
|
+
}
|
|
2198
|
+
return { ok: true, value: item.value, span: item.span };
|
|
2199
|
+
}
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
function dispatch(selector, ...arms) {
|
|
2203
|
+
if (parserUsesRouted(selector)) {
|
|
2204
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2205
|
+
}
|
|
2206
|
+
let fallback;
|
|
2207
|
+
let fallbackUsesRouted = false;
|
|
2208
|
+
const matchers = [];
|
|
2209
|
+
const cases = [];
|
|
2210
|
+
const seen = [];
|
|
2211
|
+
for (let i = 0; i < arms.length; i++) {
|
|
2212
|
+
const arm = arms[i];
|
|
2213
|
+
if (arm.kind === "otherwise") {
|
|
2214
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2215
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2216
|
+
fallback = arm.parser;
|
|
2217
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
2218
|
+
continue;
|
|
2219
|
+
}
|
|
2220
|
+
if (arm.kind === "whenMatcher") {
|
|
2221
|
+
const matcher = arm.matcher;
|
|
2222
|
+
matchers.push({
|
|
2223
|
+
kind: matcher.kind,
|
|
2224
|
+
value: matcher.value,
|
|
2225
|
+
...matcher.kind === "matches" ? { flags: matcher.flags } : {},
|
|
2226
|
+
parser: arm.parser,
|
|
2227
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2228
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2229
|
+
});
|
|
2230
|
+
continue;
|
|
2231
|
+
}
|
|
2232
|
+
for (const key of arm.keys) {
|
|
2233
|
+
const folded = asciiFoldKey(key);
|
|
2234
|
+
for (const prior of seen) {
|
|
2235
|
+
const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
|
|
2236
|
+
if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2237
|
+
}
|
|
2238
|
+
seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
|
|
2239
|
+
}
|
|
2240
|
+
cases.push({
|
|
2241
|
+
keys: arm.keys,
|
|
2242
|
+
parser: arm.parser,
|
|
2243
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2244
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
const meta = {
|
|
2248
|
+
firstSet: selector._meta.firstSet,
|
|
2249
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2250
|
+
isTrivia: false
|
|
2251
|
+
};
|
|
2252
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2253
|
+
const byFoldedKey = /* @__PURE__ */ new Map();
|
|
2254
|
+
for (const entry of cases) {
|
|
2255
|
+
for (const key of entry.keys) {
|
|
2256
|
+
if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
|
|
2257
|
+
else byKey.set(key, entry);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
return {
|
|
2261
|
+
_tag: "dispatch",
|
|
2262
|
+
_meta: meta,
|
|
2263
|
+
_def: {
|
|
2264
|
+
tag: "dispatch",
|
|
2265
|
+
selector,
|
|
2266
|
+
cases,
|
|
2267
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2268
|
+
...fallback === void 0 ? {} : { otherwise: fallback, ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {} }
|
|
2269
|
+
},
|
|
2270
|
+
parse(input, pos, ctx) {
|
|
2271
|
+
if (parserUsesRouted(selector)) {
|
|
2272
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2273
|
+
}
|
|
2274
|
+
const selectorMark = saveTriviaMark(ctx);
|
|
2275
|
+
const selected = selector.parse(input, pos, ctx);
|
|
2276
|
+
if (!selected.ok) return selected;
|
|
2277
|
+
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 });
|
|
2278
|
+
if (branch === void 0) {
|
|
2279
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2280
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2281
|
+
}
|
|
2282
|
+
const savedRouted = ctx._routed;
|
|
2283
|
+
const usesRouted = branchUsesRouted(branch);
|
|
2284
|
+
let mark = saveTriviaMark(ctx);
|
|
2285
|
+
if (usesRouted) {
|
|
2286
|
+
rollbackTrivia(ctx, selectorMark);
|
|
2287
|
+
mark = saveTriviaMark(ctx);
|
|
2288
|
+
ctx._routed = { value: selected.value, span: selected.span };
|
|
2289
|
+
}
|
|
2290
|
+
let result;
|
|
2291
|
+
try {
|
|
2292
|
+
result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
|
|
2293
|
+
} finally {
|
|
2294
|
+
if (usesRouted) ctx._routed = savedRouted;
|
|
2295
|
+
}
|
|
2296
|
+
if (!result.ok) {
|
|
2297
|
+
rollbackTrivia(ctx, mark);
|
|
2298
|
+
return { ...result, committed: true };
|
|
2299
|
+
}
|
|
2300
|
+
return {
|
|
2301
|
+
ok: true,
|
|
2302
|
+
value: [selected.value, result.value],
|
|
2303
|
+
span: { start: pos, end: result.span.end }
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
};
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2047
2309
|
// src/combinators/attempt.ts
|
|
2048
2310
|
function attempt(parser2) {
|
|
2049
2311
|
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
@@ -2066,6 +2328,7 @@ function attempt(parser2) {
|
|
|
2066
2328
|
if (result.ok) return result;
|
|
2067
2329
|
rollbackCstCapture(ctx, mark);
|
|
2068
2330
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
2331
|
+
if (result.committed) return result;
|
|
2069
2332
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
2070
2333
|
}
|
|
2071
2334
|
};
|
|
@@ -2095,6 +2358,7 @@ function repItem(combinator, input, cur, ctx, guardable) {
|
|
|
2095
2358
|
const result = combinator.parse(input, pos, ctx);
|
|
2096
2359
|
if (!result.ok) {
|
|
2097
2360
|
rollbackTrivia(ctx, mark);
|
|
2361
|
+
if (result.committed) return { fail: result, failPos: pos };
|
|
2098
2362
|
return { fail: result, failPos: pos };
|
|
2099
2363
|
}
|
|
2100
2364
|
if (result.span.end === pos) {
|
|
@@ -2138,6 +2402,7 @@ function many(combinator, opts = {}) {
|
|
|
2138
2402
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2139
2403
|
if (item === "stop") break;
|
|
2140
2404
|
if ("fail" in item) {
|
|
2405
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2141
2406
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2142
2407
|
if (sync === void 0) break;
|
|
2143
2408
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2182,6 +2447,7 @@ function atLeast(combinator, min, max) {
|
|
|
2182
2447
|
while (count < min) {
|
|
2183
2448
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2184
2449
|
if (item === "stop" || "fail" in item) {
|
|
2450
|
+
if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
|
|
2185
2451
|
expected ??= deriveExpected(combinator);
|
|
2186
2452
|
return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
|
|
2187
2453
|
}
|
|
@@ -2194,6 +2460,7 @@ function atLeast(combinator, min, max) {
|
|
|
2194
2460
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2195
2461
|
if (item === "stop") break;
|
|
2196
2462
|
if ("fail" in item) {
|
|
2463
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2197
2464
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2198
2465
|
if (sync === void 0) break;
|
|
2199
2466
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2232,6 +2499,7 @@ function optional(combinator) {
|
|
|
2232
2499
|
const result = combinator.parse(input, pos, ctx);
|
|
2233
2500
|
if (result.ok) return result;
|
|
2234
2501
|
rollbackTrivia(ctx, mark);
|
|
2502
|
+
if (result.committed) return result;
|
|
2235
2503
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
2236
2504
|
}
|
|
2237
2505
|
};
|
|
@@ -2271,6 +2539,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2271
2539
|
values.push(first.value);
|
|
2272
2540
|
cur = first.span.end;
|
|
2273
2541
|
} else {
|
|
2542
|
+
if (first.committed) return first;
|
|
2274
2543
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2275
2544
|
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
2276
2545
|
if (min >= 1) return failAt2(pos);
|
|
@@ -2298,6 +2567,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2298
2567
|
const sep = separator.parse(input, sepPos, ctx);
|
|
2299
2568
|
if (!sep.ok) {
|
|
2300
2569
|
rollbackTrivia(ctx, loopMark);
|
|
2570
|
+
if (sep.committed) return sep;
|
|
2301
2571
|
break;
|
|
2302
2572
|
}
|
|
2303
2573
|
const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
|
|
@@ -2313,6 +2583,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2313
2583
|
}
|
|
2314
2584
|
const next = combinator.parse(input, nextPos, ctx);
|
|
2315
2585
|
if (!next.ok) {
|
|
2586
|
+
if (next.committed) return next;
|
|
2316
2587
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2317
2588
|
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2318
2589
|
expected ??= deriveExpected(combinator);
|
|
@@ -2405,6 +2676,12 @@ function markUnusedValues(root) {
|
|
|
2405
2676
|
case "choice":
|
|
2406
2677
|
for (const p of def.parsers) visit(p, consumed);
|
|
2407
2678
|
return;
|
|
2679
|
+
case "dispatch":
|
|
2680
|
+
visit(def.selector, consumed);
|
|
2681
|
+
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2682
|
+
if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
|
|
2683
|
+
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2684
|
+
return;
|
|
2408
2685
|
case "node":
|
|
2409
2686
|
visit(def.parser, false);
|
|
2410
2687
|
return;
|
|
@@ -2680,6 +2957,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2680
2957
|
case "sequence":
|
|
2681
2958
|
case "choice":
|
|
2682
2959
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2960
|
+
case "dispatch":
|
|
2961
|
+
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);
|
|
2683
2962
|
case "sepBy":
|
|
2684
2963
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2685
2964
|
case "skip":
|
|
@@ -2747,6 +3026,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2747
3026
|
return parserHasTriviaSite(d.parser, seen);
|
|
2748
3027
|
case "choice":
|
|
2749
3028
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
3029
|
+
case "dispatch":
|
|
3030
|
+
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);
|
|
2750
3031
|
case "grammar":
|
|
2751
3032
|
return parserHasTriviaSite(d.parser, seen);
|
|
2752
3033
|
case "lazy": {
|
|
@@ -2772,6 +3053,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2772
3053
|
case "sequence":
|
|
2773
3054
|
case "choice":
|
|
2774
3055
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
3056
|
+
case "dispatch":
|
|
3057
|
+
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);
|
|
2775
3058
|
case "sepBy":
|
|
2776
3059
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2777
3060
|
case "skip":
|
|
@@ -3173,7 +3456,7 @@ function leaf(root, fn) {
|
|
|
3173
3456
|
}
|
|
3174
3457
|
|
|
3175
3458
|
// src/version.ts
|
|
3176
|
-
var PARSEMAN_VERSION = "0.
|
|
3459
|
+
var PARSEMAN_VERSION = "0.39.1";
|
|
3177
3460
|
|
|
3178
3461
|
// src/cst/host-mode.ts
|
|
3179
3462
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3329,6 +3612,8 @@ function classifyBroadArm(arm, resolve) {
|
|
|
3329
3612
|
}
|
|
3330
3613
|
return null;
|
|
3331
3614
|
}
|
|
3615
|
+
case "dispatch":
|
|
3616
|
+
return walk2(d.selector);
|
|
3332
3617
|
default:
|
|
3333
3618
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3334
3619
|
}
|
|
@@ -3428,6 +3713,12 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3428
3713
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3429
3714
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3430
3715
|
if (rec[k]) kids.push(rec[k]);
|
|
3716
|
+
if (d.tag === "dispatch") {
|
|
3717
|
+
kids.push(d.selector);
|
|
3718
|
+
for (const c of d.cases) kids.push(c.parser);
|
|
3719
|
+
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3720
|
+
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3721
|
+
}
|
|
3431
3722
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3432
3723
|
if (d.tag === "lazy") {
|
|
3433
3724
|
try {
|
|
@@ -3534,6 +3825,12 @@ function childrenOf(d) {
|
|
|
3534
3825
|
case "sequence":
|
|
3535
3826
|
case "choice":
|
|
3536
3827
|
return d.parsers;
|
|
3828
|
+
case "dispatch":
|
|
3829
|
+
return [
|
|
3830
|
+
d.selector,
|
|
3831
|
+
...d.cases.map((c) => c.parser),
|
|
3832
|
+
...d.otherwise === void 0 ? [] : [d.otherwise]
|
|
3833
|
+
];
|
|
3537
3834
|
case "skip":
|
|
3538
3835
|
return [d.main, d.skipped];
|
|
3539
3836
|
case "sepBy":
|
|
@@ -3590,6 +3887,8 @@ function payloadKey(p, d) {
|
|
|
3590
3887
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3591
3888
|
case "sepBy":
|
|
3592
3889
|
return `sepBy\0${d.min}\0${d.max ?? ""}\0${d.trailing ?? ""}`;
|
|
3890
|
+
case "dispatch":
|
|
3891
|
+
return `dispatch\0${d.cases.map((c) => JSON.stringify(c.keys)).join("")}\0${d.otherwise !== void 0}`;
|
|
3593
3892
|
case "expect":
|
|
3594
3893
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3595
3894
|
case "scanTo":
|
|
@@ -3661,6 +3960,11 @@ function render(p, depth = 3) {
|
|
|
3661
3960
|
return `sequence(${kids.join(", ")})`;
|
|
3662
3961
|
case "choice":
|
|
3663
3962
|
return `choice(${kids.join(", ")})`;
|
|
3963
|
+
case "dispatch": {
|
|
3964
|
+
const arms = d.cases.map((c, i) => `when([${c.keys.map((k) => JSON.stringify(k)).join(", ")}], ${kids[i + 1] ?? ""})`);
|
|
3965
|
+
if (d.otherwise !== void 0) arms.push(`otherwise(${kids[kids.length - 1] ?? ""})`);
|
|
3966
|
+
return `dispatch(${kids[0] ?? ""}, ${arms.join(", ")})`;
|
|
3967
|
+
}
|
|
3664
3968
|
case "node":
|
|
3665
3969
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3666
3970
|
case "label":
|
|
@@ -3684,6 +3988,10 @@ function segment(d, index) {
|
|
|
3684
3988
|
return `seq[${index}]`;
|
|
3685
3989
|
case "choice":
|
|
3686
3990
|
return `choice[${index}]`;
|
|
3991
|
+
case "dispatch":
|
|
3992
|
+
if (index === 0) return "dispatch.selector";
|
|
3993
|
+
if (index <= d.cases.length) return `dispatch.when[${index - 1}]`;
|
|
3994
|
+
return "dispatch.otherwise";
|
|
3687
3995
|
case "node":
|
|
3688
3996
|
return `node(${d.type ?? ""})`;
|
|
3689
3997
|
case "label":
|
|
@@ -4932,11 +5240,25 @@ function escapeClassChar(ch2) {
|
|
|
4932
5240
|
}
|
|
4933
5241
|
|
|
4934
5242
|
// src/compiler/grammar-coverage-ids.ts
|
|
5243
|
+
function idPart(value) {
|
|
5244
|
+
return encodeURIComponent(value);
|
|
5245
|
+
}
|
|
5246
|
+
function dispatchArmIds(def, path) {
|
|
5247
|
+
const ids = [];
|
|
5248
|
+
for (const entry of def.cases) ids.push(`dispatch:${path}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5249
|
+
for (const entry of def.matchers ?? []) {
|
|
5250
|
+
ids.push(`dispatch:${path}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5251
|
+
}
|
|
5252
|
+
if (def.otherwise) ids.push(`dispatch:${path}/otherwise`);
|
|
5253
|
+
return ids;
|
|
5254
|
+
}
|
|
4935
5255
|
function children(def, winners) {
|
|
4936
5256
|
switch (def.tag) {
|
|
4937
5257
|
case "sequence":
|
|
4938
5258
|
case "choice":
|
|
4939
5259
|
return def.parsers;
|
|
5260
|
+
case "dispatch":
|
|
5261
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
4940
5262
|
case "many":
|
|
4941
5263
|
case "oneOrMore":
|
|
4942
5264
|
case "optional":
|
|
@@ -4979,6 +5301,7 @@ function children(def, winners) {
|
|
|
4979
5301
|
function buildGrammarPlan(entry, winners) {
|
|
4980
5302
|
const definitions = /* @__PURE__ */ new Map();
|
|
4981
5303
|
const choices = /* @__PURE__ */ new WeakMap();
|
|
5304
|
+
const dispatches = /* @__PURE__ */ new WeakMap();
|
|
4982
5305
|
const attempts = /* @__PURE__ */ new WeakMap();
|
|
4983
5306
|
const labels = /* @__PURE__ */ new WeakMap();
|
|
4984
5307
|
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -5009,6 +5332,11 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5009
5332
|
choices.set(parser2, ids);
|
|
5010
5333
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
5011
5334
|
}
|
|
5335
|
+
if (parser2._def.tag === "dispatch") {
|
|
5336
|
+
const ids = dispatchArmIds(parser2._def, path);
|
|
5337
|
+
dispatches.set(parser2, ids);
|
|
5338
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5339
|
+
}
|
|
5012
5340
|
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
|
|
5013
5341
|
if (parser2._def.tag === "label") {
|
|
5014
5342
|
const id = `label:${path}`;
|
|
@@ -5021,7 +5349,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5021
5349
|
for (const root of roots) {
|
|
5022
5350
|
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
5023
5351
|
}
|
|
5024
|
-
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
5352
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
|
|
5025
5353
|
}
|
|
5026
5354
|
|
|
5027
5355
|
// src/compiler/scannable-run.ts
|
|
@@ -6395,12 +6723,15 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6395
6723
|
case "literal":
|
|
6396
6724
|
case "regex":
|
|
6397
6725
|
case "keywords":
|
|
6726
|
+
case "routed":
|
|
6398
6727
|
return { alts: [[seg(p._meta.firstSet, matchesEmpty(p))]] };
|
|
6399
6728
|
case "choice": {
|
|
6400
6729
|
const alts = [];
|
|
6401
6730
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6402
6731
|
return { alts };
|
|
6403
6732
|
}
|
|
6733
|
+
case "dispatch":
|
|
6734
|
+
return rec(d.selector);
|
|
6404
6735
|
case "sequence": {
|
|
6405
6736
|
const chain = [];
|
|
6406
6737
|
for (const term of d.parsers) {
|
|
@@ -6475,6 +6806,9 @@ function failReturn(expected, posExpr) {
|
|
|
6475
6806
|
function failReturnArr(expectedArr, posExpr) {
|
|
6476
6807
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6477
6808
|
}
|
|
6809
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6810
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6811
|
+
}
|
|
6478
6812
|
function hoistExpected(ctx, constArrSource) {
|
|
6479
6813
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6480
6814
|
if (name === void 0) {
|
|
@@ -6511,15 +6845,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6511
6845
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6512
6846
|
}
|
|
6513
6847
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6514
|
-
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
6848
|
+
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
|
|
6849
|
+
}
|
|
6850
|
+
function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
|
|
6851
|
+
if (ctx.failLabel) {
|
|
6852
|
+
if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
|
|
6853
|
+
return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
|
|
6854
|
+
}
|
|
6855
|
+
return committedReturnArr(expectedArr, posExpr);
|
|
6515
6856
|
}
|
|
6516
6857
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6517
6858
|
if (srcCtx !== "_ctx") {
|
|
6518
6859
|
if (ctx.failLabel) {
|
|
6519
6860
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6520
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; break ${ctx.failLabel} }`;
|
|
6861
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
|
|
6521
6862
|
}
|
|
6522
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; ${resultFromRecorded()} }`;
|
|
6863
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
|
|
6523
6864
|
}
|
|
6524
6865
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6525
6866
|
return resultFromRecorded();
|
|
@@ -6732,6 +7073,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6732
7073
|
// nothing committed remains.
|
|
6733
7074
|
case "choice":
|
|
6734
7075
|
return false;
|
|
7076
|
+
case "dispatch":
|
|
7077
|
+
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);
|
|
6735
7078
|
case "attempt":
|
|
6736
7079
|
return false;
|
|
6737
7080
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6776,6 +7119,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6776
7119
|
return true;
|
|
6777
7120
|
}
|
|
6778
7121
|
}
|
|
7122
|
+
function mayCommitFailure(p, seen = /* @__PURE__ */ new Set()) {
|
|
7123
|
+
if (seen.has(p)) return false;
|
|
7124
|
+
seen.add(p);
|
|
7125
|
+
const d = p._def;
|
|
7126
|
+
switch (d.tag) {
|
|
7127
|
+
case "dispatch":
|
|
7128
|
+
return true;
|
|
7129
|
+
case "choice":
|
|
7130
|
+
case "sequence":
|
|
7131
|
+
return d.parsers.some((x) => mayCommitFailure(x, seen));
|
|
7132
|
+
case "many":
|
|
7133
|
+
case "oneOrMore":
|
|
7134
|
+
case "optional":
|
|
7135
|
+
case "attempt":
|
|
7136
|
+
case "transform":
|
|
7137
|
+
case "label":
|
|
7138
|
+
case "field":
|
|
7139
|
+
case "grammar":
|
|
7140
|
+
case "node":
|
|
7141
|
+
return mayCommitFailure(d.parser, seen);
|
|
7142
|
+
case "sepBy":
|
|
7143
|
+
return mayCommitFailure(d.parser, seen) || mayCommitFailure(d.separator, seen);
|
|
7144
|
+
case "skip":
|
|
7145
|
+
return mayCommitFailure(d.main, seen) || mayCommitFailure(d.skipped, seen);
|
|
7146
|
+
case "token":
|
|
7147
|
+
case "leaf":
|
|
7148
|
+
return mayCommitFailure(d.parser, seen);
|
|
7149
|
+
case "withCtx":
|
|
7150
|
+
return mayCommitFailure(d.parser, seen);
|
|
7151
|
+
case "scanTo":
|
|
7152
|
+
return mayCommitFailure(d.sentinel, seen) || d.skip.some((x) => mayCommitFailure(x, seen));
|
|
7153
|
+
case "lazy": {
|
|
7154
|
+
try {
|
|
7155
|
+
return mayCommitFailure(d.thunk(), seen);
|
|
7156
|
+
} catch {
|
|
7157
|
+
return true;
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
case "unknown":
|
|
7161
|
+
return true;
|
|
7162
|
+
default:
|
|
7163
|
+
return false;
|
|
7164
|
+
}
|
|
7165
|
+
}
|
|
6779
7166
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6780
7167
|
if (seen.has(p)) return false;
|
|
6781
7168
|
seen.add(p);
|
|
@@ -6786,6 +7173,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6786
7173
|
case "keywords":
|
|
6787
7174
|
case "node":
|
|
6788
7175
|
case "token":
|
|
7176
|
+
case "routed":
|
|
6789
7177
|
case "leaf":
|
|
6790
7178
|
return true;
|
|
6791
7179
|
case "not":
|
|
@@ -6797,6 +7185,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6797
7185
|
case "sequence":
|
|
6798
7186
|
case "choice":
|
|
6799
7187
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
7188
|
+
case "dispatch":
|
|
7189
|
+
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);
|
|
6800
7190
|
case "sepBy":
|
|
6801
7191
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6802
7192
|
case "many":
|
|
@@ -6843,6 +7233,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6843
7233
|
ctx.recordFail = savedRecord;
|
|
6844
7234
|
const ind0 = ind(ctx);
|
|
6845
7235
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
7236
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6846
7237
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6847
7238
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6848
7239
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6856,6 +7247,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6856
7247
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6857
7248
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6858
7249
|
] : [],
|
|
7250
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6859
7251
|
`${ind0}${lbl}: {`,
|
|
6860
7252
|
...r.stmts,
|
|
6861
7253
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6864,7 +7256,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6864
7256
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6865
7257
|
] : []
|
|
6866
7258
|
];
|
|
6867
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
7259
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6868
7260
|
}
|
|
6869
7261
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6870
7262
|
function emitLit(def, ctx, pos) {
|
|
@@ -7241,6 +7633,186 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7241
7633
|
}
|
|
7242
7634
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7243
7635
|
}
|
|
7636
|
+
function emitTailFallible(parser2, ctx, pos) {
|
|
7637
|
+
const savedRecord = ctx.recordFail;
|
|
7638
|
+
ctx.recordFail = true;
|
|
7639
|
+
const out = emitFallible(parser2, ctx, pos);
|
|
7640
|
+
ctx.recordFail = savedRecord;
|
|
7641
|
+
return out;
|
|
7642
|
+
}
|
|
7643
|
+
function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
7644
|
+
if (seen.has(p)) return false;
|
|
7645
|
+
seen.add(p);
|
|
7646
|
+
const d = p._def;
|
|
7647
|
+
switch (d.tag) {
|
|
7648
|
+
case "expect":
|
|
7649
|
+
case "recover":
|
|
7650
|
+
return true;
|
|
7651
|
+
case "many":
|
|
7652
|
+
case "oneOrMore":
|
|
7653
|
+
case "sepBy":
|
|
7654
|
+
return recovery || mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7655
|
+
case "choice":
|
|
7656
|
+
case "sequence": {
|
|
7657
|
+
for (const item of d.parsers) {
|
|
7658
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7659
|
+
}
|
|
7660
|
+
return false;
|
|
7661
|
+
}
|
|
7662
|
+
case "dispatch": {
|
|
7663
|
+
if (mayRecordRecoveryError(d.selector, recovery, seen)) return true;
|
|
7664
|
+
for (const item of d.cases) {
|
|
7665
|
+
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7666
|
+
}
|
|
7667
|
+
if (d.matchers?.some((item) => mayRecordRecoveryError(item.parser, recovery, seen))) return true;
|
|
7668
|
+
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7669
|
+
}
|
|
7670
|
+
case "attempt":
|
|
7671
|
+
case "transform":
|
|
7672
|
+
case "label":
|
|
7673
|
+
case "field":
|
|
7674
|
+
case "grammar":
|
|
7675
|
+
case "node":
|
|
7676
|
+
case "token":
|
|
7677
|
+
case "leaf":
|
|
7678
|
+
case "withCtx":
|
|
7679
|
+
case "optional":
|
|
7680
|
+
return mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7681
|
+
case "skip":
|
|
7682
|
+
return mayRecordRecoveryError(d.main, recovery, seen) || mayRecordRecoveryError(d.skipped, recovery, seen);
|
|
7683
|
+
case "scanTo":
|
|
7684
|
+
if (mayRecordRecoveryError(d.sentinel, recovery, seen)) return true;
|
|
7685
|
+
for (const item of d.skip) {
|
|
7686
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7687
|
+
}
|
|
7688
|
+
return false;
|
|
7689
|
+
case "lazy": {
|
|
7690
|
+
try {
|
|
7691
|
+
return mayRecordRecoveryError(d.thunk(), recovery, seen);
|
|
7692
|
+
} catch {
|
|
7693
|
+
return true;
|
|
7694
|
+
}
|
|
7695
|
+
}
|
|
7696
|
+
case "unknown":
|
|
7697
|
+
return true;
|
|
7698
|
+
default:
|
|
7699
|
+
return false;
|
|
7700
|
+
}
|
|
7701
|
+
}
|
|
7702
|
+
function emitDispatchCombinator(parser2, def, ctx, pos) {
|
|
7703
|
+
if (parserUsesRouted2(def.selector)) {
|
|
7704
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
7705
|
+
}
|
|
7706
|
+
const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
|
|
7707
|
+
const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
|
|
7708
|
+
const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
|
|
7709
|
+
const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
|
|
7710
|
+
const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
|
|
7711
|
+
const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
|
|
7712
|
+
const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
|
|
7713
|
+
const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
|
|
7714
|
+
const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
|
|
7715
|
+
const selector = emit(def.selector, ctx, pos);
|
|
7716
|
+
const outV = v(ctx, "_dval");
|
|
7717
|
+
const outE = v(ctx, "_dend");
|
|
7718
|
+
const keyV = v(ctx, "_dkey");
|
|
7719
|
+
const stmts = [
|
|
7720
|
+
...selectorLeafMark ? [
|
|
7721
|
+
`${ind(ctx)}const ${selectorLeafMark} = _ctx._cstLeaves?.length ?? 0`,
|
|
7722
|
+
`${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
|
|
7723
|
+
`${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
7724
|
+
`${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
|
|
7725
|
+
`${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
|
|
7726
|
+
`${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
|
|
7727
|
+
] : [],
|
|
7728
|
+
...selector.stmts,
|
|
7729
|
+
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7730
|
+
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7731
|
+
];
|
|
7732
|
+
let wroteBranch = false;
|
|
7733
|
+
const emitSelectedTail = (entry, keyword, condition, coverageId) => {
|
|
7734
|
+
const parser3 = entry.parser;
|
|
7735
|
+
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7736
|
+
stmts.push(head);
|
|
7737
|
+
ctx.indent++;
|
|
7738
|
+
const usesRouted = branchUsesRouted2(entry);
|
|
7739
|
+
const routedV = usesRouted ? v(ctx, "_drt") : null;
|
|
7740
|
+
const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
|
|
7741
|
+
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7742
|
+
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7743
|
+
if (routedV) {
|
|
7744
|
+
stmts.push(
|
|
7745
|
+
`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
|
|
7746
|
+
...selectorLeafMark ? [
|
|
7747
|
+
`${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}`
|
|
7748
|
+
] : []
|
|
7749
|
+
);
|
|
7750
|
+
}
|
|
7751
|
+
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7752
|
+
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7753
|
+
const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
|
|
7754
|
+
stmts.push(...coverageAttempt(ctx, coverageId, pos));
|
|
7755
|
+
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7756
|
+
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7757
|
+
const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
|
|
7758
|
+
const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
|
|
7759
|
+
stmts.push(
|
|
7760
|
+
...tail.stmts,
|
|
7761
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
|
|
7762
|
+
...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
|
|
7763
|
+
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7764
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`,
|
|
7765
|
+
...coverageHit(ctx, coverageId, pos, tail.endVar)
|
|
7766
|
+
);
|
|
7767
|
+
ctx.indent--;
|
|
7768
|
+
stmts.push(`${ind(ctx)}}`);
|
|
7769
|
+
};
|
|
7770
|
+
let coverageIndex = 0;
|
|
7771
|
+
for (const entry of def.cases) {
|
|
7772
|
+
const condition = entry.keys.map((key) => emitDispatchKeyCondition(keyV, key, entry.caseInsensitive)).join(" || ");
|
|
7773
|
+
emitSelectedTail(entry, wroteBranch ? "else if" : "if", condition, coverageIds[coverageIndex++]);
|
|
7774
|
+
wroteBranch = true;
|
|
7775
|
+
}
|
|
7776
|
+
const emitMatcherTails = () => {
|
|
7777
|
+
for (const matcher of def.matchers ?? []) {
|
|
7778
|
+
emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
|
|
7779
|
+
wroteBranch = true;
|
|
7780
|
+
}
|
|
7781
|
+
};
|
|
7782
|
+
if (def.otherwise) {
|
|
7783
|
+
emitMatcherTails();
|
|
7784
|
+
const otherwiseEntry = { parser: def.otherwise, usesRouted: def.otherwiseUsesRouted };
|
|
7785
|
+
if (wroteBranch) emitSelectedTail(otherwiseEntry, "else", void 0, coverageIds[coverageIndex++]);
|
|
7786
|
+
else emitSelectedTail(otherwiseEntry, "if", "true", coverageIds[coverageIndex++]);
|
|
7787
|
+
} else {
|
|
7788
|
+
emitMatcherTails();
|
|
7789
|
+
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7790
|
+
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7791
|
+
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7792
|
+
}
|
|
7793
|
+
return { stmts, valueVar: outV, endVar: outE };
|
|
7794
|
+
}
|
|
7795
|
+
function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
|
|
7796
|
+
if (!caseInsensitive) return `${valueVar} === ${JSON.stringify(key)}`;
|
|
7797
|
+
const parts = [`${valueVar}.length === ${key.length}`];
|
|
7798
|
+
for (let i = 0; i < key.length; i++) {
|
|
7799
|
+
parts.push(foldEq(`${valueVar}.charCodeAt(${i})`, key.charCodeAt(i)));
|
|
7800
|
+
}
|
|
7801
|
+
return parts.join(" && ");
|
|
7802
|
+
}
|
|
7803
|
+
function emitDispatchMatcherCondition(valueVar, matcher) {
|
|
7804
|
+
if (matcher.kind === "matches") {
|
|
7805
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
7806
|
+
return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
|
|
7807
|
+
}
|
|
7808
|
+
const text = matcher.value;
|
|
7809
|
+
const parts = [`${valueVar}.length >= ${text.length}`];
|
|
7810
|
+
const offset = matcher.kind === "endsWith" ? `${valueVar}.length - ${text.length}` : "0";
|
|
7811
|
+
for (let i = 0; i < text.length; i++) {
|
|
7812
|
+
parts.push(matcher.caseInsensitive ? foldEq(`${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`})`, text.charCodeAt(i)) : `${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`}) === ${text.charCodeAt(i)}`);
|
|
7813
|
+
}
|
|
7814
|
+
return parts.join(" && ");
|
|
7815
|
+
}
|
|
7244
7816
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7245
7817
|
const superParser = def.parsers[superIndex];
|
|
7246
7818
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7362,12 +7934,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7362
7934
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7363
7935
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7364
7936
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7937
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7365
7938
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7366
7939
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7367
7940
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7368
7941
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7369
7942
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7370
|
-
const
|
|
7943
|
+
const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
|
|
7944
|
+
const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
7945
|
+
const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
|
|
7946
|
+
const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
|
|
7371
7947
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7372
7948
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7373
7949
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7382,7 +7958,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7382
7958
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7383
7959
|
);
|
|
7384
7960
|
}
|
|
7385
|
-
|
|
7961
|
+
if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
|
|
7962
|
+
const arm = emitFallible(p, ctx, pos, atStart);
|
|
7963
|
+
const { stmts: armStmts, okVar, valVar, endVar } = arm;
|
|
7386
7964
|
stmts.push(...armStmts);
|
|
7387
7965
|
if (autoNot && autoNot.length > 0) {
|
|
7388
7966
|
const anCode = v(ctx, "_anc");
|
|
@@ -7406,10 +7984,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7406
7984
|
stmts.push(`${ind(ctx)}}`);
|
|
7407
7985
|
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} });`} }`);
|
|
7408
7986
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7987
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7409
7988
|
} else {
|
|
7410
7989
|
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} }) }`;
|
|
7411
7990
|
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} })`} }`);
|
|
7412
7991
|
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} })`} }`);
|
|
7992
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7413
7993
|
}
|
|
7414
7994
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7415
7995
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7566,7 +8146,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7566
8146
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7567
8147
|
);
|
|
7568
8148
|
}
|
|
7569
|
-
const
|
|
8149
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
8150
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7570
8151
|
stmts.push(...iterStmts);
|
|
7571
8152
|
if (ctx.recovery) {
|
|
7572
8153
|
const rrV = v(ctx, "_rr");
|
|
@@ -7585,7 +8166,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7585
8166
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7586
8167
|
);
|
|
7587
8168
|
} else {
|
|
7588
|
-
stmts.push(`${ind(ctx)}if (!${iterOk}
|
|
8169
|
+
stmts.push(`${ind(ctx)}if (!${iterOk}) { ${rollback}${iter.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
8170
|
+
stmts.push(`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
7589
8171
|
}
|
|
7590
8172
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7591
8173
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7597,10 +8179,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7597
8179
|
function emitOptional(def, ctx, pos) {
|
|
7598
8180
|
const valV = v(ctx, "_opt");
|
|
7599
8181
|
const endV = v(ctx, "_opte");
|
|
7600
|
-
const
|
|
8182
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
8183
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7601
8184
|
const ind0 = ind(ctx);
|
|
7602
8185
|
const stmts = [
|
|
7603
8186
|
...lblStmts,
|
|
8187
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7604
8188
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7605
8189
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7606
8190
|
];
|
|
@@ -7632,7 +8216,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7632
8216
|
...preGuard,
|
|
7633
8217
|
`${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`,
|
|
7634
8218
|
...inner.stmts,
|
|
7635
|
-
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
8219
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7636
8220
|
],
|
|
7637
8221
|
valueVar: inner.valVar,
|
|
7638
8222
|
endVar: inner.endVar
|
|
@@ -7646,18 +8230,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7646
8230
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7647
8231
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7648
8232
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7649
|
-
const
|
|
8233
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
8234
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7650
8235
|
const stmts = [
|
|
7651
8236
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7652
8237
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7653
8238
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7654
8239
|
...firstStmts
|
|
7655
8240
|
];
|
|
7656
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7657
|
-
if (
|
|
8241
|
+
const failItem = (nextOkVar, nextMayCommit, itemPosVar, breakStmt) => {
|
|
8242
|
+
const commit = nextMayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : "";
|
|
8243
|
+
if (!rec) return [`${ind(ctx)}if (!${nextOkVar}) { ${commit}${breakStmt} }`];
|
|
7658
8244
|
const rr = v(ctx, "_rr");
|
|
7659
8245
|
return [
|
|
7660
8246
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
8247
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7661
8248
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7662
8249
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7663
8250
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7686,6 +8273,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7686
8273
|
stmts.push(
|
|
7687
8274
|
`${ind(ctx)}let ${didV} = false`,
|
|
7688
8275
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
8276
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7689
8277
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7690
8278
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7691
8279
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7696,6 +8284,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7696
8284
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7697
8285
|
ctx.indent++;
|
|
7698
8286
|
} else {
|
|
8287
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7699
8288
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7700
8289
|
ctx.indent++;
|
|
7701
8290
|
stmts.push(
|
|
@@ -7724,16 +8313,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7724
8313
|
);
|
|
7725
8314
|
sepAtPos = spV;
|
|
7726
8315
|
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}; `;
|
|
7727
|
-
const
|
|
7728
|
-
stmts
|
|
8316
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8317
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8318
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7729
8319
|
const post = postSepMarks();
|
|
7730
8320
|
stmts.push(...post.decl);
|
|
7731
8321
|
const npV = v(ctx, "_np");
|
|
7732
8322
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7733
|
-
const
|
|
8323
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8324
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7734
8325
|
stmts.push(
|
|
7735
8326
|
...nextStmts,
|
|
7736
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
8327
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7737
8328
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7738
8329
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7739
8330
|
);
|
|
@@ -7742,14 +8333,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7742
8333
|
const spV = v(ctx, "_sp");
|
|
7743
8334
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7744
8335
|
sepAtPos = spV;
|
|
7745
|
-
const
|
|
7746
|
-
stmts
|
|
8336
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8337
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8338
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7747
8339
|
const npV = v(ctx, "_np");
|
|
7748
8340
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7749
|
-
const
|
|
8341
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8342
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7750
8343
|
stmts.push(
|
|
7751
8344
|
...nextStmts,
|
|
7752
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
8345
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7753
8346
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7754
8347
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7755
8348
|
);
|
|
@@ -7763,15 +8356,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7763
8356
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7764
8357
|
);
|
|
7765
8358
|
}
|
|
7766
|
-
const
|
|
7767
|
-
stmts
|
|
8359
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8360
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8361
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7768
8362
|
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}; ` : "";
|
|
7769
8363
|
const post = postSepMarks();
|
|
7770
8364
|
stmts.push(...post.decl);
|
|
7771
|
-
const
|
|
8365
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
8366
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7772
8367
|
stmts.push(
|
|
7773
8368
|
...nextStmts,
|
|
7774
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
8369
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7775
8370
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7776
8371
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7777
8372
|
);
|
|
@@ -7872,6 +8467,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
7872
8467
|
endVar: pos
|
|
7873
8468
|
};
|
|
7874
8469
|
}
|
|
8470
|
+
function emitRouted(ctx, pos) {
|
|
8471
|
+
const item = v(ctx, "_rt");
|
|
8472
|
+
return {
|
|
8473
|
+
stmts: [
|
|
8474
|
+
`${ind(ctx)}const ${item} = _ctx._routed`,
|
|
8475
|
+
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8476
|
+
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8477
|
+
],
|
|
8478
|
+
valueVar: `${item}.value`,
|
|
8479
|
+
endVar: `${item}.span.end`
|
|
8480
|
+
};
|
|
8481
|
+
}
|
|
7875
8482
|
function escapeTokenLiteral(value) {
|
|
7876
8483
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
7877
8484
|
}
|
|
@@ -8152,7 +8759,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
8152
8759
|
const rv = v(ctx, "_rt");
|
|
8153
8760
|
const vv = v(ctx, "_rtv");
|
|
8154
8761
|
const ev = v(ctx, "_rte");
|
|
8155
|
-
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 }`;
|
|
8762
|
+
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 } : {}) }`;
|
|
8156
8763
|
const stmts = [
|
|
8157
8764
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8158
8765
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8233,7 +8840,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8233
8840
|
return { stmts, valueVar: valVar, endVar };
|
|
8234
8841
|
}
|
|
8235
8842
|
function emitExpect(def, ctx, pos) {
|
|
8236
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8843
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8237
8844
|
const ind0 = ind(ctx);
|
|
8238
8845
|
const errV = v(ctx, "_err");
|
|
8239
8846
|
const stmts = [
|
|
@@ -8245,6 +8852,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8245
8852
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8246
8853
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8247
8854
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8855
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8248
8856
|
`${ind0} ${valVar} = ${errV}`,
|
|
8249
8857
|
`${ind0} ${endVar} = ${pos}`,
|
|
8250
8858
|
`${ind0} ${okVar} = true`,
|
|
@@ -8255,7 +8863,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8255
8863
|
function emit(p, ctx, pos) {
|
|
8256
8864
|
const replay = ctx.replayPrefix?.get(p);
|
|
8257
8865
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8258
|
-
const
|
|
8866
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8259
8867
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8260
8868
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8261
8869
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8295,14 +8903,14 @@ function emit(p, ctx, pos) {
|
|
|
8295
8903
|
ctx.indent = 1;
|
|
8296
8904
|
ctx.failLabel = "_pfail";
|
|
8297
8905
|
ctx.recordFail = true;
|
|
8298
|
-
const r =
|
|
8906
|
+
const r = dispatch2("_pos");
|
|
8299
8907
|
ctx.indent = savedIndent;
|
|
8300
8908
|
ctx.failLabel = savedFailLabel;
|
|
8301
8909
|
ctx.recordFail = savedRecord;
|
|
8302
8910
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8303
8911
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8304
8912
|
}
|
|
8305
|
-
return instrument(
|
|
8913
|
+
return instrument(dispatch2());
|
|
8306
8914
|
}
|
|
8307
8915
|
function emitDispatch(p, ctx, pos) {
|
|
8308
8916
|
const bal = p._balancedAmbient;
|
|
@@ -8335,6 +8943,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8335
8943
|
return emitSeq(def, ctx, pos);
|
|
8336
8944
|
case "choice":
|
|
8337
8945
|
return emitChoice(p, def, ctx, pos);
|
|
8946
|
+
case "dispatch":
|
|
8947
|
+
return emitDispatchCombinator(p, def, ctx, pos);
|
|
8338
8948
|
case "attempt":
|
|
8339
8949
|
return emitAttempt(p, def, ctx, pos);
|
|
8340
8950
|
case "many":
|
|
@@ -8459,6 +9069,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8459
9069
|
return emitNot(def, ctx, pos);
|
|
8460
9070
|
case "peek":
|
|
8461
9071
|
return emitPeek(def, ctx, pos);
|
|
9072
|
+
case "routed":
|
|
9073
|
+
return emitRouted(ctx, pos);
|
|
8462
9074
|
case "node":
|
|
8463
9075
|
return emitNode(def, ctx, pos);
|
|
8464
9076
|
case "scanTo":
|
|
@@ -8555,6 +9167,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8555
9167
|
case "sequence":
|
|
8556
9168
|
case "choice":
|
|
8557
9169
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
9170
|
+
case "dispatch":
|
|
9171
|
+
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);
|
|
8558
9172
|
case "sepBy":
|
|
8559
9173
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8560
9174
|
case "scanTo":
|
|
@@ -8569,6 +9183,26 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8569
9183
|
return false;
|
|
8570
9184
|
}
|
|
8571
9185
|
}
|
|
9186
|
+
function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
|
|
9187
|
+
if (seen.has(p)) return false;
|
|
9188
|
+
seen.add(p);
|
|
9189
|
+
const d = p._def;
|
|
9190
|
+
switch (d.tag) {
|
|
9191
|
+
case "routed":
|
|
9192
|
+
return true;
|
|
9193
|
+
case "lazy": {
|
|
9194
|
+
try {
|
|
9195
|
+
return parserUsesRouted2(d.thunk(), seen);
|
|
9196
|
+
} catch {
|
|
9197
|
+
return false;
|
|
9198
|
+
}
|
|
9199
|
+
}
|
|
9200
|
+
case "dispatch":
|
|
9201
|
+
return false;
|
|
9202
|
+
default:
|
|
9203
|
+
return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
|
|
9204
|
+
}
|
|
9205
|
+
}
|
|
8572
9206
|
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
8573
9207
|
if (seen.has(p)) return false;
|
|
8574
9208
|
seen.add(p);
|
|
@@ -8588,6 +9222,8 @@ function childrenOf2(def) {
|
|
|
8588
9222
|
case "sequence":
|
|
8589
9223
|
case "choice":
|
|
8590
9224
|
return def.parsers;
|
|
9225
|
+
case "dispatch":
|
|
9226
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
8591
9227
|
case "many":
|
|
8592
9228
|
case "attempt":
|
|
8593
9229
|
case "optional":
|
|
@@ -8624,6 +9260,7 @@ function childrenOf2(def) {
|
|
|
8624
9260
|
case "regex":
|
|
8625
9261
|
case "keywords":
|
|
8626
9262
|
case "guard":
|
|
9263
|
+
case "routed":
|
|
8627
9264
|
case "unknown":
|
|
8628
9265
|
return [];
|
|
8629
9266
|
}
|
|
@@ -8631,6 +9268,7 @@ function childrenOf2(def) {
|
|
|
8631
9268
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8632
9269
|
"sequence",
|
|
8633
9270
|
"choice",
|
|
9271
|
+
"dispatch",
|
|
8634
9272
|
"many",
|
|
8635
9273
|
"oneOrMore",
|
|
8636
9274
|
"optional",
|
|
@@ -9329,6 +9967,8 @@ function childrenOf3(def) {
|
|
|
9329
9967
|
case "sequence":
|
|
9330
9968
|
case "choice":
|
|
9331
9969
|
return def.parsers;
|
|
9970
|
+
case "dispatch":
|
|
9971
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
9332
9972
|
case "many":
|
|
9333
9973
|
case "oneOrMore":
|
|
9334
9974
|
case "optional":
|
|
@@ -9357,6 +9997,7 @@ function childrenOf3(def) {
|
|
|
9357
9997
|
case "literal":
|
|
9358
9998
|
case "regex":
|
|
9359
9999
|
case "keywords":
|
|
10000
|
+
case "routed":
|
|
9360
10001
|
case "guard":
|
|
9361
10002
|
case "recover":
|
|
9362
10003
|
case "unknown":
|
|
@@ -9381,6 +10022,16 @@ function repeatOpts(min, max, trailing) {
|
|
|
9381
10022
|
if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
|
|
9382
10023
|
return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
|
|
9383
10024
|
}
|
|
10025
|
+
function matcherExpr(entry) {
|
|
10026
|
+
switch (entry.kind) {
|
|
10027
|
+
case "startsWith":
|
|
10028
|
+
return `startsWith(${JSON.stringify(entry.value)})`;
|
|
10029
|
+
case "endsWith":
|
|
10030
|
+
return `endsWith(${JSON.stringify(entry.value)})`;
|
|
10031
|
+
case "matches":
|
|
10032
|
+
return `matches(${new RegExp(entry.value, entry.flags ?? "").toString()})`;
|
|
10033
|
+
}
|
|
10034
|
+
}
|
|
9384
10035
|
function serializeRuleMap(ruleMap, scanSkip) {
|
|
9385
10036
|
try {
|
|
9386
10037
|
return new Serializer(ruleMap, scanSkip ?? []).run();
|
|
@@ -9478,6 +10129,13 @@ function evalRuleMapIR(ir) {
|
|
|
9478
10129
|
"keywords",
|
|
9479
10130
|
"sequence",
|
|
9480
10131
|
"choice",
|
|
10132
|
+
"dispatch",
|
|
10133
|
+
"when",
|
|
10134
|
+
"startsWith",
|
|
10135
|
+
"endsWith",
|
|
10136
|
+
"matches",
|
|
10137
|
+
"otherwise",
|
|
10138
|
+
"routed",
|
|
9481
10139
|
"attempt",
|
|
9482
10140
|
"many",
|
|
9483
10141
|
"oneOrMore",
|
|
@@ -9511,6 +10169,13 @@ function evalRuleMapIR(ir) {
|
|
|
9511
10169
|
keywords,
|
|
9512
10170
|
sequence,
|
|
9513
10171
|
choice,
|
|
10172
|
+
dispatch,
|
|
10173
|
+
when,
|
|
10174
|
+
startsWith,
|
|
10175
|
+
endsWith,
|
|
10176
|
+
matches,
|
|
10177
|
+
otherwise,
|
|
10178
|
+
routed,
|
|
9514
10179
|
attempt,
|
|
9515
10180
|
many,
|
|
9516
10181
|
oneOrMore,
|
|
@@ -9696,6 +10361,18 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9696
10361
|
});
|
|
9697
10362
|
return `_gch([${items.join(", ")}])`;
|
|
9698
10363
|
}
|
|
10364
|
+
case "dispatch": {
|
|
10365
|
+
const arms = def.cases.map(
|
|
10366
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`
|
|
10367
|
+
);
|
|
10368
|
+
if (def.matchers) {
|
|
10369
|
+
for (const entry of def.matchers) {
|
|
10370
|
+
arms.push(`when(${matcherExpr(entry)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`);
|
|
10371
|
+
}
|
|
10372
|
+
}
|
|
10373
|
+
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10374
|
+
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10375
|
+
}
|
|
9699
10376
|
case "many":
|
|
9700
10377
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9701
10378
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -9712,6 +10389,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9712
10389
|
return `not(${kid(def.parser)})`;
|
|
9713
10390
|
case "peek":
|
|
9714
10391
|
return `peek(${kid(def.parser)})`;
|
|
10392
|
+
case "routed":
|
|
10393
|
+
return "routed()";
|
|
9715
10394
|
case "trivia":
|
|
9716
10395
|
return `trivia(${kid(def.parser)})`;
|
|
9717
10396
|
case "token":
|
|
@@ -10733,10 +11412,20 @@ function run(entry, input, options = {}) {
|
|
|
10733
11412
|
}
|
|
10734
11413
|
|
|
10735
11414
|
// src/coverage.ts
|
|
11415
|
+
function dispatchMatcher(entry) {
|
|
11416
|
+
switch (entry.kind) {
|
|
11417
|
+
case "startsWith":
|
|
11418
|
+
return startsWith(entry.value);
|
|
11419
|
+
case "endsWith":
|
|
11420
|
+
return endsWith(entry.value);
|
|
11421
|
+
case "matches":
|
|
11422
|
+
return matches(new RegExp(entry.value, entry.flags));
|
|
11423
|
+
}
|
|
11424
|
+
}
|
|
10736
11425
|
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
10737
11426
|
function compiledGrammarCoverageDefinitions(grammar) {
|
|
10738
11427
|
const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
|
|
10739
|
-
if (!Array.isArray(definitions) || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "label"))) {
|
|
11428
|
+
if (!Array.isArray(definitions) || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "dispatch-arm" || definition.kind === "label"))) {
|
|
10740
11429
|
throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
|
|
10741
11430
|
}
|
|
10742
11431
|
return definitions;
|
|
@@ -10915,6 +11604,56 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
10915
11604
|
const unsafeSequence = sequence;
|
|
10916
11605
|
return unsafeSequence(...def.parsers.map(build));
|
|
10917
11606
|
}
|
|
11607
|
+
case "dispatch": {
|
|
11608
|
+
const ids = maps.dispatches.get(parser2) ?? [];
|
|
11609
|
+
let armIndex = 0;
|
|
11610
|
+
const dispatchStarts = [];
|
|
11611
|
+
const wrapArm = (arm, id) => {
|
|
11612
|
+
const child = build(arm);
|
|
11613
|
+
return {
|
|
11614
|
+
_tag: child._tag,
|
|
11615
|
+
_meta: child._meta,
|
|
11616
|
+
_def: child._def,
|
|
11617
|
+
parse(input, pos, ctx) {
|
|
11618
|
+
const dispatchStart = dispatchStarts[dispatchStarts.length - 1] ?? pos;
|
|
11619
|
+
if (id) trace?.write({ id, phase: "attempt", offset: dispatchStart });
|
|
11620
|
+
const result = child.parse(input, pos, ctx);
|
|
11621
|
+
if (result.ok) {
|
|
11622
|
+
if (id) {
|
|
11623
|
+
collector.hit(id);
|
|
11624
|
+
trace?.write({ id, phase: "selected", offset: dispatchStart, end: result.span.end });
|
|
11625
|
+
trace?.write({ id, phase: "success", offset: dispatchStart, end: result.span.end });
|
|
11626
|
+
}
|
|
11627
|
+
} else if (id) {
|
|
11628
|
+
trace?.write({ id, phase: "failure", offset: result.span.end });
|
|
11629
|
+
}
|
|
11630
|
+
return result;
|
|
11631
|
+
}
|
|
11632
|
+
};
|
|
11633
|
+
};
|
|
11634
|
+
const arms = def.cases.map(
|
|
11635
|
+
(entry2) => when(entry2.keys, wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0)
|
|
11636
|
+
);
|
|
11637
|
+
if (def.matchers) {
|
|
11638
|
+
for (const entry2 of def.matchers) {
|
|
11639
|
+
arms.push(when(dispatchMatcher(entry2), wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
11640
|
+
}
|
|
11641
|
+
}
|
|
11642
|
+
if (def.otherwise) arms.push(otherwise(wrapArm(def.otherwise, ids[armIndex++])));
|
|
11643
|
+
const unsafeDispatch = dispatch;
|
|
11644
|
+
const base2 = unsafeDispatch(build(def.selector), ...arms);
|
|
11645
|
+
return {
|
|
11646
|
+
...base2,
|
|
11647
|
+
parse(input, pos, ctx) {
|
|
11648
|
+
dispatchStarts.push(pos);
|
|
11649
|
+
try {
|
|
11650
|
+
return base2.parse(input, pos, ctx);
|
|
11651
|
+
} finally {
|
|
11652
|
+
dispatchStarts.pop();
|
|
11653
|
+
}
|
|
11654
|
+
}
|
|
11655
|
+
};
|
|
11656
|
+
}
|
|
10918
11657
|
case "many":
|
|
10919
11658
|
return many(build(def.parser));
|
|
10920
11659
|
case "oneOrMore":
|