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.js
CHANGED
|
@@ -59,6 +59,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
59
59
|
return d.value.length === 0;
|
|
60
60
|
case "keywords":
|
|
61
61
|
return false;
|
|
62
|
+
case "routed":
|
|
63
|
+
return false;
|
|
62
64
|
case "regex":
|
|
63
65
|
try {
|
|
64
66
|
const m = new RegExp(d.source).exec("");
|
|
@@ -1151,6 +1153,8 @@ function derive(c, seen) {
|
|
|
1151
1153
|
case "not":
|
|
1152
1154
|
case "peek":
|
|
1153
1155
|
return deriveExpected2(def.parser);
|
|
1156
|
+
case "routed":
|
|
1157
|
+
return ["routed()"];
|
|
1154
1158
|
case "lazy": {
|
|
1155
1159
|
const name = c._ruleName;
|
|
1156
1160
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -1972,42 +1976,195 @@ function sequence(...parsers) {
|
|
|
1972
1976
|
}
|
|
1973
1977
|
|
|
1974
1978
|
// src/combinators/dispatch.ts
|
|
1975
|
-
function
|
|
1979
|
+
function parserUsesRouted(parser2, seen = /* @__PURE__ */ new Set()) {
|
|
1980
|
+
if (seen.has(parser2)) return false;
|
|
1981
|
+
seen.add(parser2);
|
|
1982
|
+
const def = parser2._def;
|
|
1983
|
+
switch (def.tag) {
|
|
1984
|
+
case "routed":
|
|
1985
|
+
return true;
|
|
1986
|
+
case "sequence":
|
|
1987
|
+
case "choice":
|
|
1988
|
+
return def.parsers.some((entry) => parserUsesRouted(entry, seen));
|
|
1989
|
+
case "dispatch":
|
|
1990
|
+
return false;
|
|
1991
|
+
case "sepBy":
|
|
1992
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.separator, seen);
|
|
1993
|
+
case "skip":
|
|
1994
|
+
return parserUsesRouted(def.main, seen) || parserUsesRouted(def.skipped, seen);
|
|
1995
|
+
case "grammar":
|
|
1996
|
+
return parserUsesRouted(def.parser, seen) || (def.triviaParser ? parserUsesRouted(def.triviaParser, seen) : false);
|
|
1997
|
+
case "scanTo":
|
|
1998
|
+
return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen));
|
|
1999
|
+
case "recover":
|
|
2000
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.sentinel, seen);
|
|
2001
|
+
case "lazy":
|
|
2002
|
+
try {
|
|
2003
|
+
return parserUsesRouted(def.thunk(), seen);
|
|
2004
|
+
} catch {
|
|
2005
|
+
return false;
|
|
2006
|
+
}
|
|
2007
|
+
case "many":
|
|
2008
|
+
case "oneOrMore":
|
|
2009
|
+
case "optional":
|
|
2010
|
+
case "attempt":
|
|
2011
|
+
case "transform":
|
|
2012
|
+
case "trivia":
|
|
2013
|
+
case "token":
|
|
2014
|
+
case "leaf":
|
|
2015
|
+
case "label":
|
|
2016
|
+
case "field":
|
|
2017
|
+
case "not":
|
|
2018
|
+
case "peek":
|
|
2019
|
+
case "node":
|
|
2020
|
+
case "withCtx":
|
|
2021
|
+
case "expect":
|
|
2022
|
+
return parserUsesRouted(def.parser, seen);
|
|
2023
|
+
default:
|
|
2024
|
+
return false;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
function branchUsesRouted(branch) {
|
|
2028
|
+
return branch.usesRouted === true || parserUsesRouted(branch.parser);
|
|
2029
|
+
}
|
|
2030
|
+
function asciiFoldKey(key) {
|
|
2031
|
+
let out = "";
|
|
2032
|
+
for (let i = 0; i < key.length; i++) {
|
|
2033
|
+
const c = key.charCodeAt(i);
|
|
2034
|
+
out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
|
|
2035
|
+
}
|
|
2036
|
+
return out;
|
|
2037
|
+
}
|
|
2038
|
+
function matchesDispatchMatcher(value, matcher) {
|
|
2039
|
+
const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
|
|
2040
|
+
const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
|
|
2041
|
+
switch (matcher.kind) {
|
|
2042
|
+
case "startsWith":
|
|
2043
|
+
return candidate.startsWith(expected);
|
|
2044
|
+
case "endsWith":
|
|
2045
|
+
return candidate.endsWith(expected);
|
|
2046
|
+
case "matches": {
|
|
2047
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
2048
|
+
return new RegExp(matcher.value, flags).test(value);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
function isStringMatcher(value) {
|
|
2053
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2054
|
+
const kind = value.kind;
|
|
2055
|
+
return kind === "startsWith" || kind === "endsWith" || kind === "matches";
|
|
2056
|
+
}
|
|
2057
|
+
function fixedMatcher(kind, value) {
|
|
2058
|
+
if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
|
|
2059
|
+
if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
|
|
2060
|
+
return { kind, value };
|
|
2061
|
+
}
|
|
2062
|
+
function startsWith(prefix) {
|
|
2063
|
+
return fixedMatcher("startsWith", prefix);
|
|
2064
|
+
}
|
|
2065
|
+
function endsWith(suffix) {
|
|
2066
|
+
return fixedMatcher("endsWith", suffix);
|
|
2067
|
+
}
|
|
2068
|
+
function matches(pattern) {
|
|
2069
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
|
|
2070
|
+
if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
|
|
2071
|
+
throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
|
|
2072
|
+
}
|
|
2073
|
+
return { kind: "matches", value: pattern.source, flags: pattern.flags };
|
|
2074
|
+
}
|
|
2075
|
+
function when(key, parser2, opts = {}) {
|
|
2076
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
2077
|
+
if (isStringMatcher(key)) {
|
|
2078
|
+
return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2079
|
+
}
|
|
1976
2080
|
const keys = Array.isArray(key) ? [...key] : [key];
|
|
1977
2081
|
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
1978
2082
|
for (const item of keys) {
|
|
1979
2083
|
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
1980
2084
|
}
|
|
1981
|
-
return { kind: "when", keys, parser: parser2 };
|
|
2085
|
+
return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
1982
2086
|
}
|
|
1983
2087
|
function otherwise(parser2) {
|
|
1984
|
-
return { kind: "otherwise", parser: parser2 };
|
|
2088
|
+
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2089
|
+
}
|
|
2090
|
+
function routed() {
|
|
2091
|
+
return {
|
|
2092
|
+
_tag: "routed",
|
|
2093
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
2094
|
+
_def: { tag: "routed" },
|
|
2095
|
+
parse(_input, pos, ctx) {
|
|
2096
|
+
const item = ctx._routed;
|
|
2097
|
+
if (item === void 0) {
|
|
2098
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2099
|
+
}
|
|
2100
|
+
if (pos !== item.span.start) {
|
|
2101
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2102
|
+
}
|
|
2103
|
+
if (cstCaptureActive(ctx)) {
|
|
2104
|
+
pushCstLeaf(ctx, { _tag: "leaf", value: item.value, span: item.span });
|
|
2105
|
+
}
|
|
2106
|
+
return { ok: true, value: item.value, span: item.span };
|
|
2107
|
+
}
|
|
2108
|
+
};
|
|
1985
2109
|
}
|
|
1986
2110
|
function dispatch(selector, ...arms) {
|
|
2111
|
+
if (parserUsesRouted(selector)) {
|
|
2112
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2113
|
+
}
|
|
1987
2114
|
let fallback;
|
|
2115
|
+
let fallbackUsesRouted = false;
|
|
2116
|
+
const matchers = [];
|
|
1988
2117
|
const cases = [];
|
|
1989
|
-
const seen =
|
|
2118
|
+
const seen = [];
|
|
1990
2119
|
for (let i = 0; i < arms.length; i++) {
|
|
1991
2120
|
const arm = arms[i];
|
|
1992
2121
|
if (arm.kind === "otherwise") {
|
|
1993
2122
|
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
1994
2123
|
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
1995
2124
|
fallback = arm.parser;
|
|
2125
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
1996
2126
|
continue;
|
|
1997
2127
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2128
|
+
if (arm.kind === "whenMatcher") {
|
|
2129
|
+
const matcher = arm.matcher;
|
|
2130
|
+
matchers.push({
|
|
2131
|
+
kind: matcher.kind,
|
|
2132
|
+
value: matcher.value,
|
|
2133
|
+
...matcher.kind === "matches" ? { flags: matcher.flags } : {},
|
|
2134
|
+
parser: arm.parser,
|
|
2135
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2136
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2137
|
+
});
|
|
2138
|
+
continue;
|
|
2001
2139
|
}
|
|
2002
|
-
|
|
2140
|
+
for (const key of arm.keys) {
|
|
2141
|
+
const folded = asciiFoldKey(key);
|
|
2142
|
+
for (const prior of seen) {
|
|
2143
|
+
const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
|
|
2144
|
+
if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2145
|
+
}
|
|
2146
|
+
seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
|
|
2147
|
+
}
|
|
2148
|
+
cases.push({
|
|
2149
|
+
keys: arm.keys,
|
|
2150
|
+
parser: arm.parser,
|
|
2151
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2152
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2153
|
+
});
|
|
2003
2154
|
}
|
|
2004
2155
|
const meta = {
|
|
2005
2156
|
firstSet: selector._meta.firstSet,
|
|
2006
|
-
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2157
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2007
2158
|
isTrivia: false
|
|
2008
2159
|
};
|
|
2009
2160
|
const byKey = /* @__PURE__ */ new Map();
|
|
2010
|
-
|
|
2161
|
+
const byFoldedKey = /* @__PURE__ */ new Map();
|
|
2162
|
+
for (const entry of cases) {
|
|
2163
|
+
for (const key of entry.keys) {
|
|
2164
|
+
if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
|
|
2165
|
+
else byKey.set(key, entry);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2011
2168
|
return {
|
|
2012
2169
|
_tag: "dispatch",
|
|
2013
2170
|
_meta: meta,
|
|
@@ -2015,18 +2172,35 @@ function dispatch(selector, ...arms) {
|
|
|
2015
2172
|
tag: "dispatch",
|
|
2016
2173
|
selector,
|
|
2017
2174
|
cases,
|
|
2018
|
-
...
|
|
2175
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2176
|
+
...fallback === void 0 ? {} : { otherwise: fallback, ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {} }
|
|
2019
2177
|
},
|
|
2020
2178
|
parse(input, pos, ctx) {
|
|
2179
|
+
if (parserUsesRouted(selector)) {
|
|
2180
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2181
|
+
}
|
|
2182
|
+
const selectorMark = saveTriviaMark(ctx);
|
|
2021
2183
|
const selected = selector.parse(input, pos, ctx);
|
|
2022
2184
|
if (!selected.ok) return selected;
|
|
2023
|
-
const
|
|
2024
|
-
if (
|
|
2185
|
+
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 });
|
|
2186
|
+
if (branch === void 0) {
|
|
2025
2187
|
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2026
2188
|
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2027
2189
|
}
|
|
2028
|
-
const
|
|
2029
|
-
const
|
|
2190
|
+
const savedRouted = ctx._routed;
|
|
2191
|
+
const usesRouted = branchUsesRouted(branch);
|
|
2192
|
+
let mark = saveTriviaMark(ctx);
|
|
2193
|
+
if (usesRouted) {
|
|
2194
|
+
rollbackTrivia(ctx, selectorMark);
|
|
2195
|
+
mark = saveTriviaMark(ctx);
|
|
2196
|
+
ctx._routed = { value: selected.value, span: selected.span };
|
|
2197
|
+
}
|
|
2198
|
+
let result;
|
|
2199
|
+
try {
|
|
2200
|
+
result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
|
|
2201
|
+
} finally {
|
|
2202
|
+
if (usesRouted) ctx._routed = savedRouted;
|
|
2203
|
+
}
|
|
2030
2204
|
if (!result.ok) {
|
|
2031
2205
|
rollbackTrivia(ctx, mark);
|
|
2032
2206
|
return { ...result, committed: true };
|
|
@@ -2376,6 +2550,7 @@ function markUnusedValues(root) {
|
|
|
2376
2550
|
case "dispatch":
|
|
2377
2551
|
visit(def.selector, consumed);
|
|
2378
2552
|
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2553
|
+
if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
|
|
2379
2554
|
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2380
2555
|
return;
|
|
2381
2556
|
case "node":
|
|
@@ -2654,7 +2829,7 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2654
2829
|
case "choice":
|
|
2655
2830
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2656
2831
|
case "dispatch":
|
|
2657
|
-
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2832
|
+
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);
|
|
2658
2833
|
case "sepBy":
|
|
2659
2834
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2660
2835
|
case "skip":
|
|
@@ -2723,7 +2898,7 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2723
2898
|
case "choice":
|
|
2724
2899
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2725
2900
|
case "dispatch":
|
|
2726
|
-
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2901
|
+
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);
|
|
2727
2902
|
case "grammar":
|
|
2728
2903
|
return parserHasTriviaSite(d.parser, seen);
|
|
2729
2904
|
case "lazy": {
|
|
@@ -2750,7 +2925,7 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2750
2925
|
case "choice":
|
|
2751
2926
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2752
2927
|
case "dispatch":
|
|
2753
|
-
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2928
|
+
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);
|
|
2754
2929
|
case "sepBy":
|
|
2755
2930
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2756
2931
|
case "skip":
|
|
@@ -2811,12 +2986,30 @@ function isCstChild(value) {
|
|
|
2811
2986
|
function missingInferredType() {
|
|
2812
2987
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
2813
2988
|
}
|
|
2989
|
+
function normalizeProject(project) {
|
|
2990
|
+
if (project === void 0) return void 0;
|
|
2991
|
+
if (!Number.isInteger(project) || project < 0) {
|
|
2992
|
+
throw new Error("node() project child must be a non-negative integer");
|
|
2993
|
+
}
|
|
2994
|
+
return project;
|
|
2995
|
+
}
|
|
2996
|
+
function projectChild(children2, project, type) {
|
|
2997
|
+
if (!(project in children2)) {
|
|
2998
|
+
throw new Error(`node(${JSON.stringify(type)}) project child ${project} was not captured`);
|
|
2999
|
+
}
|
|
3000
|
+
return unwrapChild(children2[project]);
|
|
3001
|
+
}
|
|
2814
3002
|
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
2815
3003
|
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
2816
3004
|
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
2817
3005
|
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
2818
|
-
const
|
|
2819
|
-
const
|
|
3006
|
+
const buildArg = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
3007
|
+
const build = typeof buildArg === "function" ? buildArg : void 0;
|
|
3008
|
+
const opts = typeof buildArg === "function" ? maybeOpts : buildArg ?? maybeOpts;
|
|
3009
|
+
const project = normalizeProject(opts?.project);
|
|
3010
|
+
if (project !== void 0 && build !== void 0) {
|
|
3011
|
+
throw new Error("node() options cannot combine project with a build callback");
|
|
3012
|
+
}
|
|
2820
3013
|
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
2821
3014
|
const meta = {
|
|
2822
3015
|
firstSet: combinator._meta.firstSet,
|
|
@@ -2830,11 +3023,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2830
3023
|
if (unwrap && collapse) {
|
|
2831
3024
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
2832
3025
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
3026
|
+
if (project !== void 0 && (unwrap || collapse)) {
|
|
3027
|
+
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3028
|
+
}
|
|
3029
|
+
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;
|
|
3030
|
+
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3031
|
+
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
2836
3032
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
2837
|
-
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) :
|
|
3033
|
+
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
2838
3034
|
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
2839
3035
|
let failExpected;
|
|
2840
3036
|
return {
|
|
@@ -2849,14 +3045,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2849
3045
|
}
|
|
2850
3046
|
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
2851
3047
|
}
|
|
2852
|
-
const
|
|
3048
|
+
const hasDirectValue = build !== void 0 || project !== void 0;
|
|
3049
|
+
const hostCst = hasDirectValue && cstOutputHost(ctx.build);
|
|
2853
3050
|
const effTrivia = capturesTrivia || hostCst;
|
|
2854
3051
|
const effFields = capturesFields || hostCst && hasOwnFields;
|
|
2855
3052
|
const saved = beginCstNodeCapture(ctx);
|
|
2856
3053
|
const savedFields = ctx._fields;
|
|
2857
3054
|
ctx._fields = effFields ? [] : void 0;
|
|
2858
3055
|
const savedMask = ctx._triviaCaptureMask;
|
|
2859
|
-
if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
3056
|
+
if (build === void 0 && project === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
2860
3057
|
ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
|
|
2861
3058
|
}
|
|
2862
3059
|
if (!effTrivia) ctx.captureTrivia = false;
|
|
@@ -2874,7 +3071,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2874
3071
|
const nodeType = def.type ?? missingInferredType();
|
|
2875
3072
|
const cstOutput = cstOutputHost(ctx.build);
|
|
2876
3073
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2877
|
-
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 };
|
|
3074
|
+
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 };
|
|
2878
3075
|
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 };
|
|
2879
3076
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2880
3077
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3125,7 +3322,7 @@ function leaf(root, fn) {
|
|
|
3125
3322
|
}
|
|
3126
3323
|
|
|
3127
3324
|
// src/version.ts
|
|
3128
|
-
var PARSEMAN_VERSION = "0.
|
|
3325
|
+
var PARSEMAN_VERSION = "0.40.0";
|
|
3129
3326
|
|
|
3130
3327
|
// src/cst/host-mode.ts
|
|
3131
3328
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3385,6 +3582,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3385
3582
|
if (d.tag === "dispatch") {
|
|
3386
3583
|
kids.push(d.selector);
|
|
3387
3584
|
for (const c of d.cases) kids.push(c.parser);
|
|
3585
|
+
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3388
3586
|
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3389
3587
|
}
|
|
3390
3588
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
@@ -4908,13 +5106,25 @@ function escapeClassChar(ch2) {
|
|
|
4908
5106
|
}
|
|
4909
5107
|
|
|
4910
5108
|
// src/compiler/grammar-coverage-ids.ts
|
|
5109
|
+
function idPart(value) {
|
|
5110
|
+
return encodeURIComponent(value);
|
|
5111
|
+
}
|
|
5112
|
+
function dispatchArmIds(def, path2) {
|
|
5113
|
+
const ids = [];
|
|
5114
|
+
for (const entry of def.cases) ids.push(`dispatch:${path2}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5115
|
+
for (const entry of def.matchers ?? []) {
|
|
5116
|
+
ids.push(`dispatch:${path2}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5117
|
+
}
|
|
5118
|
+
if (def.otherwise) ids.push(`dispatch:${path2}/otherwise`);
|
|
5119
|
+
return ids;
|
|
5120
|
+
}
|
|
4911
5121
|
function children(def, winners) {
|
|
4912
5122
|
switch (def.tag) {
|
|
4913
5123
|
case "sequence":
|
|
4914
5124
|
case "choice":
|
|
4915
5125
|
return def.parsers;
|
|
4916
5126
|
case "dispatch":
|
|
4917
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
5127
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
4918
5128
|
case "many":
|
|
4919
5129
|
case "oneOrMore":
|
|
4920
5130
|
case "optional":
|
|
@@ -4957,6 +5167,7 @@ function children(def, winners) {
|
|
|
4957
5167
|
function buildGrammarPlan(entry, winners) {
|
|
4958
5168
|
const definitions = /* @__PURE__ */ new Map();
|
|
4959
5169
|
const choices = /* @__PURE__ */ new WeakMap();
|
|
5170
|
+
const dispatches = /* @__PURE__ */ new WeakMap();
|
|
4960
5171
|
const attempts = /* @__PURE__ */ new WeakMap();
|
|
4961
5172
|
const labels = /* @__PURE__ */ new WeakMap();
|
|
4962
5173
|
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -4987,6 +5198,11 @@ function buildGrammarPlan(entry, winners) {
|
|
|
4987
5198
|
choices.set(parser2, ids);
|
|
4988
5199
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
4989
5200
|
}
|
|
5201
|
+
if (parser2._def.tag === "dispatch") {
|
|
5202
|
+
const ids = dispatchArmIds(parser2._def, path2);
|
|
5203
|
+
dispatches.set(parser2, ids);
|
|
5204
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5205
|
+
}
|
|
4990
5206
|
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path2}`);
|
|
4991
5207
|
if (parser2._def.tag === "label") {
|
|
4992
5208
|
const id = `label:${path2}`;
|
|
@@ -4999,7 +5215,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
4999
5215
|
for (const root of roots) {
|
|
5000
5216
|
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
5001
5217
|
}
|
|
5002
|
-
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
5218
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
|
|
5003
5219
|
}
|
|
5004
5220
|
|
|
5005
5221
|
// src/compiler/scannable-run.ts
|
|
@@ -6373,6 +6589,7 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6373
6589
|
case "literal":
|
|
6374
6590
|
case "regex":
|
|
6375
6591
|
case "keywords":
|
|
6592
|
+
case "routed":
|
|
6376
6593
|
return { alts: [[seg(p._meta.firstSet, matchesEmpty(p))]] };
|
|
6377
6594
|
case "choice": {
|
|
6378
6595
|
const alts = [];
|
|
@@ -6731,7 +6948,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6731
6948
|
case "choice":
|
|
6732
6949
|
return false;
|
|
6733
6950
|
case "dispatch":
|
|
6734
|
-
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);
|
|
6951
|
+
return capturesLeaf(d.selector, seen) || d.cases.some((x) => mayLeavePartialCapture(x.parser, seen) || capturesLeaf(x.parser, seen)) || (d.matchers ? d.matchers.some((x) => mayLeavePartialCapture(x.parser, seen) || capturesLeaf(x.parser, seen)) : false) || (d.otherwise ? mayLeavePartialCapture(d.otherwise, seen) || capturesLeaf(d.otherwise, seen) : false);
|
|
6735
6952
|
case "attempt":
|
|
6736
6953
|
return false;
|
|
6737
6954
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6830,6 +7047,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6830
7047
|
case "keywords":
|
|
6831
7048
|
case "node":
|
|
6832
7049
|
case "token":
|
|
7050
|
+
case "routed":
|
|
6833
7051
|
case "leaf":
|
|
6834
7052
|
return true;
|
|
6835
7053
|
case "not":
|
|
@@ -6842,7 +7060,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6842
7060
|
case "choice":
|
|
6843
7061
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6844
7062
|
case "dispatch":
|
|
6845
|
-
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
7063
|
+
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);
|
|
6846
7064
|
case "sepBy":
|
|
6847
7065
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6848
7066
|
case "many":
|
|
@@ -7320,6 +7538,7 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7320
7538
|
for (const item of d.cases) {
|
|
7321
7539
|
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7322
7540
|
}
|
|
7541
|
+
if (d.matchers?.some((item) => mayRecordRecoveryError(item.parser, recovery, seen))) return true;
|
|
7323
7542
|
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7324
7543
|
}
|
|
7325
7544
|
case "attempt":
|
|
@@ -7354,53 +7573,120 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7354
7573
|
return false;
|
|
7355
7574
|
}
|
|
7356
7575
|
}
|
|
7357
|
-
function emitDispatchCombinator(def, ctx, pos) {
|
|
7576
|
+
function emitDispatchCombinator(parser2, def, ctx, pos) {
|
|
7577
|
+
if (parserUsesRouted2(def.selector)) {
|
|
7578
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
7579
|
+
}
|
|
7580
|
+
const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
|
|
7581
|
+
const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
|
|
7582
|
+
const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
|
|
7583
|
+
const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
|
|
7584
|
+
const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
|
|
7585
|
+
const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
|
|
7586
|
+
const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
|
|
7587
|
+
const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
|
|
7588
|
+
const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
|
|
7358
7589
|
const selector = emit(def.selector, ctx, pos);
|
|
7359
7590
|
const outV = v(ctx, "_dval");
|
|
7360
7591
|
const outE = v(ctx, "_dend");
|
|
7361
7592
|
const keyV = v(ctx, "_dkey");
|
|
7362
7593
|
const stmts = [
|
|
7594
|
+
...selectorLeafMark ? [
|
|
7595
|
+
`${ind(ctx)}const ${selectorLeafMark} = _ctx._cstLeaves?.length ?? 0`,
|
|
7596
|
+
`${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
|
|
7597
|
+
`${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
7598
|
+
`${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
|
|
7599
|
+
`${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
|
|
7600
|
+
`${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
|
|
7601
|
+
] : [],
|
|
7363
7602
|
...selector.stmts,
|
|
7364
7603
|
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7365
7604
|
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7366
7605
|
];
|
|
7367
7606
|
let wroteBranch = false;
|
|
7368
|
-
const emitSelectedTail = (
|
|
7607
|
+
const emitSelectedTail = (entry, keyword, condition, coverageId) => {
|
|
7608
|
+
const parser3 = entry.parser;
|
|
7369
7609
|
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7370
7610
|
stmts.push(head);
|
|
7371
7611
|
ctx.indent++;
|
|
7372
|
-
const
|
|
7612
|
+
const usesRouted = branchUsesRouted2(entry);
|
|
7613
|
+
const routedV = usesRouted ? v(ctx, "_drt") : null;
|
|
7614
|
+
const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
|
|
7373
7615
|
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7374
7616
|
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7617
|
+
if (routedV) {
|
|
7618
|
+
stmts.push(
|
|
7619
|
+
`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
|
|
7620
|
+
...selectorLeafMark ? [
|
|
7621
|
+
`${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}`
|
|
7622
|
+
] : []
|
|
7623
|
+
);
|
|
7624
|
+
}
|
|
7375
7625
|
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7376
7626
|
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7377
|
-
const tail = emitTailFallible(
|
|
7627
|
+
const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
|
|
7628
|
+
stmts.push(...coverageAttempt(ctx, coverageId, pos));
|
|
7378
7629
|
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7379
7630
|
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7631
|
+
const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
|
|
7632
|
+
const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
|
|
7380
7633
|
stmts.push(
|
|
7381
7634
|
...tail.stmts,
|
|
7382
|
-
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7635
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
|
|
7636
|
+
...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
|
|
7383
7637
|
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7384
|
-
`${ind(ctx)}${outE} = ${tail.endVar}
|
|
7638
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`,
|
|
7639
|
+
...coverageHit(ctx, coverageId, pos, tail.endVar)
|
|
7385
7640
|
);
|
|
7386
7641
|
ctx.indent--;
|
|
7387
7642
|
stmts.push(`${ind(ctx)}}`);
|
|
7388
7643
|
};
|
|
7644
|
+
let coverageIndex = 0;
|
|
7389
7645
|
for (const entry of def.cases) {
|
|
7390
|
-
const condition = entry.keys.map((key) =>
|
|
7391
|
-
emitSelectedTail(entry
|
|
7646
|
+
const condition = entry.keys.map((key) => emitDispatchKeyCondition(keyV, key, entry.caseInsensitive)).join(" || ");
|
|
7647
|
+
emitSelectedTail(entry, wroteBranch ? "else if" : "if", condition, coverageIds[coverageIndex++]);
|
|
7392
7648
|
wroteBranch = true;
|
|
7393
7649
|
}
|
|
7650
|
+
const emitMatcherTails = () => {
|
|
7651
|
+
for (const matcher of def.matchers ?? []) {
|
|
7652
|
+
emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
|
|
7653
|
+
wroteBranch = true;
|
|
7654
|
+
}
|
|
7655
|
+
};
|
|
7394
7656
|
if (def.otherwise) {
|
|
7395
|
-
|
|
7396
|
-
|
|
7657
|
+
emitMatcherTails();
|
|
7658
|
+
const otherwiseEntry = { parser: def.otherwise, usesRouted: def.otherwiseUsesRouted };
|
|
7659
|
+
if (wroteBranch) emitSelectedTail(otherwiseEntry, "else", void 0, coverageIds[coverageIndex++]);
|
|
7660
|
+
else emitSelectedTail(otherwiseEntry, "if", "true", coverageIds[coverageIndex++]);
|
|
7397
7661
|
} else {
|
|
7662
|
+
emitMatcherTails();
|
|
7398
7663
|
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7399
7664
|
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7400
7665
|
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7401
7666
|
}
|
|
7402
7667
|
return { stmts, valueVar: outV, endVar: outE };
|
|
7403
7668
|
}
|
|
7669
|
+
function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
|
|
7670
|
+
if (!caseInsensitive) return `${valueVar} === ${JSON.stringify(key)}`;
|
|
7671
|
+
const parts = [`${valueVar}.length === ${key.length}`];
|
|
7672
|
+
for (let i = 0; i < key.length; i++) {
|
|
7673
|
+
parts.push(foldEq(`${valueVar}.charCodeAt(${i})`, key.charCodeAt(i)));
|
|
7674
|
+
}
|
|
7675
|
+
return parts.join(" && ");
|
|
7676
|
+
}
|
|
7677
|
+
function emitDispatchMatcherCondition(valueVar, matcher) {
|
|
7678
|
+
if (matcher.kind === "matches") {
|
|
7679
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
7680
|
+
return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
|
|
7681
|
+
}
|
|
7682
|
+
const text = matcher.value;
|
|
7683
|
+
const parts = [`${valueVar}.length >= ${text.length}`];
|
|
7684
|
+
const offset = matcher.kind === "endsWith" ? `${valueVar}.length - ${text.length}` : "0";
|
|
7685
|
+
for (let i = 0; i < text.length; i++) {
|
|
7686
|
+
parts.push(matcher.caseInsensitive ? foldEq(`${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`})`, text.charCodeAt(i)) : `${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`}) === ${text.charCodeAt(i)}`);
|
|
7687
|
+
}
|
|
7688
|
+
return parts.join(" && ");
|
|
7689
|
+
}
|
|
7404
7690
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7405
7691
|
const superParser = def.parsers[superIndex];
|
|
7406
7692
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -8055,6 +8341,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
8055
8341
|
endVar: pos
|
|
8056
8342
|
};
|
|
8057
8343
|
}
|
|
8344
|
+
function emitRouted(ctx, pos) {
|
|
8345
|
+
const item = v(ctx, "_rt");
|
|
8346
|
+
return {
|
|
8347
|
+
stmts: [
|
|
8348
|
+
`${ind(ctx)}const ${item} = _ctx._routed`,
|
|
8349
|
+
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8350
|
+
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8351
|
+
],
|
|
8352
|
+
valueVar: `${item}.value`,
|
|
8353
|
+
endVar: `${item}.span.end`
|
|
8354
|
+
};
|
|
8355
|
+
}
|
|
8058
8356
|
function escapeTokenLiteral(value) {
|
|
8059
8357
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
8060
8358
|
}
|
|
@@ -8195,14 +8493,20 @@ function emitLeaf(def, ctx, pos) {
|
|
|
8195
8493
|
endVar: inner.endVar
|
|
8196
8494
|
};
|
|
8197
8495
|
}
|
|
8496
|
+
function emitNodeProjectExpr(type, project, chV) {
|
|
8497
|
+
const child = `${chV}[${project}]`;
|
|
8498
|
+
const missing = `(() => { throw new Error(${JSON.stringify(`node(${JSON.stringify(type)}) project child ${project} was not captured`)}) })()`;
|
|
8499
|
+
const value = `(${child} !== null && typeof ${child} === 'object' && ${child}._tag === 'leaf' ? ${child}.value : ${child})`;
|
|
8500
|
+
return `(${project} in ${chV} ? ${value} : ${missing})`;
|
|
8501
|
+
}
|
|
8198
8502
|
function emitNode(def, ctx, pos) {
|
|
8199
8503
|
if (def.type === void 0) {
|
|
8200
8504
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
8201
8505
|
}
|
|
8202
|
-
const structural = def.build === void 0;
|
|
8203
|
-
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
8506
|
+
const structural = def.build === void 0 && def.project === void 0;
|
|
8507
|
+
const mkType = structural || def.project !== void 0 ? null : analyzeMkInlineBuild(def);
|
|
8204
8508
|
let buildIdx = null;
|
|
8205
|
-
if (!mkType && !structural) {
|
|
8509
|
+
if (!mkType && !structural && def.project === void 0) {
|
|
8206
8510
|
buildIdx = ctx.buildFns.length;
|
|
8207
8511
|
ctx.buildFns.push(def.build);
|
|
8208
8512
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
@@ -8210,12 +8514,13 @@ function emitNode(def, ctx, pos) {
|
|
|
8210
8514
|
const i = ind(ctx);
|
|
8211
8515
|
const cstOut = ctx.hostMode === "cst" && !structural;
|
|
8212
8516
|
if (!structural && !cstOut) ctx.hostBranchElided = true;
|
|
8213
|
-
const
|
|
8214
|
-
const
|
|
8215
|
-
const
|
|
8216
|
-
const
|
|
8517
|
+
const hasProject = def.project !== void 0;
|
|
8518
|
+
const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && !hasProject && buildReadsTrivia(def);
|
|
8519
|
+
const clonesState = !structural && (cstOut || !hasProject && buildReadsState(def));
|
|
8520
|
+
const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || def.project !== void 0 || buildReadsChildren(def));
|
|
8521
|
+
const capturesRaw = !structural && (cstOut || mkType !== null || def.project === void 0 && buildReadsRaw(def));
|
|
8217
8522
|
const hasFields = parserHasOwnFields(def.parser);
|
|
8218
|
-
const capturesFields = hasFields && !structural && (cstOut || buildReadsFields(def));
|
|
8523
|
+
const capturesFields = hasFields && !structural && (cstOut || !hasProject && buildReadsFields(def));
|
|
8219
8524
|
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
8220
8525
|
const chV = v(ctx, "_ch");
|
|
8221
8526
|
const rawV = v(ctx, "_raw");
|
|
@@ -8313,7 +8618,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
8313
8618
|
);
|
|
8314
8619
|
}
|
|
8315
8620
|
const ndV = v(ctx, "_nd");
|
|
8316
|
-
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})`;
|
|
8621
|
+
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})`;
|
|
8317
8622
|
const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
8318
8623
|
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
|
|
8319
8624
|
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;
|
|
@@ -8520,7 +8825,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8520
8825
|
case "choice":
|
|
8521
8826
|
return emitChoice(p, def, ctx, pos);
|
|
8522
8827
|
case "dispatch":
|
|
8523
|
-
return emitDispatchCombinator(def, ctx, pos);
|
|
8828
|
+
return emitDispatchCombinator(p, def, ctx, pos);
|
|
8524
8829
|
case "attempt":
|
|
8525
8830
|
return emitAttempt(p, def, ctx, pos);
|
|
8526
8831
|
case "many":
|
|
@@ -8645,6 +8950,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8645
8950
|
return emitNot(def, ctx, pos);
|
|
8646
8951
|
case "peek":
|
|
8647
8952
|
return emitPeek(def, ctx, pos);
|
|
8953
|
+
case "routed":
|
|
8954
|
+
return emitRouted(ctx, pos);
|
|
8648
8955
|
case "node":
|
|
8649
8956
|
return emitNode(def, ctx, pos);
|
|
8650
8957
|
case "scanTo":
|
|
@@ -8742,7 +9049,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8742
9049
|
case "choice":
|
|
8743
9050
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8744
9051
|
case "dispatch":
|
|
8745
|
-
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
9052
|
+
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);
|
|
8746
9053
|
case "sepBy":
|
|
8747
9054
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8748
9055
|
case "scanTo":
|
|
@@ -8757,6 +9064,26 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8757
9064
|
return false;
|
|
8758
9065
|
}
|
|
8759
9066
|
}
|
|
9067
|
+
function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
|
|
9068
|
+
if (seen.has(p)) return false;
|
|
9069
|
+
seen.add(p);
|
|
9070
|
+
const d = p._def;
|
|
9071
|
+
switch (d.tag) {
|
|
9072
|
+
case "routed":
|
|
9073
|
+
return true;
|
|
9074
|
+
case "lazy": {
|
|
9075
|
+
try {
|
|
9076
|
+
return parserUsesRouted2(d.thunk(), seen);
|
|
9077
|
+
} catch {
|
|
9078
|
+
return false;
|
|
9079
|
+
}
|
|
9080
|
+
}
|
|
9081
|
+
case "dispatch":
|
|
9082
|
+
return false;
|
|
9083
|
+
default:
|
|
9084
|
+
return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
|
|
9085
|
+
}
|
|
9086
|
+
}
|
|
8760
9087
|
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
8761
9088
|
if (seen.has(p)) return false;
|
|
8762
9089
|
seen.add(p);
|
|
@@ -8777,7 +9104,7 @@ function childrenOf2(def) {
|
|
|
8777
9104
|
case "choice":
|
|
8778
9105
|
return def.parsers;
|
|
8779
9106
|
case "dispatch":
|
|
8780
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9107
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
8781
9108
|
case "many":
|
|
8782
9109
|
case "attempt":
|
|
8783
9110
|
case "optional":
|
|
@@ -8814,6 +9141,7 @@ function childrenOf2(def) {
|
|
|
8814
9141
|
case "regex":
|
|
8815
9142
|
case "keywords":
|
|
8816
9143
|
case "guard":
|
|
9144
|
+
case "routed":
|
|
8817
9145
|
case "unknown":
|
|
8818
9146
|
return [];
|
|
8819
9147
|
}
|
|
@@ -9647,7 +9975,7 @@ function childrenOf3(def) {
|
|
|
9647
9975
|
case "choice":
|
|
9648
9976
|
return def.parsers;
|
|
9649
9977
|
case "dispatch":
|
|
9650
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9978
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
9651
9979
|
case "many":
|
|
9652
9980
|
case "oneOrMore":
|
|
9653
9981
|
case "optional":
|
|
@@ -9676,6 +10004,7 @@ function childrenOf3(def) {
|
|
|
9676
10004
|
case "literal":
|
|
9677
10005
|
case "regex":
|
|
9678
10006
|
case "keywords":
|
|
10007
|
+
case "routed":
|
|
9679
10008
|
case "guard":
|
|
9680
10009
|
case "recover":
|
|
9681
10010
|
case "unknown":
|
|
@@ -9700,6 +10029,20 @@ function repeatOpts(min, max, trailing) {
|
|
|
9700
10029
|
if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
|
|
9701
10030
|
return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
|
|
9702
10031
|
}
|
|
10032
|
+
function projectOpt(project) {
|
|
10033
|
+
if (project === void 0) return void 0;
|
|
10034
|
+
return `project: ${project}`;
|
|
10035
|
+
}
|
|
10036
|
+
function matcherExpr(entry) {
|
|
10037
|
+
switch (entry.kind) {
|
|
10038
|
+
case "startsWith":
|
|
10039
|
+
return `startsWith(${JSON.stringify(entry.value)})`;
|
|
10040
|
+
case "endsWith":
|
|
10041
|
+
return `endsWith(${JSON.stringify(entry.value)})`;
|
|
10042
|
+
case "matches":
|
|
10043
|
+
return `matches(${new RegExp(entry.value, entry.flags ?? "").toString()})`;
|
|
10044
|
+
}
|
|
10045
|
+
}
|
|
9703
10046
|
function serializeRuleMap(ruleMap, scanSkip) {
|
|
9704
10047
|
try {
|
|
9705
10048
|
return new Serializer(ruleMap, scanSkip ?? []).run();
|
|
@@ -9799,7 +10142,11 @@ function evalRuleMapIR(ir) {
|
|
|
9799
10142
|
"choice",
|
|
9800
10143
|
"dispatch",
|
|
9801
10144
|
"when",
|
|
10145
|
+
"startsWith",
|
|
10146
|
+
"endsWith",
|
|
10147
|
+
"matches",
|
|
9802
10148
|
"otherwise",
|
|
10149
|
+
"routed",
|
|
9803
10150
|
"attempt",
|
|
9804
10151
|
"many",
|
|
9805
10152
|
"oneOrMore",
|
|
@@ -9835,7 +10182,11 @@ function evalRuleMapIR(ir) {
|
|
|
9835
10182
|
choice,
|
|
9836
10183
|
dispatch,
|
|
9837
10184
|
when,
|
|
10185
|
+
startsWith,
|
|
10186
|
+
endsWith,
|
|
10187
|
+
matches,
|
|
9838
10188
|
otherwise,
|
|
10189
|
+
routed,
|
|
9839
10190
|
attempt,
|
|
9840
10191
|
many,
|
|
9841
10192
|
oneOrMore,
|
|
@@ -10023,8 +10374,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10023
10374
|
}
|
|
10024
10375
|
case "dispatch": {
|
|
10025
10376
|
const arms = def.cases.map(
|
|
10026
|
-
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
10377
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`
|
|
10027
10378
|
);
|
|
10379
|
+
if (def.matchers) {
|
|
10380
|
+
for (const entry of def.matchers) {
|
|
10381
|
+
arms.push(`when(${matcherExpr(entry)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`);
|
|
10382
|
+
}
|
|
10383
|
+
}
|
|
10028
10384
|
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10029
10385
|
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10030
10386
|
}
|
|
@@ -10044,6 +10400,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10044
10400
|
return `not(${kid(def.parser)})`;
|
|
10045
10401
|
case "peek":
|
|
10046
10402
|
return `peek(${kid(def.parser)})`;
|
|
10403
|
+
case "routed":
|
|
10404
|
+
return "routed()";
|
|
10047
10405
|
case "trivia":
|
|
10048
10406
|
return `trivia(${kid(def.parser)})`;
|
|
10049
10407
|
case "token":
|
|
@@ -10068,9 +10426,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
10068
10426
|
}
|
|
10069
10427
|
case "node": {
|
|
10070
10428
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
10429
|
+
const projectEntry = projectOpt(def.project);
|
|
10071
10430
|
const optEntries = [
|
|
10072
10431
|
...def.unwrap ? ["unwrap: true"] : [],
|
|
10073
10432
|
...def.collapse ? ["collapse: true"] : [],
|
|
10433
|
+
...projectEntry === void 0 ? [] : [projectEntry],
|
|
10074
10434
|
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
10075
10435
|
...def.trailingTrivia ? ["trailingTrivia: true"] : []
|
|
10076
10436
|
];
|
|
@@ -10513,6 +10873,9 @@ function stripTsFromSource(node2, code) {
|
|
|
10513
10873
|
function isWordFactory(v2) {
|
|
10514
10874
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
10515
10875
|
}
|
|
10876
|
+
function isWhenFactory(v2) {
|
|
10877
|
+
return !!v2 && typeof v2 === "object" && v2.tag === "whenFactory";
|
|
10878
|
+
}
|
|
10516
10879
|
function isStaticValueEntry(v2) {
|
|
10517
10880
|
return !!v2 && typeof v2 === "object" && "value" in v2 && "mfSrcs" in v2;
|
|
10518
10881
|
}
|
|
@@ -10535,6 +10898,23 @@ function wordFactoryFromArgs(args, scope, code, mfs) {
|
|
|
10535
10898
|
if (typeof caseInsensitive !== "boolean") return null;
|
|
10536
10899
|
return { tag: "wordFactory", boundary: "_0-9A-Za-z", caseInsensitive };
|
|
10537
10900
|
}
|
|
10901
|
+
function dispatchWhenOptions(v2) {
|
|
10902
|
+
if (v2 === void 0) return {};
|
|
10903
|
+
if (typeof v2 !== "object" || v2 === null || Array.isArray(v2)) return null;
|
|
10904
|
+
for (const key of Object.keys(v2)) {
|
|
10905
|
+
if (key !== "caseInsensitive") return null;
|
|
10906
|
+
}
|
|
10907
|
+
const caseInsensitive = "caseInsensitive" in v2 ? v2.caseInsensitive : false;
|
|
10908
|
+
if (typeof caseInsensitive !== "boolean") return null;
|
|
10909
|
+
return { caseInsensitive };
|
|
10910
|
+
}
|
|
10911
|
+
function whenFactoryFromArgs(args, scope, code, mfs) {
|
|
10912
|
+
const [optsArg, extra] = args;
|
|
10913
|
+
if (optsArg?.type === "SpreadElement" || extra !== void 0) return null;
|
|
10914
|
+
const rawOpts = optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs);
|
|
10915
|
+
const opts = dispatchWhenOptions(rawOpts);
|
|
10916
|
+
return opts === null ? null : { tag: "whenFactory", caseInsensitive: opts.caseInsensitive ?? false };
|
|
10917
|
+
}
|
|
10538
10918
|
var SUPPORTED = {
|
|
10539
10919
|
literal: (...a) => literal(a[0], a[1]),
|
|
10540
10920
|
regex: (...a) => regex(a[0], a[1]),
|
|
@@ -10550,6 +10930,7 @@ var SUPPORTED = {
|
|
|
10550
10930
|
field: (...a) => field(a[0], a[1]),
|
|
10551
10931
|
noTrivia: (...a) => noTrivia(a[0]),
|
|
10552
10932
|
token: (...a) => token(a[0]),
|
|
10933
|
+
routed: () => routed(),
|
|
10553
10934
|
leaf: (...a) => leaf(a[0], a[1]),
|
|
10554
10935
|
expect: (...a) => expect(a[0], a[1])
|
|
10555
10936
|
};
|
|
@@ -10593,6 +10974,18 @@ function dispatchArmValue(node2, scope, code, mfs) {
|
|
|
10593
10974
|
if (node2.type !== "CallExpression") return null;
|
|
10594
10975
|
const callee = node2.callee;
|
|
10595
10976
|
if (callee.type !== "Identifier") return null;
|
|
10977
|
+
const factory = scope.get(callee.name);
|
|
10978
|
+
if (isWhenFactory(factory)) {
|
|
10979
|
+
const [keyArg, parserArg, extraArg] = node2.arguments;
|
|
10980
|
+
if (!keyArg || !parserArg || extraArg !== void 0 || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
10981
|
+
const key = anyValue(keyArg, scope, code, mfs);
|
|
10982
|
+
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
10983
|
+
if (!isCombinator(parserValue)) return null;
|
|
10984
|
+
const opts = { caseInsensitive: factory.caseInsensitive };
|
|
10985
|
+
if (typeof key === "string") return when(key, parserValue, opts);
|
|
10986
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
|
|
10987
|
+
return null;
|
|
10988
|
+
}
|
|
10596
10989
|
if (callee.name === "otherwise") {
|
|
10597
10990
|
const [parserArg] = node2.arguments;
|
|
10598
10991
|
if (!parserArg || parserArg.type === "SpreadElement") return null;
|
|
@@ -10601,13 +10994,16 @@ function dispatchArmValue(node2, scope, code, mfs) {
|
|
|
10601
10994
|
return otherwise(parserValue);
|
|
10602
10995
|
}
|
|
10603
10996
|
if (callee.name === "when") {
|
|
10604
|
-
const [keyArg, parserArg] = node2.arguments;
|
|
10605
|
-
if (!keyArg || !parserArg || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
10997
|
+
const [keyArg, parserArg, optsArg] = node2.arguments;
|
|
10998
|
+
if (!keyArg || !parserArg || keyArg.type === "SpreadElement" || parserArg.type === "SpreadElement" || optsArg?.type === "SpreadElement") return null;
|
|
10606
10999
|
const key = anyValue(keyArg, scope, code, mfs);
|
|
10607
11000
|
const parserValue = anyValue(parserArg, scope, code, mfs);
|
|
11001
|
+
const opts = dispatchWhenOptions(optsArg === void 0 ? void 0 : anyValue(optsArg, scope, code, mfs));
|
|
11002
|
+
if (opts === null) return null;
|
|
10608
11003
|
if (!isCombinator(parserValue)) return null;
|
|
10609
|
-
if (typeof key === "string") return when(key, parserValue);
|
|
10610
|
-
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue);
|
|
11004
|
+
if (typeof key === "string") return when(key, parserValue, opts);
|
|
11005
|
+
if (Array.isArray(key) && key.every((item) => typeof item === "string")) return when(key, parserValue, opts);
|
|
11006
|
+
if (isDispatchMatcher(key)) return when(key, parserValue, opts);
|
|
10611
11007
|
}
|
|
10612
11008
|
return null;
|
|
10613
11009
|
}
|
|
@@ -10618,7 +11014,16 @@ function isDispatchArm(v2) {
|
|
|
10618
11014
|
if (!v2 || typeof v2 !== "object") return false;
|
|
10619
11015
|
const rec = v2;
|
|
10620
11016
|
if (rec.kind === "otherwise") return isCombinator(rec.parser);
|
|
10621
|
-
|
|
11017
|
+
if (rec.kind === "whenMatcher") {
|
|
11018
|
+
return isDispatchMatcher(rec.matcher) && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
|
|
11019
|
+
}
|
|
11020
|
+
return rec.kind === "when" && Array.isArray(rec.keys) && rec.keys.every((key) => typeof key === "string") && typeof rec.caseInsensitive === "boolean" && isCombinator(rec.parser);
|
|
11021
|
+
}
|
|
11022
|
+
function isDispatchMatcher(v2) {
|
|
11023
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
11024
|
+
const rec = v2;
|
|
11025
|
+
if ((rec.kind === "startsWith" || rec.kind === "endsWith") && typeof rec.value === "string") return true;
|
|
11026
|
+
return rec.kind === "matches" && typeof rec.value === "string" && typeof rec.flags === "string";
|
|
10622
11027
|
}
|
|
10623
11028
|
function scopeGet(scope, name, mfs) {
|
|
10624
11029
|
const entry = scope.get(name);
|
|
@@ -10630,6 +11035,18 @@ function scopeGet(scope, name, mfs) {
|
|
|
10630
11035
|
if (isCombinator(entry)) return entry;
|
|
10631
11036
|
return null;
|
|
10632
11037
|
}
|
|
11038
|
+
function staticLiteralValue(expr) {
|
|
11039
|
+
const val = expr;
|
|
11040
|
+
return val.type === "Literal" || val.type === "BooleanLiteral" || val.type === "NumericLiteral" ? val.value : void 0;
|
|
11041
|
+
}
|
|
11042
|
+
function staticNodeProject(expr) {
|
|
11043
|
+
const literalValue = staticLiteralValue(expr);
|
|
11044
|
+
if (typeof literalValue === "number" && Number.isInteger(literalValue) && literalValue >= 0) {
|
|
11045
|
+
return { ok: true, value: literalValue };
|
|
11046
|
+
}
|
|
11047
|
+
if (typeof literalValue === "number" || literalValue !== void 0) return { ok: false };
|
|
11048
|
+
return { ok: false };
|
|
11049
|
+
}
|
|
10633
11050
|
function staticNodeOptions(expr) {
|
|
10634
11051
|
if (expr.type !== "ObjectExpression") return void 0;
|
|
10635
11052
|
const opts = {};
|
|
@@ -10639,11 +11056,14 @@ function staticNodeOptions(expr) {
|
|
|
10639
11056
|
const key = p.key;
|
|
10640
11057
|
const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? String(key.value) : void 0;
|
|
10641
11058
|
if (name === "unwrap" || name === "collapse" || name === "captureTrivia" || name === "trailingTrivia") {
|
|
10642
|
-
|
|
10643
|
-
|
|
11059
|
+
if (staticLiteralValue(p.value) === true) opts[name] = true;
|
|
11060
|
+
} else if (name === "project") {
|
|
11061
|
+
const project = staticNodeProject(p.value);
|
|
11062
|
+
if (project?.ok === false) return { project: -1 };
|
|
11063
|
+
if (project !== void 0) opts.project = project.value;
|
|
10644
11064
|
}
|
|
10645
11065
|
}
|
|
10646
|
-
return opts.unwrap || opts.collapse || opts.captureTrivia || opts.trailingTrivia ? opts : void 0;
|
|
11066
|
+
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia ? opts : void 0;
|
|
10647
11067
|
}
|
|
10648
11068
|
function exprToCombi(node2, scope, code, mfs) {
|
|
10649
11069
|
if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
|
|
@@ -10718,9 +11138,10 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
10718
11138
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
10719
11139
|
if (!isCombinator(inner)) return null;
|
|
10720
11140
|
const be = buildArg;
|
|
10721
|
-
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !(be.type === "Identifier" && be.name === "undefined");
|
|
11141
|
+
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && be.type !== "ObjectExpression" && !(be.type === "Identifier" && be.name === "undefined");
|
|
10722
11142
|
const buildSrc = hasBuild ? stripTsFromSource(be, code) : void 0;
|
|
10723
|
-
const
|
|
11143
|
+
const optionsArg = hasBuild ? optsArg : be?.type === "ObjectExpression" ? buildArg : optsArg;
|
|
11144
|
+
const opts = optionsArg !== void 0 && optionsArg.type !== "SpreadElement" ? staticNodeOptions(optionsArg) : void 0;
|
|
10724
11145
|
try {
|
|
10725
11146
|
const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
|
|
10726
11147
|
if (combi._def.tag === "node" && buildSrc !== void 0) {
|
|
@@ -11004,9 +11425,27 @@ function anyValue(node2, scope, code, mfs) {
|
|
|
11004
11425
|
if (callee.type === "Identifier" && callee.name === "makeWord") {
|
|
11005
11426
|
return wordFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
11006
11427
|
}
|
|
11428
|
+
if (callee.type === "Identifier" && callee.name === "makeWhen") {
|
|
11429
|
+
return whenFactoryFromArgs(node2.arguments, scope, code, mfs);
|
|
11430
|
+
}
|
|
11431
|
+
if (callee.type === "Identifier" && (callee.name === "startsWith" || callee.name === "endsWith")) {
|
|
11432
|
+
if (node2.arguments.length !== 1 || node2.arguments[0]?.type === "SpreadElement") return null;
|
|
11433
|
+
const value = anyValue(node2.arguments[0], scope, code, mfs);
|
|
11434
|
+
if (typeof value !== "string") return null;
|
|
11435
|
+
return callee.name === "startsWith" ? startsWith(value) : endsWith(value);
|
|
11436
|
+
}
|
|
11437
|
+
if (callee.type === "Identifier" && callee.name === "matches") {
|
|
11438
|
+
if (node2.arguments.length !== 1 || node2.arguments[0]?.type === "SpreadElement") return null;
|
|
11439
|
+
const value = anyValue(node2.arguments[0], scope, code, mfs);
|
|
11440
|
+
if (!(value instanceof RegExp)) return null;
|
|
11441
|
+
return matches(value);
|
|
11442
|
+
}
|
|
11007
11443
|
if (callee.type === "Identifier" && (callee.name === "when" || callee.name === "otherwise")) {
|
|
11008
11444
|
return dispatchArmValue(node2, scope, code, mfs);
|
|
11009
11445
|
}
|
|
11446
|
+
if (callee.type === "Identifier" && isWhenFactory(scope.get(callee.name))) {
|
|
11447
|
+
return dispatchArmValue(node2, scope, code, mfs);
|
|
11448
|
+
}
|
|
11010
11449
|
return exprToCombi(node2, scope, code, mfs);
|
|
11011
11450
|
}
|
|
11012
11451
|
return null;
|
|
@@ -11017,6 +11456,12 @@ function evaluateWordFactory(node2, scope, code) {
|
|
|
11017
11456
|
if (callee.type !== "Identifier" || callee.name !== "makeWord") return null;
|
|
11018
11457
|
return wordFactoryFromArgs(node2.arguments, scope, code);
|
|
11019
11458
|
}
|
|
11459
|
+
function evaluateWhenFactory(node2, scope, code) {
|
|
11460
|
+
if (node2.type !== "CallExpression") return null;
|
|
11461
|
+
const callee = node2.callee;
|
|
11462
|
+
if (callee.type !== "Identifier" || callee.name !== "makeWhen") return null;
|
|
11463
|
+
return whenFactoryFromArgs(node2.arguments, scope, code);
|
|
11464
|
+
}
|
|
11020
11465
|
function evaluateExpr(node2, scope, code, mapFnSources) {
|
|
11021
11466
|
return exprToCombi(node2, scope, code, mapFnSources);
|
|
11022
11467
|
}
|
|
@@ -11597,7 +12042,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
11597
12042
|
for (const match of source.matchAll(/id:\s*"([^"]+)"/g)) ids.add(match[1]);
|
|
11598
12043
|
return [...ids].sort().map((id2) => ({
|
|
11599
12044
|
id: id2,
|
|
11600
|
-
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : "choice-arm"
|
|
12045
|
+
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : id2.startsWith("dispatch:") ? "dispatch-arm" : "choice-arm"
|
|
11601
12046
|
}));
|
|
11602
12047
|
};
|
|
11603
12048
|
const localComposedCarried = /* @__PURE__ */ new Map();
|
|
@@ -12043,6 +12488,14 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
12043
12488
|
if (wordFactory) {
|
|
12044
12489
|
;
|
|
12045
12490
|
scope.set(varName, wordFactory);
|
|
12491
|
+
replacements.push({ start: init.start, end: init.end, replacement: "undefined" });
|
|
12492
|
+
continue;
|
|
12493
|
+
}
|
|
12494
|
+
const whenFactory = evaluateWhenFactory(init, scope, code);
|
|
12495
|
+
if (whenFactory) {
|
|
12496
|
+
;
|
|
12497
|
+
scope.set(varName, whenFactory);
|
|
12498
|
+
replacements.push({ start: init.start, end: init.end, replacement: "undefined" });
|
|
12046
12499
|
continue;
|
|
12047
12500
|
}
|
|
12048
12501
|
const combiArray = evaluateCombinatorArray(init, scope, code);
|