parseman 0.39.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +36 -3
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +15 -0
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts +2 -1
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/index.cjs +483 -61
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +483 -61
- package/dist/index.js.map +3 -3
- package/dist/plugin/evaluator.d.ts +6 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +520 -67
- package/dist/plugin/index.cjs.map +3 -3
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +520 -67
- package/dist/plugin/index.js.map +3 -3
- package/dist/spec/index.cjs +234 -26
- package/dist/spec/index.cjs.map +3 -3
- package/dist/spec/index.js +234 -26
- package/dist/spec/index.js.map +3 -3
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -51,6 +51,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
51
51
|
return d.value.length === 0;
|
|
52
52
|
case "keywords":
|
|
53
53
|
return false;
|
|
54
|
+
case "routed":
|
|
55
|
+
return false;
|
|
54
56
|
case "regex":
|
|
55
57
|
try {
|
|
56
58
|
const m = new RegExp(d.source).exec("");
|
|
@@ -1112,6 +1114,8 @@ function derive(c, seen) {
|
|
|
1112
1114
|
case "not":
|
|
1113
1115
|
case "peek":
|
|
1114
1116
|
return deriveExpected2(def.parser);
|
|
1117
|
+
case "routed":
|
|
1118
|
+
return ["routed()"];
|
|
1115
1119
|
case "lazy": {
|
|
1116
1120
|
const name = c._ruleName;
|
|
1117
1121
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -1936,42 +1940,198 @@ function sequence(...parsers) {
|
|
|
1936
1940
|
}
|
|
1937
1941
|
|
|
1938
1942
|
// src/combinators/dispatch.ts
|
|
1939
|
-
function
|
|
1943
|
+
function parserUsesRouted(parser2, seen = /* @__PURE__ */ new Set()) {
|
|
1944
|
+
if (seen.has(parser2)) return false;
|
|
1945
|
+
seen.add(parser2);
|
|
1946
|
+
const def = parser2._def;
|
|
1947
|
+
switch (def.tag) {
|
|
1948
|
+
case "routed":
|
|
1949
|
+
return true;
|
|
1950
|
+
case "sequence":
|
|
1951
|
+
case "choice":
|
|
1952
|
+
return def.parsers.some((entry) => parserUsesRouted(entry, seen));
|
|
1953
|
+
case "dispatch":
|
|
1954
|
+
return false;
|
|
1955
|
+
case "sepBy":
|
|
1956
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.separator, seen);
|
|
1957
|
+
case "skip":
|
|
1958
|
+
return parserUsesRouted(def.main, seen) || parserUsesRouted(def.skipped, seen);
|
|
1959
|
+
case "grammar":
|
|
1960
|
+
return parserUsesRouted(def.parser, seen) || (def.triviaParser ? parserUsesRouted(def.triviaParser, seen) : false);
|
|
1961
|
+
case "scanTo":
|
|
1962
|
+
return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen));
|
|
1963
|
+
case "recover":
|
|
1964
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.sentinel, seen);
|
|
1965
|
+
case "lazy":
|
|
1966
|
+
try {
|
|
1967
|
+
return parserUsesRouted(def.thunk(), seen);
|
|
1968
|
+
} catch {
|
|
1969
|
+
return false;
|
|
1970
|
+
}
|
|
1971
|
+
case "many":
|
|
1972
|
+
case "oneOrMore":
|
|
1973
|
+
case "optional":
|
|
1974
|
+
case "attempt":
|
|
1975
|
+
case "transform":
|
|
1976
|
+
case "trivia":
|
|
1977
|
+
case "token":
|
|
1978
|
+
case "leaf":
|
|
1979
|
+
case "label":
|
|
1980
|
+
case "field":
|
|
1981
|
+
case "not":
|
|
1982
|
+
case "peek":
|
|
1983
|
+
case "node":
|
|
1984
|
+
case "withCtx":
|
|
1985
|
+
case "expect":
|
|
1986
|
+
return parserUsesRouted(def.parser, seen);
|
|
1987
|
+
default:
|
|
1988
|
+
return false;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
function branchUsesRouted(branch) {
|
|
1992
|
+
return branch.usesRouted === true || parserUsesRouted(branch.parser);
|
|
1993
|
+
}
|
|
1994
|
+
function asciiFoldKey(key) {
|
|
1995
|
+
let out = "";
|
|
1996
|
+
for (let i = 0; i < key.length; i++) {
|
|
1997
|
+
const c = key.charCodeAt(i);
|
|
1998
|
+
out += String.fromCharCode(c >= 65 && c <= 90 ? c + 32 : c);
|
|
1999
|
+
}
|
|
2000
|
+
return out;
|
|
2001
|
+
}
|
|
2002
|
+
function matchesDispatchMatcher(value, matcher) {
|
|
2003
|
+
const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
|
|
2004
|
+
const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
|
|
2005
|
+
switch (matcher.kind) {
|
|
2006
|
+
case "startsWith":
|
|
2007
|
+
return candidate.startsWith(expected);
|
|
2008
|
+
case "endsWith":
|
|
2009
|
+
return candidate.endsWith(expected);
|
|
2010
|
+
case "matches": {
|
|
2011
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
2012
|
+
return new RegExp(matcher.value, flags).test(value);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
function isStringMatcher(value) {
|
|
2017
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2018
|
+
const kind = value.kind;
|
|
2019
|
+
return kind === "startsWith" || kind === "endsWith" || kind === "matches";
|
|
2020
|
+
}
|
|
2021
|
+
function fixedMatcher(kind, value) {
|
|
2022
|
+
if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
|
|
2023
|
+
if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
|
|
2024
|
+
return { kind, value };
|
|
2025
|
+
}
|
|
2026
|
+
function startsWith(prefix) {
|
|
2027
|
+
return fixedMatcher("startsWith", prefix);
|
|
2028
|
+
}
|
|
2029
|
+
function endsWith(suffix) {
|
|
2030
|
+
return fixedMatcher("endsWith", suffix);
|
|
2031
|
+
}
|
|
2032
|
+
function matches(pattern) {
|
|
2033
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
|
|
2034
|
+
if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
|
|
2035
|
+
throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
|
|
2036
|
+
}
|
|
2037
|
+
return { kind: "matches", value: pattern.source, flags: pattern.flags };
|
|
2038
|
+
}
|
|
2039
|
+
function when(key, parser2, opts = {}) {
|
|
2040
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
2041
|
+
if (isStringMatcher(key)) {
|
|
2042
|
+
return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2043
|
+
}
|
|
1940
2044
|
const keys = Array.isArray(key) ? [...key] : [key];
|
|
1941
2045
|
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
1942
2046
|
for (const item of keys) {
|
|
1943
2047
|
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
1944
2048
|
}
|
|
1945
|
-
return { kind: "when", keys, parser: parser2 };
|
|
2049
|
+
return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2050
|
+
}
|
|
2051
|
+
function makeWhen(opts = {}) {
|
|
2052
|
+
return (key, parser2) => when(key, parser2, opts);
|
|
1946
2053
|
}
|
|
1947
2054
|
function otherwise(parser2) {
|
|
1948
|
-
return { kind: "otherwise", parser: parser2 };
|
|
2055
|
+
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2056
|
+
}
|
|
2057
|
+
function routed() {
|
|
2058
|
+
return {
|
|
2059
|
+
_tag: "routed",
|
|
2060
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
2061
|
+
_def: { tag: "routed" },
|
|
2062
|
+
parse(_input, pos, ctx) {
|
|
2063
|
+
const item = ctx._routed;
|
|
2064
|
+
if (item === void 0) {
|
|
2065
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2066
|
+
}
|
|
2067
|
+
if (pos !== item.span.start) {
|
|
2068
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2069
|
+
}
|
|
2070
|
+
if (cstCaptureActive(ctx)) {
|
|
2071
|
+
pushCstLeaf(ctx, { _tag: "leaf", value: item.value, span: item.span });
|
|
2072
|
+
}
|
|
2073
|
+
return { ok: true, value: item.value, span: item.span };
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
1949
2076
|
}
|
|
1950
2077
|
function dispatch(selector, ...arms) {
|
|
2078
|
+
if (parserUsesRouted(selector)) {
|
|
2079
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2080
|
+
}
|
|
1951
2081
|
let fallback;
|
|
2082
|
+
let fallbackUsesRouted = false;
|
|
2083
|
+
const matchers = [];
|
|
1952
2084
|
const cases = [];
|
|
1953
|
-
const seen =
|
|
2085
|
+
const seen = [];
|
|
1954
2086
|
for (let i = 0; i < arms.length; i++) {
|
|
1955
2087
|
const arm = arms[i];
|
|
1956
2088
|
if (arm.kind === "otherwise") {
|
|
1957
2089
|
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
1958
2090
|
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
1959
2091
|
fallback = arm.parser;
|
|
2092
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
1960
2093
|
continue;
|
|
1961
2094
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2095
|
+
if (arm.kind === "whenMatcher") {
|
|
2096
|
+
const matcher = arm.matcher;
|
|
2097
|
+
matchers.push({
|
|
2098
|
+
kind: matcher.kind,
|
|
2099
|
+
value: matcher.value,
|
|
2100
|
+
...matcher.kind === "matches" ? { flags: matcher.flags } : {},
|
|
2101
|
+
parser: arm.parser,
|
|
2102
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2103
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2104
|
+
});
|
|
2105
|
+
continue;
|
|
1965
2106
|
}
|
|
1966
|
-
|
|
2107
|
+
for (const key of arm.keys) {
|
|
2108
|
+
const folded = asciiFoldKey(key);
|
|
2109
|
+
for (const prior of seen) {
|
|
2110
|
+
const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
|
|
2111
|
+
if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2112
|
+
}
|
|
2113
|
+
seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
|
|
2114
|
+
}
|
|
2115
|
+
cases.push({
|
|
2116
|
+
keys: arm.keys,
|
|
2117
|
+
parser: arm.parser,
|
|
2118
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2119
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2120
|
+
});
|
|
1967
2121
|
}
|
|
1968
2122
|
const meta = {
|
|
1969
2123
|
firstSet: selector._meta.firstSet,
|
|
1970
|
-
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2124
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
1971
2125
|
isTrivia: false
|
|
1972
2126
|
};
|
|
1973
2127
|
const byKey = /* @__PURE__ */ new Map();
|
|
1974
|
-
|
|
2128
|
+
const byFoldedKey = /* @__PURE__ */ new Map();
|
|
2129
|
+
for (const entry of cases) {
|
|
2130
|
+
for (const key of entry.keys) {
|
|
2131
|
+
if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
|
|
2132
|
+
else byKey.set(key, entry);
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
1975
2135
|
return {
|
|
1976
2136
|
_tag: "dispatch",
|
|
1977
2137
|
_meta: meta,
|
|
@@ -1979,18 +2139,35 @@ function dispatch(selector, ...arms) {
|
|
|
1979
2139
|
tag: "dispatch",
|
|
1980
2140
|
selector,
|
|
1981
2141
|
cases,
|
|
1982
|
-
...
|
|
2142
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2143
|
+
...fallback === void 0 ? {} : { otherwise: fallback, ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {} }
|
|
1983
2144
|
},
|
|
1984
2145
|
parse(input, pos, ctx) {
|
|
2146
|
+
if (parserUsesRouted(selector)) {
|
|
2147
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2148
|
+
}
|
|
2149
|
+
const selectorMark = saveTriviaMark(ctx);
|
|
1985
2150
|
const selected = selector.parse(input, pos, ctx);
|
|
1986
2151
|
if (!selected.ok) return selected;
|
|
1987
|
-
const
|
|
1988
|
-
if (
|
|
2152
|
+
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 });
|
|
2153
|
+
if (branch === void 0) {
|
|
1989
2154
|
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
1990
2155
|
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
1991
2156
|
}
|
|
1992
|
-
const
|
|
1993
|
-
const
|
|
2157
|
+
const savedRouted = ctx._routed;
|
|
2158
|
+
const usesRouted = branchUsesRouted(branch);
|
|
2159
|
+
let mark = saveTriviaMark(ctx);
|
|
2160
|
+
if (usesRouted) {
|
|
2161
|
+
rollbackTrivia(ctx, selectorMark);
|
|
2162
|
+
mark = saveTriviaMark(ctx);
|
|
2163
|
+
ctx._routed = { value: selected.value, span: selected.span };
|
|
2164
|
+
}
|
|
2165
|
+
let result;
|
|
2166
|
+
try {
|
|
2167
|
+
result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
|
|
2168
|
+
} finally {
|
|
2169
|
+
if (usesRouted) ctx._routed = savedRouted;
|
|
2170
|
+
}
|
|
1994
2171
|
if (!result.ok) {
|
|
1995
2172
|
rollbackTrivia(ctx, mark);
|
|
1996
2173
|
return { ...result, committed: true };
|
|
@@ -2377,6 +2554,7 @@ function markUnusedValues(root) {
|
|
|
2377
2554
|
case "dispatch":
|
|
2378
2555
|
visit(def.selector, consumed);
|
|
2379
2556
|
for (const entry of def.cases) visit(entry.parser, consumed);
|
|
2557
|
+
if (def.matchers) for (const entry of def.matchers) visit(entry.parser, consumed);
|
|
2380
2558
|
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2381
2559
|
return;
|
|
2382
2560
|
case "node":
|
|
@@ -2655,7 +2833,7 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2655
2833
|
case "choice":
|
|
2656
2834
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2657
2835
|
case "dispatch":
|
|
2658
|
-
return parserHasOwnFields(d.selector, seen) || d.cases.some((x) => parserHasOwnFields(x.parser, seen)) || (d.otherwise ? parserHasOwnFields(d.otherwise, seen) : false);
|
|
2836
|
+
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);
|
|
2659
2837
|
case "sepBy":
|
|
2660
2838
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2661
2839
|
case "skip":
|
|
@@ -2724,7 +2902,7 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2724
2902
|
case "choice":
|
|
2725
2903
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2726
2904
|
case "dispatch":
|
|
2727
|
-
return parserHasTriviaSite(d.selector, seen) || d.cases.some((x) => parserHasTriviaSite(x.parser, seen)) || (d.otherwise ? parserHasTriviaSite(d.otherwise, seen) : false);
|
|
2905
|
+
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);
|
|
2728
2906
|
case "grammar":
|
|
2729
2907
|
return parserHasTriviaSite(d.parser, seen);
|
|
2730
2908
|
case "lazy": {
|
|
@@ -2751,7 +2929,7 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2751
2929
|
case "choice":
|
|
2752
2930
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2753
2931
|
case "dispatch":
|
|
2754
|
-
return parserEnablesTriviaCapture(d.selector, seen) || d.cases.some((x) => parserEnablesTriviaCapture(x.parser, seen)) || (d.otherwise ? parserEnablesTriviaCapture(d.otherwise, seen) : false);
|
|
2932
|
+
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);
|
|
2755
2933
|
case "sepBy":
|
|
2756
2934
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2757
2935
|
case "skip":
|
|
@@ -2812,12 +2990,30 @@ function isCstChild(value) {
|
|
|
2812
2990
|
function missingInferredType() {
|
|
2813
2991
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
2814
2992
|
}
|
|
2993
|
+
function normalizeProject(project) {
|
|
2994
|
+
if (project === void 0) return void 0;
|
|
2995
|
+
if (!Number.isInteger(project) || project < 0) {
|
|
2996
|
+
throw new Error("node() project child must be a non-negative integer");
|
|
2997
|
+
}
|
|
2998
|
+
return project;
|
|
2999
|
+
}
|
|
3000
|
+
function projectChild(children2, project, type) {
|
|
3001
|
+
if (!(project in children2)) {
|
|
3002
|
+
throw new Error(`node(${JSON.stringify(type)}) project child ${project} was not captured`);
|
|
3003
|
+
}
|
|
3004
|
+
return unwrapChild(children2[project]);
|
|
3005
|
+
}
|
|
2815
3006
|
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
2816
3007
|
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
2817
3008
|
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
2818
3009
|
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
2819
|
-
const
|
|
2820
|
-
const
|
|
3010
|
+
const buildArg = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
3011
|
+
const build = typeof buildArg === "function" ? buildArg : void 0;
|
|
3012
|
+
const opts = typeof buildArg === "function" ? maybeOpts : buildArg ?? maybeOpts;
|
|
3013
|
+
const project = normalizeProject(opts?.project);
|
|
3014
|
+
if (project !== void 0 && build !== void 0) {
|
|
3015
|
+
throw new Error("node() options cannot combine project with a build callback");
|
|
3016
|
+
}
|
|
2821
3017
|
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
2822
3018
|
const meta = {
|
|
2823
3019
|
firstSet: combinator._meta.firstSet,
|
|
@@ -2831,11 +3027,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2831
3027
|
if (unwrap && collapse) {
|
|
2832
3028
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
2833
3029
|
}
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
3030
|
+
if (project !== void 0 && (unwrap || collapse)) {
|
|
3031
|
+
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3032
|
+
}
|
|
3033
|
+
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;
|
|
3034
|
+
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3035
|
+
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
2837
3036
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
2838
|
-
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) :
|
|
3037
|
+
const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
2839
3038
|
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
2840
3039
|
let failExpected;
|
|
2841
3040
|
return {
|
|
@@ -2850,14 +3049,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2850
3049
|
}
|
|
2851
3050
|
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
2852
3051
|
}
|
|
2853
|
-
const
|
|
3052
|
+
const hasDirectValue = build !== void 0 || project !== void 0;
|
|
3053
|
+
const hostCst = hasDirectValue && cstOutputHost(ctx.build);
|
|
2854
3054
|
const effTrivia = capturesTrivia || hostCst;
|
|
2855
3055
|
const effFields = capturesFields || hostCst && hasOwnFields;
|
|
2856
3056
|
const saved = beginCstNodeCapture(ctx);
|
|
2857
3057
|
const savedFields = ctx._fields;
|
|
2858
3058
|
ctx._fields = effFields ? [] : void 0;
|
|
2859
3059
|
const savedMask = ctx._triviaCaptureMask;
|
|
2860
|
-
if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
3060
|
+
if (build === void 0 && project === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
2861
3061
|
ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
|
|
2862
3062
|
}
|
|
2863
3063
|
if (!effTrivia) ctx.captureTrivia = false;
|
|
@@ -2875,7 +3075,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2875
3075
|
const nodeType = def.type ?? missingInferredType();
|
|
2876
3076
|
const cstOutput = cstOutputHost(ctx.build);
|
|
2877
3077
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2878
|
-
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 };
|
|
3078
|
+
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 };
|
|
2879
3079
|
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 };
|
|
2880
3080
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2881
3081
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3153,7 +3353,7 @@ function leaf(root, fn) {
|
|
|
3153
3353
|
}
|
|
3154
3354
|
|
|
3155
3355
|
// src/version.ts
|
|
3156
|
-
var PARSEMAN_VERSION = "0.
|
|
3356
|
+
var PARSEMAN_VERSION = "0.40.0";
|
|
3157
3357
|
|
|
3158
3358
|
// src/cst/host-mode.ts
|
|
3159
3359
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3413,6 +3613,7 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3413
3613
|
if (d.tag === "dispatch") {
|
|
3414
3614
|
kids.push(d.selector);
|
|
3415
3615
|
for (const c of d.cases) kids.push(c.parser);
|
|
3616
|
+
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3416
3617
|
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3417
3618
|
}
|
|
3418
3619
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
@@ -4936,13 +5137,25 @@ function escapeClassChar(ch2) {
|
|
|
4936
5137
|
}
|
|
4937
5138
|
|
|
4938
5139
|
// src/compiler/grammar-coverage-ids.ts
|
|
5140
|
+
function idPart(value) {
|
|
5141
|
+
return encodeURIComponent(value);
|
|
5142
|
+
}
|
|
5143
|
+
function dispatchArmIds(def, path) {
|
|
5144
|
+
const ids = [];
|
|
5145
|
+
for (const entry of def.cases) ids.push(`dispatch:${path}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5146
|
+
for (const entry of def.matchers ?? []) {
|
|
5147
|
+
ids.push(`dispatch:${path}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5148
|
+
}
|
|
5149
|
+
if (def.otherwise) ids.push(`dispatch:${path}/otherwise`);
|
|
5150
|
+
return ids;
|
|
5151
|
+
}
|
|
4939
5152
|
function children(def, winners) {
|
|
4940
5153
|
switch (def.tag) {
|
|
4941
5154
|
case "sequence":
|
|
4942
5155
|
case "choice":
|
|
4943
5156
|
return def.parsers;
|
|
4944
5157
|
case "dispatch":
|
|
4945
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
5158
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
4946
5159
|
case "many":
|
|
4947
5160
|
case "oneOrMore":
|
|
4948
5161
|
case "optional":
|
|
@@ -4985,6 +5198,7 @@ function children(def, winners) {
|
|
|
4985
5198
|
function buildGrammarPlan(entry, winners) {
|
|
4986
5199
|
const definitions = /* @__PURE__ */ new Map();
|
|
4987
5200
|
const choices = /* @__PURE__ */ new WeakMap();
|
|
5201
|
+
const dispatches = /* @__PURE__ */ new WeakMap();
|
|
4988
5202
|
const attempts = /* @__PURE__ */ new WeakMap();
|
|
4989
5203
|
const labels = /* @__PURE__ */ new WeakMap();
|
|
4990
5204
|
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -5015,6 +5229,11 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5015
5229
|
choices.set(parser2, ids);
|
|
5016
5230
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
5017
5231
|
}
|
|
5232
|
+
if (parser2._def.tag === "dispatch") {
|
|
5233
|
+
const ids = dispatchArmIds(parser2._def, path);
|
|
5234
|
+
dispatches.set(parser2, ids);
|
|
5235
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5236
|
+
}
|
|
5018
5237
|
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
|
|
5019
5238
|
if (parser2._def.tag === "label") {
|
|
5020
5239
|
const id = `label:${path}`;
|
|
@@ -5027,7 +5246,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5027
5246
|
for (const root of roots) {
|
|
5028
5247
|
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
5029
5248
|
}
|
|
5030
|
-
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
5249
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
|
|
5031
5250
|
}
|
|
5032
5251
|
|
|
5033
5252
|
// src/compiler/scannable-run.ts
|
|
@@ -6401,6 +6620,7 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6401
6620
|
case "literal":
|
|
6402
6621
|
case "regex":
|
|
6403
6622
|
case "keywords":
|
|
6623
|
+
case "routed":
|
|
6404
6624
|
return { alts: [[seg(p._meta.firstSet, matchesEmpty(p))]] };
|
|
6405
6625
|
case "choice": {
|
|
6406
6626
|
const alts = [];
|
|
@@ -6751,7 +6971,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6751
6971
|
case "choice":
|
|
6752
6972
|
return false;
|
|
6753
6973
|
case "dispatch":
|
|
6754
|
-
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);
|
|
6974
|
+
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);
|
|
6755
6975
|
case "attempt":
|
|
6756
6976
|
return false;
|
|
6757
6977
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6850,6 +7070,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6850
7070
|
case "keywords":
|
|
6851
7071
|
case "node":
|
|
6852
7072
|
case "token":
|
|
7073
|
+
case "routed":
|
|
6853
7074
|
case "leaf":
|
|
6854
7075
|
return true;
|
|
6855
7076
|
case "not":
|
|
@@ -6862,7 +7083,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6862
7083
|
case "choice":
|
|
6863
7084
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
6864
7085
|
case "dispatch":
|
|
6865
|
-
return capturesLeaf(d.selector, seen) || d.cases.some((x) => capturesLeaf(x.parser, seen)) || (d.otherwise ? capturesLeaf(d.otherwise, seen) : false);
|
|
7086
|
+
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);
|
|
6866
7087
|
case "sepBy":
|
|
6867
7088
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6868
7089
|
case "many":
|
|
@@ -7340,6 +7561,7 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7340
7561
|
for (const item of d.cases) {
|
|
7341
7562
|
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7342
7563
|
}
|
|
7564
|
+
if (d.matchers?.some((item) => mayRecordRecoveryError(item.parser, recovery, seen))) return true;
|
|
7343
7565
|
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7344
7566
|
}
|
|
7345
7567
|
case "attempt":
|
|
@@ -7374,53 +7596,120 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
|
7374
7596
|
return false;
|
|
7375
7597
|
}
|
|
7376
7598
|
}
|
|
7377
|
-
function emitDispatchCombinator(def, ctx, pos) {
|
|
7599
|
+
function emitDispatchCombinator(parser2, def, ctx, pos) {
|
|
7600
|
+
if (parserUsesRouted2(def.selector)) {
|
|
7601
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
7602
|
+
}
|
|
7603
|
+
const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
|
|
7604
|
+
const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
|
|
7605
|
+
const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
|
|
7606
|
+
const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
|
|
7607
|
+
const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
|
|
7608
|
+
const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
|
|
7609
|
+
const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
|
|
7610
|
+
const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
|
|
7611
|
+
const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
|
|
7378
7612
|
const selector = emit(def.selector, ctx, pos);
|
|
7379
7613
|
const outV = v(ctx, "_dval");
|
|
7380
7614
|
const outE = v(ctx, "_dend");
|
|
7381
7615
|
const keyV = v(ctx, "_dkey");
|
|
7382
7616
|
const stmts = [
|
|
7617
|
+
...selectorLeafMark ? [
|
|
7618
|
+
`${ind(ctx)}const ${selectorLeafMark} = _ctx._cstLeaves?.length ?? 0`,
|
|
7619
|
+
`${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
|
|
7620
|
+
`${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
7621
|
+
`${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
|
|
7622
|
+
`${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
|
|
7623
|
+
`${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
|
|
7624
|
+
] : [],
|
|
7383
7625
|
...selector.stmts,
|
|
7384
7626
|
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7385
7627
|
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7386
7628
|
];
|
|
7387
7629
|
let wroteBranch = false;
|
|
7388
|
-
const emitSelectedTail = (
|
|
7630
|
+
const emitSelectedTail = (entry, keyword, condition, coverageId) => {
|
|
7631
|
+
const parser3 = entry.parser;
|
|
7389
7632
|
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7390
7633
|
stmts.push(head);
|
|
7391
7634
|
ctx.indent++;
|
|
7392
|
-
const
|
|
7635
|
+
const usesRouted = branchUsesRouted2(entry);
|
|
7636
|
+
const routedV = usesRouted ? v(ctx, "_drt") : null;
|
|
7637
|
+
const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
|
|
7393
7638
|
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7394
7639
|
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7640
|
+
if (routedV) {
|
|
7641
|
+
stmts.push(
|
|
7642
|
+
`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
|
|
7643
|
+
...selectorLeafMark ? [
|
|
7644
|
+
`${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}`
|
|
7645
|
+
] : []
|
|
7646
|
+
);
|
|
7647
|
+
}
|
|
7395
7648
|
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7396
7649
|
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7397
|
-
const tail = emitTailFallible(
|
|
7650
|
+
const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
|
|
7651
|
+
stmts.push(...coverageAttempt(ctx, coverageId, pos));
|
|
7398
7652
|
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7399
7653
|
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7654
|
+
const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
|
|
7655
|
+
const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
|
|
7400
7656
|
stmts.push(
|
|
7401
7657
|
...tail.stmts,
|
|
7402
|
-
`${ind(ctx)}if (!${tail.okVar}) { ${errorRollback}${logRollback}${committedFailBody(ctx)} }`,
|
|
7658
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
|
|
7659
|
+
...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
|
|
7403
7660
|
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7404
|
-
`${ind(ctx)}${outE} = ${tail.endVar}
|
|
7661
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`,
|
|
7662
|
+
...coverageHit(ctx, coverageId, pos, tail.endVar)
|
|
7405
7663
|
);
|
|
7406
7664
|
ctx.indent--;
|
|
7407
7665
|
stmts.push(`${ind(ctx)}}`);
|
|
7408
7666
|
};
|
|
7667
|
+
let coverageIndex = 0;
|
|
7409
7668
|
for (const entry of def.cases) {
|
|
7410
|
-
const condition = entry.keys.map((key) =>
|
|
7411
|
-
emitSelectedTail(entry
|
|
7669
|
+
const condition = entry.keys.map((key) => emitDispatchKeyCondition(keyV, key, entry.caseInsensitive)).join(" || ");
|
|
7670
|
+
emitSelectedTail(entry, wroteBranch ? "else if" : "if", condition, coverageIds[coverageIndex++]);
|
|
7412
7671
|
wroteBranch = true;
|
|
7413
7672
|
}
|
|
7673
|
+
const emitMatcherTails = () => {
|
|
7674
|
+
for (const matcher of def.matchers ?? []) {
|
|
7675
|
+
emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
|
|
7676
|
+
wroteBranch = true;
|
|
7677
|
+
}
|
|
7678
|
+
};
|
|
7414
7679
|
if (def.otherwise) {
|
|
7415
|
-
|
|
7416
|
-
|
|
7680
|
+
emitMatcherTails();
|
|
7681
|
+
const otherwiseEntry = { parser: def.otherwise, usesRouted: def.otherwiseUsesRouted };
|
|
7682
|
+
if (wroteBranch) emitSelectedTail(otherwiseEntry, "else", void 0, coverageIds[coverageIndex++]);
|
|
7683
|
+
else emitSelectedTail(otherwiseEntry, "if", "true", coverageIds[coverageIndex++]);
|
|
7417
7684
|
} else {
|
|
7685
|
+
emitMatcherTails();
|
|
7418
7686
|
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7419
7687
|
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7420
7688
|
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7421
7689
|
}
|
|
7422
7690
|
return { stmts, valueVar: outV, endVar: outE };
|
|
7423
7691
|
}
|
|
7692
|
+
function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
|
|
7693
|
+
if (!caseInsensitive) return `${valueVar} === ${JSON.stringify(key)}`;
|
|
7694
|
+
const parts = [`${valueVar}.length === ${key.length}`];
|
|
7695
|
+
for (let i = 0; i < key.length; i++) {
|
|
7696
|
+
parts.push(foldEq(`${valueVar}.charCodeAt(${i})`, key.charCodeAt(i)));
|
|
7697
|
+
}
|
|
7698
|
+
return parts.join(" && ");
|
|
7699
|
+
}
|
|
7700
|
+
function emitDispatchMatcherCondition(valueVar, matcher) {
|
|
7701
|
+
if (matcher.kind === "matches") {
|
|
7702
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
7703
|
+
return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
|
|
7704
|
+
}
|
|
7705
|
+
const text = matcher.value;
|
|
7706
|
+
const parts = [`${valueVar}.length >= ${text.length}`];
|
|
7707
|
+
const offset = matcher.kind === "endsWith" ? `${valueVar}.length - ${text.length}` : "0";
|
|
7708
|
+
for (let i = 0; i < text.length; i++) {
|
|
7709
|
+
parts.push(matcher.caseInsensitive ? foldEq(`${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`})`, text.charCodeAt(i)) : `${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`}) === ${text.charCodeAt(i)}`);
|
|
7710
|
+
}
|
|
7711
|
+
return parts.join(" && ");
|
|
7712
|
+
}
|
|
7424
7713
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7425
7714
|
const superParser = def.parsers[superIndex];
|
|
7426
7715
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -8075,6 +8364,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
8075
8364
|
endVar: pos
|
|
8076
8365
|
};
|
|
8077
8366
|
}
|
|
8367
|
+
function emitRouted(ctx, pos) {
|
|
8368
|
+
const item = v(ctx, "_rt");
|
|
8369
|
+
return {
|
|
8370
|
+
stmts: [
|
|
8371
|
+
`${ind(ctx)}const ${item} = _ctx._routed`,
|
|
8372
|
+
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8373
|
+
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8374
|
+
],
|
|
8375
|
+
valueVar: `${item}.value`,
|
|
8376
|
+
endVar: `${item}.span.end`
|
|
8377
|
+
};
|
|
8378
|
+
}
|
|
8078
8379
|
function escapeTokenLiteral(value) {
|
|
8079
8380
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
8080
8381
|
}
|
|
@@ -8215,14 +8516,20 @@ function emitLeaf(def, ctx, pos) {
|
|
|
8215
8516
|
endVar: inner.endVar
|
|
8216
8517
|
};
|
|
8217
8518
|
}
|
|
8519
|
+
function emitNodeProjectExpr(type, project, chV) {
|
|
8520
|
+
const child = `${chV}[${project}]`;
|
|
8521
|
+
const missing = `(() => { throw new Error(${JSON.stringify(`node(${JSON.stringify(type)}) project child ${project} was not captured`)}) })()`;
|
|
8522
|
+
const value = `(${child} !== null && typeof ${child} === 'object' && ${child}._tag === 'leaf' ? ${child}.value : ${child})`;
|
|
8523
|
+
return `(${project} in ${chV} ? ${value} : ${missing})`;
|
|
8524
|
+
}
|
|
8218
8525
|
function emitNode(def, ctx, pos) {
|
|
8219
8526
|
if (def.type === void 0) {
|
|
8220
8527
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
8221
8528
|
}
|
|
8222
|
-
const structural = def.build === void 0;
|
|
8223
|
-
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
8529
|
+
const structural = def.build === void 0 && def.project === void 0;
|
|
8530
|
+
const mkType = structural || def.project !== void 0 ? null : analyzeMkInlineBuild(def);
|
|
8224
8531
|
let buildIdx = null;
|
|
8225
|
-
if (!mkType && !structural) {
|
|
8532
|
+
if (!mkType && !structural && def.project === void 0) {
|
|
8226
8533
|
buildIdx = ctx.buildFns.length;
|
|
8227
8534
|
ctx.buildFns.push(def.build);
|
|
8228
8535
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
@@ -8230,12 +8537,13 @@ function emitNode(def, ctx, pos) {
|
|
|
8230
8537
|
const i = ind(ctx);
|
|
8231
8538
|
const cstOut = ctx.hostMode === "cst" && !structural;
|
|
8232
8539
|
if (!structural && !cstOut) ctx.hostBranchElided = true;
|
|
8233
|
-
const
|
|
8234
|
-
const
|
|
8235
|
-
const
|
|
8236
|
-
const
|
|
8540
|
+
const hasProject = def.project !== void 0;
|
|
8541
|
+
const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && !hasProject && buildReadsTrivia(def);
|
|
8542
|
+
const clonesState = !structural && (cstOut || !hasProject && buildReadsState(def));
|
|
8543
|
+
const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || def.project !== void 0 || buildReadsChildren(def));
|
|
8544
|
+
const capturesRaw = !structural && (cstOut || mkType !== null || def.project === void 0 && buildReadsRaw(def));
|
|
8237
8545
|
const hasFields = parserHasOwnFields(def.parser);
|
|
8238
|
-
const capturesFields = hasFields && !structural && (cstOut || buildReadsFields(def));
|
|
8546
|
+
const capturesFields = hasFields && !structural && (cstOut || !hasProject && buildReadsFields(def));
|
|
8239
8547
|
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
8240
8548
|
const chV = v(ctx, "_ch");
|
|
8241
8549
|
const rawV = v(ctx, "_raw");
|
|
@@ -8333,7 +8641,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
8333
8641
|
);
|
|
8334
8642
|
}
|
|
8335
8643
|
const ndV = v(ctx, "_nd");
|
|
8336
|
-
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})`;
|
|
8644
|
+
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})`;
|
|
8337
8645
|
const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
8338
8646
|
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
|
|
8339
8647
|
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;
|
|
@@ -8540,7 +8848,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8540
8848
|
case "choice":
|
|
8541
8849
|
return emitChoice(p, def, ctx, pos);
|
|
8542
8850
|
case "dispatch":
|
|
8543
|
-
return emitDispatchCombinator(def, ctx, pos);
|
|
8851
|
+
return emitDispatchCombinator(p, def, ctx, pos);
|
|
8544
8852
|
case "attempt":
|
|
8545
8853
|
return emitAttempt(p, def, ctx, pos);
|
|
8546
8854
|
case "many":
|
|
@@ -8665,6 +8973,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8665
8973
|
return emitNot(def, ctx, pos);
|
|
8666
8974
|
case "peek":
|
|
8667
8975
|
return emitPeek(def, ctx, pos);
|
|
8976
|
+
case "routed":
|
|
8977
|
+
return emitRouted(ctx, pos);
|
|
8668
8978
|
case "node":
|
|
8669
8979
|
return emitNode(def, ctx, pos);
|
|
8670
8980
|
case "scanTo":
|
|
@@ -8762,7 +9072,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8762
9072
|
case "choice":
|
|
8763
9073
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
8764
9074
|
case "dispatch":
|
|
8765
|
-
return hasNodeDef(d.selector, seen) || d.cases.some((x) => hasNodeDef(x.parser, seen)) || (d.otherwise ? hasNodeDef(d.otherwise, seen) : false);
|
|
9075
|
+
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);
|
|
8766
9076
|
case "sepBy":
|
|
8767
9077
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8768
9078
|
case "scanTo":
|
|
@@ -8777,6 +9087,26 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8777
9087
|
return false;
|
|
8778
9088
|
}
|
|
8779
9089
|
}
|
|
9090
|
+
function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
|
|
9091
|
+
if (seen.has(p)) return false;
|
|
9092
|
+
seen.add(p);
|
|
9093
|
+
const d = p._def;
|
|
9094
|
+
switch (d.tag) {
|
|
9095
|
+
case "routed":
|
|
9096
|
+
return true;
|
|
9097
|
+
case "lazy": {
|
|
9098
|
+
try {
|
|
9099
|
+
return parserUsesRouted2(d.thunk(), seen);
|
|
9100
|
+
} catch {
|
|
9101
|
+
return false;
|
|
9102
|
+
}
|
|
9103
|
+
}
|
|
9104
|
+
case "dispatch":
|
|
9105
|
+
return false;
|
|
9106
|
+
default:
|
|
9107
|
+
return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
|
|
9108
|
+
}
|
|
9109
|
+
}
|
|
8780
9110
|
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
8781
9111
|
if (seen.has(p)) return false;
|
|
8782
9112
|
seen.add(p);
|
|
@@ -8797,7 +9127,7 @@ function childrenOf2(def) {
|
|
|
8797
9127
|
case "choice":
|
|
8798
9128
|
return def.parsers;
|
|
8799
9129
|
case "dispatch":
|
|
8800
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9130
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
8801
9131
|
case "many":
|
|
8802
9132
|
case "attempt":
|
|
8803
9133
|
case "optional":
|
|
@@ -8834,6 +9164,7 @@ function childrenOf2(def) {
|
|
|
8834
9164
|
case "regex":
|
|
8835
9165
|
case "keywords":
|
|
8836
9166
|
case "guard":
|
|
9167
|
+
case "routed":
|
|
8837
9168
|
case "unknown":
|
|
8838
9169
|
return [];
|
|
8839
9170
|
}
|
|
@@ -9541,7 +9872,7 @@ function childrenOf3(def) {
|
|
|
9541
9872
|
case "choice":
|
|
9542
9873
|
return def.parsers;
|
|
9543
9874
|
case "dispatch":
|
|
9544
|
-
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.otherwise ? [def.otherwise] : []];
|
|
9875
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
9545
9876
|
case "many":
|
|
9546
9877
|
case "oneOrMore":
|
|
9547
9878
|
case "optional":
|
|
@@ -9570,6 +9901,7 @@ function childrenOf3(def) {
|
|
|
9570
9901
|
case "literal":
|
|
9571
9902
|
case "regex":
|
|
9572
9903
|
case "keywords":
|
|
9904
|
+
case "routed":
|
|
9573
9905
|
case "guard":
|
|
9574
9906
|
case "recover":
|
|
9575
9907
|
case "unknown":
|
|
@@ -9594,6 +9926,20 @@ function repeatOpts(min, max, trailing) {
|
|
|
9594
9926
|
if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
|
|
9595
9927
|
return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
|
|
9596
9928
|
}
|
|
9929
|
+
function projectOpt(project) {
|
|
9930
|
+
if (project === void 0) return void 0;
|
|
9931
|
+
return `project: ${project}`;
|
|
9932
|
+
}
|
|
9933
|
+
function matcherExpr(entry) {
|
|
9934
|
+
switch (entry.kind) {
|
|
9935
|
+
case "startsWith":
|
|
9936
|
+
return `startsWith(${JSON.stringify(entry.value)})`;
|
|
9937
|
+
case "endsWith":
|
|
9938
|
+
return `endsWith(${JSON.stringify(entry.value)})`;
|
|
9939
|
+
case "matches":
|
|
9940
|
+
return `matches(${new RegExp(entry.value, entry.flags ?? "").toString()})`;
|
|
9941
|
+
}
|
|
9942
|
+
}
|
|
9597
9943
|
function serializeRuleMap(ruleMap, scanSkip) {
|
|
9598
9944
|
try {
|
|
9599
9945
|
return new Serializer(ruleMap, scanSkip ?? []).run();
|
|
@@ -9693,7 +10039,11 @@ function evalRuleMapIR(ir) {
|
|
|
9693
10039
|
"choice",
|
|
9694
10040
|
"dispatch",
|
|
9695
10041
|
"when",
|
|
10042
|
+
"startsWith",
|
|
10043
|
+
"endsWith",
|
|
10044
|
+
"matches",
|
|
9696
10045
|
"otherwise",
|
|
10046
|
+
"routed",
|
|
9697
10047
|
"attempt",
|
|
9698
10048
|
"many",
|
|
9699
10049
|
"oneOrMore",
|
|
@@ -9729,7 +10079,11 @@ function evalRuleMapIR(ir) {
|
|
|
9729
10079
|
choice,
|
|
9730
10080
|
dispatch,
|
|
9731
10081
|
when,
|
|
10082
|
+
startsWith,
|
|
10083
|
+
endsWith,
|
|
10084
|
+
matches,
|
|
9732
10085
|
otherwise,
|
|
10086
|
+
routed,
|
|
9733
10087
|
attempt,
|
|
9734
10088
|
many,
|
|
9735
10089
|
oneOrMore,
|
|
@@ -9917,8 +10271,13 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9917
10271
|
}
|
|
9918
10272
|
case "dispatch": {
|
|
9919
10273
|
const arms = def.cases.map(
|
|
9920
|
-
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)})`
|
|
10274
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`
|
|
9921
10275
|
);
|
|
10276
|
+
if (def.matchers) {
|
|
10277
|
+
for (const entry of def.matchers) {
|
|
10278
|
+
arms.push(`when(${matcherExpr(entry)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`);
|
|
10279
|
+
}
|
|
10280
|
+
}
|
|
9922
10281
|
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
9923
10282
|
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
9924
10283
|
}
|
|
@@ -9938,6 +10297,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9938
10297
|
return `not(${kid(def.parser)})`;
|
|
9939
10298
|
case "peek":
|
|
9940
10299
|
return `peek(${kid(def.parser)})`;
|
|
10300
|
+
case "routed":
|
|
10301
|
+
return "routed()";
|
|
9941
10302
|
case "trivia":
|
|
9942
10303
|
return `trivia(${kid(def.parser)})`;
|
|
9943
10304
|
case "token":
|
|
@@ -9962,9 +10323,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9962
10323
|
}
|
|
9963
10324
|
case "node": {
|
|
9964
10325
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
10326
|
+
const projectEntry = projectOpt(def.project);
|
|
9965
10327
|
const optEntries = [
|
|
9966
10328
|
...def.unwrap ? ["unwrap: true"] : [],
|
|
9967
10329
|
...def.collapse ? ["collapse: true"] : [],
|
|
10330
|
+
...projectEntry === void 0 ? [] : [projectEntry],
|
|
9968
10331
|
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
9969
10332
|
...def.trailingTrivia ? ["trailingTrivia: true"] : []
|
|
9970
10333
|
];
|
|
@@ -10959,10 +11322,20 @@ function run(entry, input, options = {}) {
|
|
|
10959
11322
|
}
|
|
10960
11323
|
|
|
10961
11324
|
// src/coverage.ts
|
|
11325
|
+
function dispatchMatcher(entry) {
|
|
11326
|
+
switch (entry.kind) {
|
|
11327
|
+
case "startsWith":
|
|
11328
|
+
return startsWith(entry.value);
|
|
11329
|
+
case "endsWith":
|
|
11330
|
+
return endsWith(entry.value);
|
|
11331
|
+
case "matches":
|
|
11332
|
+
return matches(new RegExp(entry.value, entry.flags));
|
|
11333
|
+
}
|
|
11334
|
+
}
|
|
10962
11335
|
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
10963
11336
|
function compiledGrammarCoverageDefinitions(grammar) {
|
|
10964
11337
|
const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
|
|
10965
|
-
if (!Array.isArray(definitions) || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "label"))) {
|
|
11338
|
+
if (!Array.isArray(definitions) || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "dispatch-arm" || definition.kind === "label"))) {
|
|
10966
11339
|
throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
|
|
10967
11340
|
}
|
|
10968
11341
|
return definitions;
|
|
@@ -11142,10 +11515,54 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
11142
11515
|
return unsafeSequence(...def.parsers.map(build));
|
|
11143
11516
|
}
|
|
11144
11517
|
case "dispatch": {
|
|
11145
|
-
const
|
|
11146
|
-
|
|
11518
|
+
const ids = maps.dispatches.get(parser2) ?? [];
|
|
11519
|
+
let armIndex = 0;
|
|
11520
|
+
const dispatchStarts = [];
|
|
11521
|
+
const wrapArm = (arm, id) => {
|
|
11522
|
+
const child = build(arm);
|
|
11523
|
+
return {
|
|
11524
|
+
_tag: child._tag,
|
|
11525
|
+
_meta: child._meta,
|
|
11526
|
+
_def: child._def,
|
|
11527
|
+
parse(input, pos, ctx) {
|
|
11528
|
+
const dispatchStart = dispatchStarts[dispatchStarts.length - 1] ?? pos;
|
|
11529
|
+
if (id) trace?.write({ id, phase: "attempt", offset: dispatchStart });
|
|
11530
|
+
const result = child.parse(input, pos, ctx);
|
|
11531
|
+
if (result.ok) {
|
|
11532
|
+
if (id) {
|
|
11533
|
+
collector.hit(id);
|
|
11534
|
+
trace?.write({ id, phase: "selected", offset: dispatchStart, end: result.span.end });
|
|
11535
|
+
trace?.write({ id, phase: "success", offset: dispatchStart, end: result.span.end });
|
|
11536
|
+
}
|
|
11537
|
+
} else if (id) {
|
|
11538
|
+
trace?.write({ id, phase: "failure", offset: result.span.end });
|
|
11539
|
+
}
|
|
11540
|
+
return result;
|
|
11541
|
+
}
|
|
11542
|
+
};
|
|
11543
|
+
};
|
|
11544
|
+
const arms = def.cases.map(
|
|
11545
|
+
(entry2) => when(entry2.keys, wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0)
|
|
11546
|
+
);
|
|
11547
|
+
if (def.matchers) {
|
|
11548
|
+
for (const entry2 of def.matchers) {
|
|
11549
|
+
arms.push(when(dispatchMatcher(entry2), wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
11550
|
+
}
|
|
11551
|
+
}
|
|
11552
|
+
if (def.otherwise) arms.push(otherwise(wrapArm(def.otherwise, ids[armIndex++])));
|
|
11147
11553
|
const unsafeDispatch = dispatch;
|
|
11148
|
-
|
|
11554
|
+
const base2 = unsafeDispatch(build(def.selector), ...arms);
|
|
11555
|
+
return {
|
|
11556
|
+
...base2,
|
|
11557
|
+
parse(input, pos, ctx) {
|
|
11558
|
+
dispatchStarts.push(pos);
|
|
11559
|
+
try {
|
|
11560
|
+
return base2.parse(input, pos, ctx);
|
|
11561
|
+
} finally {
|
|
11562
|
+
dispatchStarts.pop();
|
|
11563
|
+
}
|
|
11564
|
+
}
|
|
11565
|
+
};
|
|
11149
11566
|
}
|
|
11150
11567
|
case "many":
|
|
11151
11568
|
return many(build(def.parser));
|
|
@@ -11190,7 +11607,7 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
11190
11607
|
case "peek":
|
|
11191
11608
|
return peek(build(def.parser));
|
|
11192
11609
|
case "node": {
|
|
11193
|
-
const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
|
|
11610
|
+
const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.project !== void 0 ? { project: def.project } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
|
|
11194
11611
|
return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
|
|
11195
11612
|
}
|
|
11196
11613
|
case "guard":
|
|
@@ -11593,6 +12010,7 @@ export {
|
|
|
11593
12010
|
cstBuildHost,
|
|
11594
12011
|
dispatch,
|
|
11595
12012
|
duplicationFindingCount,
|
|
12013
|
+
endsWith,
|
|
11596
12014
|
expect,
|
|
11597
12015
|
extractCharClasses,
|
|
11598
12016
|
field,
|
|
@@ -11615,8 +12033,10 @@ export {
|
|
|
11615
12033
|
lineBreaksIn,
|
|
11616
12034
|
lineStartWithin,
|
|
11617
12035
|
literal,
|
|
12036
|
+
makeWhen,
|
|
11618
12037
|
makeWord,
|
|
11619
12038
|
many,
|
|
12039
|
+
matches,
|
|
11620
12040
|
noTrivia,
|
|
11621
12041
|
node,
|
|
11622
12042
|
not,
|
|
@@ -11633,6 +12053,7 @@ export {
|
|
|
11633
12053
|
regex,
|
|
11634
12054
|
relativize,
|
|
11635
12055
|
relativizeCST,
|
|
12056
|
+
routed,
|
|
11636
12057
|
rules,
|
|
11637
12058
|
run,
|
|
11638
12059
|
runWithGrammarCoverage,
|
|
@@ -11642,6 +12063,7 @@ export {
|
|
|
11642
12063
|
shiftAbsolute,
|
|
11643
12064
|
siteToString,
|
|
11644
12065
|
skip,
|
|
12066
|
+
startsWith,
|
|
11645
12067
|
token,
|
|
11646
12068
|
transform,
|
|
11647
12069
|
trivia,
|