parseman 0.38.0 → 0.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/duplication.d.ts.map +1 -1
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/combinators/attempt.d.ts.map +1 -1
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +53 -0
- package/dist/combinators/dispatch.d.ts.map +1 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts +2 -1
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/index.cjs +772 -33
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +772 -33
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs.map +2 -2
- package/dist/language-service/index.js.map +2 -2
- package/dist/plugin/evaluator.d.ts +6 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +840 -33
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +840 -33
- package/dist/plugin/index.js.map +4 -4
- package/dist/spec/index.cjs +294 -1
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +294 -1
- package/dist/spec/index.js.map +4 -4
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.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("");
|
|
@@ -77,6 +79,8 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
77
79
|
return d.parsers.every(me);
|
|
78
80
|
case "choice":
|
|
79
81
|
return d.parsers.some(me);
|
|
82
|
+
case "dispatch":
|
|
83
|
+
return me(d.selector);
|
|
80
84
|
case "transform":
|
|
81
85
|
case "label":
|
|
82
86
|
case "trivia":
|
|
@@ -150,6 +154,8 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
150
154
|
case "keywords":
|
|
151
155
|
return p._meta.firstSet;
|
|
152
156
|
// terminals: no refs, cached set is exact
|
|
157
|
+
case "dispatch":
|
|
158
|
+
return fs(d.selector);
|
|
153
159
|
case "lazy":
|
|
154
160
|
try {
|
|
155
161
|
return fs(d.thunk());
|
|
@@ -1067,6 +1073,8 @@ function derive(c, seen) {
|
|
|
1067
1073
|
return [def.label];
|
|
1068
1074
|
case "choice":
|
|
1069
1075
|
return def.parsers.flatMap(deriveExpected2);
|
|
1076
|
+
case "dispatch":
|
|
1077
|
+
return deriveExpected2(def.selector);
|
|
1070
1078
|
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1071
1079
|
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1072
1080
|
// able to fail first — deriving from term 0 alone named a token the parse
|
|
@@ -1106,6 +1114,8 @@ function derive(c, seen) {
|
|
|
1106
1114
|
case "not":
|
|
1107
1115
|
case "peek":
|
|
1108
1116
|
return deriveExpected2(def.parser);
|
|
1117
|
+
case "routed":
|
|
1118
|
+
return ["routed()"];
|
|
1109
1119
|
case "lazy": {
|
|
1110
1120
|
const name = c._ruleName;
|
|
1111
1121
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -1208,6 +1218,7 @@ function choice(...args) {
|
|
|
1208
1218
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
1209
1219
|
if (result.ok) return result;
|
|
1210
1220
|
expected.push(...result.expected);
|
|
1221
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1211
1222
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1212
1223
|
}
|
|
1213
1224
|
return {
|
|
@@ -1248,6 +1259,7 @@ function choice(...args) {
|
|
|
1248
1259
|
rollbackCstCapture(ctx, mark);
|
|
1249
1260
|
if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
|
|
1250
1261
|
expected.push(...result.expected);
|
|
1262
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1251
1263
|
continue;
|
|
1252
1264
|
}
|
|
1253
1265
|
const checks = autoNot[i];
|
|
@@ -1927,6 +1939,248 @@ function sequence(...parsers) {
|
|
|
1927
1939
|
};
|
|
1928
1940
|
}
|
|
1929
1941
|
|
|
1942
|
+
// src/combinators/dispatch.ts
|
|
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
|
+
}
|
|
2044
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2045
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2046
|
+
for (const item of keys) {
|
|
2047
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2048
|
+
}
|
|
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);
|
|
2053
|
+
}
|
|
2054
|
+
function otherwise(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
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
function dispatch(selector, ...arms) {
|
|
2078
|
+
if (parserUsesRouted(selector)) {
|
|
2079
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2080
|
+
}
|
|
2081
|
+
let fallback;
|
|
2082
|
+
let fallbackUsesRouted = false;
|
|
2083
|
+
const matchers = [];
|
|
2084
|
+
const cases = [];
|
|
2085
|
+
const seen = [];
|
|
2086
|
+
for (let i = 0; i < arms.length; i++) {
|
|
2087
|
+
const arm = arms[i];
|
|
2088
|
+
if (arm.kind === "otherwise") {
|
|
2089
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2090
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2091
|
+
fallback = arm.parser;
|
|
2092
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
2093
|
+
continue;
|
|
2094
|
+
}
|
|
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;
|
|
2106
|
+
}
|
|
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
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
const meta = {
|
|
2123
|
+
firstSet: selector._meta.firstSet,
|
|
2124
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2125
|
+
isTrivia: false
|
|
2126
|
+
};
|
|
2127
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
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
|
+
}
|
|
2135
|
+
return {
|
|
2136
|
+
_tag: "dispatch",
|
|
2137
|
+
_meta: meta,
|
|
2138
|
+
_def: {
|
|
2139
|
+
tag: "dispatch",
|
|
2140
|
+
selector,
|
|
2141
|
+
cases,
|
|
2142
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2143
|
+
...fallback === void 0 ? {} : { otherwise: fallback, ...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {} }
|
|
2144
|
+
},
|
|
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);
|
|
2150
|
+
const selected = selector.parse(input, pos, ctx);
|
|
2151
|
+
if (!selected.ok) return selected;
|
|
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) {
|
|
2154
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2155
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2156
|
+
}
|
|
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
|
+
}
|
|
2171
|
+
if (!result.ok) {
|
|
2172
|
+
rollbackTrivia(ctx, mark);
|
|
2173
|
+
return { ...result, committed: true };
|
|
2174
|
+
}
|
|
2175
|
+
return {
|
|
2176
|
+
ok: true,
|
|
2177
|
+
value: [selected.value, result.value],
|
|
2178
|
+
span: { start: pos, end: result.span.end }
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
|
|
1930
2184
|
// src/combinators/attempt.ts
|
|
1931
2185
|
function attempt(parser2) {
|
|
1932
2186
|
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
@@ -1949,6 +2203,7 @@ function attempt(parser2) {
|
|
|
1949
2203
|
if (result.ok) return result;
|
|
1950
2204
|
rollbackCstCapture(ctx, mark);
|
|
1951
2205
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
2206
|
+
if (result.committed) return result;
|
|
1952
2207
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
1953
2208
|
}
|
|
1954
2209
|
};
|
|
@@ -1978,6 +2233,7 @@ function repItem(combinator, input, cur, ctx, guardable) {
|
|
|
1978
2233
|
const result = combinator.parse(input, pos, ctx);
|
|
1979
2234
|
if (!result.ok) {
|
|
1980
2235
|
rollbackTrivia(ctx, mark);
|
|
2236
|
+
if (result.committed) return { fail: result, failPos: pos };
|
|
1981
2237
|
return { fail: result, failPos: pos };
|
|
1982
2238
|
}
|
|
1983
2239
|
if (result.span.end === pos) {
|
|
@@ -2021,6 +2277,7 @@ function many(combinator, opts = {}) {
|
|
|
2021
2277
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2022
2278
|
if (item === "stop") break;
|
|
2023
2279
|
if ("fail" in item) {
|
|
2280
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2024
2281
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2025
2282
|
if (sync === void 0) break;
|
|
2026
2283
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2065,6 +2322,7 @@ function atLeast(combinator, min, max) {
|
|
|
2065
2322
|
while (count < min) {
|
|
2066
2323
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2067
2324
|
if (item === "stop" || "fail" in item) {
|
|
2325
|
+
if (item !== "stop" && !item.fail.ok && item.fail.committed) return item.fail;
|
|
2068
2326
|
expected ??= deriveExpected(combinator);
|
|
2069
2327
|
return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
|
|
2070
2328
|
}
|
|
@@ -2077,6 +2335,7 @@ function atLeast(combinator, min, max) {
|
|
|
2077
2335
|
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
2078
2336
|
if (item === "stop") break;
|
|
2079
2337
|
if ("fail" in item) {
|
|
2338
|
+
if (!item.fail.ok && item.fail.committed) return item.fail;
|
|
2080
2339
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
2081
2340
|
if (sync === void 0) break;
|
|
2082
2341
|
if (matchesAt(sync, input, item.failPos, ctx)) break;
|
|
@@ -2115,6 +2374,7 @@ function optional(combinator) {
|
|
|
2115
2374
|
const result = combinator.parse(input, pos, ctx);
|
|
2116
2375
|
if (result.ok) return result;
|
|
2117
2376
|
rollbackTrivia(ctx, mark);
|
|
2377
|
+
if (result.committed) return result;
|
|
2118
2378
|
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
2119
2379
|
}
|
|
2120
2380
|
};
|
|
@@ -2154,6 +2414,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2154
2414
|
values.push(first.value);
|
|
2155
2415
|
cur = first.span.end;
|
|
2156
2416
|
} else {
|
|
2417
|
+
if (first.committed) return first;
|
|
2157
2418
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2158
2419
|
if (term === void 0 || matchesAt(term, input, pos, ctx)) {
|
|
2159
2420
|
if (min >= 1) return failAt2(pos);
|
|
@@ -2181,6 +2442,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2181
2442
|
const sep = separator.parse(input, sepPos, ctx);
|
|
2182
2443
|
if (!sep.ok) {
|
|
2183
2444
|
rollbackTrivia(ctx, loopMark);
|
|
2445
|
+
if (sep.committed) return sep;
|
|
2184
2446
|
break;
|
|
2185
2447
|
}
|
|
2186
2448
|
const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
|
|
@@ -2196,6 +2458,7 @@ function sepBy(combinator, separator, opts = {}) {
|
|
|
2196
2458
|
}
|
|
2197
2459
|
const next = combinator.parse(input, nextPos, ctx);
|
|
2198
2460
|
if (!next.ok) {
|
|
2461
|
+
if (next.committed) return next;
|
|
2199
2462
|
const term = ctx._tolerant ? ctx._sync : void 0;
|
|
2200
2463
|
if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
|
|
2201
2464
|
expected ??= deriveExpected(combinator);
|
|
@@ -2288,6 +2551,12 @@ function markUnusedValues(root) {
|
|
|
2288
2551
|
case "choice":
|
|
2289
2552
|
for (const p of def.parsers) visit(p, consumed);
|
|
2290
2553
|
return;
|
|
2554
|
+
case "dispatch":
|
|
2555
|
+
visit(def.selector, consumed);
|
|
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);
|
|
2558
|
+
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2559
|
+
return;
|
|
2291
2560
|
case "node":
|
|
2292
2561
|
visit(def.parser, false);
|
|
2293
2562
|
return;
|
|
@@ -2563,6 +2832,8 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2563
2832
|
case "sequence":
|
|
2564
2833
|
case "choice":
|
|
2565
2834
|
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
2835
|
+
case "dispatch":
|
|
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);
|
|
2566
2837
|
case "sepBy":
|
|
2567
2838
|
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
2568
2839
|
case "skip":
|
|
@@ -2630,6 +2901,8 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2630
2901
|
return parserHasTriviaSite(d.parser, seen);
|
|
2631
2902
|
case "choice":
|
|
2632
2903
|
return d.parsers.some((x) => parserHasTriviaSite(x, seen));
|
|
2904
|
+
case "dispatch":
|
|
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);
|
|
2633
2906
|
case "grammar":
|
|
2634
2907
|
return parserHasTriviaSite(d.parser, seen);
|
|
2635
2908
|
case "lazy": {
|
|
@@ -2655,6 +2928,8 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2655
2928
|
case "sequence":
|
|
2656
2929
|
case "choice":
|
|
2657
2930
|
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2931
|
+
case "dispatch":
|
|
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);
|
|
2658
2933
|
case "sepBy":
|
|
2659
2934
|
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2660
2935
|
case "skip":
|
|
@@ -3056,7 +3331,7 @@ function leaf(root, fn) {
|
|
|
3056
3331
|
}
|
|
3057
3332
|
|
|
3058
3333
|
// src/version.ts
|
|
3059
|
-
var PARSEMAN_VERSION = "0.
|
|
3334
|
+
var PARSEMAN_VERSION = "0.39.1";
|
|
3060
3335
|
|
|
3061
3336
|
// src/cst/host-mode.ts
|
|
3062
3337
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3212,6 +3487,8 @@ function classifyBroadArm(arm, resolve) {
|
|
|
3212
3487
|
}
|
|
3213
3488
|
return null;
|
|
3214
3489
|
}
|
|
3490
|
+
case "dispatch":
|
|
3491
|
+
return walk2(d.selector);
|
|
3215
3492
|
default:
|
|
3216
3493
|
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3217
3494
|
}
|
|
@@ -3311,6 +3588,12 @@ function analyzeGatingRules(ruleMap, opts) {
|
|
|
3311
3588
|
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3312
3589
|
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3313
3590
|
if (rec[k]) kids.push(rec[k]);
|
|
3591
|
+
if (d.tag === "dispatch") {
|
|
3592
|
+
kids.push(d.selector);
|
|
3593
|
+
for (const c of d.cases) kids.push(c.parser);
|
|
3594
|
+
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3595
|
+
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3596
|
+
}
|
|
3314
3597
|
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3315
3598
|
if (d.tag === "lazy") {
|
|
3316
3599
|
try {
|
|
@@ -3417,6 +3700,12 @@ function childrenOf(d) {
|
|
|
3417
3700
|
case "sequence":
|
|
3418
3701
|
case "choice":
|
|
3419
3702
|
return d.parsers;
|
|
3703
|
+
case "dispatch":
|
|
3704
|
+
return [
|
|
3705
|
+
d.selector,
|
|
3706
|
+
...d.cases.map((c) => c.parser),
|
|
3707
|
+
...d.otherwise === void 0 ? [] : [d.otherwise]
|
|
3708
|
+
];
|
|
3420
3709
|
case "skip":
|
|
3421
3710
|
return [d.main, d.skipped];
|
|
3422
3711
|
case "sepBy":
|
|
@@ -3473,6 +3762,8 @@ function payloadKey(p, d) {
|
|
|
3473
3762
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|
|
3474
3763
|
case "sepBy":
|
|
3475
3764
|
return `sepBy\0${d.min}\0${d.max ?? ""}\0${d.trailing ?? ""}`;
|
|
3765
|
+
case "dispatch":
|
|
3766
|
+
return `dispatch\0${d.cases.map((c) => JSON.stringify(c.keys)).join("")}\0${d.otherwise !== void 0}`;
|
|
3476
3767
|
case "expect":
|
|
3477
3768
|
return `expect\0${d.label ?? ""}\0${d.expected.join("")}`;
|
|
3478
3769
|
case "scanTo":
|
|
@@ -3544,6 +3835,11 @@ function render(p, depth = 3) {
|
|
|
3544
3835
|
return `sequence(${kids.join(", ")})`;
|
|
3545
3836
|
case "choice":
|
|
3546
3837
|
return `choice(${kids.join(", ")})`;
|
|
3838
|
+
case "dispatch": {
|
|
3839
|
+
const arms = d.cases.map((c, i) => `when([${c.keys.map((k) => JSON.stringify(k)).join(", ")}], ${kids[i + 1] ?? ""})`);
|
|
3840
|
+
if (d.otherwise !== void 0) arms.push(`otherwise(${kids[kids.length - 1] ?? ""})`);
|
|
3841
|
+
return `dispatch(${kids[0] ?? ""}, ${arms.join(", ")})`;
|
|
3842
|
+
}
|
|
3547
3843
|
case "node":
|
|
3548
3844
|
return `node(${d.type ? `'${d.type}', ` : ""}${kids[0] ?? ""})`;
|
|
3549
3845
|
case "label":
|
|
@@ -3567,6 +3863,10 @@ function segment(d, index) {
|
|
|
3567
3863
|
return `seq[${index}]`;
|
|
3568
3864
|
case "choice":
|
|
3569
3865
|
return `choice[${index}]`;
|
|
3866
|
+
case "dispatch":
|
|
3867
|
+
if (index === 0) return "dispatch.selector";
|
|
3868
|
+
if (index <= d.cases.length) return `dispatch.when[${index - 1}]`;
|
|
3869
|
+
return "dispatch.otherwise";
|
|
3570
3870
|
case "node":
|
|
3571
3871
|
return `node(${d.type ?? ""})`;
|
|
3572
3872
|
case "label":
|
|
@@ -4815,11 +5115,25 @@ function escapeClassChar(ch2) {
|
|
|
4815
5115
|
}
|
|
4816
5116
|
|
|
4817
5117
|
// src/compiler/grammar-coverage-ids.ts
|
|
5118
|
+
function idPart(value) {
|
|
5119
|
+
return encodeURIComponent(value);
|
|
5120
|
+
}
|
|
5121
|
+
function dispatchArmIds(def, path) {
|
|
5122
|
+
const ids = [];
|
|
5123
|
+
for (const entry of def.cases) ids.push(`dispatch:${path}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5124
|
+
for (const entry of def.matchers ?? []) {
|
|
5125
|
+
ids.push(`dispatch:${path}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5126
|
+
}
|
|
5127
|
+
if (def.otherwise) ids.push(`dispatch:${path}/otherwise`);
|
|
5128
|
+
return ids;
|
|
5129
|
+
}
|
|
4818
5130
|
function children(def, winners) {
|
|
4819
5131
|
switch (def.tag) {
|
|
4820
5132
|
case "sequence":
|
|
4821
5133
|
case "choice":
|
|
4822
5134
|
return def.parsers;
|
|
5135
|
+
case "dispatch":
|
|
5136
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
4823
5137
|
case "many":
|
|
4824
5138
|
case "oneOrMore":
|
|
4825
5139
|
case "optional":
|
|
@@ -4862,6 +5176,7 @@ function children(def, winners) {
|
|
|
4862
5176
|
function buildGrammarPlan(entry, winners) {
|
|
4863
5177
|
const definitions = /* @__PURE__ */ new Map();
|
|
4864
5178
|
const choices = /* @__PURE__ */ new WeakMap();
|
|
5179
|
+
const dispatches = /* @__PURE__ */ new WeakMap();
|
|
4865
5180
|
const attempts = /* @__PURE__ */ new WeakMap();
|
|
4866
5181
|
const labels = /* @__PURE__ */ new WeakMap();
|
|
4867
5182
|
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -4892,6 +5207,11 @@ function buildGrammarPlan(entry, winners) {
|
|
|
4892
5207
|
choices.set(parser2, ids);
|
|
4893
5208
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
4894
5209
|
}
|
|
5210
|
+
if (parser2._def.tag === "dispatch") {
|
|
5211
|
+
const ids = dispatchArmIds(parser2._def, path);
|
|
5212
|
+
dispatches.set(parser2, ids);
|
|
5213
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5214
|
+
}
|
|
4895
5215
|
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
|
|
4896
5216
|
if (parser2._def.tag === "label") {
|
|
4897
5217
|
const id = `label:${path}`;
|
|
@@ -4904,7 +5224,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
4904
5224
|
for (const root of roots) {
|
|
4905
5225
|
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
4906
5226
|
}
|
|
4907
|
-
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
5227
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules: rules2 };
|
|
4908
5228
|
}
|
|
4909
5229
|
|
|
4910
5230
|
// src/compiler/scannable-run.ts
|
|
@@ -6278,12 +6598,15 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6278
6598
|
case "literal":
|
|
6279
6599
|
case "regex":
|
|
6280
6600
|
case "keywords":
|
|
6601
|
+
case "routed":
|
|
6281
6602
|
return { alts: [[seg(p._meta.firstSet, matchesEmpty(p))]] };
|
|
6282
6603
|
case "choice": {
|
|
6283
6604
|
const alts = [];
|
|
6284
6605
|
for (const arm of d.parsers) alts.push(...rec(arm).alts);
|
|
6285
6606
|
return { alts };
|
|
6286
6607
|
}
|
|
6608
|
+
case "dispatch":
|
|
6609
|
+
return rec(d.selector);
|
|
6287
6610
|
case "sequence": {
|
|
6288
6611
|
const chain = [];
|
|
6289
6612
|
for (const term of d.parsers) {
|
|
@@ -6358,6 +6681,9 @@ function failReturn(expected, posExpr) {
|
|
|
6358
6681
|
function failReturnArr(expectedArr, posExpr) {
|
|
6359
6682
|
return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
6360
6683
|
}
|
|
6684
|
+
function committedReturnArr(expectedArr, posExpr) {
|
|
6685
|
+
return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
|
|
6686
|
+
}
|
|
6361
6687
|
function hoistExpected(ctx, constArrSource) {
|
|
6362
6688
|
let name = ctx.expectedMap.get(constArrSource);
|
|
6363
6689
|
if (name === void 0) {
|
|
@@ -6394,15 +6720,22 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
|
6394
6720
|
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
6395
6721
|
}
|
|
6396
6722
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
6397
|
-
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
6723
|
+
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
|
|
6724
|
+
}
|
|
6725
|
+
function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
|
|
6726
|
+
if (ctx.failLabel) {
|
|
6727
|
+
if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
|
|
6728
|
+
return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
|
|
6729
|
+
}
|
|
6730
|
+
return committedReturnArr(expectedArr, posExpr);
|
|
6398
6731
|
}
|
|
6399
6732
|
function propagateFailBody(ctx, srcCtx = "_ctx") {
|
|
6400
6733
|
if (srcCtx !== "_ctx") {
|
|
6401
6734
|
if (ctx.failLabel) {
|
|
6402
6735
|
if (!ctx.recordFail) return `break ${ctx.failLabel}`;
|
|
6403
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; break ${ctx.failLabel} }`;
|
|
6736
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
|
|
6404
6737
|
}
|
|
6405
|
-
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; ${resultFromRecorded()} }`;
|
|
6738
|
+
return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
|
|
6406
6739
|
}
|
|
6407
6740
|
if (ctx.failLabel) return `break ${ctx.failLabel}`;
|
|
6408
6741
|
return resultFromRecorded();
|
|
@@ -6615,6 +6948,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6615
6948
|
// nothing committed remains.
|
|
6616
6949
|
case "choice":
|
|
6617
6950
|
return false;
|
|
6951
|
+
case "dispatch":
|
|
6952
|
+
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);
|
|
6618
6953
|
case "attempt":
|
|
6619
6954
|
return false;
|
|
6620
6955
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
@@ -6659,6 +6994,50 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6659
6994
|
return true;
|
|
6660
6995
|
}
|
|
6661
6996
|
}
|
|
6997
|
+
function mayCommitFailure(p, seen = /* @__PURE__ */ new Set()) {
|
|
6998
|
+
if (seen.has(p)) return false;
|
|
6999
|
+
seen.add(p);
|
|
7000
|
+
const d = p._def;
|
|
7001
|
+
switch (d.tag) {
|
|
7002
|
+
case "dispatch":
|
|
7003
|
+
return true;
|
|
7004
|
+
case "choice":
|
|
7005
|
+
case "sequence":
|
|
7006
|
+
return d.parsers.some((x) => mayCommitFailure(x, seen));
|
|
7007
|
+
case "many":
|
|
7008
|
+
case "oneOrMore":
|
|
7009
|
+
case "optional":
|
|
7010
|
+
case "attempt":
|
|
7011
|
+
case "transform":
|
|
7012
|
+
case "label":
|
|
7013
|
+
case "field":
|
|
7014
|
+
case "grammar":
|
|
7015
|
+
case "node":
|
|
7016
|
+
return mayCommitFailure(d.parser, seen);
|
|
7017
|
+
case "sepBy":
|
|
7018
|
+
return mayCommitFailure(d.parser, seen) || mayCommitFailure(d.separator, seen);
|
|
7019
|
+
case "skip":
|
|
7020
|
+
return mayCommitFailure(d.main, seen) || mayCommitFailure(d.skipped, seen);
|
|
7021
|
+
case "token":
|
|
7022
|
+
case "leaf":
|
|
7023
|
+
return mayCommitFailure(d.parser, seen);
|
|
7024
|
+
case "withCtx":
|
|
7025
|
+
return mayCommitFailure(d.parser, seen);
|
|
7026
|
+
case "scanTo":
|
|
7027
|
+
return mayCommitFailure(d.sentinel, seen) || d.skip.some((x) => mayCommitFailure(x, seen));
|
|
7028
|
+
case "lazy": {
|
|
7029
|
+
try {
|
|
7030
|
+
return mayCommitFailure(d.thunk(), seen);
|
|
7031
|
+
} catch {
|
|
7032
|
+
return true;
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
case "unknown":
|
|
7036
|
+
return true;
|
|
7037
|
+
default:
|
|
7038
|
+
return false;
|
|
7039
|
+
}
|
|
7040
|
+
}
|
|
6662
7041
|
function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
6663
7042
|
if (seen.has(p)) return false;
|
|
6664
7043
|
seen.add(p);
|
|
@@ -6669,6 +7048,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6669
7048
|
case "keywords":
|
|
6670
7049
|
case "node":
|
|
6671
7050
|
case "token":
|
|
7051
|
+
case "routed":
|
|
6672
7052
|
case "leaf":
|
|
6673
7053
|
return true;
|
|
6674
7054
|
case "not":
|
|
@@ -6680,6 +7060,8 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
6680
7060
|
case "sequence":
|
|
6681
7061
|
case "choice":
|
|
6682
7062
|
return d.parsers.some((x) => capturesLeaf(x, seen));
|
|
7063
|
+
case "dispatch":
|
|
7064
|
+
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);
|
|
6683
7065
|
case "sepBy":
|
|
6684
7066
|
return capturesLeaf(d.parser, seen) || capturesLeaf(d.separator, seen);
|
|
6685
7067
|
case "many":
|
|
@@ -6726,6 +7108,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6726
7108
|
ctx.recordFail = savedRecord;
|
|
6727
7109
|
const ind0 = ind(ctx);
|
|
6728
7110
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
7111
|
+
const mayCommit = mayCommitFailure(inner);
|
|
6729
7112
|
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
6730
7113
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
6731
7114
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
@@ -6739,6 +7122,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6739
7122
|
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
6740
7123
|
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
6741
7124
|
] : [],
|
|
7125
|
+
...mayCommit ? [`${ind0}_ctx._fc = false`] : [],
|
|
6742
7126
|
`${ind0}${lbl}: {`,
|
|
6743
7127
|
...r.stmts,
|
|
6744
7128
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
@@ -6747,7 +7131,7 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
6747
7131
|
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
6748
7132
|
] : []
|
|
6749
7133
|
];
|
|
6750
|
-
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
7134
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV, mayCommit };
|
|
6751
7135
|
}
|
|
6752
7136
|
var CHARCODE_CHAIN_MAX = 16;
|
|
6753
7137
|
function emitLit(def, ctx, pos) {
|
|
@@ -7124,6 +7508,186 @@ function emitChoice(parser2, def, ctx, pos) {
|
|
|
7124
7508
|
}
|
|
7125
7509
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
7126
7510
|
}
|
|
7511
|
+
function emitTailFallible(parser2, ctx, pos) {
|
|
7512
|
+
const savedRecord = ctx.recordFail;
|
|
7513
|
+
ctx.recordFail = true;
|
|
7514
|
+
const out = emitFallible(parser2, ctx, pos);
|
|
7515
|
+
ctx.recordFail = savedRecord;
|
|
7516
|
+
return out;
|
|
7517
|
+
}
|
|
7518
|
+
function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
|
|
7519
|
+
if (seen.has(p)) return false;
|
|
7520
|
+
seen.add(p);
|
|
7521
|
+
const d = p._def;
|
|
7522
|
+
switch (d.tag) {
|
|
7523
|
+
case "expect":
|
|
7524
|
+
case "recover":
|
|
7525
|
+
return true;
|
|
7526
|
+
case "many":
|
|
7527
|
+
case "oneOrMore":
|
|
7528
|
+
case "sepBy":
|
|
7529
|
+
return recovery || mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7530
|
+
case "choice":
|
|
7531
|
+
case "sequence": {
|
|
7532
|
+
for (const item of d.parsers) {
|
|
7533
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7534
|
+
}
|
|
7535
|
+
return false;
|
|
7536
|
+
}
|
|
7537
|
+
case "dispatch": {
|
|
7538
|
+
if (mayRecordRecoveryError(d.selector, recovery, seen)) return true;
|
|
7539
|
+
for (const item of d.cases) {
|
|
7540
|
+
if (mayRecordRecoveryError(item.parser, recovery, seen)) return true;
|
|
7541
|
+
}
|
|
7542
|
+
if (d.matchers?.some((item) => mayRecordRecoveryError(item.parser, recovery, seen))) return true;
|
|
7543
|
+
return d.otherwise ? mayRecordRecoveryError(d.otherwise, recovery, seen) : false;
|
|
7544
|
+
}
|
|
7545
|
+
case "attempt":
|
|
7546
|
+
case "transform":
|
|
7547
|
+
case "label":
|
|
7548
|
+
case "field":
|
|
7549
|
+
case "grammar":
|
|
7550
|
+
case "node":
|
|
7551
|
+
case "token":
|
|
7552
|
+
case "leaf":
|
|
7553
|
+
case "withCtx":
|
|
7554
|
+
case "optional":
|
|
7555
|
+
return mayRecordRecoveryError(d.parser, recovery, seen);
|
|
7556
|
+
case "skip":
|
|
7557
|
+
return mayRecordRecoveryError(d.main, recovery, seen) || mayRecordRecoveryError(d.skipped, recovery, seen);
|
|
7558
|
+
case "scanTo":
|
|
7559
|
+
if (mayRecordRecoveryError(d.sentinel, recovery, seen)) return true;
|
|
7560
|
+
for (const item of d.skip) {
|
|
7561
|
+
if (mayRecordRecoveryError(item, recovery, seen)) return true;
|
|
7562
|
+
}
|
|
7563
|
+
return false;
|
|
7564
|
+
case "lazy": {
|
|
7565
|
+
try {
|
|
7566
|
+
return mayRecordRecoveryError(d.thunk(), recovery, seen);
|
|
7567
|
+
} catch {
|
|
7568
|
+
return true;
|
|
7569
|
+
}
|
|
7570
|
+
}
|
|
7571
|
+
case "unknown":
|
|
7572
|
+
return true;
|
|
7573
|
+
default:
|
|
7574
|
+
return false;
|
|
7575
|
+
}
|
|
7576
|
+
}
|
|
7577
|
+
function emitDispatchCombinator(parser2, def, ctx, pos) {
|
|
7578
|
+
if (parserUsesRouted2(def.selector)) {
|
|
7579
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
7580
|
+
}
|
|
7581
|
+
const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
|
|
7582
|
+
const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
|
|
7583
|
+
const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
|
|
7584
|
+
const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
|
|
7585
|
+
const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
|
|
7586
|
+
const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
|
|
7587
|
+
const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
|
|
7588
|
+
const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
|
|
7589
|
+
const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
|
|
7590
|
+
const selector = emit(def.selector, ctx, pos);
|
|
7591
|
+
const outV = v(ctx, "_dval");
|
|
7592
|
+
const outE = v(ctx, "_dend");
|
|
7593
|
+
const keyV = v(ctx, "_dkey");
|
|
7594
|
+
const stmts = [
|
|
7595
|
+
...selectorLeafMark ? [
|
|
7596
|
+
`${ind(ctx)}const ${selectorLeafMark} = _ctx._cstLeaves?.length ?? 0`,
|
|
7597
|
+
`${ind(ctx)}const ${selectorRawMark} = _ctx._cstRawChildren?.length ?? 0`,
|
|
7598
|
+
`${ind(ctx)}const ${selectorTriviaMark} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
7599
|
+
`${ind(ctx)}const ${selectorLogMark} = _ctx._triviaLog?.length ?? 0`,
|
|
7600
|
+
`${ind(ctx)}const ${selectorFieldMark} = _ctx._fields?.length ?? 0`,
|
|
7601
|
+
`${ind(ctx)}const ${selectorErrorMark} = _ctx._errors?.length ?? 0`
|
|
7602
|
+
] : [],
|
|
7603
|
+
...selector.stmts,
|
|
7604
|
+
`${ind(ctx)}const ${keyV} = ${selector.valueVar}`,
|
|
7605
|
+
`${ind(ctx)}let ${outV}, ${outE} = ${selector.endVar}`
|
|
7606
|
+
];
|
|
7607
|
+
let wroteBranch = false;
|
|
7608
|
+
const emitSelectedTail = (entry, keyword, condition, coverageId) => {
|
|
7609
|
+
const parser3 = entry.parser;
|
|
7610
|
+
const head = keyword === "else" ? `${ind(ctx)}else {` : `${ind(ctx)}${keyword} (${condition}) {`;
|
|
7611
|
+
stmts.push(head);
|
|
7612
|
+
ctx.indent++;
|
|
7613
|
+
const usesRouted = branchUsesRouted2(entry);
|
|
7614
|
+
const routedV = usesRouted ? v(ctx, "_drt") : null;
|
|
7615
|
+
const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
|
|
7616
|
+
const errMark = mayError ? v(ctx, "_derr") : null;
|
|
7617
|
+
const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
|
|
7618
|
+
if (routedV) {
|
|
7619
|
+
stmts.push(
|
|
7620
|
+
`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
|
|
7621
|
+
...selectorLeafMark ? [
|
|
7622
|
+
`${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}`
|
|
7623
|
+
] : []
|
|
7624
|
+
);
|
|
7625
|
+
}
|
|
7626
|
+
if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
|
|
7627
|
+
if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
|
|
7628
|
+
const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
|
|
7629
|
+
stmts.push(...coverageAttempt(ctx, coverageId, pos));
|
|
7630
|
+
const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
|
|
7631
|
+
const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
|
|
7632
|
+
const routedRollback = routedV ? `_ctx._routed = ${routedV}; ` : "";
|
|
7633
|
+
const coverageFailure = coverageId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageId)}, phase: 'failure', offset: _ctx._fe }); `;
|
|
7634
|
+
stmts.push(
|
|
7635
|
+
...tail.stmts,
|
|
7636
|
+
`${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
|
|
7637
|
+
...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
|
|
7638
|
+
`${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
|
|
7639
|
+
`${ind(ctx)}${outE} = ${tail.endVar}`,
|
|
7640
|
+
...coverageHit(ctx, coverageId, pos, tail.endVar)
|
|
7641
|
+
);
|
|
7642
|
+
ctx.indent--;
|
|
7643
|
+
stmts.push(`${ind(ctx)}}`);
|
|
7644
|
+
};
|
|
7645
|
+
let coverageIndex = 0;
|
|
7646
|
+
for (const entry of def.cases) {
|
|
7647
|
+
const condition = entry.keys.map((key) => emitDispatchKeyCondition(keyV, key, entry.caseInsensitive)).join(" || ");
|
|
7648
|
+
emitSelectedTail(entry, wroteBranch ? "else if" : "if", condition, coverageIds[coverageIndex++]);
|
|
7649
|
+
wroteBranch = true;
|
|
7650
|
+
}
|
|
7651
|
+
const emitMatcherTails = () => {
|
|
7652
|
+
for (const matcher of def.matchers ?? []) {
|
|
7653
|
+
emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
|
|
7654
|
+
wroteBranch = true;
|
|
7655
|
+
}
|
|
7656
|
+
};
|
|
7657
|
+
if (def.otherwise) {
|
|
7658
|
+
emitMatcherTails();
|
|
7659
|
+
const otherwiseEntry = { parser: def.otherwise, usesRouted: def.otherwiseUsesRouted };
|
|
7660
|
+
if (wroteBranch) emitSelectedTail(otherwiseEntry, "else", void 0, coverageIds[coverageIndex++]);
|
|
7661
|
+
else emitSelectedTail(otherwiseEntry, "if", "true", coverageIds[coverageIndex++]);
|
|
7662
|
+
} else {
|
|
7663
|
+
emitMatcherTails();
|
|
7664
|
+
const expected = JSON.stringify(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))));
|
|
7665
|
+
const fail = failArrBody(ctx, expected, selector.endVar);
|
|
7666
|
+
stmts.push(wroteBranch ? `${ind(ctx)}else { ${fail} }` : `${ind(ctx)}${fail}`);
|
|
7667
|
+
}
|
|
7668
|
+
return { stmts, valueVar: outV, endVar: outE };
|
|
7669
|
+
}
|
|
7670
|
+
function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
|
|
7671
|
+
if (!caseInsensitive) return `${valueVar} === ${JSON.stringify(key)}`;
|
|
7672
|
+
const parts = [`${valueVar}.length === ${key.length}`];
|
|
7673
|
+
for (let i = 0; i < key.length; i++) {
|
|
7674
|
+
parts.push(foldEq(`${valueVar}.charCodeAt(${i})`, key.charCodeAt(i)));
|
|
7675
|
+
}
|
|
7676
|
+
return parts.join(" && ");
|
|
7677
|
+
}
|
|
7678
|
+
function emitDispatchMatcherCondition(valueVar, matcher) {
|
|
7679
|
+
if (matcher.kind === "matches") {
|
|
7680
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
7681
|
+
return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
|
|
7682
|
+
}
|
|
7683
|
+
const text = matcher.value;
|
|
7684
|
+
const parts = [`${valueVar}.length >= ${text.length}`];
|
|
7685
|
+
const offset = matcher.kind === "endsWith" ? `${valueVar}.length - ${text.length}` : "0";
|
|
7686
|
+
for (let i = 0; i < text.length; i++) {
|
|
7687
|
+
parts.push(matcher.caseInsensitive ? foldEq(`${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`})`, text.charCodeAt(i)) : `${valueVar}.charCodeAt(${offset}${i === 0 ? "" : ` + ${i}`}) === ${text.charCodeAt(i)}`);
|
|
7688
|
+
}
|
|
7689
|
+
return parts.join(" && ");
|
|
7690
|
+
}
|
|
7127
7691
|
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
7128
7692
|
const superParser = def.parsers[superIndex];
|
|
7129
7693
|
const regexDef = getCoreRegexDef(superParser);
|
|
@@ -7245,12 +7809,16 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7245
7809
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
7246
7810
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
7247
7811
|
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
7812
|
+
const armMayRecordError = mayRecordRecoveryError(p, !!ctx.recovery);
|
|
7248
7813
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
7249
7814
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
7250
7815
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
7251
7816
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
7252
7817
|
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
7253
|
-
const
|
|
7818
|
+
const markErrors = armMayRecordError ? v(ctx, "_cme") : null;
|
|
7819
|
+
const captureRollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
7820
|
+
const errorRollback = markErrors ? `if (_ctx._errors && _ctx._errors.length !== ${markErrors}) _ctx._errors.length = ${markErrors}` : "";
|
|
7821
|
+
const rollback = [captureRollback, errorRollback].filter(Boolean).join("; ");
|
|
7254
7822
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
7255
7823
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
7256
7824
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -7265,7 +7833,9 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7265
7833
|
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
7266
7834
|
);
|
|
7267
7835
|
}
|
|
7268
|
-
|
|
7836
|
+
if (markErrors) stmts.push(`${ind(ctx)}const ${markErrors} = _ctx._errors?.length ?? 0`);
|
|
7837
|
+
const arm = emitFallible(p, ctx, pos, atStart);
|
|
7838
|
+
const { stmts: armStmts, okVar, valVar, endVar } = arm;
|
|
7269
7839
|
stmts.push(...armStmts);
|
|
7270
7840
|
if (autoNot && autoNot.length > 0) {
|
|
7271
7841
|
const anCode = v(ctx, "_anc");
|
|
@@ -7289,10 +7859,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
|
7289
7859
|
stmts.push(`${ind(ctx)}}`);
|
|
7290
7860
|
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}; ${coverageBase === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} });`} }`);
|
|
7291
7861
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
7862
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7292
7863
|
} else {
|
|
7293
7864
|
const rejectedFlush = autoRejectedV === void 0 ? "" : `; for (const _rejectedId of ${autoRejectedV}) { _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'failure', offset: ${pos} }); _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'backtrack', offset: ${pos} }) }`;
|
|
7294
7865
|
stmts.push(`${ind(ctx)}if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true${coverageBase === void 0 ? "" : `${rejectedFlush}; _ctx._grammarCoverage?.(${JSON.stringify(`${coverageBase}${i}`)}); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'selected', offset: ${pos}, end: ${endVar} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'success', offset: ${pos}, end: ${endVar} })`} }`);
|
|
7295
7866
|
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}${rollback ? `; ${rollback}` : ""}${coverageBase === void 0 ? "" : `; _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} })`} }`);
|
|
7867
|
+
if (arm.mayCommit) stmts.push(`${ind(ctx)}if (!${resOkV} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7296
7868
|
}
|
|
7297
7869
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
7298
7870
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -7449,7 +8021,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7449
8021
|
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
7450
8022
|
);
|
|
7451
8023
|
}
|
|
7452
|
-
const
|
|
8024
|
+
const iter = emitFallible(def.parser, ctx, itemPos, true);
|
|
8025
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = iter;
|
|
7453
8026
|
stmts.push(...iterStmts);
|
|
7454
8027
|
if (ctx.recovery) {
|
|
7455
8028
|
const rrV = v(ctx, "_rr");
|
|
@@ -7468,7 +8041,8 @@ function emitMany(def, ctx, pos) {
|
|
|
7468
8041
|
`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`
|
|
7469
8042
|
);
|
|
7470
8043
|
} else {
|
|
7471
|
-
stmts.push(`${ind(ctx)}if (!${iterOk}
|
|
8044
|
+
stmts.push(`${ind(ctx)}if (!${iterOk}) { ${rollback}${iter.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
8045
|
+
stmts.push(`${ind(ctx)}if (${iterEnd} <= ${itemPos}) { ${rollback}break }`);
|
|
7472
8046
|
}
|
|
7473
8047
|
if (wantValue) stmts.push(`${ind(ctx)}${arrV}.push(${iterVal})`);
|
|
7474
8048
|
else if (maxV !== null) stmts.push(`${ind(ctx)}${maxV}++`);
|
|
@@ -7480,10 +8054,12 @@ function emitMany(def, ctx, pos) {
|
|
|
7480
8054
|
function emitOptional(def, ctx, pos) {
|
|
7481
8055
|
const valV = v(ctx, "_opt");
|
|
7482
8056
|
const endV = v(ctx, "_opte");
|
|
7483
|
-
const
|
|
8057
|
+
const inner = emitFallible(def.parser, ctx, pos, true);
|
|
8058
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = inner;
|
|
7484
8059
|
const ind0 = ind(ctx);
|
|
7485
8060
|
const stmts = [
|
|
7486
8061
|
...lblStmts,
|
|
8062
|
+
...inner.mayCommit ? [`${ind0}if (!${okVar} && _ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7487
8063
|
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
7488
8064
|
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
7489
8065
|
];
|
|
@@ -7515,7 +8091,7 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
7515
8091
|
...preGuard,
|
|
7516
8092
|
`${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${trivia2} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`,
|
|
7517
8093
|
...inner.stmts,
|
|
7518
|
-
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
8094
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback}${inner.mayCommit ? ` if (_ctx._fc) ${committedFailBody(ctx)};` : ""} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
7519
8095
|
],
|
|
7520
8096
|
valueVar: inner.valVar,
|
|
7521
8097
|
endVar: inner.endVar
|
|
@@ -7529,18 +8105,21 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7529
8105
|
const exp = rec ? hoistExpected(ctx, deriveExpectedArr([def.parser])) : "";
|
|
7530
8106
|
const sepSent = rec ? syncSentinelExpr(firstSetOf(def.separator)) : null;
|
|
7531
8107
|
const scanSync = sepSent ? `_ctx._rec.or(${sepSent}, ${mySyncV})` : mySyncV;
|
|
7532
|
-
const
|
|
8108
|
+
const first = emitFallible(def.parser, ctx, pos, true);
|
|
8109
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = first;
|
|
7533
8110
|
const stmts = [
|
|
7534
8111
|
`${ind(ctx)}const ${arrV} = []`,
|
|
7535
8112
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
7536
8113
|
...rec ? [`${ind(ctx)}const ${mySyncV} = _ctx._sync`] : [],
|
|
7537
8114
|
...firstStmts
|
|
7538
8115
|
];
|
|
7539
|
-
const failItem = (nextOkVar, itemPosVar, breakStmt) => {
|
|
7540
|
-
if (
|
|
8116
|
+
const failItem = (nextOkVar, nextMayCommit, itemPosVar, breakStmt) => {
|
|
8117
|
+
const commit = nextMayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : "";
|
|
8118
|
+
if (!rec) return [`${ind(ctx)}if (!${nextOkVar}) { ${commit}${breakStmt} }`];
|
|
7541
8119
|
const rr = v(ctx, "_rr");
|
|
7542
8120
|
return [
|
|
7543
8121
|
`${ind(ctx)}if (!${nextOkVar}) {`,
|
|
8122
|
+
...nextMayCommit ? [`${ind(ctx)} if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7544
8123
|
`${ind(ctx)} if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${itemPosVar}, _ctx)) {`,
|
|
7545
8124
|
`${ind(ctx)} const ${rr} = _ctx._rec.scan(input, ${itemPosVar}, _ctx, ${scanSync}, ${exp})`,
|
|
7546
8125
|
`${ind(ctx)} ${arrV}.push(${rr}.error); _ctx._rec.capture(_ctx, ${rr}.error); ${curV} = ${rr}.end; continue`,
|
|
@@ -7569,6 +8148,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7569
8148
|
stmts.push(
|
|
7570
8149
|
`${ind(ctx)}let ${didV} = false`,
|
|
7571
8150
|
`${ind(ctx)}if (${firstOk}) { ${arrV}.push(${firstVal}); ${curV} = ${firstEnd}; ${didV} = true }`,
|
|
8151
|
+
...first.mayCommit ? [`${ind(ctx)}else if (_ctx._fc) ${committedFailBody(ctx)}`] : [],
|
|
7572
8152
|
`${ind(ctx)}else if (_ctx._tolerant && ${mySyncV} !== undefined && !_ctx._rec.at(${mySyncV}, input, ${pos}, _ctx)) {`,
|
|
7573
8153
|
`${ind(ctx)} const ${rr0} = _ctx._rec.scan(input, ${pos}, _ctx, ${scanSync}, ${exp})`,
|
|
7574
8154
|
`${ind(ctx)} ${arrV}.push(${rr0}.error); _ctx._rec.capture(_ctx, ${rr0}.error); ${curV} = ${rr0}.end; ${didV} = true`,
|
|
@@ -7579,6 +8159,7 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7579
8159
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
7580
8160
|
ctx.indent++;
|
|
7581
8161
|
} else {
|
|
8162
|
+
if (first.mayCommit) stmts.push(`${ind(ctx)}if (!${firstOk} && _ctx._fc) ${committedFailBody(ctx)}`);
|
|
7582
8163
|
stmts.push(`${ind(ctx)}if (${firstOk}) {`);
|
|
7583
8164
|
ctx.indent++;
|
|
7584
8165
|
stmts.push(
|
|
@@ -7607,16 +8188,18 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7607
8188
|
);
|
|
7608
8189
|
sepAtPos = spV;
|
|
7609
8190
|
const rollbackToSep = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markV}) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${markTl}) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}; `;
|
|
7610
|
-
const
|
|
7611
|
-
stmts
|
|
8191
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8192
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8193
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7612
8194
|
const post = postSepMarks();
|
|
7613
8195
|
stmts.push(...post.decl);
|
|
7614
8196
|
const npV = v(ctx, "_np");
|
|
7615
8197
|
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`);
|
|
7616
|
-
const
|
|
8198
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8199
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7617
8200
|
stmts.push(
|
|
7618
8201
|
...nextStmts,
|
|
7619
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
8202
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, rollbackToSep, post.rb)),
|
|
7620
8203
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7621
8204
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7622
8205
|
);
|
|
@@ -7625,14 +8208,16 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7625
8208
|
const spV = v(ctx, "_sp");
|
|
7626
8209
|
stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
|
|
7627
8210
|
sepAtPos = spV;
|
|
7628
|
-
const
|
|
7629
|
-
stmts
|
|
8211
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8212
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8213
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7630
8214
|
const npV = v(ctx, "_np");
|
|
7631
8215
|
stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
|
|
7632
|
-
const
|
|
8216
|
+
const next = emitFallible(def.parser, ctx, npV, true);
|
|
8217
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7633
8218
|
stmts.push(
|
|
7634
8219
|
...nextStmts,
|
|
7635
|
-
...failItem(nextOk, npV, itemFailBreak(sepEnd, "", "")),
|
|
8220
|
+
...failItem(nextOk, next.mayCommit, npV, itemFailBreak(sepEnd, "", "")),
|
|
7636
8221
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7637
8222
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7638
8223
|
);
|
|
@@ -7646,15 +8231,17 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
7646
8231
|
`${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
|
|
7647
8232
|
);
|
|
7648
8233
|
}
|
|
7649
|
-
const
|
|
7650
|
-
stmts
|
|
8234
|
+
const sep = emitFallible(def.separator, ctx, sepAtPos, true);
|
|
8235
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
|
|
8236
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
|
|
7651
8237
|
const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; ` : "";
|
|
7652
8238
|
const post = postSepMarks();
|
|
7653
8239
|
stmts.push(...post.decl);
|
|
7654
|
-
const
|
|
8240
|
+
const next = emitFallible(def.parser, ctx, sepEnd, true);
|
|
8241
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = next;
|
|
7655
8242
|
stmts.push(
|
|
7656
8243
|
...nextStmts,
|
|
7657
|
-
...failItem(nextOk, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
8244
|
+
...failItem(nextOk, next.mayCommit, sepEnd, itemFailBreak(sepEnd, nextRb, post.rb)),
|
|
7658
8245
|
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
7659
8246
|
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
7660
8247
|
);
|
|
@@ -7755,6 +8342,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
7755
8342
|
endVar: pos
|
|
7756
8343
|
};
|
|
7757
8344
|
}
|
|
8345
|
+
function emitRouted(ctx, pos) {
|
|
8346
|
+
const item = v(ctx, "_rt");
|
|
8347
|
+
return {
|
|
8348
|
+
stmts: [
|
|
8349
|
+
`${ind(ctx)}const ${item} = _ctx._routed`,
|
|
8350
|
+
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8351
|
+
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8352
|
+
],
|
|
8353
|
+
valueVar: `${item}.value`,
|
|
8354
|
+
endVar: `${item}.span.end`
|
|
8355
|
+
};
|
|
8356
|
+
}
|
|
7758
8357
|
function escapeTokenLiteral(value) {
|
|
7759
8358
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
7760
8359
|
}
|
|
@@ -8035,7 +8634,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
8035
8634
|
const rv = v(ctx, "_rt");
|
|
8036
8635
|
const vv = v(ctx, "_rtv");
|
|
8037
8636
|
const ev = v(ctx, "_rte");
|
|
8038
|
-
const failStmt = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${rv}.span.start; _ctx._fx = ${rv}.expected; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : `return { ok: false, expected: ${rv}.expected, span: ${rv}.span }`;
|
|
8637
|
+
const failStmt = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${rv}.span.start; _ctx._fx = ${rv}.expected; _ctx._fc = ${rv}.committed === true; break ${ctx.failLabel} }` : `{ _ctx._fc = ${rv}.committed === true; break ${ctx.failLabel} }` : `return { ok: false, expected: ${rv}.expected, span: ${rv}.span, ...(${rv}.committed ? { committed: true } : {}) }`;
|
|
8039
8638
|
const stmts = [
|
|
8040
8639
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
8041
8640
|
...emitIfFail(ctx, `!${rv}.ok`, failStmt),
|
|
@@ -8116,7 +8715,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
8116
8715
|
return { stmts, valueVar: valVar, endVar };
|
|
8117
8716
|
}
|
|
8118
8717
|
function emitExpect(def, ctx, pos) {
|
|
8119
|
-
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
8718
|
+
const { stmts: innerStmts, okVar, valVar, endVar, mayCommit } = emitFallible(def.parser, ctx, pos);
|
|
8120
8719
|
const ind0 = ind(ctx);
|
|
8121
8720
|
const errV = v(ctx, "_err");
|
|
8122
8721
|
const stmts = [
|
|
@@ -8128,6 +8727,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8128
8727
|
// interpreter (expect.ts) and the list-recovery emit sites — guarded on
|
|
8129
8728
|
// `_ctx._tolerant`, under which the driver always installs `_ctx._rec`.
|
|
8130
8729
|
`${ind0} if (_ctx._tolerant) _ctx._rec.capture(_ctx, ${errV})`,
|
|
8730
|
+
...mayCommit ? [`${ind0} _ctx._fc = false`] : [],
|
|
8131
8731
|
`${ind0} ${valVar} = ${errV}`,
|
|
8132
8732
|
`${ind0} ${endVar} = ${pos}`,
|
|
8133
8733
|
`${ind0} ${okVar} = true`,
|
|
@@ -8138,7 +8738,7 @@ function emitExpect(def, ctx, pos) {
|
|
|
8138
8738
|
function emit(p, ctx, pos) {
|
|
8139
8739
|
const replay = ctx.replayPrefix?.get(p);
|
|
8140
8740
|
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
8141
|
-
const
|
|
8741
|
+
const dispatch2 = (emissionPos = pos) => {
|
|
8142
8742
|
const savedRule = ctx.activeCoverageRuleId;
|
|
8143
8743
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
8144
8744
|
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
@@ -8178,14 +8778,14 @@ function emit(p, ctx, pos) {
|
|
|
8178
8778
|
ctx.indent = 1;
|
|
8179
8779
|
ctx.failLabel = "_pfail";
|
|
8180
8780
|
ctx.recordFail = true;
|
|
8181
|
-
const r =
|
|
8781
|
+
const r = dispatch2("_pos");
|
|
8182
8782
|
ctx.indent = savedIndent;
|
|
8183
8783
|
ctx.failLabel = savedFailLabel;
|
|
8184
8784
|
ctx.recordFail = savedRecord;
|
|
8185
8785
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
8186
8786
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
8187
8787
|
}
|
|
8188
|
-
return instrument(
|
|
8788
|
+
return instrument(dispatch2());
|
|
8189
8789
|
}
|
|
8190
8790
|
function emitDispatch(p, ctx, pos) {
|
|
8191
8791
|
const bal = p._balancedAmbient;
|
|
@@ -8218,6 +8818,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8218
8818
|
return emitSeq(def, ctx, pos);
|
|
8219
8819
|
case "choice":
|
|
8220
8820
|
return emitChoice(p, def, ctx, pos);
|
|
8821
|
+
case "dispatch":
|
|
8822
|
+
return emitDispatchCombinator(p, def, ctx, pos);
|
|
8221
8823
|
case "attempt":
|
|
8222
8824
|
return emitAttempt(p, def, ctx, pos);
|
|
8223
8825
|
case "many":
|
|
@@ -8342,6 +8944,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
8342
8944
|
return emitNot(def, ctx, pos);
|
|
8343
8945
|
case "peek":
|
|
8344
8946
|
return emitPeek(def, ctx, pos);
|
|
8947
|
+
case "routed":
|
|
8948
|
+
return emitRouted(ctx, pos);
|
|
8345
8949
|
case "node":
|
|
8346
8950
|
return emitNode(def, ctx, pos);
|
|
8347
8951
|
case "scanTo":
|
|
@@ -8438,6 +9042,8 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8438
9042
|
case "sequence":
|
|
8439
9043
|
case "choice":
|
|
8440
9044
|
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
9045
|
+
case "dispatch":
|
|
9046
|
+
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);
|
|
8441
9047
|
case "sepBy":
|
|
8442
9048
|
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
8443
9049
|
case "scanTo":
|
|
@@ -8452,6 +9058,26 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
8452
9058
|
return false;
|
|
8453
9059
|
}
|
|
8454
9060
|
}
|
|
9061
|
+
function parserUsesRouted2(p, seen = /* @__PURE__ */ new Set()) {
|
|
9062
|
+
if (seen.has(p)) return false;
|
|
9063
|
+
seen.add(p);
|
|
9064
|
+
const d = p._def;
|
|
9065
|
+
switch (d.tag) {
|
|
9066
|
+
case "routed":
|
|
9067
|
+
return true;
|
|
9068
|
+
case "lazy": {
|
|
9069
|
+
try {
|
|
9070
|
+
return parserUsesRouted2(d.thunk(), seen);
|
|
9071
|
+
} catch {
|
|
9072
|
+
return false;
|
|
9073
|
+
}
|
|
9074
|
+
}
|
|
9075
|
+
case "dispatch":
|
|
9076
|
+
return false;
|
|
9077
|
+
default:
|
|
9078
|
+
return childrenOf2(d).some((child) => parserUsesRouted2(child, seen));
|
|
9079
|
+
}
|
|
9080
|
+
}
|
|
8455
9081
|
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
8456
9082
|
if (seen.has(p)) return false;
|
|
8457
9083
|
seen.add(p);
|
|
@@ -8471,6 +9097,8 @@ function childrenOf2(def) {
|
|
|
8471
9097
|
case "sequence":
|
|
8472
9098
|
case "choice":
|
|
8473
9099
|
return def.parsers;
|
|
9100
|
+
case "dispatch":
|
|
9101
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
8474
9102
|
case "many":
|
|
8475
9103
|
case "attempt":
|
|
8476
9104
|
case "optional":
|
|
@@ -8507,6 +9135,7 @@ function childrenOf2(def) {
|
|
|
8507
9135
|
case "regex":
|
|
8508
9136
|
case "keywords":
|
|
8509
9137
|
case "guard":
|
|
9138
|
+
case "routed":
|
|
8510
9139
|
case "unknown":
|
|
8511
9140
|
return [];
|
|
8512
9141
|
}
|
|
@@ -8514,6 +9143,7 @@ function childrenOf2(def) {
|
|
|
8514
9143
|
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
8515
9144
|
"sequence",
|
|
8516
9145
|
"choice",
|
|
9146
|
+
"dispatch",
|
|
8517
9147
|
"many",
|
|
8518
9148
|
"oneOrMore",
|
|
8519
9149
|
"optional",
|
|
@@ -9212,6 +9842,8 @@ function childrenOf3(def) {
|
|
|
9212
9842
|
case "sequence":
|
|
9213
9843
|
case "choice":
|
|
9214
9844
|
return def.parsers;
|
|
9845
|
+
case "dispatch":
|
|
9846
|
+
return [def.selector, ...def.cases.map((entry) => entry.parser), ...def.matchers ? def.matchers.map((entry) => entry.parser) : [], ...def.otherwise ? [def.otherwise] : []];
|
|
9215
9847
|
case "many":
|
|
9216
9848
|
case "oneOrMore":
|
|
9217
9849
|
case "optional":
|
|
@@ -9240,6 +9872,7 @@ function childrenOf3(def) {
|
|
|
9240
9872
|
case "literal":
|
|
9241
9873
|
case "regex":
|
|
9242
9874
|
case "keywords":
|
|
9875
|
+
case "routed":
|
|
9243
9876
|
case "guard":
|
|
9244
9877
|
case "recover":
|
|
9245
9878
|
case "unknown":
|
|
@@ -9264,6 +9897,16 @@ function repeatOpts(min, max, trailing) {
|
|
|
9264
9897
|
if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
|
|
9265
9898
|
return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
|
|
9266
9899
|
}
|
|
9900
|
+
function matcherExpr(entry) {
|
|
9901
|
+
switch (entry.kind) {
|
|
9902
|
+
case "startsWith":
|
|
9903
|
+
return `startsWith(${JSON.stringify(entry.value)})`;
|
|
9904
|
+
case "endsWith":
|
|
9905
|
+
return `endsWith(${JSON.stringify(entry.value)})`;
|
|
9906
|
+
case "matches":
|
|
9907
|
+
return `matches(${new RegExp(entry.value, entry.flags ?? "").toString()})`;
|
|
9908
|
+
}
|
|
9909
|
+
}
|
|
9267
9910
|
function serializeRuleMap(ruleMap, scanSkip) {
|
|
9268
9911
|
try {
|
|
9269
9912
|
return new Serializer(ruleMap, scanSkip ?? []).run();
|
|
@@ -9361,6 +10004,13 @@ function evalRuleMapIR(ir) {
|
|
|
9361
10004
|
"keywords",
|
|
9362
10005
|
"sequence",
|
|
9363
10006
|
"choice",
|
|
10007
|
+
"dispatch",
|
|
10008
|
+
"when",
|
|
10009
|
+
"startsWith",
|
|
10010
|
+
"endsWith",
|
|
10011
|
+
"matches",
|
|
10012
|
+
"otherwise",
|
|
10013
|
+
"routed",
|
|
9364
10014
|
"attempt",
|
|
9365
10015
|
"many",
|
|
9366
10016
|
"oneOrMore",
|
|
@@ -9394,6 +10044,13 @@ function evalRuleMapIR(ir) {
|
|
|
9394
10044
|
keywords,
|
|
9395
10045
|
sequence,
|
|
9396
10046
|
choice,
|
|
10047
|
+
dispatch,
|
|
10048
|
+
when,
|
|
10049
|
+
startsWith,
|
|
10050
|
+
endsWith,
|
|
10051
|
+
matches,
|
|
10052
|
+
otherwise,
|
|
10053
|
+
routed,
|
|
9397
10054
|
attempt,
|
|
9398
10055
|
many,
|
|
9399
10056
|
oneOrMore,
|
|
@@ -9579,6 +10236,18 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9579
10236
|
});
|
|
9580
10237
|
return `_gch([${items.join(", ")}])`;
|
|
9581
10238
|
}
|
|
10239
|
+
case "dispatch": {
|
|
10240
|
+
const arms = def.cases.map(
|
|
10241
|
+
(entry) => `when(${entry.keys.length === 1 ? JSON.stringify(entry.keys[0]) : JSON.stringify(entry.keys)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`
|
|
10242
|
+
);
|
|
10243
|
+
if (def.matchers) {
|
|
10244
|
+
for (const entry of def.matchers) {
|
|
10245
|
+
arms.push(`when(${matcherExpr(entry)}, ${kid(entry.parser)}${entry.caseInsensitive ? ", { caseInsensitive: true }" : ""})`);
|
|
10246
|
+
}
|
|
10247
|
+
}
|
|
10248
|
+
if (def.otherwise) arms.push(`otherwise(${kid(def.otherwise)})`);
|
|
10249
|
+
return `dispatch(${kid(def.selector)}${arms.length === 0 ? "" : `, ${arms.join(", ")}`})`;
|
|
10250
|
+
}
|
|
9582
10251
|
case "many":
|
|
9583
10252
|
return `many(${kid(def.parser)}${repeatOpts(def.min, def.max)})`;
|
|
9584
10253
|
// A `oneOrMore` def with min > 1 came from `many(x, { min: n })`; round-trip
|
|
@@ -9595,6 +10264,8 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
9595
10264
|
return `not(${kid(def.parser)})`;
|
|
9596
10265
|
case "peek":
|
|
9597
10266
|
return `peek(${kid(def.parser)})`;
|
|
10267
|
+
case "routed":
|
|
10268
|
+
return "routed()";
|
|
9598
10269
|
case "trivia":
|
|
9599
10270
|
return `trivia(${kid(def.parser)})`;
|
|
9600
10271
|
case "token":
|
|
@@ -10616,10 +11287,20 @@ function run(entry, input, options = {}) {
|
|
|
10616
11287
|
}
|
|
10617
11288
|
|
|
10618
11289
|
// src/coverage.ts
|
|
11290
|
+
function dispatchMatcher(entry) {
|
|
11291
|
+
switch (entry.kind) {
|
|
11292
|
+
case "startsWith":
|
|
11293
|
+
return startsWith(entry.value);
|
|
11294
|
+
case "endsWith":
|
|
11295
|
+
return endsWith(entry.value);
|
|
11296
|
+
case "matches":
|
|
11297
|
+
return matches(new RegExp(entry.value, entry.flags));
|
|
11298
|
+
}
|
|
11299
|
+
}
|
|
10619
11300
|
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
10620
11301
|
function compiledGrammarCoverageDefinitions(grammar) {
|
|
10621
11302
|
const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
|
|
10622
|
-
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"))) {
|
|
11303
|
+
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"))) {
|
|
10623
11304
|
throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
|
|
10624
11305
|
}
|
|
10625
11306
|
return definitions;
|
|
@@ -10798,6 +11479,56 @@ function coverageEntry(entry, collector, maps, trace) {
|
|
|
10798
11479
|
const unsafeSequence = sequence;
|
|
10799
11480
|
return unsafeSequence(...def.parsers.map(build));
|
|
10800
11481
|
}
|
|
11482
|
+
case "dispatch": {
|
|
11483
|
+
const ids = maps.dispatches.get(parser2) ?? [];
|
|
11484
|
+
let armIndex = 0;
|
|
11485
|
+
const dispatchStarts = [];
|
|
11486
|
+
const wrapArm = (arm, id) => {
|
|
11487
|
+
const child = build(arm);
|
|
11488
|
+
return {
|
|
11489
|
+
_tag: child._tag,
|
|
11490
|
+
_meta: child._meta,
|
|
11491
|
+
_def: child._def,
|
|
11492
|
+
parse(input, pos, ctx) {
|
|
11493
|
+
const dispatchStart = dispatchStarts[dispatchStarts.length - 1] ?? pos;
|
|
11494
|
+
if (id) trace?.write({ id, phase: "attempt", offset: dispatchStart });
|
|
11495
|
+
const result = child.parse(input, pos, ctx);
|
|
11496
|
+
if (result.ok) {
|
|
11497
|
+
if (id) {
|
|
11498
|
+
collector.hit(id);
|
|
11499
|
+
trace?.write({ id, phase: "selected", offset: dispatchStart, end: result.span.end });
|
|
11500
|
+
trace?.write({ id, phase: "success", offset: dispatchStart, end: result.span.end });
|
|
11501
|
+
}
|
|
11502
|
+
} else if (id) {
|
|
11503
|
+
trace?.write({ id, phase: "failure", offset: result.span.end });
|
|
11504
|
+
}
|
|
11505
|
+
return result;
|
|
11506
|
+
}
|
|
11507
|
+
};
|
|
11508
|
+
};
|
|
11509
|
+
const arms = def.cases.map(
|
|
11510
|
+
(entry2) => when(entry2.keys, wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0)
|
|
11511
|
+
);
|
|
11512
|
+
if (def.matchers) {
|
|
11513
|
+
for (const entry2 of def.matchers) {
|
|
11514
|
+
arms.push(when(dispatchMatcher(entry2), wrapArm(entry2.parser, ids[armIndex++]), entry2.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
11515
|
+
}
|
|
11516
|
+
}
|
|
11517
|
+
if (def.otherwise) arms.push(otherwise(wrapArm(def.otherwise, ids[armIndex++])));
|
|
11518
|
+
const unsafeDispatch = dispatch;
|
|
11519
|
+
const base2 = unsafeDispatch(build(def.selector), ...arms);
|
|
11520
|
+
return {
|
|
11521
|
+
...base2,
|
|
11522
|
+
parse(input, pos, ctx) {
|
|
11523
|
+
dispatchStarts.push(pos);
|
|
11524
|
+
try {
|
|
11525
|
+
return base2.parse(input, pos, ctx);
|
|
11526
|
+
} finally {
|
|
11527
|
+
dispatchStarts.pop();
|
|
11528
|
+
}
|
|
11529
|
+
}
|
|
11530
|
+
};
|
|
11531
|
+
}
|
|
10801
11532
|
case "many":
|
|
10802
11533
|
return many(build(def.parser));
|
|
10803
11534
|
case "oneOrMore":
|
|
@@ -11242,7 +11973,9 @@ export {
|
|
|
11242
11973
|
createGrammarTraceSink,
|
|
11243
11974
|
createVisitor,
|
|
11244
11975
|
cstBuildHost,
|
|
11976
|
+
dispatch,
|
|
11245
11977
|
duplicationFindingCount,
|
|
11978
|
+
endsWith,
|
|
11246
11979
|
expect,
|
|
11247
11980
|
extractCharClasses,
|
|
11248
11981
|
field,
|
|
@@ -11265,8 +11998,10 @@ export {
|
|
|
11265
11998
|
lineBreaksIn,
|
|
11266
11999
|
lineStartWithin,
|
|
11267
12000
|
literal,
|
|
12001
|
+
makeWhen,
|
|
11268
12002
|
makeWord,
|
|
11269
12003
|
many,
|
|
12004
|
+
matches,
|
|
11270
12005
|
noTrivia,
|
|
11271
12006
|
node,
|
|
11272
12007
|
not,
|
|
@@ -11274,6 +12009,7 @@ export {
|
|
|
11274
12009
|
oneOrMore,
|
|
11275
12010
|
oneOrMoreSep,
|
|
11276
12011
|
optional,
|
|
12012
|
+
otherwise,
|
|
11277
12013
|
parse,
|
|
11278
12014
|
parseDoc,
|
|
11279
12015
|
parser,
|
|
@@ -11282,6 +12018,7 @@ export {
|
|
|
11282
12018
|
regex,
|
|
11283
12019
|
relativize,
|
|
11284
12020
|
relativizeCST,
|
|
12021
|
+
routed,
|
|
11285
12022
|
rules,
|
|
11286
12023
|
run,
|
|
11287
12024
|
runWithGrammarCoverage,
|
|
@@ -11291,12 +12028,14 @@ export {
|
|
|
11291
12028
|
shiftAbsolute,
|
|
11292
12029
|
siteToString,
|
|
11293
12030
|
skip,
|
|
12031
|
+
startsWith,
|
|
11294
12032
|
token,
|
|
11295
12033
|
transform,
|
|
11296
12034
|
trivia,
|
|
11297
12035
|
triviaEntries,
|
|
11298
12036
|
triviaKindMask,
|
|
11299
12037
|
walk,
|
|
12038
|
+
when,
|
|
11300
12039
|
withCtx,
|
|
11301
12040
|
word
|
|
11302
12041
|
};
|