parseman 0.28.1 → 0.30.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/dist/combinators/attempt.d.ts.map +1 -1
- package/dist/combinators/choice.d.ts +11 -0
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts +7 -0
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +24 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +10 -0
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/index.cjs +256 -17
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +256 -17
- package/dist/index.js.map +3 -3
- package/dist/language-service/index.cjs.map +2 -2
- package/dist/language-service/index.js.map +2 -2
- package/dist/plugin/index.cjs +257 -18
- package/dist/plugin/index.cjs.map +3 -3
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +257 -18
- package/dist/plugin/index.js.map +3 -3
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -61,6 +61,15 @@ function intersects(a, b) {
|
|
|
61
61
|
function fromChar(code) {
|
|
62
62
|
return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
|
|
63
63
|
}
|
|
64
|
+
function startsFirstSet(combinator, input, pos) {
|
|
65
|
+
const fs2 = combinator._meta.firstSet;
|
|
66
|
+
if (fs2.kind === "any") return true;
|
|
67
|
+
if (fs2.kind === "empty") return false;
|
|
68
|
+
const code = input.codePointAt(pos);
|
|
69
|
+
if (code === void 0) return false;
|
|
70
|
+
for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
64
73
|
function fromRange(lo, hi) {
|
|
65
74
|
return { kind: "ranges", ranges: [{ lo, hi }] };
|
|
66
75
|
}
|
|
@@ -1020,6 +1029,17 @@ function deriveExpected(c) {
|
|
|
1020
1029
|
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1021
1030
|
case "attempt":
|
|
1022
1031
|
return deriveExpected(def.parser);
|
|
1032
|
+
// Delegating wrappers whose first-token failure is their inner parser's — must
|
|
1033
|
+
// pass through so a start-failure (and the first-set-miss fast-path in attempt/
|
|
1034
|
+
// node, which reads this) names the real expected token, not the wrapper tag.
|
|
1035
|
+
case "field":
|
|
1036
|
+
case "withCtx":
|
|
1037
|
+
case "recover":
|
|
1038
|
+
return deriveExpected(def.parser);
|
|
1039
|
+
case "skip":
|
|
1040
|
+
return deriveExpected(def.main);
|
|
1041
|
+
case "expect":
|
|
1042
|
+
return def.expected;
|
|
1023
1043
|
case "node":
|
|
1024
1044
|
case "grammar":
|
|
1025
1045
|
case "trivia":
|
|
@@ -1080,7 +1100,7 @@ function choice(...args) {
|
|
|
1080
1100
|
disjoint
|
|
1081
1101
|
};
|
|
1082
1102
|
const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
|
|
1083
|
-
const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
|
|
1103
|
+
const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
|
|
1084
1104
|
let greedyLitMap = null;
|
|
1085
1105
|
let sortedParsers = null;
|
|
1086
1106
|
const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
|
|
@@ -1206,8 +1226,47 @@ function detectStrategy(parsers) {
|
|
|
1206
1226
|
);
|
|
1207
1227
|
return { tag: "literalsLongestFirst", sortedIndices };
|
|
1208
1228
|
}
|
|
1229
|
+
const shared = detectSharedPrefix(parsers);
|
|
1230
|
+
if (shared !== null) return shared;
|
|
1209
1231
|
return { tag: "firstMatch" };
|
|
1210
1232
|
}
|
|
1233
|
+
function bareLeadingTermKey(term) {
|
|
1234
|
+
const d = term._def;
|
|
1235
|
+
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
1236
|
+
if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
|
|
1237
|
+
return null;
|
|
1238
|
+
}
|
|
1239
|
+
function detectSharedPrefix(parsers) {
|
|
1240
|
+
if (parsers.length < 2) return null;
|
|
1241
|
+
let key = null;
|
|
1242
|
+
let prefix = null;
|
|
1243
|
+
const members = [];
|
|
1244
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1245
|
+
const term0 = leadingTermOfArm(parsers[i]);
|
|
1246
|
+
if (term0 === null) return null;
|
|
1247
|
+
const k = bareLeadingTermKey(term0);
|
|
1248
|
+
if (k === null) return null;
|
|
1249
|
+
if (key === null) {
|
|
1250
|
+
key = k;
|
|
1251
|
+
prefix = term0;
|
|
1252
|
+
} else if (k !== key) return null;
|
|
1253
|
+
members.push(i);
|
|
1254
|
+
}
|
|
1255
|
+
if (prefix === null || members.length < 2) return null;
|
|
1256
|
+
return { tag: "sharedPrefix", prefix, members };
|
|
1257
|
+
}
|
|
1258
|
+
function leadingTermOfArm(arm) {
|
|
1259
|
+
let d = arm._def;
|
|
1260
|
+
for (; ; ) {
|
|
1261
|
+
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
|
|
1262
|
+
d = d.parser._def;
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
break;
|
|
1266
|
+
}
|
|
1267
|
+
if (d.tag !== "sequence" || d.parsers.length < 2) return null;
|
|
1268
|
+
return d.parsers[0];
|
|
1269
|
+
}
|
|
1211
1270
|
function computeAutoNot(parsers) {
|
|
1212
1271
|
return parsers.map((p, i) => {
|
|
1213
1272
|
const litVal = getCoreLiteralValue(p);
|
|
@@ -1801,11 +1860,20 @@ function sequence(...parsers) {
|
|
|
1801
1860
|
|
|
1802
1861
|
// src/combinators/attempt.ts
|
|
1803
1862
|
function attempt(parser2) {
|
|
1863
|
+
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
1864
|
+
let failExpected;
|
|
1804
1865
|
return {
|
|
1805
1866
|
_tag: "attempt",
|
|
1806
1867
|
_meta: parser2._meta,
|
|
1807
1868
|
_def: { tag: "attempt", parser: parser2 },
|
|
1808
1869
|
parse(input, pos, ctx) {
|
|
1870
|
+
if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
|
|
1871
|
+
if (failExpected === void 0) {
|
|
1872
|
+
const e = deriveExpected(parser2);
|
|
1873
|
+
failExpected = e.length > 0 ? e : [parser2._tag];
|
|
1874
|
+
}
|
|
1875
|
+
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
1876
|
+
}
|
|
1809
1877
|
const mark = saveCstMark(ctx);
|
|
1810
1878
|
const log = ctx._triviaLog?.length;
|
|
1811
1879
|
const result = parser2.parse(input, pos, ctx);
|
|
@@ -1818,7 +1886,7 @@ function attempt(parser2) {
|
|
|
1818
1886
|
}
|
|
1819
1887
|
|
|
1820
1888
|
// src/combinators/repeat.ts
|
|
1821
|
-
function repItem(combinator, input, cur, ctx) {
|
|
1889
|
+
function repItem(combinator, input, cur, ctx, guardable) {
|
|
1822
1890
|
const mark = saveTriviaMark(ctx);
|
|
1823
1891
|
let pos = cur;
|
|
1824
1892
|
if (ctx.trivia) {
|
|
@@ -1834,6 +1902,10 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1834
1902
|
rollbackTrivia(ctx, mark);
|
|
1835
1903
|
return "stop";
|
|
1836
1904
|
}
|
|
1905
|
+
if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
|
|
1906
|
+
rollbackTrivia(ctx, mark);
|
|
1907
|
+
return "stop";
|
|
1908
|
+
}
|
|
1837
1909
|
const result = combinator.parse(input, pos, ctx);
|
|
1838
1910
|
if (!result.ok) {
|
|
1839
1911
|
rollbackTrivia(ctx, mark);
|
|
@@ -1853,6 +1925,7 @@ function many(combinator) {
|
|
|
1853
1925
|
};
|
|
1854
1926
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1855
1927
|
let expected;
|
|
1928
|
+
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
1856
1929
|
return {
|
|
1857
1930
|
_tag: "many",
|
|
1858
1931
|
_meta: meta,
|
|
@@ -1861,7 +1934,7 @@ function many(combinator) {
|
|
|
1861
1934
|
const values = def.valueUnused ? void 0 : [];
|
|
1862
1935
|
let cur = pos;
|
|
1863
1936
|
while (cur < input.length) {
|
|
1864
|
-
const item = repItem(combinator, input, cur, ctx);
|
|
1937
|
+
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
1865
1938
|
if (item === "stop") break;
|
|
1866
1939
|
if ("fail" in item) {
|
|
1867
1940
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
@@ -1889,6 +1962,7 @@ function oneOrMore(combinator) {
|
|
|
1889
1962
|
};
|
|
1890
1963
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1891
1964
|
let expected;
|
|
1965
|
+
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
1892
1966
|
return {
|
|
1893
1967
|
_tag: "oneOrMore",
|
|
1894
1968
|
_meta: meta,
|
|
@@ -1899,7 +1973,7 @@ function oneOrMore(combinator) {
|
|
|
1899
1973
|
const values = def.valueUnused ? void 0 : [first.value];
|
|
1900
1974
|
let cur = first.span.end;
|
|
1901
1975
|
while (cur < input.length) {
|
|
1902
|
-
const item = repItem(combinator, input, cur, ctx);
|
|
1976
|
+
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
1903
1977
|
if (item === "stop") break;
|
|
1904
1978
|
if ("fail" in item) {
|
|
1905
1979
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
@@ -1942,15 +2016,6 @@ function optional(combinator) {
|
|
|
1942
2016
|
}
|
|
1943
2017
|
};
|
|
1944
2018
|
}
|
|
1945
|
-
function startsFirstSet(combinator, input, pos) {
|
|
1946
|
-
const fs2 = combinator._meta.firstSet;
|
|
1947
|
-
if (fs2.kind === "any") return true;
|
|
1948
|
-
if (fs2.kind === "empty") return false;
|
|
1949
|
-
const code = input.codePointAt(pos);
|
|
1950
|
-
if (code === void 0) return false;
|
|
1951
|
-
for (const r of fs2.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1952
|
-
return false;
|
|
1953
|
-
}
|
|
1954
2019
|
function sepBy(combinator, separator) {
|
|
1955
2020
|
const meta = {
|
|
1956
2021
|
firstSet: combinator._meta.firstSet,
|
|
@@ -2447,11 +2512,20 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2447
2512
|
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
|
|
2448
2513
|
const clonesState = build ? buildReadsState(def) : true;
|
|
2449
2514
|
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
2515
|
+
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
2516
|
+
let failExpected;
|
|
2450
2517
|
return {
|
|
2451
2518
|
_tag: "node",
|
|
2452
2519
|
_meta: meta,
|
|
2453
2520
|
_def: def,
|
|
2454
2521
|
parse(input, pos, ctx) {
|
|
2522
|
+
if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
|
|
2523
|
+
if (failExpected === void 0) {
|
|
2524
|
+
const e = deriveExpected(combinator);
|
|
2525
|
+
failExpected = e.length > 0 ? e : [combinator._tag];
|
|
2526
|
+
}
|
|
2527
|
+
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
2528
|
+
}
|
|
2455
2529
|
const saved = beginCstNodeCapture(ctx);
|
|
2456
2530
|
const savedFields = ctx._fields;
|
|
2457
2531
|
ctx._fields = capturesFields ? [] : void 0;
|
|
@@ -4151,6 +4225,61 @@ function tryInlineDestructureTransform(src, valueVars) {
|
|
|
4151
4225
|
}
|
|
4152
4226
|
|
|
4153
4227
|
// src/compiler/codegen.ts
|
|
4228
|
+
function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
4229
|
+
if (seen.has(p)) return { concrete: empty(), refs: [] };
|
|
4230
|
+
seen.add(p);
|
|
4231
|
+
const d = p._def;
|
|
4232
|
+
const rec = (c) => leadingFirstSetRecipe(c, seen);
|
|
4233
|
+
const merge = (a, b) => ({ concrete: union(a.concrete, b.concrete), refs: [...a.refs, ...b.refs] });
|
|
4234
|
+
switch (d.tag) {
|
|
4235
|
+
case "lazy": {
|
|
4236
|
+
const name = p._ruleName;
|
|
4237
|
+
if (name !== void 0) return { concrete: empty(), refs: [name] };
|
|
4238
|
+
try {
|
|
4239
|
+
return rec(d.thunk());
|
|
4240
|
+
} catch {
|
|
4241
|
+
return { concrete: any(), refs: [] };
|
|
4242
|
+
}
|
|
4243
|
+
}
|
|
4244
|
+
case "literal":
|
|
4245
|
+
case "regex":
|
|
4246
|
+
case "keywords":
|
|
4247
|
+
return { concrete: p._meta.firstSet, refs: [] };
|
|
4248
|
+
case "choice": {
|
|
4249
|
+
let out = { concrete: empty(), refs: [] };
|
|
4250
|
+
for (const arm of d.parsers) out = merge(out, rec(arm));
|
|
4251
|
+
return out;
|
|
4252
|
+
}
|
|
4253
|
+
case "sequence": {
|
|
4254
|
+
let out = { concrete: empty(), refs: [] };
|
|
4255
|
+
for (const term of d.parsers) {
|
|
4256
|
+
out = merge(out, rec(term));
|
|
4257
|
+
if (!matchesEmpty(term)) return out;
|
|
4258
|
+
}
|
|
4259
|
+
return out;
|
|
4260
|
+
}
|
|
4261
|
+
case "oneOrMore":
|
|
4262
|
+
case "many":
|
|
4263
|
+
case "optional":
|
|
4264
|
+
case "transform":
|
|
4265
|
+
case "label":
|
|
4266
|
+
case "field":
|
|
4267
|
+
case "trivia":
|
|
4268
|
+
case "token":
|
|
4269
|
+
case "leaf":
|
|
4270
|
+
case "node":
|
|
4271
|
+
case "grammar":
|
|
4272
|
+
case "expect":
|
|
4273
|
+
return rec(d.parser);
|
|
4274
|
+
case "sepBy":
|
|
4275
|
+
return rec(d.parser);
|
|
4276
|
+
case "skip":
|
|
4277
|
+
return rec(d.main);
|
|
4278
|
+
// not / scanTo / guard / withCtx / recover / unknown → shallow set (safe).
|
|
4279
|
+
default:
|
|
4280
|
+
return { concrete: p._meta.firstSet, refs: [] };
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4154
4283
|
var HOST_READS_DECL = "const _hostReads = (b, n) => { if (b === undefined) return false; let s; try { s = Function.prototype.toString.call(b) } catch (e) { return true } if (/\\barguments\\b/.test(s)) return true; const m = /^[^(]*\\(([\\s\\S]*?)\\)/.exec(s); if (m && /\\.\\.\\.|=/.test(m[1])) return true; return b.length > n }";
|
|
4155
4284
|
var _loweringSink = null;
|
|
4156
4285
|
function beginLoweringCapture() {
|
|
@@ -4392,6 +4521,7 @@ var SWITCH_RANGE_LIMIT = 4;
|
|
|
4392
4521
|
var SWITCH_MAX_CASES = 48;
|
|
4393
4522
|
var SWITCH_MIN_CASES = 3;
|
|
4394
4523
|
var _forceDisjointIf = false;
|
|
4524
|
+
var _forceNoSharedPrefix = false;
|
|
4395
4525
|
function planDisjointDispatch(parsers) {
|
|
4396
4526
|
const cases = [];
|
|
4397
4527
|
let total = 0;
|
|
@@ -5027,7 +5157,7 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, cov
|
|
|
5027
5157
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
5028
5158
|
return { stmts, valueVar: valV, endVar: endV };
|
|
5029
5159
|
}
|
|
5030
|
-
function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
5160
|
+
function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
5031
5161
|
const resValV = v(ctx, "_crv");
|
|
5032
5162
|
const resEndV = v(ctx, "_cre");
|
|
5033
5163
|
const resOkV = v(ctx, "_crok");
|
|
@@ -5041,6 +5171,7 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
|
5041
5171
|
...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
|
|
5042
5172
|
`${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
|
|
5043
5173
|
];
|
|
5174
|
+
if (preStmts) stmts.push(...preStmts);
|
|
5044
5175
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
5045
5176
|
const p = def.parsers[i];
|
|
5046
5177
|
const gate = def.gates[i];
|
|
@@ -5048,11 +5179,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
|
5048
5179
|
const atStart = failsAtStart(p);
|
|
5049
5180
|
const staticFx = armStaticExpected(ctx, p);
|
|
5050
5181
|
const deferRuleName = ctx.deferFirstSetRefs ? p._ruleName : void 0;
|
|
5051
|
-
const
|
|
5182
|
+
const baseFsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
|
|
5052
5183
|
if (p._meta.firstSet.kind !== "any" || matchesEmpty(p)) return null;
|
|
5053
5184
|
const deep = firstSetOf(p);
|
|
5054
5185
|
return deep.kind === "ranges" ? firstSetCond(codeV, deep) : null;
|
|
5055
5186
|
})();
|
|
5187
|
+
const fsGuard = armGuardPrefix === void 0 ? baseFsGuard : baseFsGuard === null ? armGuardPrefix : `${armGuardPrefix} && (${baseFsGuard})`;
|
|
5056
5188
|
let gateCond = null;
|
|
5057
5189
|
if (gate) {
|
|
5058
5190
|
const gateIdx = ctx.mapFns.length;
|
|
@@ -5121,11 +5253,64 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
|
5121
5253
|
stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
|
|
5122
5254
|
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
5123
5255
|
}
|
|
5256
|
+
function emitsAsNamedFn(p, ctx) {
|
|
5257
|
+
if (p._def.tag === "lazy") return true;
|
|
5258
|
+
if (ctx.ruleNames?.has(p)) return true;
|
|
5259
|
+
if (ctx.namedParsers.has(p)) return true;
|
|
5260
|
+
const usage = ctx.lazyUsage;
|
|
5261
|
+
return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
|
|
5262
|
+
}
|
|
5263
|
+
function armReplayInScope(arm, ctx) {
|
|
5264
|
+
let p = arm;
|
|
5265
|
+
for (; ; ) {
|
|
5266
|
+
if (emitsAsNamedFn(p, ctx)) return false;
|
|
5267
|
+
const d = p._def;
|
|
5268
|
+
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
|
|
5269
|
+
p = d.parser;
|
|
5270
|
+
continue;
|
|
5271
|
+
}
|
|
5272
|
+
return d.tag === "sequence";
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
function emitSharedPrefix(def, strategy, ctx, pos) {
|
|
5276
|
+
const { prefix, members } = strategy;
|
|
5277
|
+
const savedCapturing = ctx.capturing;
|
|
5278
|
+
ctx.capturing = false;
|
|
5279
|
+
const pfx = emitFallible(prefix, ctx, pos, false);
|
|
5280
|
+
ctx.capturing = savedCapturing;
|
|
5281
|
+
const map = ctx.replayPrefix ??= /* @__PURE__ */ new Map();
|
|
5282
|
+
const keys = [];
|
|
5283
|
+
for (const i of members) {
|
|
5284
|
+
const term0 = leadingTermOfArm(def.parsers[i]);
|
|
5285
|
+
if (term0 === null) continue;
|
|
5286
|
+
map.set(term0, { valVar: pfx.valVar, endVar: pfx.endVar });
|
|
5287
|
+
keys.push(term0);
|
|
5288
|
+
}
|
|
5289
|
+
const r = emitFirstMatch(def, ctx, pos, void 0, pfx.stmts, pfx.okVar);
|
|
5290
|
+
for (const k of keys) map.delete(k);
|
|
5291
|
+
return r;
|
|
5292
|
+
}
|
|
5293
|
+
function emitReplayPrefixLeaf(ctx, pos, replay) {
|
|
5294
|
+
const vv = v(ctx);
|
|
5295
|
+
return {
|
|
5296
|
+
stmts: [
|
|
5297
|
+
`${ind(ctx)}const ${vv} = ${replay.valVar}`,
|
|
5298
|
+
...emitLeafCapture(ctx, vv, pos, replay.endVar)
|
|
5299
|
+
],
|
|
5300
|
+
valueVar: vv,
|
|
5301
|
+
endVar: replay.endVar
|
|
5302
|
+
};
|
|
5303
|
+
}
|
|
5124
5304
|
function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
|
|
5125
5305
|
if (strategy.tag === "greedyClassify")
|
|
5126
5306
|
return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
|
|
5127
5307
|
if (strategy.tag === "literalsLongestFirst")
|
|
5128
5308
|
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
|
|
5309
|
+
if (strategy.tag === "sharedPrefix") {
|
|
5310
|
+
if (!_forceNoSharedPrefix && coverageBase === void 0 && !ctx.recovery && strategy.members.every((i) => armReplayInScope(def.parsers[i], ctx)))
|
|
5311
|
+
return emitSharedPrefix(def, strategy, ctx, pos);
|
|
5312
|
+
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
5313
|
+
}
|
|
5129
5314
|
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
5130
5315
|
}
|
|
5131
5316
|
function pushMapFn(ctx, fn, src) {
|
|
@@ -5205,6 +5390,13 @@ function emitMany(def, ctx, pos) {
|
|
|
5205
5390
|
itemPos = npV;
|
|
5206
5391
|
}
|
|
5207
5392
|
}
|
|
5393
|
+
if (!ctx.recovery && !ctx.coverage && !failsAtStart(def.parser) && needsFirstSetGuard(def.parser)) {
|
|
5394
|
+
const lcV = v(ctx, "_lc");
|
|
5395
|
+
stmts.push(
|
|
5396
|
+
`${ind(ctx)}const ${lcV} = ${itemPos} < input.length ? (input.codePointAt(${itemPos}) ?? -1) : -1`,
|
|
5397
|
+
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
5398
|
+
);
|
|
5399
|
+
}
|
|
5208
5400
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
5209
5401
|
stmts.push(...iterStmts);
|
|
5210
5402
|
if (ctx.recovery) {
|
|
@@ -5255,8 +5447,19 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
5255
5447
|
const rollback = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${trivia2}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${log}; if (_ctx._fields) _ctx._fields.length = ${fields}; if (_ctx._errors) _ctx._errors.length = ${errors}`;
|
|
5256
5448
|
const traceId = ctx.coverage?.plan.attempts.get(p);
|
|
5257
5449
|
const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
|
|
5450
|
+
const preGuard = [];
|
|
5451
|
+
if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
|
|
5452
|
+
const gcV = v(ctx, "_agc");
|
|
5453
|
+
const gExp = armStaticExpected(ctx, def.parser);
|
|
5454
|
+
const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(gExp, pos)} }`;
|
|
5455
|
+
preGuard.push(
|
|
5456
|
+
`${ind(ctx)}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
|
|
5457
|
+
`${ind(ctx)}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
|
|
5458
|
+
);
|
|
5459
|
+
}
|
|
5258
5460
|
return {
|
|
5259
5461
|
stmts: [
|
|
5462
|
+
...preGuard,
|
|
5260
5463
|
`${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`,
|
|
5261
5464
|
...inner.stmts,
|
|
5262
5465
|
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
@@ -5636,7 +5839,18 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5636
5839
|
const saveTrivia = needsTriviaFrame ? `, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}` : "";
|
|
5637
5840
|
const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${capTLv ?? "false"}; _ctx._cstTriviaLog = ${innerTl}${smk ? `; _ctx._triviaCaptureMask = ${capTLv} && _ctx.build !== undefined && _ctx.build._parsemanTriviaKinds !== undefined ? _ctx.build._parsemanTriviaKinds(${JSON.stringify(def.type)}) : ${smk}` : ""}` : "";
|
|
5638
5841
|
const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
|
|
5842
|
+
const preGuard = [];
|
|
5843
|
+
if (!ctx.recovery && !ctx.coverage && (capturesChildren || structural) && needsFirstSetGuard(def.parser)) {
|
|
5844
|
+
const gcV = v(ctx, "_ngc");
|
|
5845
|
+
const gExp = armStaticExpected(ctx, def.parser);
|
|
5846
|
+
const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(gExp, pos);
|
|
5847
|
+
preGuard.push(
|
|
5848
|
+
`${i}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
|
|
5849
|
+
`${i}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
|
|
5850
|
+
);
|
|
5851
|
+
}
|
|
5639
5852
|
const stmts = [
|
|
5853
|
+
...preGuard,
|
|
5640
5854
|
profHoist,
|
|
5641
5855
|
allocStmt,
|
|
5642
5856
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
@@ -5810,6 +6024,8 @@ function emitExpect(def, ctx, pos) {
|
|
|
5810
6024
|
return { stmts, valueVar: valVar, endVar };
|
|
5811
6025
|
}
|
|
5812
6026
|
function emit(p, ctx, pos) {
|
|
6027
|
+
const replay = ctx.replayPrefix?.get(p);
|
|
6028
|
+
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
5813
6029
|
const dispatch = (emissionPos = pos) => {
|
|
5814
6030
|
const savedRule = ctx.activeCoverageRuleId;
|
|
5815
6031
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
@@ -6663,6 +6879,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6663
6879
|
].join("\n")));
|
|
6664
6880
|
}
|
|
6665
6881
|
const firstSets = /* @__PURE__ */ new Map();
|
|
6882
|
+
const firstSetRecipes = /* @__PURE__ */ new Map();
|
|
6666
6883
|
for (const [key, rule] of ruleMap) {
|
|
6667
6884
|
let resolved = rule;
|
|
6668
6885
|
const d = rule._def;
|
|
@@ -6674,6 +6891,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6674
6891
|
}
|
|
6675
6892
|
}
|
|
6676
6893
|
firstSets.set(key, canMatchEmptyAtStart(resolved) ? { kind: "any" } : resolved._meta.firstSet);
|
|
6894
|
+
firstSetRecipes.set(key, canMatchEmptyAtStart(resolved) ? { concrete: any(), refs: [] } : leadingFirstSetRecipe(resolved));
|
|
6677
6895
|
}
|
|
6678
6896
|
return {
|
|
6679
6897
|
ns,
|
|
@@ -6682,6 +6900,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6682
6900
|
ruleFns,
|
|
6683
6901
|
wrappers,
|
|
6684
6902
|
firstSets,
|
|
6903
|
+
firstSetRecipes,
|
|
6685
6904
|
deps: ruleDependencies(ruleMap),
|
|
6686
6905
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
6687
6906
|
needsHostReads: !!ctx.needsHostReads,
|
|
@@ -7328,10 +7547,30 @@ function fusedBody(pieces) {
|
|
|
7328
7547
|
];
|
|
7329
7548
|
const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
|
|
7330
7549
|
const rawBody = [...lines, "return {", wrapperEntries.join(",\n"), "}"].join("\n");
|
|
7331
|
-
const
|
|
7550
|
+
const ANY2 = { kind: "any" };
|
|
7551
|
+
const recipes = /* @__PURE__ */ new Map();
|
|
7552
|
+
const shallow = /* @__PURE__ */ new Map();
|
|
7332
7553
|
for (const [k, p] of winner) {
|
|
7554
|
+
const r = p.firstSetRecipes?.get(k);
|
|
7555
|
+
if (r) recipes.set(k, r);
|
|
7333
7556
|
const fs2 = p.firstSets?.get(k);
|
|
7334
|
-
if (fs2)
|
|
7557
|
+
if (fs2) shallow.set(k, fs2);
|
|
7558
|
+
}
|
|
7559
|
+
const finalFS = /* @__PURE__ */ new Map();
|
|
7560
|
+
for (const [k] of winner) finalFS.set(k, recipes.get(k)?.concrete ?? shallow.get(k) ?? ANY2);
|
|
7561
|
+
for (let iter = 0; iter <= recipes.size; iter++) {
|
|
7562
|
+
let changed = false;
|
|
7563
|
+
for (const [k, r] of recipes) {
|
|
7564
|
+
let fs2 = r.concrete;
|
|
7565
|
+
for (const ref2 of r.refs) {
|
|
7566
|
+
fs2 = union(fs2, recipes.has(ref2) || shallow.has(ref2) ? finalFS.get(ref2) ?? ANY2 : ANY2);
|
|
7567
|
+
}
|
|
7568
|
+
if (JSON.stringify(finalFS.get(k)) !== JSON.stringify(fs2)) {
|
|
7569
|
+
finalFS.set(k, fs2);
|
|
7570
|
+
changed = true;
|
|
7571
|
+
}
|
|
7572
|
+
}
|
|
7573
|
+
if (!changed) break;
|
|
7335
7574
|
}
|
|
7336
7575
|
const body = rawBody.replace(
|
|
7337
7576
|
// Rule name + code-point var are both JS identifiers (rule names are validated
|
|
@@ -8502,7 +8741,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8502
8741
|
const mapLit = (m, stripVals = false) => `new Map([${[...m].map(
|
|
8503
8742
|
([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(stripVals && typeof v2 === "string" ? stripIndent(v2) : v2)}]`
|
|
8504
8743
|
).join(", ")}])`;
|
|
8505
|
-
return `{ ns: ${JSON.stringify(p.ns)}, keys: ${JSON.stringify(p.keys)}, prelude: ${JSON.stringify(p.prelude.map(stripIndent))}, ruleFns: ${mapLit(p.ruleFns, true)}, wrappers: ${mapLit(p.wrappers, true)}, firstSets: ${mapLit(p.firstSets)}, deps: ${mapLit(p.deps)}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, hasDirectBuilders: ${p.hasDirectBuilders === true}, isRecognitionOnly: ${p.isRecognitionOnly === true}, mfFns: [], buildFns: [] }`;
|
|
8744
|
+
return `{ ns: ${JSON.stringify(p.ns)}, keys: ${JSON.stringify(p.keys)}, prelude: ${JSON.stringify(p.prelude.map(stripIndent))}, ruleFns: ${mapLit(p.ruleFns, true)}, wrappers: ${mapLit(p.wrappers, true)}, firstSets: ${mapLit(p.firstSets)}, firstSetRecipes: ${p.firstSetRecipes ? mapLit(p.firstSetRecipes) : "new Map()"}, deps: ${mapLit(p.deps)}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, hasDirectBuilders: ${p.hasDirectBuilders === true}, isRecognitionOnly: ${p.isRecognitionOnly === true}, mfFns: [], buildFns: [] }`;
|
|
8506
8745
|
};
|
|
8507
8746
|
const isSpread = (it) => "__spreadLocal" in it;
|
|
8508
8747
|
const isIR = (it) => "ir" in it && !("ruleFns" in it);
|