parseman 0.39.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +36 -3
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +15 -0
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/compiler/codegen.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 +483 -61
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +483 -61
- package/dist/index.js.map +3 -3
- package/dist/plugin/evaluator.d.ts +6 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +520 -67
- package/dist/plugin/index.cjs.map +3 -3
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +520 -67
- package/dist/plugin/index.js.map +3 -3
- package/dist/spec/index.cjs +234 -26
- package/dist/spec/index.cjs.map +3 -3
- package/dist/spec/index.js +234 -26
- package/dist/spec/index.js.map +3 -3
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -57,6 +57,7 @@ __export(index_exports, {
|
|
|
57
57
|
cstBuildHost: () => cstBuildHost,
|
|
58
58
|
dispatch: () => dispatch,
|
|
59
59
|
duplicationFindingCount: () => duplicationFindingCount,
|
|
60
|
+
endsWith: () => endsWith,
|
|
60
61
|
expect: () => expect,
|
|
61
62
|
extractCharClasses: () => extractCharClasses,
|
|
62
63
|
field: () => field,
|
|
@@ -79,8 +80,10 @@ __export(index_exports, {
|
|
|
79
80
|
lineBreaksIn: () => lineBreaksIn,
|
|
80
81
|
lineStartWithin: () => lineStartWithin,
|
|
81
82
|
literal: () => literal,
|
|
83
|
+
makeWhen: () => makeWhen,
|
|
82
84
|
makeWord: () => makeWord,
|
|
83
85
|
many: () => many,
|
|
86
|
+
matches: () => matches,
|
|
84
87
|
noTrivia: () => noTrivia,
|
|
85
88
|
node: () => node,
|
|
86
89
|
not: () => not,
|
|
@@ -97,6 +100,7 @@ __export(index_exports, {
|
|
|
97
100
|
regex: () => regex,
|
|
98
101
|
relativize: () => relativize,
|
|
99
102
|
relativizeCST: () => relativizeCST,
|
|
103
|
+
routed: () => routed,
|
|
100
104
|
rules: () => rules,
|
|
101
105
|
run: () => run,
|
|
102
106
|
runWithGrammarCoverage: () => runWithGrammarCoverage,
|
|
@@ -106,6 +110,7 @@ __export(index_exports, {
|
|
|
106
110
|
shiftAbsolute: () => shiftAbsolute,
|
|
107
111
|
siteToString: () => siteToString,
|
|
108
112
|
skip: () => skip,
|
|
113
|
+
startsWith: () => startsWith,
|
|
109
114
|
token: () => token,
|
|
110
115
|
transform: () => transform,
|
|
111
116
|
trivia: () => trivia,
|
|
@@ -171,6 +176,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
171
176
|
return d.value.length === 0;
|
|
172
177
|
case "keywords":
|
|
173
178
|
return false;
|
|
179
|
+
case "routed":
|
|
180
|
+
return false;
|
|
174
181
|
case "regex":
|
|
175
182
|
try {
|
|
176
183
|
const m = new RegExp(d.source).exec("");
|
|
@@ -1232,6 +1239,8 @@ function derive(c, seen) {
|
|
|
1232
1239
|
case "not":
|
|
1233
1240
|
case "peek":
|
|
1234
1241
|
return deriveExpected2(def.parser);
|
|
1242
|
+
case "routed":
|
|
1243
|
+
return ["routed()"];
|
|
1235
1244
|
case "lazy": {
|
|
1236
1245
|
const name = c._ruleName;
|
|
1237
1246
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -2056,42 +2065,198 @@ function sequence(...parsers) {
|
|
|
2056
2065
|
}
|
|
2057
2066
|
|
|
2058
2067
|
// src/combinators/dispatch.ts
|
|
2059
|
-
function
|
|
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
|
+
}
|
|
2060
2169
|
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2061
2170
|
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2062
2171
|
for (const item of keys) {
|
|
2063
2172
|
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2064
2173
|
}
|
|
2065
|
-
return { kind: "when", keys, parser: parser2 };
|
|
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);
|
|
2066
2178
|
}
|
|
2067
2179
|
function otherwise(parser2) {
|
|
2068
|
-
return { kind: "otherwise", parser: 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
|
+
};
|
|
2069
2201
|
}
|
|
2070
2202
|
function dispatch(selector, ...arms) {
|
|
2203
|
+
if (parserUsesRouted(selector)) {
|
|
2204
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2205
|
+
}
|
|
2071
2206
|
let fallback;
|
|
2207
|
+
let fallbackUsesRouted = false;
|
|
2208
|
+
const matchers = [];
|
|
2072
2209
|
const cases = [];
|
|
2073
|
-
const seen =
|
|
2210
|
+
const seen = [];
|
|
2074
2211
|
for (let i = 0; i < arms.length; i++) {
|
|
2075
2212
|
const arm = arms[i];
|
|
2076
2213
|
if (arm.kind === "otherwise") {
|
|
2077
2214
|
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2078
2215
|
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2079
2216
|
fallback = arm.parser;
|
|
2217
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
2080
2218
|
continue;
|
|
2081
2219
|
}
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
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;
|
|
2085
2231
|
}
|
|
2086
|
-
|
|
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
|
+
});
|
|
2087
2246
|
}
|
|
2088
2247
|
const meta = {
|
|
2089
2248
|
firstSet: selector._meta.firstSet,
|
|
2090
|
-
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2249
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2091
2250
|
isTrivia: false
|
|
2092
2251
|
};
|
|
2093
2252
|
const byKey = /* @__PURE__ */ new Map();
|
|
2094
|
-
|
|
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
|
+
}
|
|
2095
2260
|
return {
|
|
2096
2261
|
_tag: "dispatch",
|
|
2097
2262
|
_meta: meta,
|
|
@@ -2099,18 +2264,35 @@ function dispatch(selector, ...arms) {
|
|
|
2099
2264
|
tag: "dispatch",
|
|
2100
2265
|
selector,
|
|
2101
2266
|
cases,
|
|
2102
|
-
...
|
|
2267
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2268
|
+
...fallback === void 0 ? {} : { otherwise: fallback, ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {} }
|
|
2103
2269
|
},
|
|
2104
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);
|
|
2105
2275
|
const selected = selector.parse(input, pos, ctx);
|
|
2106
2276
|
if (!selected.ok) return selected;
|
|
2107
|
-
const
|
|
2108
|
-
if (
|
|
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) {
|
|
2109
2279
|
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2110
2280
|
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2111
2281
|
}
|
|
2112
|
-
const
|
|
2113
|
-
const
|
|
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
|
+
}
|
|
2114
2296
|
if (!result.ok) {
|
|
2115
2297
|
rollbackTrivia(ctx, mark);
|
|
2116
2298
|
return { ...result, committed: true };
|
|
@@ -2497,6 +2679,7 @@ function markUnusedValues(root) {
|
|
|
2497
2679
|
case "dispatch":
|
|
2498
2680
|
visit(def.selector, consumed);
|
|
2499
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);
|
|
2500
2683
|
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2501
2684
|
return;
|
|
2502
2685
|
case "node":
|
|
@@ -2775,7 +2958,7 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2775
2958
|
case "choice":
|
|
2776
2959
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2777
2960
|
case "dispatch":
|
|
2778
|
-
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
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);
|
|
2779
2962
|
case "sepBy":
|
|
2780
2963
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2781
2964
|
case "skip":
|
|
@@ -2844,7 +3027,7 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2844
3027
|
case "choice":
|
|
2845
3028
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2846
3029
|
case "dispatch":
|
|
2847
|
-
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
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);
|
|
2848
3031
|
case "grammar":
|
|
2849
3032
|
return parserHasTriviaSite(d.parser, seen);
|
|
2850
3033
|
case "lazy": {
|
|
@@ -2871,7 +3054,7 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2871
3054
|
case "choice":
|
|
2872
3055
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2873
3056
|
case "dispatch":
|
|
2874
|
-
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
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);
|
|
2875
3058
|
case "sepBy":
|
|
2876
3059
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2877
3060
|
case "skip":
|
|
@@ -2932,12 +3115,30 @@ function isCstChild(value) {
|
|
|
2932
3115
|
function missingInferredType() {
|
|
2933
3116
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
2934
3117
|
}
|
|
3118
|
+
function normalizeProject(project) {
|
|
3119
|
+
if (project === void 0) return void 0;
|
|
3120
|
+
if (!Number.isInteger(project) || project < 0) {
|
|
3121
|
+
throw new Error("node() project child must be a non-negative integer");
|
|
3122
|
+
}
|
|
3123
|
+
return project;
|
|
3124
|
+
}
|
|
3125
|
+
function projectChild(children2, project, type) {
|
|
3126
|
+
if (!(project in children2)) {
|
|
3127
|
+
throw new Error(`node(${JSON.stringify(type)}) project child ${project} was not captured`);
|
|
3128
|
+
}
|
|
3129
|
+
return unwrapChild(children2[project]);
|
|
3130
|
+
}
|
|
2935
3131
|
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
2936
3132
|
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
2937
3133
|
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
2938
3134
|
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
2939
|
-
const
|
|
2940
|
-
const
|
|
3135
|
+
const buildArg = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
3136
|
+
const build = typeof buildArg === "function" ? buildArg : void 0;
|
|
3137
|
+
const opts = typeof buildArg === "function" ? maybeOpts : buildArg ?? maybeOpts;
|
|
3138
|
+
const project = normalizeProject(opts?.project);
|
|
3139
|
+
if (project !== void 0 && build !== void 0) {
|
|
3140
|
+
throw new Error("node() options cannot combine project with a build callback");
|
|
3141
|
+
}
|
|
2941
3142
|
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
2942
3143
|
const meta = {
|
|
2943
3144
|
firstSet: combinator._meta.firstSet,
|
|
@@ -2951,11 +3152,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2951
3152
|
if (unwrap && collapse) {
|
|
2952
3153
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
2953
3154
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
3155
|
+
if (project !== void 0 && (unwrap || collapse)) {
|
|
3156
|
+
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3157
|
+
}
|
|
3158
|
+
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
|
|
3159
|
+
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3160
|
+
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
2957
3161
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
2958
|
-
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) :
|
|
3162
|
+
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
2959
3163
|
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
2960
3164
|
let failExpected;
|
|
2961
3165
|
return {
|
|
@@ -2970,14 +3174,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2970
3174
|
}
|
|
2971
3175
|
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
2972
3176
|
}
|
|
2973
|
-
const
|
|
3177
|
+
const hasDirectValue = build !== void 0 || project !== void 0;
|
|
3178
|
+
const hostCst = hasDirectValue && cstOutputHost(ctx.build);
|
|
2974
3179
|
const effTrivia = capturesTrivia || hostCst;
|
|
2975
3180
|
const effFields = capturesFields || hostCst && hasOwnFields;
|
|
2976
3181
|
const saved = beginCstNodeCapture(ctx);
|
|
2977
3182
|
const savedFields = ctx._fields;
|
|
2978
3183
|
ctx._fields = effFields ? [] : void 0;
|
|
2979
3184
|
const savedMask = ctx._triviaCaptureMask;
|
|
2980
|
-
if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
3185
|
+
if (build === void 0 && project === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
2981
3186
|
ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
|
|
2982
3187
|
}
|
|
2983
3188
|
if (!effTrivia) ctx.captureTrivia = false;
|
|
@@ -2995,7 +3200,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2995
3200
|
const nodeType = def.type ?? missingInferredType();
|
|
2996
3201
|
const cstOutput = cstOutputHost(ctx.build);
|
|
2997
3202
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2998
|
-
const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
|
|
3203
|
+
const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
|
|
2999
3204
|
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span: r.span };
|
|
3000
3205
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
3001
3206
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3273,7 +3478,7 @@ function leaf(root, fn) {
|
|
|
3273
3478
|
}
|
|
3274
3479
|
|
|
3275
3480
|
// src/version.ts
|
|
3276
|
-
var PARSEMAN_VERSION = "0.
|
|
3481
|
+
var PARSEMAN_VERSION = "0.40.0";
|
|
3277
3482
|
|
|
3278
3483
|
// src/cst/host-mode.ts
|
|
3279
3484
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3533,6 +3738,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3533
3738
|
if (d.tag === "dispatch") {
|
|
3534
3739
|
kids.push(d.selector);
|
|
3535
3740
|
for (const c of d.cases) kids.push(c.parser);
|
|
3741
|
+
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3536
3742
|
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3537
3743
|
}
|
|
3538
3744
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
@@ -5056,13 +5262,25 @@ function escapeClassChar(ch2) {
|
|
|
5056
5262
|
}
|
|
5057
5263
|
|
|
5058
5264
|
// src/compiler/grammar-coverage-ids.ts
|
|
5265
|
+
function idPart(value) {
|
|
5266
|
+
return encodeURIComponent(value);
|
|
5267
|
+
}
|
|
5268
|
+
function dispatchArmIds(def, path) {
|
|
5269
|
+
const ids = [];
|
|
5270
|
+
for (const entry of def.cases) ids.push(`dispatch:${path}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5271
|
+
for (const entry of def.matchers ?? []) {
|
|
5272
|
+
ids.push(`dispatch:${path}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5273
|
+
}
|
|
5274
|
+
if (def.otherwise) ids.push(`dispatch:${path}/otherwise`);
|
|
5275
|
+
return ids;
|
|
5276
|
+
}
|
|
5059
5277
|
function children(def, winners) {
|
|
5060
5278
|
switch (def.tag) {
|
|
5061
5279
|
case "sequence":
|
|
5062
5280
|
case "choice":
|
|
5063
5281
|
return def.parsers;
|
|
5064
5282
|
case "dispatch":
|
|
5065
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
5283
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
5066
5284
|
case "many":
|
|
5067
5285
|
case "oneOrMore":
|
|
5068
5286
|
case "optional":
|
|
@@ -5105,6 +5323,7 @@ function children(def, winners) {
|
|
|
5105
5323
|
function buildGrammarPlan(entry, winners) {
|
|
5106
5324
|
const definitions = /* @__PURE__ */ new Map();
|
|
5107
5325
|
const choices = /* @__PURE__ */ new WeakMap();
|
|
5326
|
+
const dispatches = /* @__PURE__ */ new WeakMap();
|
|
5108
5327
|
const attempts = /* @__PURE__ */ new WeakMap();
|
|
5109
5328
|
const labels = /* @__PURE__ */ new WeakMap();
|
|
5110
5329
|
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -5135,6 +5354,11 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5135
5354
|
choices.set(parser2, ids);
|
|
5136
5355
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
5137
5356
|
}
|
|
5357
|
+
if (parser2._def.tag === "dispatch") {
|
|
5358
|
+
const ids = dispatchArmIds(parser2._def, path);
|
|
5359
|
+
dispatches.set(parser2, ids);
|
|
5360
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5361
|
+
}
|
|
5138
5362
|
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
|
|
5139
5363
|
if (parser2._def.tag === "label") {
|
|
5140
5364
|
const id = `label:${path}`;
|
|
@@ -5147,7 +5371,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5147
5371
|
for (const root of roots) {
|
|
5148
5372
|
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
5149
5373
|
}
|
|
5150
|
-
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
5374
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
|
|
5151
5375
|
}
|
|
5152
5376
|
|
|
5153
5377
|
// src/compiler/scannable-run.ts
|
|
@@ -6521,6 +6745,7 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6521
6745
|
case "literal":
|
|
6522
6746
|
case "regex":
|
|
6523
6747
|
case "keywords":
|
|
6748
|
+
case "routed":
|
|
6524
6749
|
return { alts: [[seg(p._meta.firstSet, matchesEmpty(p))]] };
|
|
6525
6750
|
case "choice": {
|
|
6526
6751
|
const alts = [];
|
|
@@ -6871,7 +7096,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6871
7096
|
case "choice":
|
|
6872
7097
|
return false;
|
|
6873
7098
|
case "dispatch":
|
|
6874
|
-
return capturesLeaf(d.selector, seen) || d.cases.some((x) => mayLeavePartialCapture(x.parser, seen) || capturesLeaf(x.parser, seen)) || (d.otherwise ? mayLeavePartialCapture(d.otherwise, seen) || capturesLeaf(d.otherwise, seen) : false);
|
|
7099
|
+
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);
|
|
6875
7100
|
case "attempt":
|
|
6876
7101
|
return false;
|
|
6877
7102
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6970,6 +7195,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6970
7195
|
case "keywords":
|
|
6971
7196
|
case "node":
|
|
6972
7197
|
case "token":
|
|
7198
|
+
case "routed":
|
|
6973
7199
|
case "leaf":
|
|
6974
7200
|
return true;
|
|
6975
7201
|
case "not":
|
|
@@ -6982,7 +7208,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6982
7208
|
case "choice":
|
|
6983
7209
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6984
7210
|
case "dispatch":
|
|
6985
|
-
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
7211
|
+
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);
|
|
6986
7212
|
case "sepBy":
|
|
6987
7213
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6988
7214
|
case "many":
|
|
@@ -7460,6 +7686,7 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7460
7686
|
for (const item of d.cases) {
|
|
7461
7687
|
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7462
7688
|
}
|
|
7689
|
+
if (d.matchers?.some((item) => mayRecordRecoveryError(item.parser, recovery, seen))) return true;
|
|
7463
7690
|
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7464
7691
|
}
|
|
7465
7692
|
case "attempt":
|
|
@@ -7494,53 +7721,120 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7494
7721
|
return false;
|
|
7495
7722
|
}
|
|
7496
7723
|
}
|
|
7497
|
-
function emitDispatchCombinator(def, ctx, pos) {
|
|
7724
|
+
function emitDispatchCombinator(parser2, def, ctx, pos) {
|
|
7725
|
+
if (parserUsesRouted2(def.selector)) {
|
|
7726
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
7727
|
+
}
|
|
7728
|
+
const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
|
|
7729
|
+
const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
|
|
7730
|
+
const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
|
|
7731
|
+
const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
|
|
7732
|
+
const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
|
|
7733
|
+
const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
|
|
7734
|
+
const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
|
|
7735
|
+
const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
|
|
7736
|
+
const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
|
|
7498
7737
|
const selector = emit(def.selector, ctx, pos);
|
|
7499
7738
|
const outV = v(ctx, "_dval");
|
|
7500
7739
|
const outE = v(ctx, "_dend");
|
|
7501
7740
|
const keyV = v(ctx, "_dkey");
|
|
7502
7741
|
const stmts = [
|
|
7742
|
+
...selectorLeafMark ? [
|
|
7743
|
+
`${ind(ctx)}const ${selectorLeafMark} = _ctx._cstLeaves?.length ?? 0`,
|
|
7744
|
+
`${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
|
|
7745
|
+
`${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
7746
|
+
`${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
|
|
7747
|
+
`${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
|
|
7748
|
+
`${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
|
|
7749
|
+
] : [],
|
|
7503
7750
|
...selector.stmts,
|
|
7504
7751
|
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7505
7752
|
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7506
7753
|
];
|
|
7507
7754
|
let wroteBranch = false;
|
|
7508
|
-
const emitSelectedTail = (
|
|
7755
|
+
const emitSelectedTail = (entry, keyword, condition, coverageId) => {
|
|
7756
|
+
const parser3 = entry.parser;
|
|
7509
7757
|
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7510
7758
|
stmts.push(head);
|
|
7511
7759
|
ctx.indent++;
|
|
7512
|
-
const
|
|
7760
|
+
const usesRouted = branchUsesRouted2(entry);
|
|
7761
|
+
const routedV = usesRouted ? v(ctx, "_drt") : null;
|
|
7762
|
+
const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
|
|
7513
7763
|
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7514
7764
|
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7765
|
+
if (routedV) {
|
|
7766
|
+
stmts.push(
|
|
7767
|
+
`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
|
|
7768
|
+
...selectorLeafMark ? [
|
|
7769
|
+
`${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}`
|
|
7770
|
+
] : []
|
|
7771
|
+
);
|
|
7772
|
+
}
|
|
7515
7773
|
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7516
7774
|
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7517
|
-
const tail = emitTailFallible(
|
|
7775
|
+
const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
|
|
7776
|
+
stmts.push(...coverageAttempt(ctx, coverageId, pos));
|
|
7518
7777
|
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7519
7778
|
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7779
|
+
const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
|
|
7780
|
+
const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
|
|
7520
7781
|
stmts.push(
|
|
7521
7782
|
...tail.stmts,
|
|
7522
|
-
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7783
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
|
|
7784
|
+
...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
|
|
7523
7785
|
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7524
|
-
`${ind(ctx)}${outE} = ${tail.endVar}
|
|
7786
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`,
|
|
7787
|
+
...coverageHit(ctx, coverageId, pos, tail.endVar)
|
|
7525
7788
|
);
|
|
7526
7789
|
ctx.indent--;
|
|
7527
7790
|
stmts.push(`${ind(ctx)}}`);
|
|
7528
7791
|
};
|
|
7792
|
+
let coverageIndex = 0;
|
|
7529
7793
|
for (const entry of def.cases) {
|
|
7530
|
-
const condition = entry.keys.map((key) =>
|
|
7531
|
-
emitSelectedTail(entry
|
|
7794
|
+
const condition = entry.keys.map((key) => emitDispatchKeyCondition(keyV, key, entry.caseInsensitive)).join(" || ");
|
|
7795
|
+
emitSelectedTail(entry, wroteBranch ? "else if" : "if", condition, coverageIds[coverageIndex++]);
|
|
7532
7796
|
wroteBranch = true;
|
|
7533
7797
|
}
|
|
7798
|
+
const emitMatcherTails = () => {
|
|
7799
|
+
for (const matcher of def.matchers ?? []) {
|
|
7800
|
+
emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
|
|
7801
|
+
wroteBranch = true;
|
|
7802
|
+
}
|
|
7803
|
+
};
|
|
7534
7804
|
if (def.otherwise) {
|
|
7535
|
-
|
|
7536
|
-
|
|
7805
|
+
emitMatcherTails();
|
|
7806
|
+
const otherwiseEntry = { parser: def.otherwise, usesRouted: def.otherwiseUsesRouted };
|
|
7807
|
+
if (wroteBranch) emitSelectedTail(otherwiseEntry, "else", void 0, coverageIds[coverageIndex++]);
|
|
7808
|
+
else emitSelectedTail(otherwiseEntry, "if", "true", coverageIds[coverageIndex++]);
|
|
7537
7809
|
} else {
|
|
7810
|
+
emitMatcherTails();
|
|
7538
7811
|
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7539
7812
|
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7540
7813
|
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7541
7814
|
}
|
|
7542
7815
|
return { stmts, valueVar: outV, endVar: outE };
|
|
7543
7816
|
}
|
|
7817
|
+
function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
|
|
7818
|
+
if (!caseInsensitive) return `${valueVar} === ${JSON.stringify(key)}`;
|
|
7819
|
+
const parts = [`${valueVar}.length === ${key.length}`];
|
|
7820
|
+
for (let i = 0; i < key.length; i++) {
|
|
7821
|
+
parts.push(foldEq(`${valueVar}.charCodeAt(${i})`, key.charCodeAt(i)));
|
|
7822
|
+
}
|
|
7823
|
+
return parts.join(" && ");
|
|
7824
|
+
}
|
|
7825
|
+
function emitDispatchMatcherCondition(valueVar, matcher) {
|
|
7826
|
+
if (matcher.kind === "matches") {
|
|
7827
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
7828
|
+
return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
|
|
7829
|
+
}
|
|
7830
|
+
const text = matcher.value;
|
|
7831
|
+
const parts = [`${valueVar}.length >= ${text.length}`];
|
|
7832
|
+
const offset = matcher.kind === "endsWith" ? `${valueVar}.length - ${text.length}` : "0";
|
|
7833
|
+
for (let i = 0; i < text.length; i++) {
|
|
7834
|
+
parts.push(matcher.caseInsensitive ? foldEq(`${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`})`, text.charCodeAt(i)) : `${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`}) === ${text.charCodeAt(i)}`);
|
|
7835
|
+
}
|
|
7836
|
+
return parts.join(" && ");
|
|
7837
|
+
}
|
|
7544
7838
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7545
7839
|
const superParser = def.parsers[superIndex];
|
|
7546
7840
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -8195,6 +8489,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
8195
8489
|
endVar: pos
|
|
8196
8490
|
};
|
|
8197
8491
|
}
|
|
8492
|
+
function emitRouted(ctx, pos) {
|
|
8493
|
+
const item = v(ctx, "_rt");
|
|
8494
|
+
return {
|
|
8495
|
+
stmts: [
|
|
8496
|
+
`${ind(ctx)}const ${item} = _ctx._routed`,
|
|
8497
|
+
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8498
|
+
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8499
|
+
],
|
|
8500
|
+
valueVar: `${item}.value`,
|
|
8501
|
+
endVar: `${item}.span.end`
|
|
8502
|
+
};
|
|
8503
|
+
}
|
|
8198
8504
|
function escapeTokenLiteral(value) {
|
|
8199
8505
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
8200
8506
|
}
|
|
@@ -8335,14 +8641,20 @@ function emitLeaf(def, ctx, pos) {
|
|
|
8335
8641
|
endVar: inner.endVar
|
|
8336
8642
|
};
|
|
8337
8643
|
}
|
|
8644
|
+
function emitNodeProjectExpr(type, project, chV) {
|
|
8645
|
+
const child = `${chV}[${project}]`;
|
|
8646
|
+
const missing = `(() => { throw new Error(${JSON.stringify(`node(${JSON.stringify(type)}) project child ${project} was not captured`)}) })()`;
|
|
8647
|
+
const value = `(${child} !== null && typeof ${child} === 'object' && ${child}._tag === 'leaf' ? ${child}.value : ${child})`;
|
|
8648
|
+
return `(${project} in ${chV} ? ${value} : ${missing})`;
|
|
8649
|
+
}
|
|
8338
8650
|
function emitNode(def, ctx, pos) {
|
|
8339
8651
|
if (def.type === void 0) {
|
|
8340
8652
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
8341
8653
|
}
|
|
8342
|
-
const structural = def.build === void 0;
|
|
8343
|
-
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
8654
|
+
const structural = def.build === void 0 && def.project === void 0;
|
|
8655
|
+
const mkType = structural || def.project !== void 0 ? null : analyzeMkInlineBuild(def);
|
|
8344
8656
|
let buildIdx = null;
|
|
8345
|
-
if (!mkType && !structural) {
|
|
8657
|
+
if (!mkType && !structural && def.project === void 0) {
|
|
8346
8658
|
buildIdx = ctx.buildFns.length;
|
|
8347
8659
|
ctx.buildFns.push(def.build);
|
|
8348
8660
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
@@ -8350,12 +8662,13 @@ function emitNode(def, ctx, pos) {
|
|
|
8350
8662
|
const i = ind(ctx);
|
|
8351
8663
|
const cstOut = ctx.hostMode === "cst" && !structural;
|
|
8352
8664
|
if (!structural && !cstOut) ctx.hostBranchElided = true;
|
|
8353
|
-
const
|
|
8354
|
-
const
|
|
8355
|
-
const
|
|
8356
|
-
const
|
|
8665
|
+
const hasProject = def.project !== void 0;
|
|
8666
|
+
const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && !hasProject && buildReadsTrivia(def);
|
|
8667
|
+
const clonesState = !structural && (cstOut || !hasProject && buildReadsState(def));
|
|
8668
|
+
const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || def.project !== void 0 || buildReadsChildren(def));
|
|
8669
|
+
const capturesRaw = !structural && (cstOut || mkType !== null || def.project === void 0 && buildReadsRaw(def));
|
|
8357
8670
|
const hasFields = parserHasOwnFields(def.parser);
|
|
8358
|
-
const capturesFields = hasFields && !structural && (cstOut || buildReadsFields(def));
|
|
8671
|
+
const capturesFields = hasFields && !structural && (cstOut || !hasProject && buildReadsFields(def));
|
|
8359
8672
|
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
8360
8673
|
const chV = v(ctx, "_ch");
|
|
8361
8674
|
const rawV = v(ctx, "_raw");
|
|
@@ -8453,7 +8766,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
8453
8766
|
);
|
|
8454
8767
|
}
|
|
8455
8768
|
const ndV = v(ctx, "_nd");
|
|
8456
|
-
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
8769
|
+
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
8457
8770
|
const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
8458
8771
|
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
|
|
8459
8772
|
const hostCollapseExpr = structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
|
|
@@ -8660,7 +8973,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8660
8973
|
case "choice":
|
|
8661
8974
|
return emitChoice(p, def, ctx, pos);
|
|
8662
8975
|
case "dispatch":
|
|
8663
|
-
return emitDispatchCombinator(def, ctx, pos);
|
|
8976
|
+
return emitDispatchCombinator(p, def, ctx, pos);
|
|
8664
8977
|
case "attempt":
|
|
8665
8978
|
return emitAttempt(p, def, ctx, pos);
|
|
8666
8979
|
case "many":
|
|
@@ -8785,6 +9098,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8785
9098
|
return emitNot(def, ctx, pos);
|
|
8786
9099
|
case "peek":
|
|
8787
9100
|
return emitPeek(def, ctx, pos);
|
|
9101
|
+
case "routed":
|
|
9102
|
+
return emitRouted(ctx, pos);
|
|
8788
9103
|
case "node":
|
|
8789
9104
|
return emitNode(def, ctx, pos);
|
|
8790
9105
|
case "scanTo":
|
|
@@ -8882,7 +9197,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8882
9197
|
case "choice":
|
|
8883
9198
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8884
9199
|
case "dispatch":
|
|
8885
|
-
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
9200
|
+
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);
|
|
8886
9201
|
case "sepBy":
|
|
8887
9202
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8888
9203
|
case "scanTo":
|
|
@@ -8897,6 +9212,26 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8897
9212
|
return false;
|
|
8898
9213
|
}
|
|
8899
9214
|
}
|
|
9215
|
+
function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
|
|
9216
|
+
if (seen.has(p)) return false;
|
|
9217
|
+
seen.add(p);
|
|
9218
|
+
const d = p._def;
|
|
9219
|
+
switch (d.tag) {
|
|
9220
|
+
case "routed":
|
|
9221
|
+
return true;
|
|
9222
|
+
case "lazy": {
|
|
9223
|
+
try {
|
|
9224
|
+
return parserUsesRouted2(d.thunk(), seen);
|
|
9225
|
+
} catch {
|
|
9226
|
+
return false;
|
|
9227
|
+
}
|
|
9228
|
+
}
|
|
9229
|
+
case "dispatch":
|
|
9230
|
+
return false;
|
|
9231
|
+
default:
|
|
9232
|
+
return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
|
|
9233
|
+
}
|
|
9234
|
+
}
|
|
8900
9235
|
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
8901
9236
|
if (seen.has(p)) return false;
|
|
8902
9237
|
seen.add(p);
|
|
@@ -8917,7 +9252,7 @@ function childrenOf2(def) {
|
|
|
8917
9252
|
case "choice":
|
|
8918
9253
|
return def.parsers;
|
|
8919
9254
|
case "dispatch":
|
|
8920
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9255
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
8921
9256
|
case "many":
|
|
8922
9257
|
case "attempt":
|
|
8923
9258
|
case "optional":
|
|
@@ -8954,6 +9289,7 @@ function childrenOf2(def) {
|
|
|
8954
9289
|
case "regex":
|
|
8955
9290
|
case "keywords":
|
|
8956
9291
|
case "guard":
|
|
9292
|
+
case "routed":
|
|
8957
9293
|
case "unknown":
|
|
8958
9294
|
return [];
|
|
8959
9295
|
}
|
|
@@ -9661,7 +9997,7 @@ function childrenOf3(def) {
|
|
|
9661
9997
|
case "choice":
|
|
9662
9998
|
return def.parsers;
|
|
9663
9999
|
case "dispatch":
|
|
9664
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
10000
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
9665
10001
|
case "many":
|
|
9666
10002
|
case "oneOrMore":
|
|
9667
10003
|
case "optional":
|
|
@@ -9690,6 +10026,7 @@ function childrenOf3(def) {
|
|
|
9690
10026
|
case "literal":
|
|
9691
10027
|
case "regex":
|
|
9692
10028
|
case "keywords":
|
|
10029
|
+
case "routed":
|
|
9693
10030
|
case "guard":
|
|
9694
10031
|
case "recover":
|
|
9695
10032
|
case "unknown":
|
|
@@ -9714,6 +10051,20 @@ function repeatOpts(min, max, trailing) {
|
|
|
9714
10051
|
if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
|
|
9715
10052
|
return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
|
|
9716
10053
|
}
|
|
10054
|
+
function projectOpt(project) {
|
|
10055
|
+
if (project === void 0) return void 0;
|
|
10056
|
+
return `project: ${project}`;
|
|
10057
|
+
}
|
|
10058
|
+
function matcherExpr(entry) {
|
|
10059
|
+
switch (entry.kind) {
|
|
10060
|
+
case "startsWith":
|
|
10061
|
+
return `startsWith(${JSON.stringify(entry.value)})`;
|
|
10062
|
+
case "endsWith":
|
|
10063
|
+
return `endsWith(${JSON.stringify(entry.value)})`;
|
|
10064
|
+
case "matches":
|
|
10065
|
+
return `matches(${new RegExp(entry.value, entry.flags ?? "").toString()})`;
|
|
10066
|
+
}
|
|
10067
|
+
}
|
|
9717
10068
|
function serializeRuleMap(ruleMap, scanSkip) {
|
|
9718
10069
|
try {
|
|
9719
10070
|
return new Serializer(ruleMap, scanSkip ?? []).run();
|
|
@@ -9813,7 +10164,11 @@ function evalRuleMapIR(ir) {
|
|
|
9813
10164
|
"choice",
|
|
9814
10165
|
"dispatch",
|
|
9815
10166
|
"when",
|
|
10167
|
+
"startsWith",
|
|
10168
|
+
"endsWith",
|
|
10169
|
+
"matches",
|
|
9816
10170
|
"otherwise",
|
|
10171
|
+
"routed",
|
|
9817
10172
|
"attempt",
|
|
9818
10173
|
"many",
|
|
9819
10174
|
"oneOrMore",
|
|
@@ -9849,7 +10204,11 @@ function evalRuleMapIR(ir) {
|
|
|
9849
10204
|
choice,
|
|
9850
10205
|
dispatch,
|
|
9851
10206
|
when,
|
|
10207
|
+
startsWith,
|
|
10208
|
+
endsWith,
|
|
10209
|
+
matches,
|
|
9852
10210
|
otherwise,
|
|
10211
|
+
routed,
|
|
9853
10212
|
attempt,
|
|
9854
10213
|
many,
|
|
9855
10214
|
oneOrMore,
|
|
@@ -10037,8 +10396,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10037
10396
|
}
|
|
10038
10397
|
case "dispatch": {
|
|
10039
10398
|
const arms = def.cases.map(
|
|
10040
|
-
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
10399
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`
|
|
10041
10400
|
);
|
|
10401
|
+
if (def.matchers) {
|
|
10402
|
+
for (const entry of def.matchers) {
|
|
10403
|
+
arms.push(`when(${matcherExpr(entry)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`);
|
|
10404
|
+
}
|
|
10405
|
+
}
|
|
10042
10406
|
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10043
10407
|
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10044
10408
|
}
|
|
@@ -10058,6 +10422,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10058
10422
|
return `not(${kid(def.parser)})`;
|
|
10059
10423
|
case "peek":
|
|
10060
10424
|
return `peek(${kid(def.parser)})`;
|
|
10425
|
+
case "routed":
|
|
10426
|
+
return "routed()";
|
|
10061
10427
|
case "trivia":
|
|
10062
10428
|
return `trivia(${kid(def.parser)})`;
|
|
10063
10429
|
case "token":
|
|
@@ -10082,9 +10448,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10082
10448
|
}
|
|
10083
10449
|
case "node": {
|
|
10084
10450
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
10451
|
+
const projectEntry = projectOpt(def.project);
|
|
10085
10452
|
const optEntries = [
|
|
10086
10453
|
...def.unwrap ? ["unwrap: true"] : [],
|
|
10087
10454
|
...def.collapse ? ["collapse: true"] : [],
|
|
10455
|
+
...projectEntry === void 0 ? [] : [projectEntry],
|
|
10088
10456
|
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
10089
10457
|
...def.trailingTrivia ? ["trailingTrivia: true"] : []
|
|
10090
10458
|
];
|
|
@@ -11079,10 +11447,20 @@ function run(entry, input, options = {}) {
|
|
|
11079
11447
|
}
|
|
11080
11448
|
|
|
11081
11449
|
// src/coverage.ts
|
|
11450
|
+
function dispatchMatcher(entry) {
|
|
11451
|
+
switch (entry.kind) {
|
|
11452
|
+
case "startsWith":
|
|
11453
|
+
return startsWith(entry.value);
|
|
11454
|
+
case "endsWith":
|
|
11455
|
+
return endsWith(entry.value);
|
|
11456
|
+
case "matches":
|
|
11457
|
+
return matches(new RegExp(entry.value, entry.flags));
|
|
11458
|
+
}
|
|
11459
|
+
}
|
|
11082
11460
|
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
11083
11461
|
function compiledGrammarCoverageDefinitions(grammar) {
|
|
11084
11462
|
const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
|
|
11085
|
-
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"))) {
|
|
11463
|
+
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"))) {
|
|
11086
11464
|
throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
|
|
11087
11465
|
}
|
|
11088
11466
|
return definitions;
|
|
@@ -11262,10 +11640,54 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
11262
11640
|
return unsafeSequence(...def.parsers.map(build));
|
|
11263
11641
|
}
|
|
11264
11642
|
case "dispatch": {
|
|
11265
|
-
const
|
|
11266
|
-
|
|
11643
|
+
const ids = maps.dispatches.get(parser2) ?? [];
|
|
11644
|
+
let armIndex = 0;
|
|
11645
|
+
const dispatchStarts = [];
|
|
11646
|
+
const wrapArm = (arm, id) => {
|
|
11647
|
+
const child = build(arm);
|
|
11648
|
+
return {
|
|
11649
|
+
_tag: child._tag,
|
|
11650
|
+
_meta: child._meta,
|
|
11651
|
+
_def: child._def,
|
|
11652
|
+
parse(input, pos, ctx) {
|
|
11653
|
+
const dispatchStart = dispatchStarts[dispatchStarts.length - 1] ?? pos;
|
|
11654
|
+
if (id) trace?.write({ id, phase: "attempt", offset: dispatchStart });
|
|
11655
|
+
const result = child.parse(input, pos, ctx);
|
|
11656
|
+
if (result.ok) {
|
|
11657
|
+
if (id) {
|
|
11658
|
+
collector.hit(id);
|
|
11659
|
+
trace?.write({ id, phase: "selected", offset: dispatchStart, end: result.span.end });
|
|
11660
|
+
trace?.write({ id, phase: "success", offset: dispatchStart, end: result.span.end });
|
|
11661
|
+
}
|
|
11662
|
+
} else if (id) {
|
|
11663
|
+
trace?.write({ id, phase: "failure", offset: result.span.end });
|
|
11664
|
+
}
|
|
11665
|
+
return result;
|
|
11666
|
+
}
|
|
11667
|
+
};
|
|
11668
|
+
};
|
|
11669
|
+
const arms = def.cases.map(
|
|
11670
|
+
(entry2) => when(entry2.keys, wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0)
|
|
11671
|
+
);
|
|
11672
|
+
if (def.matchers) {
|
|
11673
|
+
for (const entry2 of def.matchers) {
|
|
11674
|
+
arms.push(when(dispatchMatcher(entry2), wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
11675
|
+
}
|
|
11676
|
+
}
|
|
11677
|
+
if (def.otherwise) arms.push(otherwise(wrapArm(def.otherwise, ids[armIndex++])));
|
|
11267
11678
|
const unsafeDispatch = dispatch;
|
|
11268
|
-
|
|
11679
|
+
const base2 = unsafeDispatch(build(def.selector), ...arms);
|
|
11680
|
+
return {
|
|
11681
|
+
...base2,
|
|
11682
|
+
parse(input, pos, ctx) {
|
|
11683
|
+
dispatchStarts.push(pos);
|
|
11684
|
+
try {
|
|
11685
|
+
return base2.parse(input, pos, ctx);
|
|
11686
|
+
} finally {
|
|
11687
|
+
dispatchStarts.pop();
|
|
11688
|
+
}
|
|
11689
|
+
}
|
|
11690
|
+
};
|
|
11269
11691
|
}
|
|
11270
11692
|
case "many":
|
|
11271
11693
|
return many(build(def.parser));
|
|
@@ -11310,7 +11732,7 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
11310
11732
|
case "peek":
|
|
11311
11733
|
return peek(build(def.parser));
|
|
11312
11734
|
case "node": {
|
|
11313
|
-
const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
|
|
11735
|
+
const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.project !== void 0 ? { project: def.project } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
|
|
11314
11736
|
return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
|
|
11315
11737
|
}
|
|
11316
11738
|
case "guard":
|