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/index.js
CHANGED
|
@@ -18,6 +18,15 @@ function intersects(a, b) {
|
|
|
18
18
|
function fromChar(code) {
|
|
19
19
|
return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
|
|
20
20
|
}
|
|
21
|
+
function startsFirstSet(combinator, input, pos) {
|
|
22
|
+
const fs = combinator._meta.firstSet;
|
|
23
|
+
if (fs.kind === "any") return true;
|
|
24
|
+
if (fs.kind === "empty") return false;
|
|
25
|
+
const code = input.codePointAt(pos);
|
|
26
|
+
if (code === void 0) return false;
|
|
27
|
+
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
21
30
|
function fromRange(lo, hi) {
|
|
22
31
|
return { kind: "ranges", ranges: [{ lo, hi }] };
|
|
23
32
|
}
|
|
@@ -944,6 +953,17 @@ function deriveExpected(c) {
|
|
|
944
953
|
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
945
954
|
case "attempt":
|
|
946
955
|
return deriveExpected(def.parser);
|
|
956
|
+
// Delegating wrappers whose first-token failure is their inner parser's — must
|
|
957
|
+
// pass through so a start-failure (and the first-set-miss fast-path in attempt/
|
|
958
|
+
// node, which reads this) names the real expected token, not the wrapper tag.
|
|
959
|
+
case "field":
|
|
960
|
+
case "withCtx":
|
|
961
|
+
case "recover":
|
|
962
|
+
return deriveExpected(def.parser);
|
|
963
|
+
case "skip":
|
|
964
|
+
return deriveExpected(def.main);
|
|
965
|
+
case "expect":
|
|
966
|
+
return def.expected;
|
|
947
967
|
case "node":
|
|
948
968
|
case "grammar":
|
|
949
969
|
case "trivia":
|
|
@@ -1007,7 +1027,7 @@ function choice(...args) {
|
|
|
1007
1027
|
disjoint
|
|
1008
1028
|
};
|
|
1009
1029
|
const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
|
|
1010
|
-
const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
|
|
1030
|
+
const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
|
|
1011
1031
|
let greedyLitMap = null;
|
|
1012
1032
|
let sortedParsers = null;
|
|
1013
1033
|
const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
|
|
@@ -1133,8 +1153,47 @@ function detectStrategy(parsers) {
|
|
|
1133
1153
|
);
|
|
1134
1154
|
return { tag: "literalsLongestFirst", sortedIndices };
|
|
1135
1155
|
}
|
|
1156
|
+
const shared = detectSharedPrefix(parsers);
|
|
1157
|
+
if (shared !== null) return shared;
|
|
1136
1158
|
return { tag: "firstMatch" };
|
|
1137
1159
|
}
|
|
1160
|
+
function bareLeadingTermKey(term) {
|
|
1161
|
+
const d = term._def;
|
|
1162
|
+
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
1163
|
+
if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
|
|
1164
|
+
return null;
|
|
1165
|
+
}
|
|
1166
|
+
function detectSharedPrefix(parsers) {
|
|
1167
|
+
if (parsers.length < 2) return null;
|
|
1168
|
+
let key = null;
|
|
1169
|
+
let prefix = null;
|
|
1170
|
+
const members = [];
|
|
1171
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1172
|
+
const term0 = leadingTermOfArm(parsers[i]);
|
|
1173
|
+
if (term0 === null) return null;
|
|
1174
|
+
const k = bareLeadingTermKey(term0);
|
|
1175
|
+
if (k === null) return null;
|
|
1176
|
+
if (key === null) {
|
|
1177
|
+
key = k;
|
|
1178
|
+
prefix = term0;
|
|
1179
|
+
} else if (k !== key) return null;
|
|
1180
|
+
members.push(i);
|
|
1181
|
+
}
|
|
1182
|
+
if (prefix === null || members.length < 2) return null;
|
|
1183
|
+
return { tag: "sharedPrefix", prefix, members };
|
|
1184
|
+
}
|
|
1185
|
+
function leadingTermOfArm(arm) {
|
|
1186
|
+
let d = arm._def;
|
|
1187
|
+
for (; ; ) {
|
|
1188
|
+
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
|
|
1189
|
+
d = d.parser._def;
|
|
1190
|
+
continue;
|
|
1191
|
+
}
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
if (d.tag !== "sequence" || d.parsers.length < 2) return null;
|
|
1195
|
+
return d.parsers[0];
|
|
1196
|
+
}
|
|
1138
1197
|
function computeAutoNot(parsers) {
|
|
1139
1198
|
return parsers.map((p, i) => {
|
|
1140
1199
|
const litVal = getCoreLiteralValue(p);
|
|
@@ -1728,11 +1787,20 @@ function sequence(...parsers) {
|
|
|
1728
1787
|
|
|
1729
1788
|
// src/combinators/attempt.ts
|
|
1730
1789
|
function attempt(parser2) {
|
|
1790
|
+
const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
|
|
1791
|
+
let failExpected;
|
|
1731
1792
|
return {
|
|
1732
1793
|
_tag: "attempt",
|
|
1733
1794
|
_meta: parser2._meta,
|
|
1734
1795
|
_def: { tag: "attempt", parser: parser2 },
|
|
1735
1796
|
parse(input, pos, ctx) {
|
|
1797
|
+
if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
|
|
1798
|
+
if (failExpected === void 0) {
|
|
1799
|
+
const e = deriveExpected(parser2);
|
|
1800
|
+
failExpected = e.length > 0 ? e : [parser2._tag];
|
|
1801
|
+
}
|
|
1802
|
+
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
1803
|
+
}
|
|
1736
1804
|
const mark = saveCstMark(ctx);
|
|
1737
1805
|
const log = ctx._triviaLog?.length;
|
|
1738
1806
|
const result = parser2.parse(input, pos, ctx);
|
|
@@ -1745,7 +1813,7 @@ function attempt(parser2) {
|
|
|
1745
1813
|
}
|
|
1746
1814
|
|
|
1747
1815
|
// src/combinators/repeat.ts
|
|
1748
|
-
function repItem(combinator, input, cur, ctx) {
|
|
1816
|
+
function repItem(combinator, input, cur, ctx, guardable) {
|
|
1749
1817
|
const mark = saveTriviaMark(ctx);
|
|
1750
1818
|
let pos = cur;
|
|
1751
1819
|
if (ctx.trivia) {
|
|
@@ -1761,6 +1829,10 @@ function repItem(combinator, input, cur, ctx) {
|
|
|
1761
1829
|
rollbackTrivia(ctx, mark);
|
|
1762
1830
|
return "stop";
|
|
1763
1831
|
}
|
|
1832
|
+
if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
|
|
1833
|
+
rollbackTrivia(ctx, mark);
|
|
1834
|
+
return "stop";
|
|
1835
|
+
}
|
|
1764
1836
|
const result = combinator.parse(input, pos, ctx);
|
|
1765
1837
|
if (!result.ok) {
|
|
1766
1838
|
rollbackTrivia(ctx, mark);
|
|
@@ -1780,6 +1852,7 @@ function many(combinator) {
|
|
|
1780
1852
|
};
|
|
1781
1853
|
const def = { tag: "many", parser: combinator, min: 0 };
|
|
1782
1854
|
let expected;
|
|
1855
|
+
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
1783
1856
|
return {
|
|
1784
1857
|
_tag: "many",
|
|
1785
1858
|
_meta: meta,
|
|
@@ -1788,7 +1861,7 @@ function many(combinator) {
|
|
|
1788
1861
|
const values = def.valueUnused ? void 0 : [];
|
|
1789
1862
|
let cur = pos;
|
|
1790
1863
|
while (cur < input.length) {
|
|
1791
|
-
const item = repItem(combinator, input, cur, ctx);
|
|
1864
|
+
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
1792
1865
|
if (item === "stop") break;
|
|
1793
1866
|
if ("fail" in item) {
|
|
1794
1867
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
@@ -1816,6 +1889,7 @@ function oneOrMore(combinator) {
|
|
|
1816
1889
|
};
|
|
1817
1890
|
const def = { tag: "oneOrMore", parser: combinator, min: 1 };
|
|
1818
1891
|
let expected;
|
|
1892
|
+
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
1819
1893
|
return {
|
|
1820
1894
|
_tag: "oneOrMore",
|
|
1821
1895
|
_meta: meta,
|
|
@@ -1826,7 +1900,7 @@ function oneOrMore(combinator) {
|
|
|
1826
1900
|
const values = def.valueUnused ? void 0 : [first.value];
|
|
1827
1901
|
let cur = first.span.end;
|
|
1828
1902
|
while (cur < input.length) {
|
|
1829
|
-
const item = repItem(combinator, input, cur, ctx);
|
|
1903
|
+
const item = repItem(combinator, input, cur, ctx, guardable);
|
|
1830
1904
|
if (item === "stop") break;
|
|
1831
1905
|
if ("fail" in item) {
|
|
1832
1906
|
const sync = ctx._tolerant ? ctx._sync : void 0;
|
|
@@ -1869,15 +1943,6 @@ function optional(combinator) {
|
|
|
1869
1943
|
}
|
|
1870
1944
|
};
|
|
1871
1945
|
}
|
|
1872
|
-
function startsFirstSet(combinator, input, pos) {
|
|
1873
|
-
const fs = combinator._meta.firstSet;
|
|
1874
|
-
if (fs.kind === "any") return true;
|
|
1875
|
-
if (fs.kind === "empty") return false;
|
|
1876
|
-
const code = input.codePointAt(pos);
|
|
1877
|
-
if (code === void 0) return false;
|
|
1878
|
-
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1879
|
-
return false;
|
|
1880
|
-
}
|
|
1881
1946
|
function sepBy(combinator, separator) {
|
|
1882
1947
|
const meta = {
|
|
1883
1948
|
firstSet: combinator._meta.firstSet,
|
|
@@ -2411,11 +2476,20 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2411
2476
|
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
|
|
2412
2477
|
const clonesState = build ? buildReadsState(def) : true;
|
|
2413
2478
|
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
2479
|
+
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
2480
|
+
let failExpected;
|
|
2414
2481
|
return {
|
|
2415
2482
|
_tag: "node",
|
|
2416
2483
|
_meta: meta,
|
|
2417
2484
|
_def: def,
|
|
2418
2485
|
parse(input, pos, ctx) {
|
|
2486
|
+
if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
|
|
2487
|
+
if (failExpected === void 0) {
|
|
2488
|
+
const e = deriveExpected(combinator);
|
|
2489
|
+
failExpected = e.length > 0 ? e : [combinator._tag];
|
|
2490
|
+
}
|
|
2491
|
+
return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
|
|
2492
|
+
}
|
|
2419
2493
|
const saved = beginCstNodeCapture(ctx);
|
|
2420
2494
|
const savedFields = ctx._fields;
|
|
2421
2495
|
ctx._fields = capturesFields ? [] : void 0;
|
|
@@ -4140,6 +4214,61 @@ function tryInlineDestructureTransform(src, valueVars) {
|
|
|
4140
4214
|
}
|
|
4141
4215
|
|
|
4142
4216
|
// src/compiler/codegen.ts
|
|
4217
|
+
function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
4218
|
+
if (seen.has(p)) return { concrete: empty(), refs: [] };
|
|
4219
|
+
seen.add(p);
|
|
4220
|
+
const d = p._def;
|
|
4221
|
+
const rec = (c) => leadingFirstSetRecipe(c, seen);
|
|
4222
|
+
const merge2 = (a, b) => ({ concrete: union(a.concrete, b.concrete), refs: [...a.refs, ...b.refs] });
|
|
4223
|
+
switch (d.tag) {
|
|
4224
|
+
case "lazy": {
|
|
4225
|
+
const name = p._ruleName;
|
|
4226
|
+
if (name !== void 0) return { concrete: empty(), refs: [name] };
|
|
4227
|
+
try {
|
|
4228
|
+
return rec(d.thunk());
|
|
4229
|
+
} catch {
|
|
4230
|
+
return { concrete: any(), refs: [] };
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
case "literal":
|
|
4234
|
+
case "regex":
|
|
4235
|
+
case "keywords":
|
|
4236
|
+
return { concrete: p._meta.firstSet, refs: [] };
|
|
4237
|
+
case "choice": {
|
|
4238
|
+
let out = { concrete: empty(), refs: [] };
|
|
4239
|
+
for (const arm of d.parsers) out = merge2(out, rec(arm));
|
|
4240
|
+
return out;
|
|
4241
|
+
}
|
|
4242
|
+
case "sequence": {
|
|
4243
|
+
let out = { concrete: empty(), refs: [] };
|
|
4244
|
+
for (const term of d.parsers) {
|
|
4245
|
+
out = merge2(out, rec(term));
|
|
4246
|
+
if (!matchesEmpty(term)) return out;
|
|
4247
|
+
}
|
|
4248
|
+
return out;
|
|
4249
|
+
}
|
|
4250
|
+
case "oneOrMore":
|
|
4251
|
+
case "many":
|
|
4252
|
+
case "optional":
|
|
4253
|
+
case "transform":
|
|
4254
|
+
case "label":
|
|
4255
|
+
case "field":
|
|
4256
|
+
case "trivia":
|
|
4257
|
+
case "token":
|
|
4258
|
+
case "leaf":
|
|
4259
|
+
case "node":
|
|
4260
|
+
case "grammar":
|
|
4261
|
+
case "expect":
|
|
4262
|
+
return rec(d.parser);
|
|
4263
|
+
case "sepBy":
|
|
4264
|
+
return rec(d.parser);
|
|
4265
|
+
case "skip":
|
|
4266
|
+
return rec(d.main);
|
|
4267
|
+
// not / scanTo / guard / withCtx / recover / unknown → shallow set (safe).
|
|
4268
|
+
default:
|
|
4269
|
+
return { concrete: p._meta.firstSet, refs: [] };
|
|
4270
|
+
}
|
|
4271
|
+
}
|
|
4143
4272
|
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 }";
|
|
4144
4273
|
var _loweringSink = null;
|
|
4145
4274
|
function v(ctx, prefix = "_v") {
|
|
@@ -4373,6 +4502,7 @@ var SWITCH_RANGE_LIMIT = 4;
|
|
|
4373
4502
|
var SWITCH_MAX_CASES = 48;
|
|
4374
4503
|
var SWITCH_MIN_CASES = 3;
|
|
4375
4504
|
var _forceDisjointIf = false;
|
|
4505
|
+
var _forceNoSharedPrefix = false;
|
|
4376
4506
|
function planDisjointDispatch(parsers) {
|
|
4377
4507
|
const cases = [];
|
|
4378
4508
|
let total = 0;
|
|
@@ -5008,7 +5138,7 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, cov
|
|
|
5008
5138
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
5009
5139
|
return { stmts, valueVar: valV, endVar: endV };
|
|
5010
5140
|
}
|
|
5011
|
-
function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
5141
|
+
function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
|
|
5012
5142
|
const resValV = v(ctx, "_crv");
|
|
5013
5143
|
const resEndV = v(ctx, "_cre");
|
|
5014
5144
|
const resOkV = v(ctx, "_crok");
|
|
@@ -5022,6 +5152,7 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
|
5022
5152
|
...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
|
|
5023
5153
|
`${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
|
|
5024
5154
|
];
|
|
5155
|
+
if (preStmts) stmts.push(...preStmts);
|
|
5025
5156
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
5026
5157
|
const p = def.parsers[i];
|
|
5027
5158
|
const gate = def.gates[i];
|
|
@@ -5029,11 +5160,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
|
5029
5160
|
const atStart = failsAtStart(p);
|
|
5030
5161
|
const staticFx = armStaticExpected(ctx, p);
|
|
5031
5162
|
const deferRuleName = ctx.deferFirstSetRefs ? p._ruleName : void 0;
|
|
5032
|
-
const
|
|
5163
|
+
const baseFsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
|
|
5033
5164
|
if (p._meta.firstSet.kind !== "any" || matchesEmpty(p)) return null;
|
|
5034
5165
|
const deep = firstSetOf(p);
|
|
5035
5166
|
return deep.kind === "ranges" ? firstSetCond(codeV, deep) : null;
|
|
5036
5167
|
})();
|
|
5168
|
+
const fsGuard = armGuardPrefix === void 0 ? baseFsGuard : baseFsGuard === null ? armGuardPrefix : `${armGuardPrefix} && (${baseFsGuard})`;
|
|
5037
5169
|
let gateCond = null;
|
|
5038
5170
|
if (gate) {
|
|
5039
5171
|
const gateIdx = ctx.mapFns.length;
|
|
@@ -5102,11 +5234,64 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
|
5102
5234
|
stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
|
|
5103
5235
|
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
5104
5236
|
}
|
|
5237
|
+
function emitsAsNamedFn(p, ctx) {
|
|
5238
|
+
if (p._def.tag === "lazy") return true;
|
|
5239
|
+
if (ctx.ruleNames?.has(p)) return true;
|
|
5240
|
+
if (ctx.namedParsers.has(p)) return true;
|
|
5241
|
+
const usage = ctx.lazyUsage;
|
|
5242
|
+
return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
|
|
5243
|
+
}
|
|
5244
|
+
function armReplayInScope(arm, ctx) {
|
|
5245
|
+
let p = arm;
|
|
5246
|
+
for (; ; ) {
|
|
5247
|
+
if (emitsAsNamedFn(p, ctx)) return false;
|
|
5248
|
+
const d = p._def;
|
|
5249
|
+
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
|
|
5250
|
+
p = d.parser;
|
|
5251
|
+
continue;
|
|
5252
|
+
}
|
|
5253
|
+
return d.tag === "sequence";
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
function emitSharedPrefix(def, strategy, ctx, pos) {
|
|
5257
|
+
const { prefix, members } = strategy;
|
|
5258
|
+
const savedCapturing = ctx.capturing;
|
|
5259
|
+
ctx.capturing = false;
|
|
5260
|
+
const pfx = emitFallible(prefix, ctx, pos, false);
|
|
5261
|
+
ctx.capturing = savedCapturing;
|
|
5262
|
+
const map = ctx.replayPrefix ??= /* @__PURE__ */ new Map();
|
|
5263
|
+
const keys = [];
|
|
5264
|
+
for (const i of members) {
|
|
5265
|
+
const term0 = leadingTermOfArm(def.parsers[i]);
|
|
5266
|
+
if (term0 === null) continue;
|
|
5267
|
+
map.set(term0, { valVar: pfx.valVar, endVar: pfx.endVar });
|
|
5268
|
+
keys.push(term0);
|
|
5269
|
+
}
|
|
5270
|
+
const r = emitFirstMatch(def, ctx, pos, void 0, pfx.stmts, pfx.okVar);
|
|
5271
|
+
for (const k of keys) map.delete(k);
|
|
5272
|
+
return r;
|
|
5273
|
+
}
|
|
5274
|
+
function emitReplayPrefixLeaf(ctx, pos, replay) {
|
|
5275
|
+
const vv = v(ctx);
|
|
5276
|
+
return {
|
|
5277
|
+
stmts: [
|
|
5278
|
+
`${ind(ctx)}const ${vv} = ${replay.valVar}`,
|
|
5279
|
+
...emitLeafCapture(ctx, vv, pos, replay.endVar)
|
|
5280
|
+
],
|
|
5281
|
+
valueVar: vv,
|
|
5282
|
+
endVar: replay.endVar
|
|
5283
|
+
};
|
|
5284
|
+
}
|
|
5105
5285
|
function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
|
|
5106
5286
|
if (strategy.tag === "greedyClassify")
|
|
5107
5287
|
return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
|
|
5108
5288
|
if (strategy.tag === "literalsLongestFirst")
|
|
5109
5289
|
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
|
|
5290
|
+
if (strategy.tag === "sharedPrefix") {
|
|
5291
|
+
if (!_forceNoSharedPrefix && coverageBase === void 0 && !ctx.recovery && strategy.members.every((i) => armReplayInScope(def.parsers[i], ctx)))
|
|
5292
|
+
return emitSharedPrefix(def, strategy, ctx, pos);
|
|
5293
|
+
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
5294
|
+
}
|
|
5110
5295
|
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
5111
5296
|
}
|
|
5112
5297
|
function pushMapFn(ctx, fn, src) {
|
|
@@ -5186,6 +5371,13 @@ function emitMany(def, ctx, pos) {
|
|
|
5186
5371
|
itemPos = npV;
|
|
5187
5372
|
}
|
|
5188
5373
|
}
|
|
5374
|
+
if (!ctx.recovery && !ctx.coverage && !failsAtStart(def.parser) && needsFirstSetGuard(def.parser)) {
|
|
5375
|
+
const lcV = v(ctx, "_lc");
|
|
5376
|
+
stmts.push(
|
|
5377
|
+
`${ind(ctx)}const ${lcV} = ${itemPos} < input.length ? (input.codePointAt(${itemPos}) ?? -1) : -1`,
|
|
5378
|
+
`${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
|
|
5379
|
+
);
|
|
5380
|
+
}
|
|
5189
5381
|
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
|
|
5190
5382
|
stmts.push(...iterStmts);
|
|
5191
5383
|
if (ctx.recovery) {
|
|
@@ -5236,8 +5428,19 @@ function emitAttempt(p, def, ctx, pos) {
|
|
|
5236
5428
|
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}`;
|
|
5237
5429
|
const traceId = ctx.coverage?.plan.attempts.get(p);
|
|
5238
5430
|
const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
|
|
5431
|
+
const preGuard = [];
|
|
5432
|
+
if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
|
|
5433
|
+
const gcV = v(ctx, "_agc");
|
|
5434
|
+
const gExp = armStaticExpected(ctx, def.parser);
|
|
5435
|
+
const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(gExp, pos)} }`;
|
|
5436
|
+
preGuard.push(
|
|
5437
|
+
`${ind(ctx)}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
|
|
5438
|
+
`${ind(ctx)}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
|
|
5439
|
+
);
|
|
5440
|
+
}
|
|
5239
5441
|
return {
|
|
5240
5442
|
stmts: [
|
|
5443
|
+
...preGuard,
|
|
5241
5444
|
`${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`,
|
|
5242
5445
|
...inner.stmts,
|
|
5243
5446
|
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
@@ -5617,7 +5820,18 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5617
5820
|
const saveTrivia = needsTriviaFrame ? `, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}` : "";
|
|
5618
5821
|
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}` : ""}` : "";
|
|
5619
5822
|
const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
|
|
5823
|
+
const preGuard = [];
|
|
5824
|
+
if (!ctx.recovery && !ctx.coverage && (capturesChildren || structural) && needsFirstSetGuard(def.parser)) {
|
|
5825
|
+
const gcV = v(ctx, "_ngc");
|
|
5826
|
+
const gExp = armStaticExpected(ctx, def.parser);
|
|
5827
|
+
const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(gExp, pos);
|
|
5828
|
+
preGuard.push(
|
|
5829
|
+
`${i}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
|
|
5830
|
+
`${i}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
|
|
5831
|
+
);
|
|
5832
|
+
}
|
|
5620
5833
|
const stmts = [
|
|
5834
|
+
...preGuard,
|
|
5621
5835
|
profHoist,
|
|
5622
5836
|
allocStmt,
|
|
5623
5837
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
@@ -5791,6 +6005,8 @@ function emitExpect(def, ctx, pos) {
|
|
|
5791
6005
|
return { stmts, valueVar: valVar, endVar };
|
|
5792
6006
|
}
|
|
5793
6007
|
function emit(p, ctx, pos) {
|
|
6008
|
+
const replay = ctx.replayPrefix?.get(p);
|
|
6009
|
+
if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
|
|
5794
6010
|
const dispatch = (emissionPos = pos) => {
|
|
5795
6011
|
const savedRule = ctx.activeCoverageRuleId;
|
|
5796
6012
|
const rule = ctx.coverage?.plan.rules.get(p);
|
|
@@ -6534,6 +6750,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6534
6750
|
].join("\n")));
|
|
6535
6751
|
}
|
|
6536
6752
|
const firstSets = /* @__PURE__ */ new Map();
|
|
6753
|
+
const firstSetRecipes = /* @__PURE__ */ new Map();
|
|
6537
6754
|
for (const [key, rule] of ruleMap) {
|
|
6538
6755
|
let resolved = rule;
|
|
6539
6756
|
const d = rule._def;
|
|
@@ -6545,6 +6762,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6545
6762
|
}
|
|
6546
6763
|
}
|
|
6547
6764
|
firstSets.set(key, canMatchEmptyAtStart(resolved) ? { kind: "any" } : resolved._meta.firstSet);
|
|
6765
|
+
firstSetRecipes.set(key, canMatchEmptyAtStart(resolved) ? { concrete: any(), refs: [] } : leadingFirstSetRecipe(resolved));
|
|
6548
6766
|
}
|
|
6549
6767
|
return {
|
|
6550
6768
|
ns,
|
|
@@ -6553,6 +6771,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6553
6771
|
ruleFns,
|
|
6554
6772
|
wrappers,
|
|
6555
6773
|
firstSets,
|
|
6774
|
+
firstSetRecipes,
|
|
6556
6775
|
deps: ruleDependencies(ruleMap),
|
|
6557
6776
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
6558
6777
|
needsHostReads: !!ctx.needsHostReads,
|
|
@@ -7188,10 +7407,30 @@ function fusedBody(pieces) {
|
|
|
7188
7407
|
];
|
|
7189
7408
|
const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
|
|
7190
7409
|
const rawBody = [...lines, "return {", wrapperEntries.join(",\n"), "}"].join("\n");
|
|
7191
|
-
const
|
|
7410
|
+
const ANY2 = { kind: "any" };
|
|
7411
|
+
const recipes = /* @__PURE__ */ new Map();
|
|
7412
|
+
const shallow = /* @__PURE__ */ new Map();
|
|
7192
7413
|
for (const [k, p] of winner) {
|
|
7414
|
+
const r = p.firstSetRecipes?.get(k);
|
|
7415
|
+
if (r) recipes.set(k, r);
|
|
7193
7416
|
const fs = p.firstSets?.get(k);
|
|
7194
|
-
if (fs)
|
|
7417
|
+
if (fs) shallow.set(k, fs);
|
|
7418
|
+
}
|
|
7419
|
+
const finalFS = /* @__PURE__ */ new Map();
|
|
7420
|
+
for (const [k] of winner) finalFS.set(k, recipes.get(k)?.concrete ?? shallow.get(k) ?? ANY2);
|
|
7421
|
+
for (let iter = 0; iter <= recipes.size; iter++) {
|
|
7422
|
+
let changed = false;
|
|
7423
|
+
for (const [k, r] of recipes) {
|
|
7424
|
+
let fs = r.concrete;
|
|
7425
|
+
for (const ref2 of r.refs) {
|
|
7426
|
+
fs = union(fs, recipes.has(ref2) || shallow.has(ref2) ? finalFS.get(ref2) ?? ANY2 : ANY2);
|
|
7427
|
+
}
|
|
7428
|
+
if (JSON.stringify(finalFS.get(k)) !== JSON.stringify(fs)) {
|
|
7429
|
+
finalFS.set(k, fs);
|
|
7430
|
+
changed = true;
|
|
7431
|
+
}
|
|
7432
|
+
}
|
|
7433
|
+
if (!changed) break;
|
|
7195
7434
|
}
|
|
7196
7435
|
const body = rawBody.replace(
|
|
7197
7436
|
// Rule name + code-point var are both JS identifiers (rule names are validated
|