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/plugin/index.cjs
CHANGED
|
@@ -94,6 +94,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
94
94
|
return d.value.length === 0;
|
|
95
95
|
case "keywords":
|
|
96
96
|
return false;
|
|
97
|
+
case "routed":
|
|
98
|
+
return false;
|
|
97
99
|
case "regex":
|
|
98
100
|
try {
|
|
99
101
|
const m = new RegExp(d.source).exec("");
|
|
@@ -1186,6 +1188,8 @@ function derive(c, seen) {
|
|
|
1186
1188
|
case "not":
|
|
1187
1189
|
case "peek":
|
|
1188
1190
|
return deriveExpected2(def.parser);
|
|
1191
|
+
case "routed":
|
|
1192
|
+
return ["routed()"];
|
|
1189
1193
|
case "lazy": {
|
|
1190
1194
|
const name = c._ruleName;
|
|
1191
1195
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -2007,42 +2011,195 @@ function sequence(...parsers) {
|
|
|
2007
2011
|
}
|
|
2008
2012
|
|
|
2009
2013
|
// src/combinators/dispatch.ts
|
|
2010
|
-
function
|
|
2014
|
+
function parserUsesRouted(parser2, seen = /* @__PURE__ */ new Set()) {
|
|
2015
|
+
if (seen.has(parser2)) return false;
|
|
2016
|
+
seen.add(parser2);
|
|
2017
|
+
const def = parser2._def;
|
|
2018
|
+
switch (def.tag) {
|
|
2019
|
+
case "routed":
|
|
2020
|
+
return true;
|
|
2021
|
+
case "sequence":
|
|
2022
|
+
case "choice":
|
|
2023
|
+
return def.parsers.some((entry) => parserUsesRouted(entry, seen));
|
|
2024
|
+
case "dispatch":
|
|
2025
|
+
return false;
|
|
2026
|
+
case "sepBy":
|
|
2027
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.separator, seen);
|
|
2028
|
+
case "skip":
|
|
2029
|
+
return parserUsesRouted(def.main, seen) || parserUsesRouted(def.skipped, seen);
|
|
2030
|
+
case "grammar":
|
|
2031
|
+
return parserUsesRouted(def.parser, seen) || (def.triviaParser ? parserUsesRouted(def.triviaParser, seen) : false);
|
|
2032
|
+
case "scanTo":
|
|
2033
|
+
return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen));
|
|
2034
|
+
case "recover":
|
|
2035
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.sentinel, seen);
|
|
2036
|
+
case "lazy":
|
|
2037
|
+
try {
|
|
2038
|
+
return parserUsesRouted(def.thunk(), seen);
|
|
2039
|
+
} catch {
|
|
2040
|
+
return false;
|
|
2041
|
+
}
|
|
2042
|
+
case "many":
|
|
2043
|
+
case "oneOrMore":
|
|
2044
|
+
case "optional":
|
|
2045
|
+
case "attempt":
|
|
2046
|
+
case "transform":
|
|
2047
|
+
case "trivia":
|
|
2048
|
+
case "token":
|
|
2049
|
+
case "leaf":
|
|
2050
|
+
case "label":
|
|
2051
|
+
case "field":
|
|
2052
|
+
case "not":
|
|
2053
|
+
case "peek":
|
|
2054
|
+
case "node":
|
|
2055
|
+
case "withCtx":
|
|
2056
|
+
case "expect":
|
|
2057
|
+
return parserUsesRouted(def.parser, seen);
|
|
2058
|
+
default:
|
|
2059
|
+
return false;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
function branchUsesRouted(branch) {
|
|
2063
|
+
return branch.usesRouted === true || parserUsesRouted(branch.parser);
|
|
2064
|
+
}
|
|
2065
|
+
function asciiFoldKey(key) {
|
|
2066
|
+
let out = "";
|
|
2067
|
+
for (let i = 0; i < key.length; i++) {
|
|
2068
|
+
const c = key.charCodeAt(i);
|
|
2069
|
+
out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
|
|
2070
|
+
}
|
|
2071
|
+
return out;
|
|
2072
|
+
}
|
|
2073
|
+
function matchesDispatchMatcher(value, matcher) {
|
|
2074
|
+
const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
|
|
2075
|
+
const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
|
|
2076
|
+
switch (matcher.kind) {
|
|
2077
|
+
case "startsWith":
|
|
2078
|
+
return candidate.startsWith(expected);
|
|
2079
|
+
case "endsWith":
|
|
2080
|
+
return candidate.endsWith(expected);
|
|
2081
|
+
case "matches": {
|
|
2082
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
2083
|
+
return new RegExp(matcher.value, flags).test(value);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
function isStringMatcher(value) {
|
|
2088
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2089
|
+
const kind = value.kind;
|
|
2090
|
+
return kind === "startsWith" || kind === "endsWith" || kind === "matches";
|
|
2091
|
+
}
|
|
2092
|
+
function fixedMatcher(kind, value) {
|
|
2093
|
+
if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
|
|
2094
|
+
if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
|
|
2095
|
+
return { kind, value };
|
|
2096
|
+
}
|
|
2097
|
+
function startsWith(prefix) {
|
|
2098
|
+
return fixedMatcher("startsWith", prefix);
|
|
2099
|
+
}
|
|
2100
|
+
function endsWith(suffix) {
|
|
2101
|
+
return fixedMatcher("endsWith", suffix);
|
|
2102
|
+
}
|
|
2103
|
+
function matches(pattern) {
|
|
2104
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
|
|
2105
|
+
if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
|
|
2106
|
+
throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
|
|
2107
|
+
}
|
|
2108
|
+
return { kind: "matches", value: pattern.source, flags: pattern.flags };
|
|
2109
|
+
}
|
|
2110
|
+
function when(key, parser2, opts = {}) {
|
|
2111
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
2112
|
+
if (isStringMatcher(key)) {
|
|
2113
|
+
return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2114
|
+
}
|
|
2011
2115
|
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2012
2116
|
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2013
2117
|
for (const item of keys) {
|
|
2014
2118
|
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2015
2119
|
}
|
|
2016
|
-
return { kind: "when", keys, parser: parser2 };
|
|
2120
|
+
return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2017
2121
|
}
|
|
2018
2122
|
function otherwise(parser2) {
|
|
2019
|
-
return { kind: "otherwise", parser: parser2 };
|
|
2123
|
+
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2124
|
+
}
|
|
2125
|
+
function routed() {
|
|
2126
|
+
return {
|
|
2127
|
+
_tag: "routed",
|
|
2128
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
2129
|
+
_def: { tag: "routed" },
|
|
2130
|
+
parse(_input, pos, ctx) {
|
|
2131
|
+
const item = ctx._routed;
|
|
2132
|
+
if (item === void 0) {
|
|
2133
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2134
|
+
}
|
|
2135
|
+
if (pos !== item.span.start) {
|
|
2136
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2137
|
+
}
|
|
2138
|
+
if (cstCaptureActive(ctx)) {
|
|
2139
|
+
pushCstLeaf(ctx, { _tag: "leaf", value: item.value, span: item.span });
|
|
2140
|
+
}
|
|
2141
|
+
return { ok: true, value: item.value, span: item.span };
|
|
2142
|
+
}
|
|
2143
|
+
};
|
|
2020
2144
|
}
|
|
2021
2145
|
function dispatch(selector, ...arms) {
|
|
2146
|
+
if (parserUsesRouted(selector)) {
|
|
2147
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2148
|
+
}
|
|
2022
2149
|
let fallback;
|
|
2150
|
+
let fallbackUsesRouted = false;
|
|
2151
|
+
const matchers = [];
|
|
2023
2152
|
const cases = [];
|
|
2024
|
-
const seen =
|
|
2153
|
+
const seen = [];
|
|
2025
2154
|
for (let i = 0; i < arms.length; i++) {
|
|
2026
2155
|
const arm = arms[i];
|
|
2027
2156
|
if (arm.kind === "otherwise") {
|
|
2028
2157
|
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2029
2158
|
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2030
2159
|
fallback = arm.parser;
|
|
2160
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
2031
2161
|
continue;
|
|
2032
2162
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2163
|
+
if (arm.kind === "whenMatcher") {
|
|
2164
|
+
const matcher = arm.matcher;
|
|
2165
|
+
matchers.push({
|
|
2166
|
+
kind: matcher.kind,
|
|
2167
|
+
value: matcher.value,
|
|
2168
|
+
...matcher.kind === "matches" ? { flags: matcher.flags } : {},
|
|
2169
|
+
parser: arm.parser,
|
|
2170
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2171
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2172
|
+
});
|
|
2173
|
+
continue;
|
|
2036
2174
|
}
|
|
2037
|
-
|
|
2175
|
+
for (const key of arm.keys) {
|
|
2176
|
+
const folded = asciiFoldKey(key);
|
|
2177
|
+
for (const prior of seen) {
|
|
2178
|
+
const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
|
|
2179
|
+
if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2180
|
+
}
|
|
2181
|
+
seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
|
|
2182
|
+
}
|
|
2183
|
+
cases.push({
|
|
2184
|
+
keys: arm.keys,
|
|
2185
|
+
parser: arm.parser,
|
|
2186
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2187
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2188
|
+
});
|
|
2038
2189
|
}
|
|
2039
2190
|
const meta = {
|
|
2040
2191
|
firstSet: selector._meta.firstSet,
|
|
2041
|
-
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2192
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2042
2193
|
isTrivia: false
|
|
2043
2194
|
};
|
|
2044
2195
|
const byKey = /* @__PURE__ */ new Map();
|
|
2045
|
-
|
|
2196
|
+
const byFoldedKey = /* @__PURE__ */ new Map();
|
|
2197
|
+
for (const entry of cases) {
|
|
2198
|
+
for (const key of entry.keys) {
|
|
2199
|
+
if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
|
|
2200
|
+
else byKey.set(key, entry);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2046
2203
|
return {
|
|
2047
2204
|
_tag: "dispatch",
|
|
2048
2205
|
_meta: meta,
|
|
@@ -2050,18 +2207,35 @@ function dispatch(selector, ...arms) {
|
|
|
2050
2207
|
tag: "dispatch",
|
|
2051
2208
|
selector,
|
|
2052
2209
|
cases,
|
|
2053
|
-
...
|
|
2210
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2211
|
+
...fallback === void 0 ? {} : { otherwise: fallback, ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {} }
|
|
2054
2212
|
},
|
|
2055
2213
|
parse(input, pos, ctx) {
|
|
2214
|
+
if (parserUsesRouted(selector)) {
|
|
2215
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2216
|
+
}
|
|
2217
|
+
const selectorMark = saveTriviaMark(ctx);
|
|
2056
2218
|
const selected = selector.parse(input, pos, ctx);
|
|
2057
2219
|
if (!selected.ok) return selected;
|
|
2058
|
-
const
|
|
2059
|
-
if (
|
|
2220
|
+
const branch = byKey.get(selected.value) ?? (byFoldedKey.size === 0 ? void 0 : byFoldedKey.get(asciiFoldKey(selected.value))) ?? matchers.find((matcher) => matchesDispatchMatcher(selected.value, matcher)) ?? (fallback === void 0 ? void 0 : { keys: [], parser: fallback, caseInsensitive: false, usesRouted: fallbackUsesRouted });
|
|
2221
|
+
if (branch === void 0) {
|
|
2060
2222
|
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2061
2223
|
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2062
2224
|
}
|
|
2063
|
-
const
|
|
2064
|
-
const
|
|
2225
|
+
const savedRouted = ctx._routed;
|
|
2226
|
+
const usesRouted = branchUsesRouted(branch);
|
|
2227
|
+
let mark = saveTriviaMark(ctx);
|
|
2228
|
+
if (usesRouted) {
|
|
2229
|
+
rollbackTrivia(ctx, selectorMark);
|
|
2230
|
+
mark = saveTriviaMark(ctx);
|
|
2231
|
+
ctx._routed = { value: selected.value, span: selected.span };
|
|
2232
|
+
}
|
|
2233
|
+
let result;
|
|
2234
|
+
try {
|
|
2235
|
+
result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
|
|
2236
|
+
} finally {
|
|
2237
|
+
if (usesRouted) ctx._routed = savedRouted;
|
|
2238
|
+
}
|
|
2065
2239
|
if (!result.ok) {
|
|
2066
2240
|
rollbackTrivia(ctx, mark);
|
|
2067
2241
|
return { ...result, committed: true };
|
|
@@ -2411,6 +2585,7 @@ function markUnusedValues(root) {
|
|
|
2411
2585
|
case "dispatch":
|
|
2412
2586
|
visit(def.selector, consumed);
|
|
2413
2587
|
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2588
|
+
if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
|
|
2414
2589
|
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2415
2590
|
return;
|
|
2416
2591
|
case "node":
|
|
@@ -2689,7 +2864,7 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2689
2864
|
case "choice":
|
|
2690
2865
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2691
2866
|
case "dispatch":
|
|
2692
|
-
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2867
|
+
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => parserHasOwnFields(entry.parser, seen)) : false) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2693
2868
|
case "sepBy":
|
|
2694
2869
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2695
2870
|
case "skip":
|
|
@@ -2758,7 +2933,7 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2758
2933
|
case "choice":
|
|
2759
2934
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2760
2935
|
case "dispatch":
|
|
2761
|
-
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2936
|
+
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => parserHasTriviaSite(entry.parser, seen)) : false) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2762
2937
|
case "grammar":
|
|
2763
2938
|
return parserHasTriviaSite(d.parser, seen);
|
|
2764
2939
|
case "lazy": {
|
|
@@ -2785,7 +2960,7 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2785
2960
|
case "choice":
|
|
2786
2961
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2787
2962
|
case "dispatch":
|
|
2788
|
-
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2963
|
+
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.matchers ? d.matchers.some((entry) => parserEnablesTriviaCapture(entry.parser, seen)) : false) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2789
2964
|
case "sepBy":
|
|
2790
2965
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2791
2966
|
case "skip":
|
|
@@ -2846,12 +3021,30 @@ function isCstChild(value) {
|
|
|
2846
3021
|
function missingInferredType() {
|
|
2847
3022
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
2848
3023
|
}
|
|
3024
|
+
function normalizeProject(project) {
|
|
3025
|
+
if (project === void 0) return void 0;
|
|
3026
|
+
if (!Number.isInteger(project) || project < 0) {
|
|
3027
|
+
throw new Error("node() project child must be a non-negative integer");
|
|
3028
|
+
}
|
|
3029
|
+
return project;
|
|
3030
|
+
}
|
|
3031
|
+
function projectChild(children2, project, type) {
|
|
3032
|
+
if (!(project in children2)) {
|
|
3033
|
+
throw new Error(`node(${JSON.stringify(type)}) project child ${project} was not captured`);
|
|
3034
|
+
}
|
|
3035
|
+
return unwrapChild(children2[project]);
|
|
3036
|
+
}
|
|
2849
3037
|
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
2850
3038
|
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
2851
3039
|
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
2852
3040
|
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
2853
|
-
const
|
|
2854
|
-
const
|
|
3041
|
+
const buildArg = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
3042
|
+
const build = typeof buildArg === "function" ? buildArg : void 0;
|
|
3043
|
+
const opts = typeof buildArg === "function" ? maybeOpts : buildArg ?? maybeOpts;
|
|
3044
|
+
const project = normalizeProject(opts?.project);
|
|
3045
|
+
if (project !== void 0 && build !== void 0) {
|
|
3046
|
+
throw new Error("node() options cannot combine project with a build callback");
|
|
3047
|
+
}
|
|
2855
3048
|
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
2856
3049
|
const meta = {
|
|
2857
3050
|
firstSet: combinator._meta.firstSet,
|
|
@@ -2865,11 +3058,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2865
3058
|
if (unwrap && collapse) {
|
|
2866
3059
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
2867
3060
|
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
3061
|
+
if (project !== void 0 && (unwrap || collapse)) {
|
|
3062
|
+
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3063
|
+
}
|
|
3064
|
+
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;
|
|
3065
|
+
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3066
|
+
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
2871
3067
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
2872
|
-
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) :
|
|
3068
|
+
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
2873
3069
|
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
2874
3070
|
let failExpected;
|
|
2875
3071
|
return {
|
|
@@ -2884,14 +3080,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2884
3080
|
}
|
|
2885
3081
|
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
2886
3082
|
}
|
|
2887
|
-
const
|
|
3083
|
+
const hasDirectValue = build !== void 0 || project !== void 0;
|
|
3084
|
+
const hostCst = hasDirectValue && cstOutputHost(ctx.build);
|
|
2888
3085
|
const effTrivia = capturesTrivia || hostCst;
|
|
2889
3086
|
const effFields = capturesFields || hostCst && hasOwnFields;
|
|
2890
3087
|
const saved = beginCstNodeCapture(ctx);
|
|
2891
3088
|
const savedFields = ctx._fields;
|
|
2892
3089
|
ctx._fields = effFields ? [] : void 0;
|
|
2893
3090
|
const savedMask = ctx._triviaCaptureMask;
|
|
2894
|
-
if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
3091
|
+
if (build === void 0 && project === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
2895
3092
|
ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
|
|
2896
3093
|
}
|
|
2897
3094
|
if (!effTrivia) ctx.captureTrivia = false;
|
|
@@ -2909,7 +3106,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2909
3106
|
const nodeType = def.type ?? missingInferredType();
|
|
2910
3107
|
const cstOutput = cstOutputHost(ctx.build);
|
|
2911
3108
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2912
|
-
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 };
|
|
3109
|
+
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 };
|
|
2913
3110
|
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 };
|
|
2914
3111
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2915
3112
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3160,7 +3357,7 @@ function leaf(root, fn) {
|
|
|
3160
3357
|
}
|
|
3161
3358
|
|
|
3162
3359
|
// src/version.ts
|
|
3163
|
-
var PARSEMAN_VERSION = "0.
|
|
3360
|
+
var PARSEMAN_VERSION = "0.40.0";
|
|
3164
3361
|
|
|
3165
3362
|
// src/cst/host-mode.ts
|
|
3166
3363
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3420,6 +3617,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3420
3617
|
if (d.tag === "dispatch") {
|
|
3421
3618
|
kids.push(d.selector);
|
|
3422
3619
|
for (const c of d.cases) kids.push(c.parser);
|
|
3620
|
+
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3423
3621
|
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3424
3622
|
}
|
|
3425
3623
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
@@ -4943,13 +5141,25 @@ function escapeClassChar(ch2) {
|
|
|
4943
5141
|
}
|
|
4944
5142
|
|
|
4945
5143
|
// src/compiler/grammar-coverage-ids.ts
|
|
5144
|
+
function idPart(value) {
|
|
5145
|
+
return encodeURIComponent(value);
|
|
5146
|
+
}
|
|
5147
|
+
function dispatchArmIds(def, path2) {
|
|
5148
|
+
const ids = [];
|
|
5149
|
+
for (const entry of def.cases) ids.push(`dispatch:${path2}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5150
|
+
for (const entry of def.matchers ?? []) {
|
|
5151
|
+
ids.push(`dispatch:${path2}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5152
|
+
}
|
|
5153
|
+
if (def.otherwise) ids.push(`dispatch:${path2}/otherwise`);
|
|
5154
|
+
return ids;
|
|
5155
|
+
}
|
|
4946
5156
|
function children(def, winners) {
|
|
4947
5157
|
switch (def.tag) {
|
|
4948
5158
|
case "sequence":
|
|
4949
5159
|
case "choice":
|
|
4950
5160
|
return def.parsers;
|
|
4951
5161
|
case "dispatch":
|
|
4952
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
5162
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
4953
5163
|
case "many":
|
|
4954
5164
|
case "oneOrMore":
|
|
4955
5165
|
case "optional":
|
|
@@ -4992,6 +5202,7 @@ function children(def, winners) {
|
|
|
4992
5202
|
function buildGrammarPlan(entry, winners) {
|
|
4993
5203
|
const definitions = /* @__PURE__ */ new Map();
|
|
4994
5204
|
const choices = /* @__PURE__ */ new WeakMap();
|
|
5205
|
+
const dispatches = /* @__PURE__ */ new WeakMap();
|
|
4995
5206
|
const attempts = /* @__PURE__ */ new WeakMap();
|
|
4996
5207
|
const labels = /* @__PURE__ */ new WeakMap();
|
|
4997
5208
|
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -5022,6 +5233,11 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5022
5233
|
choices.set(parser2, ids);
|
|
5023
5234
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
5024
5235
|
}
|
|
5236
|
+
if (parser2._def.tag === "dispatch") {
|
|
5237
|
+
const ids = dispatchArmIds(parser2._def, path2);
|
|
5238
|
+
dispatches.set(parser2, ids);
|
|
5239
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5240
|
+
}
|
|
5025
5241
|
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path2}`);
|
|
5026
5242
|
if (parser2._def.tag === "label") {
|
|
5027
5243
|
const id = `label:${path2}`;
|
|
@@ -5034,7 +5250,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5034
5250
|
for (const root of roots) {
|
|
5035
5251
|
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
5036
5252
|
}
|
|
5037
|
-
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
5253
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
|
|
5038
5254
|
}
|
|
5039
5255
|
|
|
5040
5256
|
// src/compiler/scannable-run.ts
|
|
@@ -6408,6 +6624,7 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6408
6624
|
case "literal":
|
|
6409
6625
|
case "regex":
|
|
6410
6626
|
case "keywords":
|
|
6627
|
+
case "routed":
|
|
6411
6628
|
return { alts: [[seg(p._meta.firstSet, matchesEmpty(p))]] };
|
|
6412
6629
|
case "choice": {
|
|
6413
6630
|
const alts = [];
|
|
@@ -6766,7 +6983,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6766
6983
|
case "choice":
|
|
6767
6984
|
return false;
|
|
6768
6985
|
case "dispatch":
|
|
6769
|
-
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);
|
|
6986
|
+
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);
|
|
6770
6987
|
case "attempt":
|
|
6771
6988
|
return false;
|
|
6772
6989
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6865,6 +7082,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6865
7082
|
case "keywords":
|
|
6866
7083
|
case "node":
|
|
6867
7084
|
case "token":
|
|
7085
|
+
case "routed":
|
|
6868
7086
|
case "leaf":
|
|
6869
7087
|
return true;
|
|
6870
7088
|
case "not":
|
|
@@ -6877,7 +7095,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6877
7095
|
case "choice":
|
|
6878
7096
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6879
7097
|
case "dispatch":
|
|
6880
|
-
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
7098
|
+
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);
|
|
6881
7099
|
case "sepBy":
|
|
6882
7100
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6883
7101
|
case "many":
|
|
@@ -7355,6 +7573,7 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7355
7573
|
for (const item of d.cases) {
|
|
7356
7574
|
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7357
7575
|
}
|
|
7576
|
+
if (d.matchers?.some((item) => mayRecordRecoveryError(item.parser, recovery, seen))) return true;
|
|
7358
7577
|
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7359
7578
|
}
|
|
7360
7579
|
case "attempt":
|
|
@@ -7389,53 +7608,120 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7389
7608
|
return false;
|
|
7390
7609
|
}
|
|
7391
7610
|
}
|
|
7392
|
-
function emitDispatchCombinator(def, ctx, pos) {
|
|
7611
|
+
function emitDispatchCombinator(parser2, def, ctx, pos) {
|
|
7612
|
+
if (parserUsesRouted2(def.selector)) {
|
|
7613
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
7614
|
+
}
|
|
7615
|
+
const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
|
|
7616
|
+
const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
|
|
7617
|
+
const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
|
|
7618
|
+
const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
|
|
7619
|
+
const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
|
|
7620
|
+
const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
|
|
7621
|
+
const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
|
|
7622
|
+
const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
|
|
7623
|
+
const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
|
|
7393
7624
|
const selector = emit(def.selector, ctx, pos);
|
|
7394
7625
|
const outV = v(ctx, "_dval");
|
|
7395
7626
|
const outE = v(ctx, "_dend");
|
|
7396
7627
|
const keyV = v(ctx, "_dkey");
|
|
7397
7628
|
const stmts = [
|
|
7629
|
+
...selectorLeafMark ? [
|
|
7630
|
+
`${ind(ctx)}const ${selectorLeafMark} = _ctx._cstLeaves?.length ?? 0`,
|
|
7631
|
+
`${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
|
|
7632
|
+
`${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
7633
|
+
`${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
|
|
7634
|
+
`${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
|
|
7635
|
+
`${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
|
|
7636
|
+
] : [],
|
|
7398
7637
|
...selector.stmts,
|
|
7399
7638
|
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7400
7639
|
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7401
7640
|
];
|
|
7402
7641
|
let wroteBranch = false;
|
|
7403
|
-
const emitSelectedTail = (
|
|
7642
|
+
const emitSelectedTail = (entry, keyword, condition, coverageId) => {
|
|
7643
|
+
const parser3 = entry.parser;
|
|
7404
7644
|
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7405
7645
|
stmts.push(head);
|
|
7406
7646
|
ctx.indent++;
|
|
7407
|
-
const
|
|
7647
|
+
const usesRouted = branchUsesRouted2(entry);
|
|
7648
|
+
const routedV = usesRouted ? v(ctx, "_drt") : null;
|
|
7649
|
+
const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
|
|
7408
7650
|
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7409
7651
|
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7652
|
+
if (routedV) {
|
|
7653
|
+
stmts.push(
|
|
7654
|
+
`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
|
|
7655
|
+
...selectorLeafMark ? [
|
|
7656
|
+
`${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}`
|
|
7657
|
+
] : []
|
|
7658
|
+
);
|
|
7659
|
+
}
|
|
7410
7660
|
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7411
7661
|
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7412
|
-
const tail = emitTailFallible(
|
|
7662
|
+
const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
|
|
7663
|
+
stmts.push(...coverageAttempt(ctx, coverageId, pos));
|
|
7413
7664
|
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7414
7665
|
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7666
|
+
const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
|
|
7667
|
+
const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
|
|
7415
7668
|
stmts.push(
|
|
7416
7669
|
...tail.stmts,
|
|
7417
|
-
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7670
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
|
|
7671
|
+
...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
|
|
7418
7672
|
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7419
|
-
`${ind(ctx)}${outE} = ${tail.endVar}
|
|
7673
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`,
|
|
7674
|
+
...coverageHit(ctx, coverageId, pos, tail.endVar)
|
|
7420
7675
|
);
|
|
7421
7676
|
ctx.indent--;
|
|
7422
7677
|
stmts.push(`${ind(ctx)}}`);
|
|
7423
7678
|
};
|
|
7679
|
+
let coverageIndex = 0;
|
|
7424
7680
|
for (const entry of def.cases) {
|
|
7425
|
-
const condition = entry.keys.map((key) =>
|
|
7426
|
-
emitSelectedTail(entry
|
|
7681
|
+
const condition = entry.keys.map((key) => emitDispatchKeyCondition(keyV, key, entry.caseInsensitive)).join(" || ");
|
|
7682
|
+
emitSelectedTail(entry, wroteBranch ? "else if" : "if", condition, coverageIds[coverageIndex++]);
|
|
7427
7683
|
wroteBranch = true;
|
|
7428
7684
|
}
|
|
7685
|
+
const emitMatcherTails = () => {
|
|
7686
|
+
for (const matcher of def.matchers ?? []) {
|
|
7687
|
+
emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
|
|
7688
|
+
wroteBranch = true;
|
|
7689
|
+
}
|
|
7690
|
+
};
|
|
7429
7691
|
if (def.otherwise) {
|
|
7430
|
-
|
|
7431
|
-
|
|
7692
|
+
emitMatcherTails();
|
|
7693
|
+
const otherwiseEntry = { parser: def.otherwise, usesRouted: def.otherwiseUsesRouted };
|
|
7694
|
+
if (wroteBranch) emitSelectedTail(otherwiseEntry, "else", void 0, coverageIds[coverageIndex++]);
|
|
7695
|
+
else emitSelectedTail(otherwiseEntry, "if", "true", coverageIds[coverageIndex++]);
|
|
7432
7696
|
} else {
|
|
7697
|
+
emitMatcherTails();
|
|
7433
7698
|
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7434
7699
|
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7435
7700
|
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7436
7701
|
}
|
|
7437
7702
|
return { stmts, valueVar: outV, endVar: outE };
|
|
7438
7703
|
}
|
|
7704
|
+
function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
|
|
7705
|
+
if (!caseInsensitive) return `${valueVar} === ${JSON.stringify(key)}`;
|
|
7706
|
+
const parts = [`${valueVar}.length === ${key.length}`];
|
|
7707
|
+
for (let i = 0; i < key.length; i++) {
|
|
7708
|
+
parts.push(foldEq(`${valueVar}.charCodeAt(${i})`, key.charCodeAt(i)));
|
|
7709
|
+
}
|
|
7710
|
+
return parts.join(" && ");
|
|
7711
|
+
}
|
|
7712
|
+
function emitDispatchMatcherCondition(valueVar, matcher) {
|
|
7713
|
+
if (matcher.kind === "matches") {
|
|
7714
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
7715
|
+
return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
|
|
7716
|
+
}
|
|
7717
|
+
const text = matcher.value;
|
|
7718
|
+
const parts = [`${valueVar}.length >= ${text.length}`];
|
|
7719
|
+
const offset = matcher.kind === "endsWith" ? `${valueVar}.length - ${text.length}` : "0";
|
|
7720
|
+
for (let i = 0; i < text.length; i++) {
|
|
7721
|
+
parts.push(matcher.caseInsensitive ? foldEq(`${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`})`, text.charCodeAt(i)) : `${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`}) === ${text.charCodeAt(i)}`);
|
|
7722
|
+
}
|
|
7723
|
+
return parts.join(" && ");
|
|
7724
|
+
}
|
|
7439
7725
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7440
7726
|
const superParser = def.parsers[superIndex];
|
|
7441
7727
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -8090,6 +8376,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
8090
8376
|
endVar: pos
|
|
8091
8377
|
};
|
|
8092
8378
|
}
|
|
8379
|
+
function emitRouted(ctx, pos) {
|
|
8380
|
+
const item = v(ctx, "_rt");
|
|
8381
|
+
return {
|
|
8382
|
+
stmts: [
|
|
8383
|
+
`${ind(ctx)}const ${item} = _ctx._routed`,
|
|
8384
|
+
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8385
|
+
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8386
|
+
],
|
|
8387
|
+
valueVar: `${item}.value`,
|
|
8388
|
+
endVar: `${item}.span.end`
|
|
8389
|
+
};
|
|
8390
|
+
}
|
|
8093
8391
|
function escapeTokenLiteral(value) {
|
|
8094
8392
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
8095
8393
|
}
|
|
@@ -8230,14 +8528,20 @@ function emitLeaf(def, ctx, pos) {
|
|
|
8230
8528
|
endVar: inner.endVar
|
|
8231
8529
|
};
|
|
8232
8530
|
}
|
|
8531
|
+
function emitNodeProjectExpr(type, project, chV) {
|
|
8532
|
+
const child = `${chV}[${project}]`;
|
|
8533
|
+
const missing = `(() => { throw new Error(${JSON.stringify(`node(${JSON.stringify(type)}) project child ${project} was not captured`)}) })()`;
|
|
8534
|
+
const value = `(${child} !== null && typeof ${child} === 'object' && ${child}._tag === 'leaf' ? ${child}.value : ${child})`;
|
|
8535
|
+
return `(${project} in ${chV} ? ${value} : ${missing})`;
|
|
8536
|
+
}
|
|
8233
8537
|
function emitNode(def, ctx, pos) {
|
|
8234
8538
|
if (def.type === void 0) {
|
|
8235
8539
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
8236
8540
|
}
|
|
8237
|
-
const structural = def.build === void 0;
|
|
8238
|
-
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
8541
|
+
const structural = def.build === void 0 && def.project === void 0;
|
|
8542
|
+
const mkType = structural || def.project !== void 0 ? null : analyzeMkInlineBuild(def);
|
|
8239
8543
|
let buildIdx = null;
|
|
8240
|
-
if (!mkType && !structural) {
|
|
8544
|
+
if (!mkType && !structural && def.project === void 0) {
|
|
8241
8545
|
buildIdx = ctx.buildFns.length;
|
|
8242
8546
|
ctx.buildFns.push(def.build);
|
|
8243
8547
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
@@ -8245,12 +8549,13 @@ function emitNode(def, ctx, pos) {
|
|
|
8245
8549
|
const i = ind(ctx);
|
|
8246
8550
|
const cstOut = ctx.hostMode === "cst" && !structural;
|
|
8247
8551
|
if (!structural && !cstOut) ctx.hostBranchElided = true;
|
|
8248
|
-
const
|
|
8249
|
-
const
|
|
8250
|
-
const
|
|
8251
|
-
const
|
|
8552
|
+
const hasProject = def.project !== void 0;
|
|
8553
|
+
const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && !hasProject && buildReadsTrivia(def);
|
|
8554
|
+
const clonesState = !structural && (cstOut || !hasProject && buildReadsState(def));
|
|
8555
|
+
const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || def.project !== void 0 || buildReadsChildren(def));
|
|
8556
|
+
const capturesRaw = !structural && (cstOut || mkType !== null || def.project === void 0 && buildReadsRaw(def));
|
|
8252
8557
|
const hasFields = parserHasOwnFields(def.parser);
|
|
8253
|
-
const capturesFields = hasFields && !structural && (cstOut || buildReadsFields(def));
|
|
8558
|
+
const capturesFields = hasFields && !structural && (cstOut || !hasProject && buildReadsFields(def));
|
|
8254
8559
|
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
8255
8560
|
const chV = v(ctx, "_ch");
|
|
8256
8561
|
const rawV = v(ctx, "_raw");
|
|
@@ -8348,7 +8653,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
8348
8653
|
);
|
|
8349
8654
|
}
|
|
8350
8655
|
const ndV = v(ctx, "_nd");
|
|
8351
|
-
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})`;
|
|
8656
|
+
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})`;
|
|
8352
8657
|
const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
8353
8658
|
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
|
|
8354
8659
|
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;
|
|
@@ -8555,7 +8860,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8555
8860
|
case "choice":
|
|
8556
8861
|
return emitChoice(p, def, ctx, pos);
|
|
8557
8862
|
case "dispatch":
|
|
8558
|
-
return emitDispatchCombinator(def, ctx, pos);
|
|
8863
|
+
return emitDispatchCombinator(p, def, ctx, pos);
|
|
8559
8864
|
case "attempt":
|
|
8560
8865
|
return emitAttempt(p, def, ctx, pos);
|
|
8561
8866
|
case "many":
|
|
@@ -8680,6 +8985,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8680
8985
|
return emitNot(def, ctx, pos);
|
|
8681
8986
|
case "peek":
|
|
8682
8987
|
return emitPeek(def, ctx, pos);
|
|
8988
|
+
case "routed":
|
|
8989
|
+
return emitRouted(ctx, pos);
|
|
8683
8990
|
case "node":
|
|
8684
8991
|
return emitNode(def, ctx, pos);
|
|
8685
8992
|
case "scanTo":
|
|
@@ -8777,7 +9084,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8777
9084
|
case "choice":
|
|
8778
9085
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8779
9086
|
case "dispatch":
|
|
8780
|
-
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
9087
|
+
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);
|
|
8781
9088
|
case "sepBy":
|
|
8782
9089
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8783
9090
|
case "scanTo":
|
|
@@ -8792,6 +9099,26 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8792
9099
|
return false;
|
|
8793
9100
|
}
|
|
8794
9101
|
}
|
|
9102
|
+
function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
|
|
9103
|
+
if (seen.has(p)) return false;
|
|
9104
|
+
seen.add(p);
|
|
9105
|
+
const d = p._def;
|
|
9106
|
+
switch (d.tag) {
|
|
9107
|
+
case "routed":
|
|
9108
|
+
return true;
|
|
9109
|
+
case "lazy": {
|
|
9110
|
+
try {
|
|
9111
|
+
return parserUsesRouted2(d.thunk(), seen);
|
|
9112
|
+
} catch {
|
|
9113
|
+
return false;
|
|
9114
|
+
}
|
|
9115
|
+
}
|
|
9116
|
+
case "dispatch":
|
|
9117
|
+
return false;
|
|
9118
|
+
default:
|
|
9119
|
+
return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
8795
9122
|
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
8796
9123
|
if (seen.has(p)) return false;
|
|
8797
9124
|
seen.add(p);
|
|
@@ -8812,7 +9139,7 @@ function childrenOf2(def) {
|
|
|
8812
9139
|
case "choice":
|
|
8813
9140
|
return def.parsers;
|
|
8814
9141
|
case "dispatch":
|
|
8815
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9142
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
8816
9143
|
case "many":
|
|
8817
9144
|
case "attempt":
|
|
8818
9145
|
case "optional":
|
|
@@ -8849,6 +9176,7 @@ function childrenOf2(def) {
|
|
|
8849
9176
|
case "regex":
|
|
8850
9177
|
case "keywords":
|
|
8851
9178
|
case "guard":
|
|
9179
|
+
case "routed":
|
|
8852
9180
|
case "unknown":
|
|
8853
9181
|
return [];
|
|
8854
9182
|
}
|
|
@@ -9682,7 +10010,7 @@ function childrenOf3(def) {
|
|
|
9682
10010
|
case "choice":
|
|
9683
10011
|
return def.parsers;
|
|
9684
10012
|
case "dispatch":
|
|
9685
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
10013
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
9686
10014
|
case "many":
|
|
9687
10015
|
case "oneOrMore":
|
|
9688
10016
|
case "optional":
|
|
@@ -9711,6 +10039,7 @@ function childrenOf3(def) {
|
|
|
9711
10039
|
case "literal":
|
|
9712
10040
|
case "regex":
|
|
9713
10041
|
case "keywords":
|
|
10042
|
+
case "routed":
|
|
9714
10043
|
case "guard":
|
|
9715
10044
|
case "recover":
|
|
9716
10045
|
case "unknown":
|
|
@@ -9735,6 +10064,20 @@ function repeatOpts(min, max, trailing) {
|
|
|
9735
10064
|
if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
|
|
9736
10065
|
return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
|
|
9737
10066
|
}
|
|
10067
|
+
function projectOpt(project) {
|
|
10068
|
+
if (project === void 0) return void 0;
|
|
10069
|
+
return `project: ${project}`;
|
|
10070
|
+
}
|
|
10071
|
+
function matcherExpr(entry) {
|
|
10072
|
+
switch (entry.kind) {
|
|
10073
|
+
case "startsWith":
|
|
10074
|
+
return `startsWith(${JSON.stringify(entry.value)})`;
|
|
10075
|
+
case "endsWith":
|
|
10076
|
+
return `endsWith(${JSON.stringify(entry.value)})`;
|
|
10077
|
+
case "matches":
|
|
10078
|
+
return `matches(${new RegExp(entry.value, entry.flags ?? "").toString()})`;
|
|
10079
|
+
}
|
|
10080
|
+
}
|
|
9738
10081
|
function serializeRuleMap(ruleMap, scanSkip) {
|
|
9739
10082
|
try {
|
|
9740
10083
|
return new Serializer(ruleMap, scanSkip ?? []).run();
|
|
@@ -9834,7 +10177,11 @@ function evalRuleMapIR(ir) {
|
|
|
9834
10177
|
"choice",
|
|
9835
10178
|
"dispatch",
|
|
9836
10179
|
"when",
|
|
10180
|
+
"startsWith",
|
|
10181
|
+
"endsWith",
|
|
10182
|
+
"matches",
|
|
9837
10183
|
"otherwise",
|
|
10184
|
+
"routed",
|
|
9838
10185
|
"attempt",
|
|
9839
10186
|
"many",
|
|
9840
10187
|
"oneOrMore",
|
|
@@ -9870,7 +10217,11 @@ function evalRuleMapIR(ir) {
|
|
|
9870
10217
|
choice,
|
|
9871
10218
|
dispatch,
|
|
9872
10219
|
when,
|
|
10220
|
+
startsWith,
|
|
10221
|
+
endsWith,
|
|
10222
|
+
matches,
|
|
9873
10223
|
otherwise,
|
|
10224
|
+
routed,
|
|
9874
10225
|
attempt,
|
|
9875
10226
|
many,
|
|
9876
10227
|
oneOrMore,
|
|
@@ -10058,8 +10409,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10058
10409
|
}
|
|
10059
10410
|
case "dispatch": {
|
|
10060
10411
|
const arms = def.cases.map(
|
|
10061
|
-
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
10412
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`
|
|
10062
10413
|
);
|
|
10414
|
+
if (def.matchers) {
|
|
10415
|
+
for (const entry of def.matchers) {
|
|
10416
|
+
arms.push(`when(${matcherExpr(entry)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`);
|
|
10417
|
+
}
|
|
10418
|
+
}
|
|
10063
10419
|
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10064
10420
|
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10065
10421
|
}
|
|
@@ -10079,6 +10435,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10079
10435
|
return `not(${kid(def.parser)})`;
|
|
10080
10436
|
case "peek":
|
|
10081
10437
|
return `peek(${kid(def.parser)})`;
|
|
10438
|
+
case "routed":
|
|
10439
|
+
return "routed()";
|
|
10082
10440
|
case "trivia":
|
|
10083
10441
|
return `trivia(${kid(def.parser)})`;
|
|
10084
10442
|
case "token":
|
|
@@ -10103,9 +10461,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10103
10461
|
}
|
|
10104
10462
|
case "node": {
|
|
10105
10463
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
10464
|
+
const projectEntry = projectOpt(def.project);
|
|
10106
10465
|
const optEntries = [
|
|
10107
10466
|
...def.unwrap ? ["unwrap: true"] : [],
|
|
10108
10467
|
...def.collapse ? ["collapse: true"] : [],
|
|
10468
|
+
...projectEntry === void 0 ? [] : [projectEntry],
|
|
10109
10469
|
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
10110
10470
|
...def.trailingTrivia ? ["trailingTrivia: true"] : []
|
|
10111
10471
|
];
|
|
@@ -10548,6 +10908,9 @@ function stripTsFromSource(node2, code) {
|
|
|
10548
10908
|
function isWordFactory(v2) {
|
|
10549
10909
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
10550
10910
|
}
|
|
10911
|
+
function isWhenFactory(v2) {
|
|
10912
|
+
return !!v2 && typeof v2 === "object" && v2.tag === "whenFactory";
|
|
10913
|
+
}
|
|
10551
10914
|
function isStaticValueEntry(v2) {
|
|
10552
10915
|
return !!v2 && typeof v2 === "object" && "value" in v2 && "mfSrcs" in v2;
|
|
10553
10916
|
}
|
|
@@ -10570,6 +10933,23 @@ function wordFactoryFromArgs(args, scope, code, mfs) {
|
|
|
10570
10933
|
if (typeof caseInsensitive !== "boolean") return null;
|
|
10571
10934
|
return { tag: "wordFactory", boundary: "_0-9A-Za-z", caseInsensitive };
|
|
10572
10935
|
}
|
|
10936
|
+
function dispatchWhenOptions(v2) {
|
|
10937
|
+
if (v2 === void 0) return {};
|
|
10938
|
+
if (typeof v2 !== "object" || v2 === null || Array.isArray(v2)) return null;
|
|
10939
|
+
for (const key of Object.keys(v2)) {
|
|
10940
|
+
if (key !== "caseInsensitive") return null;
|
|
10941
|
+
}
|
|
10942
|
+
const caseInsensitive = "caseInsensitive" in v2 ? v2.caseInsensitive : false;
|
|
10943
|
+
if (typeof caseInsensitive !== "boolean") return null;
|
|
10944
|
+
return { caseInsensitive };
|
|
10945
|
+
}
|
|
10946
|
+
function whenFactoryFromArgs(args, scope, code, mfs) {
|
|
10947
|
+
const [optsArg, extra] = args;
|
|
10948
|
+
if (optsArg?.type === "SpreadElement" || extra !== void 0) return null;
|
|
10949
|
+
const rawOpts = optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs);
|
|
10950
|
+
const opts = dispatchWhenOptions(rawOpts);
|
|
10951
|
+
return opts === null ? null : { tag: "whenFactory", caseInsensitive: opts.caseInsensitive ?? false };
|
|
10952
|
+
}
|
|
10573
10953
|
var SUPPORTED = {
|
|
10574
10954
|
literal: (...a) => literal(a[0], a[1]),
|
|
10575
10955
|
regex: (...a) => regex(a[0], a[1]),
|
|
@@ -10585,6 +10965,7 @@ var SUPPORTED = {
|
|
|
10585
10965
|
field: (...a) => field(a[0], a[1]),
|
|
10586
10966
|
noTrivia: (...a) => noTrivia(a[0]),
|
|
10587
10967
|
token: (...a) => token(a[0]),
|
|
10968
|
+
routed: () => routed(),
|
|
10588
10969
|
leaf: (...a) => leaf(a[0], a[1]),
|
|
10589
10970
|
expect: (...a) => expect(a[0], a[1])
|
|
10590
10971
|
};
|
|
@@ -10628,6 +11009,18 @@ function dispatchArmValue(node2, scope, code, mfs) {
|
|
|
10628
11009
|
if (node2.type !== "CallExpression") return null;
|
|
10629
11010
|
const callee = node2.callee;
|
|
10630
11011
|
if (callee.type !== "Identifier") return null;
|
|
11012
|
+
const factory = scope.get(callee.name);
|
|
11013
|
+
if (isWhenFactory(factory)) {
|
|
11014
|
+
const [keyArg, parserArg, extraArg] = node2.arguments;
|
|
11015
|
+
if (!keyArg || !parserArg || extraArg !== void 0 || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
11016
|
+
const key = anyValue(keyArg, scope, code, mfs);
|
|
11017
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
11018
|
+
if (!isCombinator(parserValue)) return null;
|
|
11019
|
+
const opts = { caseInsensitive: factory.caseInsensitive };
|
|
11020
|
+
if (typeof key === "string") return when(key, parserValue, opts);
|
|
11021
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
|
|
11022
|
+
return null;
|
|
11023
|
+
}
|
|
10631
11024
|
if (callee.name === "otherwise") {
|
|
10632
11025
|
const [parserArg] = node2.arguments;
|
|
10633
11026
|
if (!parserArg || parserArg.type === "SpreadElement") return null;
|
|
@@ -10636,13 +11029,16 @@ function dispatchArmValue(node2, scope, code, mfs) {
|
|
|
10636
11029
|
return otherwise(parserValue);
|
|
10637
11030
|
}
|
|
10638
11031
|
if (callee.name === "when") {
|
|
10639
|
-
const [keyArg, parserArg] = node2.arguments;
|
|
10640
|
-
if (!keyArg || !parserArg || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
11032
|
+
const [keyArg, parserArg, optsArg] = node2.arguments;
|
|
11033
|
+
if (!keyArg || !parserArg || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement" || optsArg?.type === "SpreadElement") return null;
|
|
10641
11034
|
const key = anyValue(keyArg, scope, code, mfs);
|
|
10642
11035
|
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
11036
|
+
const opts = dispatchWhenOptions(optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs));
|
|
11037
|
+
if (opts === null) return null;
|
|
10643
11038
|
if (!isCombinator(parserValue)) return null;
|
|
10644
|
-
if (typeof key === "string") return when(key, parserValue);
|
|
10645
|
-
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue);
|
|
11039
|
+
if (typeof key === "string") return when(key, parserValue, opts);
|
|
11040
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
|
|
11041
|
+
if (isDispatchMatcher(key)) return when(key, parserValue, opts);
|
|
10646
11042
|
}
|
|
10647
11043
|
return null;
|
|
10648
11044
|
}
|
|
@@ -10653,7 +11049,16 @@ function isDispatchArm(v2) {
|
|
|
10653
11049
|
if (!v2 || typeof v2 !== "object") return false;
|
|
10654
11050
|
const rec = v2;
|
|
10655
11051
|
if (rec.kind === "otherwise") return isCombinator(rec.parser);
|
|
10656
|
-
|
|
11052
|
+
if (rec.kind === "whenMatcher") {
|
|
11053
|
+
return isDispatchMatcher(rec.matcher) && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
|
|
11054
|
+
}
|
|
11055
|
+
return rec.kind === "when" && Array.isArray(rec.keys) && rec.keys.every((key) => typeof key === "string") && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
|
|
11056
|
+
}
|
|
11057
|
+
function isDispatchMatcher(v2) {
|
|
11058
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
11059
|
+
const rec = v2;
|
|
11060
|
+
if ((rec.kind === "startsWith" || rec.kind === "endsWith") && typeof rec.value === "string") return true;
|
|
11061
|
+
return rec.kind === "matches" && typeof rec.value === "string" && typeof rec.flags === "string";
|
|
10657
11062
|
}
|
|
10658
11063
|
function scopeGet(scope, name, mfs) {
|
|
10659
11064
|
const entry = scope.get(name);
|
|
@@ -10665,6 +11070,18 @@ function scopeGet(scope, name, mfs) {
|
|
|
10665
11070
|
if (isCombinator(entry)) return entry;
|
|
10666
11071
|
return null;
|
|
10667
11072
|
}
|
|
11073
|
+
function staticLiteralValue(expr) {
|
|
11074
|
+
const val = expr;
|
|
11075
|
+
return val.type === "Literal" || val.type === "BooleanLiteral" || val.type === "NumericLiteral" ? val.value : void 0;
|
|
11076
|
+
}
|
|
11077
|
+
function staticNodeProject(expr) {
|
|
11078
|
+
const literalValue = staticLiteralValue(expr);
|
|
11079
|
+
if (typeof literalValue === "number" && Number.isInteger(literalValue) && literalValue >= 0) {
|
|
11080
|
+
return { ok: true, value: literalValue };
|
|
11081
|
+
}
|
|
11082
|
+
if (typeof literalValue === "number" || literalValue !== void 0) return { ok: false };
|
|
11083
|
+
return { ok: false };
|
|
11084
|
+
}
|
|
10668
11085
|
function staticNodeOptions(expr) {
|
|
10669
11086
|
if (expr.type !== "ObjectExpression") return void 0;
|
|
10670
11087
|
const opts = {};
|
|
@@ -10674,11 +11091,14 @@ function staticNodeOptions(expr) {
|
|
|
10674
11091
|
const key = p.key;
|
|
10675
11092
|
const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? String(key.value) : void 0;
|
|
10676
11093
|
if (name === "unwrap" || name === "collapse" || name === "captureTrivia" || name === "trailingTrivia") {
|
|
10677
|
-
|
|
10678
|
-
|
|
11094
|
+
if (staticLiteralValue(p.value) === true) opts[name] = true;
|
|
11095
|
+
} else if (name === "project") {
|
|
11096
|
+
const project = staticNodeProject(p.value);
|
|
11097
|
+
if (project?.ok === false) return { project: -1 };
|
|
11098
|
+
if (project !== void 0) opts.project = project.value;
|
|
10679
11099
|
}
|
|
10680
11100
|
}
|
|
10681
|
-
return opts.unwrap || opts.collapse || opts.captureTrivia || opts.trailingTrivia ? opts : void 0;
|
|
11101
|
+
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia ? opts : void 0;
|
|
10682
11102
|
}
|
|
10683
11103
|
function exprToCombi(node2, scope, code, mfs) {
|
|
10684
11104
|
if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
|
|
@@ -10753,9 +11173,10 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10753
11173
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
10754
11174
|
if (!isCombinator(inner)) return null;
|
|
10755
11175
|
const be = buildArg;
|
|
10756
|
-
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !(be.type === "Identifier" && be.name === "undefined");
|
|
11176
|
+
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && be.type !== "ObjectExpression" && !(be.type === "Identifier" && be.name === "undefined");
|
|
10757
11177
|
const buildSrc = hasBuild ? stripTsFromSource(be, code) : void 0;
|
|
10758
|
-
const
|
|
11178
|
+
const optionsArg = hasBuild ? optsArg : be?.type === "ObjectExpression" ? buildArg : optsArg;
|
|
11179
|
+
const opts = optionsArg !== void 0 && optionsArg.type !== "SpreadElement" ? staticNodeOptions(optionsArg) : void 0;
|
|
10759
11180
|
try {
|
|
10760
11181
|
const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
|
|
10761
11182
|
if (combi._def.tag === "node" && buildSrc !== void 0) {
|
|
@@ -11039,9 +11460,27 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
11039
11460
|
if (callee.type === "Identifier" && callee.name === "makeWord") {
|
|
11040
11461
|
return wordFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
11041
11462
|
}
|
|
11463
|
+
if (callee.type === "Identifier" && callee.name === "makeWhen") {
|
|
11464
|
+
return whenFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
11465
|
+
}
|
|
11466
|
+
if (callee.type === "Identifier" && (callee.name === "startsWith" || callee.name === "endsWith")) {
|
|
11467
|
+
if (node2.arguments.length !== 1 || node2.arguments[0]?.type === "SpreadElement") return null;
|
|
11468
|
+
const value = anyValue(node2.arguments[0], scope, code, mfs);
|
|
11469
|
+
if (typeof value !== "string") return null;
|
|
11470
|
+
return callee.name === "startsWith" ? startsWith(value) : endsWith(value);
|
|
11471
|
+
}
|
|
11472
|
+
if (callee.type === "Identifier" && callee.name === "matches") {
|
|
11473
|
+
if (node2.arguments.length !== 1 || node2.arguments[0]?.type === "SpreadElement") return null;
|
|
11474
|
+
const value = anyValue(node2.arguments[0], scope, code, mfs);
|
|
11475
|
+
if (!(value instanceof RegExp)) return null;
|
|
11476
|
+
return matches(value);
|
|
11477
|
+
}
|
|
11042
11478
|
if (callee.type === "Identifier" && (callee.name === "when" || callee.name === "otherwise")) {
|
|
11043
11479
|
return dispatchArmValue(node2, scope, code, mfs);
|
|
11044
11480
|
}
|
|
11481
|
+
if (callee.type === "Identifier" && isWhenFactory(scope.get(callee.name))) {
|
|
11482
|
+
return dispatchArmValue(node2, scope, code, mfs);
|
|
11483
|
+
}
|
|
11045
11484
|
return exprToCombi(node2, scope, code, mfs);
|
|
11046
11485
|
}
|
|
11047
11486
|
return null;
|
|
@@ -11052,6 +11491,12 @@ function evaluateWordFactory(node2, scope, code) {
|
|
|
11052
11491
|
if (callee.type !== "Identifier" || callee.name !== "makeWord") return null;
|
|
11053
11492
|
return wordFactoryFromArgs(node2.arguments, scope, code);
|
|
11054
11493
|
}
|
|
11494
|
+
function evaluateWhenFactory(node2, scope, code) {
|
|
11495
|
+
if (node2.type !== "CallExpression") return null;
|
|
11496
|
+
const callee = node2.callee;
|
|
11497
|
+
if (callee.type !== "Identifier" || callee.name !== "makeWhen") return null;
|
|
11498
|
+
return whenFactoryFromArgs(node2.arguments, scope, code);
|
|
11499
|
+
}
|
|
11055
11500
|
function evaluateExpr(node2, scope, code, mapFnSources) {
|
|
11056
11501
|
return exprToCombi(node2, scope, code, mapFnSources);
|
|
11057
11502
|
}
|
|
@@ -11632,7 +12077,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
11632
12077
|
for (const match of source.matchAll(/id:\s*"([^"]+)"/g)) ids.add(match[1]);
|
|
11633
12078
|
return [...ids].sort().map((id2) => ({
|
|
11634
12079
|
id: id2,
|
|
11635
|
-
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : "choice-arm"
|
|
12080
|
+
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : id2.startsWith("dispatch:") ? "dispatch-arm" : "choice-arm"
|
|
11636
12081
|
}));
|
|
11637
12082
|
};
|
|
11638
12083
|
const localComposedCarried = /* @__PURE__ */ new Map();
|
|
@@ -12078,6 +12523,14 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
12078
12523
|
if (wordFactory) {
|
|
12079
12524
|
;
|
|
12080
12525
|
scope.set(varName, wordFactory);
|
|
12526
|
+
replacements.push({ start: init.start, end: init.end, replacement: "undefined" });
|
|
12527
|
+
continue;
|
|
12528
|
+
}
|
|
12529
|
+
const whenFactory = evaluateWhenFactory(init, scope, code);
|
|
12530
|
+
if (whenFactory) {
|
|
12531
|
+
;
|
|
12532
|
+
scope.set(varName, whenFactory);
|
|
12533
|
+
replacements.push({ start: init.start, end: init.end, replacement: "undefined" });
|
|
12081
12534
|
continue;
|
|
12082
12535
|
}
|
|
12083
12536
|
const combiArray = evaluateCombinatorArray(init, scope, code);
|