parseman 0.44.0 → 0.45.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/analysis/diagnose.d.ts +118 -0
- package/dist/analysis/diagnose.d.ts.map +1 -0
- package/dist/analysis/gating.d.ts +9 -9
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/analysis/grammar.d.ts.map +1 -1
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +19 -1
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +19 -0
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts +28 -0
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +80 -60
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/degradation.d.ts +123 -0
- package/dist/compiler/degradation.d.ts.map +1 -0
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/inline-build.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +1 -1
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/coverage.d.ts +13 -0
- package/dist/coverage.d.ts.map +1 -1
- package/dist/cst/reflection.d.ts.map +1 -1
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +707 -471
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +707 -471
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +40 -30
- package/dist/language-service/index.cjs.map +3 -3
- package/dist/language-service/index.js +40 -30
- package/dist/language-service/index.js.map +3 -3
- package/dist/oracle/digest.d.ts +132 -6
- package/dist/oracle/digest.d.ts.map +1 -1
- package/dist/oracle/index.cjs +136 -305
- package/dist/oracle/index.cjs.map +4 -4
- package/dist/oracle/index.d.ts +43 -31
- package/dist/oracle/index.d.ts.map +1 -1
- package/dist/oracle/index.js +136 -305
- package/dist/oracle/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +3 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +1127 -747
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts +18 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1127 -747
- package/dist/plugin/index.js.map +4 -4
- package/dist/plugin/reducer-resolver.d.ts +41 -0
- package/dist/plugin/reducer-resolver.d.ts.map +1 -0
- package/dist/run/index.cjs +33 -30
- package/dist/run/index.cjs.map +2 -2
- package/dist/run/index.js +33 -30
- package/dist/run/index.js.map +2 -2
- package/dist/spec/index.cjs +221 -34
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +221 -34
- package/dist/spec/index.js.map +4 -4
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +7 -3
- package/dist/combinators/guard.d.ts +0 -8
- package/dist/combinators/guard.d.ts.map +0 -1
- package/dist/cst/offset-model.d.ts +0 -119
- package/dist/cst/offset-model.d.ts.map +0 -1
- package/dist/oracle/corpus.d.ts +0 -32
- package/dist/oracle/corpus.d.ts.map +0 -1
- package/dist/oracle/identity.d.ts +0 -117
- package/dist/oracle/identity.d.ts.map +0 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -34,18 +34,18 @@ __export(plugin_exports, {
|
|
|
34
34
|
transformMacro: () => transformMacro
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(plugin_exports);
|
|
37
|
-
var
|
|
38
|
-
var
|
|
37
|
+
var fs2 = __toESM(require("node:fs"), 1);
|
|
38
|
+
var path2 = __toESM(require("node:path"), 1);
|
|
39
39
|
var import_unplugin = require("unplugin");
|
|
40
|
-
var
|
|
40
|
+
var import_oxc_parser3 = require("oxc-parser");
|
|
41
41
|
var import_oxc_resolver = require("oxc-resolver");
|
|
42
42
|
var import_magic_string = __toESM(require("magic-string"), 1);
|
|
43
43
|
|
|
44
44
|
// src/combinators/first-set.ts
|
|
45
|
-
function resolveNamedRef(p,
|
|
46
|
-
if (
|
|
45
|
+
function resolveNamedRef(p, resolve3) {
|
|
46
|
+
if (resolve3 === void 0) return void 0;
|
|
47
47
|
const name = p._ruleName;
|
|
48
|
-
return name === void 0 ? void 0 :
|
|
48
|
+
return name === void 0 ? void 0 : resolve3(name);
|
|
49
49
|
}
|
|
50
50
|
function union(a, b) {
|
|
51
51
|
if (a.kind === "any" || b.kind === "any") return { kind: "any" };
|
|
@@ -67,12 +67,12 @@ function fromChar(code) {
|
|
|
67
67
|
return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
|
|
68
68
|
}
|
|
69
69
|
function startsFirstSet(combinator, input, pos) {
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
if (
|
|
70
|
+
const fs3 = combinator._meta.firstSet;
|
|
71
|
+
if (fs3.kind === "any") return true;
|
|
72
|
+
if (fs3.kind === "empty") return false;
|
|
73
73
|
const code = input.codePointAt(pos);
|
|
74
74
|
if (code === void 0) return false;
|
|
75
|
-
for (const r of
|
|
75
|
+
for (const r of fs3.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
78
|
function fromRange(lo, hi) {
|
|
@@ -84,18 +84,19 @@ function any() {
|
|
|
84
84
|
function empty() {
|
|
85
85
|
return { kind: "empty" };
|
|
86
86
|
}
|
|
87
|
-
function matchesEmpty(p, seen = /* @__PURE__ */ new Set(),
|
|
87
|
+
function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve3) {
|
|
88
88
|
if (seen.has(p)) return true;
|
|
89
89
|
seen.add(p);
|
|
90
|
-
const me = (c) => matchesEmpty(c, seen,
|
|
90
|
+
const me = (c) => matchesEmpty(c, seen, resolve3);
|
|
91
91
|
const d = p._def;
|
|
92
92
|
switch (d.tag) {
|
|
93
93
|
case "literal":
|
|
94
94
|
return d.value.length === 0;
|
|
95
95
|
case "keywords":
|
|
96
96
|
return false;
|
|
97
|
+
// The routed token itself is the selector's match, never empty; a fallback can be.
|
|
97
98
|
case "routed":
|
|
98
|
-
return false;
|
|
99
|
+
return d.fallback === void 0 ? false : me(d.fallback);
|
|
99
100
|
case "regex":
|
|
100
101
|
try {
|
|
101
102
|
const m = new RegExp(d.source).exec("");
|
|
@@ -141,7 +142,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
141
142
|
try {
|
|
142
143
|
return me(d.thunk());
|
|
143
144
|
} catch {
|
|
144
|
-
const t = resolveNamedRef(p,
|
|
145
|
+
const t = resolveNamedRef(p, resolve3);
|
|
145
146
|
return t ? me(t) : true;
|
|
146
147
|
}
|
|
147
148
|
default:
|
|
@@ -167,29 +168,29 @@ function narrowBy(acc, constraint) {
|
|
|
167
168
|
}
|
|
168
169
|
return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
|
|
169
170
|
}
|
|
170
|
-
function applyAssertion(
|
|
171
|
-
if (assertion === null) return
|
|
172
|
-
if (
|
|
173
|
-
return narrowBy(
|
|
171
|
+
function applyAssertion(fs3, assertion) {
|
|
172
|
+
if (assertion === null) return fs3;
|
|
173
|
+
if (fs3.kind === "empty") return assertion;
|
|
174
|
+
return narrowBy(fs3, assertion) ?? fs3;
|
|
174
175
|
}
|
|
175
176
|
function sequenceFirstSet(parsers) {
|
|
176
|
-
let
|
|
177
|
+
let fs3 = empty();
|
|
177
178
|
let assertion = null;
|
|
178
179
|
for (const p of parsers) {
|
|
179
180
|
if (isPositiveLookahead(p)) {
|
|
180
181
|
assertion = narrowBy(assertion, p._meta.firstSet);
|
|
181
182
|
continue;
|
|
182
183
|
}
|
|
183
|
-
if (!isZeroWidthAssertion(p))
|
|
184
|
-
if (!matchesEmpty(p)) return applyAssertion(
|
|
184
|
+
if (!isZeroWidthAssertion(p)) fs3 = union(fs3, p._meta.firstSet);
|
|
185
|
+
if (!matchesEmpty(p)) return applyAssertion(fs3, assertion);
|
|
185
186
|
}
|
|
186
|
-
return applyAssertion(
|
|
187
|
+
return applyAssertion(fs3, assertion);
|
|
187
188
|
}
|
|
188
|
-
function firstSetOf(p, seen = /* @__PURE__ */ new Set(),
|
|
189
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve3) {
|
|
189
190
|
if (seen.has(p)) return any();
|
|
190
191
|
seen.add(p);
|
|
191
|
-
const
|
|
192
|
-
const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(),
|
|
192
|
+
const fs3 = (c) => firstSetOf(c, seen, resolve3);
|
|
193
|
+
const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve3);
|
|
193
194
|
const d = p._def;
|
|
194
195
|
switch (d.tag) {
|
|
195
196
|
case "literal":
|
|
@@ -198,17 +199,17 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
198
199
|
return p._meta.firstSet;
|
|
199
200
|
// terminals: no refs, cached set is exact
|
|
200
201
|
case "dispatch":
|
|
201
|
-
return
|
|
202
|
+
return fs3(d.selector);
|
|
202
203
|
case "lazy":
|
|
203
204
|
try {
|
|
204
|
-
return
|
|
205
|
+
return fs3(d.thunk());
|
|
205
206
|
} catch {
|
|
206
|
-
const t = resolveNamedRef(p,
|
|
207
|
-
return t ?
|
|
207
|
+
const t = resolveNamedRef(p, resolve3);
|
|
208
|
+
return t ? fs3(t) : any();
|
|
208
209
|
}
|
|
209
210
|
case "choice": {
|
|
210
211
|
let out = empty();
|
|
211
|
-
for (const arm of d.parsers) out = union(out,
|
|
212
|
+
for (const arm of d.parsers) out = union(out, fs3(arm));
|
|
212
213
|
return out;
|
|
213
214
|
}
|
|
214
215
|
case "sequence": {
|
|
@@ -216,17 +217,17 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
216
217
|
let assertion = null;
|
|
217
218
|
for (const term of d.parsers) {
|
|
218
219
|
if (isPositiveLookahead(term)) {
|
|
219
|
-
assertion = narrowBy(assertion,
|
|
220
|
+
assertion = narrowBy(assertion, fs3(term));
|
|
220
221
|
continue;
|
|
221
222
|
}
|
|
222
|
-
if (!isZeroWidthAssertion(term)) out = union(out,
|
|
223
|
+
if (!isZeroWidthAssertion(term)) out = union(out, fs3(term));
|
|
223
224
|
if (!empties(term)) return applyAssertion(out, assertion);
|
|
224
225
|
}
|
|
225
226
|
return applyAssertion(out, assertion);
|
|
226
227
|
}
|
|
227
228
|
case "peek": {
|
|
228
229
|
const inner = d.parser;
|
|
229
|
-
return empties(inner) ? any() :
|
|
230
|
+
return empties(inner) ? any() : fs3(inner);
|
|
230
231
|
}
|
|
231
232
|
case "oneOrMore":
|
|
232
233
|
case "many":
|
|
@@ -239,12 +240,12 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
239
240
|
case "node":
|
|
240
241
|
case "grammar":
|
|
241
242
|
case "expect":
|
|
242
|
-
return
|
|
243
|
+
return fs3(d.parser);
|
|
243
244
|
case "sepBy":
|
|
244
|
-
return
|
|
245
|
+
return fs3(d.parser);
|
|
245
246
|
// both min 0 and min 1 start with the item
|
|
246
247
|
case "skip":
|
|
247
|
-
return
|
|
248
|
+
return fs3(d.main);
|
|
248
249
|
default:
|
|
249
250
|
return p._meta.firstSet;
|
|
250
251
|
}
|
|
@@ -715,13 +716,13 @@ function shortScanner(source, flags) {
|
|
|
715
716
|
return minOne && end === pos ? null : end;
|
|
716
717
|
};
|
|
717
718
|
}
|
|
718
|
-
function asciiCaseFold(
|
|
719
|
-
if (
|
|
720
|
-
const ranges =
|
|
719
|
+
function asciiCaseFold(fs3) {
|
|
720
|
+
if (fs3.kind !== "ranges") return fs3;
|
|
721
|
+
const ranges = fs3.ranges.map((r) => ({ lo: r.lo, hi: r.hi }));
|
|
721
722
|
const add = (lo, hi) => {
|
|
722
723
|
if (lo <= hi) ranges.push({ lo, hi });
|
|
723
724
|
};
|
|
724
|
-
for (const r of
|
|
725
|
+
for (const r of fs3.ranges) {
|
|
725
726
|
const uLo = Math.max(r.lo, 65), uHi = Math.min(r.hi, 90);
|
|
726
727
|
add(uLo + 32, uHi + 32);
|
|
727
728
|
const lLo = Math.max(r.lo, 97), lHi = Math.min(r.hi, 122);
|
|
@@ -779,9 +780,9 @@ function charNode(set, nl) {
|
|
|
779
780
|
return { t: "char", set, nl };
|
|
780
781
|
}
|
|
781
782
|
function rangesToSet(ranges) {
|
|
782
|
-
let
|
|
783
|
-
for (const [lo, hi] of ranges)
|
|
784
|
-
return
|
|
783
|
+
let fs3 = empty();
|
|
784
|
+
for (const [lo, hi] of ranges) fs3 = union(fs3, fromRange(lo, hi));
|
|
785
|
+
return fs3;
|
|
785
786
|
}
|
|
786
787
|
function rangesHaveNewline(ranges) {
|
|
787
788
|
return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
|
|
@@ -987,17 +988,17 @@ function firstSet(n) {
|
|
|
987
988
|
case "rep":
|
|
988
989
|
return firstSet(n.node);
|
|
989
990
|
case "alt": {
|
|
990
|
-
let
|
|
991
|
-
for (const arm of n.arms)
|
|
992
|
-
return
|
|
991
|
+
let fs3 = empty();
|
|
992
|
+
for (const arm of n.arms) fs3 = union(fs3, firstSet(arm));
|
|
993
|
+
return fs3;
|
|
993
994
|
}
|
|
994
995
|
case "seq": {
|
|
995
|
-
let
|
|
996
|
+
let fs3 = empty();
|
|
996
997
|
for (const part of n.parts) {
|
|
997
|
-
|
|
998
|
+
fs3 = union(fs3, firstSet(part));
|
|
998
999
|
if (!nullable(part)) break;
|
|
999
1000
|
}
|
|
1000
|
-
return
|
|
1001
|
+
return fs3;
|
|
1001
1002
|
}
|
|
1002
1003
|
}
|
|
1003
1004
|
}
|
|
@@ -1672,12 +1673,12 @@ function orSentinel(a, b) {
|
|
|
1672
1673
|
}
|
|
1673
1674
|
};
|
|
1674
1675
|
}
|
|
1675
|
-
function firstSetSentinel(
|
|
1676
|
-
if (
|
|
1677
|
-
const ranges =
|
|
1676
|
+
function firstSetSentinel(fs3) {
|
|
1677
|
+
if (fs3.kind !== "ranges" || fs3.ranges.length === 0) return null;
|
|
1678
|
+
const ranges = fs3.ranges;
|
|
1678
1679
|
return {
|
|
1679
1680
|
_tag: "firstSetSentinel",
|
|
1680
|
-
_meta: { firstSet:
|
|
1681
|
+
_meta: { firstSet: fs3, canMatchNewline: false, isTrivia: false },
|
|
1681
1682
|
_def: { tag: "unknown" },
|
|
1682
1683
|
parse(input, pos) {
|
|
1683
1684
|
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
@@ -1719,11 +1720,11 @@ function sequence(...parsers) {
|
|
|
1719
1720
|
let followSentinels;
|
|
1720
1721
|
function parseTolerant(input, pos, ctx) {
|
|
1721
1722
|
followSentinels ??= parsers.map((_, i) => {
|
|
1722
|
-
const
|
|
1723
|
+
const fs3 = parsers.slice(i + 1).reduce(
|
|
1723
1724
|
(acc, p) => union(acc, firstSetOf(p)),
|
|
1724
1725
|
{ kind: "empty" }
|
|
1725
1726
|
);
|
|
1726
|
-
return firstSetSentinel(
|
|
1727
|
+
return firstSetSentinel(fs3);
|
|
1727
1728
|
});
|
|
1728
1729
|
const values = def.valueUnused ? void 0 : [];
|
|
1729
1730
|
let cur = pos;
|
|
@@ -1866,8 +1867,11 @@ function derive(c, seen) {
|
|
|
1866
1867
|
case "not":
|
|
1867
1868
|
case "peek":
|
|
1868
1869
|
return deriveExpected2(def.parser);
|
|
1870
|
+
// A bare routed() can only fail as "there is no routed token here". With a
|
|
1871
|
+
// fallback, THAT is the branch that can fail, so its expectations are the useful
|
|
1872
|
+
// ones — the routed path either succeeds or is not taken.
|
|
1869
1873
|
case "routed":
|
|
1870
|
-
return ["routed()"];
|
|
1874
|
+
return def.fallback === void 0 ? ["routed()"] : deriveExpected2(def.fallback);
|
|
1871
1875
|
case "lazy": {
|
|
1872
1876
|
const name = c._ruleName;
|
|
1873
1877
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -2054,7 +2058,7 @@ function detectStrategy(parsers) {
|
|
|
2054
2058
|
function bareLeadingTermKey(term) {
|
|
2055
2059
|
const d = term._def;
|
|
2056
2060
|
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
2057
|
-
if (d.tag === "regex") return `R:${d.source
|
|
2061
|
+
if (d.tag === "regex") return `R:${JSON.stringify([d.source, d.flags])}`;
|
|
2058
2062
|
return null;
|
|
2059
2063
|
}
|
|
2060
2064
|
function detectSharedPrefix(parsers) {
|
|
@@ -2170,10 +2174,10 @@ function codesToFirstSet(codes) {
|
|
|
2170
2174
|
ranges.push({ lo, hi });
|
|
2171
2175
|
return { kind: "ranges", ranges };
|
|
2172
2176
|
}
|
|
2173
|
-
function inFirstSet(code,
|
|
2174
|
-
if (
|
|
2175
|
-
if (
|
|
2176
|
-
for (const r of
|
|
2177
|
+
function inFirstSet(code, fs3) {
|
|
2178
|
+
if (fs3.kind === "any") return true;
|
|
2179
|
+
if (fs3.kind === "empty") return false;
|
|
2180
|
+
for (const r of fs3.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
2177
2181
|
return false;
|
|
2178
2182
|
}
|
|
2179
2183
|
function areDisjoint(sets) {
|
|
@@ -2186,9 +2190,9 @@ function areDisjoint(sets) {
|
|
|
2186
2190
|
function buildAsciiDispatch(parsers) {
|
|
2187
2191
|
const table = Array(128).fill(-1);
|
|
2188
2192
|
for (let i = 0; i < parsers.length; i++) {
|
|
2189
|
-
const
|
|
2190
|
-
if (
|
|
2191
|
-
for (const { lo, hi } of
|
|
2193
|
+
const fs3 = parsers[i]._meta.firstSet;
|
|
2194
|
+
if (fs3.kind !== "ranges") continue;
|
|
2195
|
+
for (const { lo, hi } of fs3.ranges) {
|
|
2192
2196
|
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
2193
2197
|
table[code] = i;
|
|
2194
2198
|
}
|
|
@@ -2309,17 +2313,21 @@ function when(key, parser2, opts = {}) {
|
|
|
2309
2313
|
function otherwise(parser2) {
|
|
2310
2314
|
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2311
2315
|
}
|
|
2312
|
-
function routed() {
|
|
2316
|
+
function routed(fallback) {
|
|
2313
2317
|
return {
|
|
2314
2318
|
_tag: "routed",
|
|
2315
|
-
_meta: {
|
|
2316
|
-
|
|
2319
|
+
_meta: {
|
|
2320
|
+
// The routed token is whatever the selector matched, so the first set stays
|
|
2321
|
+
// `any` even with a fallback — `any` already subsumes the fallback's.
|
|
2322
|
+
firstSet: { kind: "any" },
|
|
2323
|
+
canMatchNewline: fallback?._meta.canMatchNewline ?? false,
|
|
2324
|
+
isTrivia: false
|
|
2325
|
+
},
|
|
2326
|
+
_def: fallback === void 0 ? { tag: "routed" } : { tag: "routed", fallback },
|
|
2317
2327
|
parse(_input, pos, ctx) {
|
|
2318
2328
|
const item = ctx._routed;
|
|
2319
|
-
if (item === void 0) {
|
|
2320
|
-
|
|
2321
|
-
}
|
|
2322
|
-
if (pos !== item.span.start) {
|
|
2329
|
+
if (item === void 0 || pos !== item.span.start) {
|
|
2330
|
+
if (fallback !== void 0) return fallback.parse(_input, pos, ctx);
|
|
2323
2331
|
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2324
2332
|
}
|
|
2325
2333
|
if (cstCaptureActive(ctx)) {
|
|
@@ -2826,12 +2834,12 @@ function markUnusedValues(root) {
|
|
|
2826
2834
|
}
|
|
2827
2835
|
};
|
|
2828
2836
|
const resolveRoot = (c) => {
|
|
2829
|
-
const
|
|
2837
|
+
const guard = /* @__PURE__ */ new Set();
|
|
2830
2838
|
let cur = c;
|
|
2831
|
-
while (!
|
|
2839
|
+
while (!guard.has(cur)) {
|
|
2832
2840
|
const d = cur._def;
|
|
2833
2841
|
if (d.tag !== "lazy") return cur;
|
|
2834
|
-
|
|
2842
|
+
guard.add(cur);
|
|
2835
2843
|
try {
|
|
2836
2844
|
cur = d.thunk();
|
|
2837
2845
|
} catch {
|
|
@@ -2973,10 +2981,11 @@ function childrenOf(def) {
|
|
|
2973
2981
|
return [def.main, def.skipped];
|
|
2974
2982
|
case "scanTo":
|
|
2975
2983
|
return [def.sentinel, ...def.skip];
|
|
2984
|
+
case "routed":
|
|
2985
|
+
return def.fallback ? [def.fallback] : [];
|
|
2976
2986
|
case "literal":
|
|
2977
2987
|
case "regex":
|
|
2978
2988
|
case "keywords":
|
|
2979
|
-
case "routed":
|
|
2980
2989
|
case "guard":
|
|
2981
2990
|
case "lazy":
|
|
2982
2991
|
case "unknown":
|
|
@@ -3199,54 +3208,275 @@ function peek(combinator) {
|
|
|
3199
3208
|
};
|
|
3200
3209
|
}
|
|
3201
3210
|
|
|
3211
|
+
// src/compiler/degradation.ts
|
|
3212
|
+
function formatDegradation(d) {
|
|
3213
|
+
return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
|
|
3214
|
+
}
|
|
3215
|
+
var DETAIL_CAP = 8;
|
|
3216
|
+
function formatDegradations(list) {
|
|
3217
|
+
const byCode = /* @__PURE__ */ new Map();
|
|
3218
|
+
for (const d of list) {
|
|
3219
|
+
const bucket = byCode.get(d.code);
|
|
3220
|
+
if (bucket) bucket.push(d);
|
|
3221
|
+
else byCode.set(d.code, [d]);
|
|
3222
|
+
}
|
|
3223
|
+
const out = [];
|
|
3224
|
+
for (const [code, items] of byCode) {
|
|
3225
|
+
for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
|
|
3226
|
+
if (items.length > DETAIL_CAP) {
|
|
3227
|
+
out.push(
|
|
3228
|
+
`[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
|
|
3229
|
+
);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
return out;
|
|
3233
|
+
}
|
|
3234
|
+
var _sinks = [];
|
|
3235
|
+
function beginDegradationCapture() {
|
|
3236
|
+
_sinks.push(/* @__PURE__ */ new Map());
|
|
3237
|
+
}
|
|
3238
|
+
function endDegradationCapture() {
|
|
3239
|
+
const sink = _sinks.pop();
|
|
3240
|
+
return sink ? [...sink.values()] : [];
|
|
3241
|
+
}
|
|
3242
|
+
function degradationCaptureDepth() {
|
|
3243
|
+
return _sinks.length;
|
|
3244
|
+
}
|
|
3245
|
+
function unwindDegradationCapture(depth) {
|
|
3246
|
+
const found = [];
|
|
3247
|
+
while (_sinks.length > depth) {
|
|
3248
|
+
const sink = _sinks.pop();
|
|
3249
|
+
found.unshift(...sink.values());
|
|
3250
|
+
}
|
|
3251
|
+
return found;
|
|
3252
|
+
}
|
|
3253
|
+
function resolveDegradationLevel(explicit) {
|
|
3254
|
+
if (explicit !== void 0) return explicit;
|
|
3255
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
|
|
3256
|
+
if (env === "off" || env === "warn" || env === "error") return env;
|
|
3257
|
+
return "warn";
|
|
3258
|
+
}
|
|
3259
|
+
function degradationKey(d) {
|
|
3260
|
+
return JSON.stringify([d.code, d.where, d.subject]);
|
|
3261
|
+
}
|
|
3262
|
+
function recordDegradation(d) {
|
|
3263
|
+
const level = resolveDegradationLevel();
|
|
3264
|
+
if (level === "off") return;
|
|
3265
|
+
const key = degradationKey(d);
|
|
3266
|
+
const sink = _sinks[_sinks.length - 1];
|
|
3267
|
+
if (sink) {
|
|
3268
|
+
if (!sink.has(key)) sink.set(key, d);
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
if (_immediate.has(key)) return;
|
|
3272
|
+
_immediate.add(key);
|
|
3273
|
+
if (level === "error") throw new Error(`parseman: degraded compilation path
|
|
3274
|
+
${formatDegradation(d)}`);
|
|
3275
|
+
console.warn(formatDegradation(d));
|
|
3276
|
+
}
|
|
3277
|
+
var _immediate = /* @__PURE__ */ new Set();
|
|
3278
|
+
function beginCompileDegradationDrain() {
|
|
3279
|
+
if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
|
|
3280
|
+
};
|
|
3281
|
+
const depth = degradationCaptureDepth();
|
|
3282
|
+
beginDegradationCapture();
|
|
3283
|
+
return (report) => {
|
|
3284
|
+
const found = unwindDegradationCapture(depth);
|
|
3285
|
+
if (!report || found.length === 0) return;
|
|
3286
|
+
const fresh = found.filter((d) => {
|
|
3287
|
+
const k = degradationKey(d);
|
|
3288
|
+
if (_immediate.has(k)) return false;
|
|
3289
|
+
_immediate.add(k);
|
|
3290
|
+
return true;
|
|
3291
|
+
});
|
|
3292
|
+
if (fresh.length === 0) return;
|
|
3293
|
+
const lines = formatDegradations(fresh);
|
|
3294
|
+
if (resolveDegradationLevel() === "error") {
|
|
3295
|
+
throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
|
|
3296
|
+
${lines.join("\n")}`);
|
|
3297
|
+
}
|
|
3298
|
+
for (const l of lines) console.warn(l);
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3202
3302
|
// src/compiler/build-arity.ts
|
|
3203
3303
|
function cstOutputHost(build) {
|
|
3204
3304
|
return build?._parsemanCstOutput === true;
|
|
3205
3305
|
}
|
|
3206
|
-
var
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
|
|
3306
|
+
var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
|
|
3307
|
+
var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
|
|
3308
|
+
var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
|
|
3309
|
+
var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
|
|
3211
3310
|
function confirmedBuildArity(src) {
|
|
3212
3311
|
const s = src.trim();
|
|
3213
|
-
|
|
3214
|
-
if (
|
|
3215
|
-
if (
|
|
3216
|
-
const inner = (
|
|
3217
|
-
if (inner ===
|
|
3218
|
-
|
|
3312
|
+
if (NATIVE_CODE_RE.test(s)) return null;
|
|
3313
|
+
if (/\barguments\b/.test(s)) return null;
|
|
3314
|
+
if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
|
|
3315
|
+
const inner = paramListText(s);
|
|
3316
|
+
if (inner === null) return null;
|
|
3317
|
+
if (inner.trim() === "") return 0;
|
|
3318
|
+
const parts = splitTopLevel(inner);
|
|
3319
|
+
if (parts === null) return null;
|
|
3219
3320
|
for (const part of parts) {
|
|
3220
|
-
if (!
|
|
3321
|
+
if (!isConfirmableParam(part.trim())) return null;
|
|
3221
3322
|
}
|
|
3222
|
-
if (/\barguments\b/.test(s)) return null;
|
|
3223
3323
|
return parts.length;
|
|
3224
3324
|
}
|
|
3325
|
+
function paramListText(s) {
|
|
3326
|
+
const open = PARAM_LIST_OPEN_RE.exec(s);
|
|
3327
|
+
if (!open) return null;
|
|
3328
|
+
const start = open[0].length;
|
|
3329
|
+
const end = matchingParen(s, start);
|
|
3330
|
+
if (end === null) return null;
|
|
3331
|
+
if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
|
|
3332
|
+
return s.slice(start, end);
|
|
3333
|
+
}
|
|
3334
|
+
function matchingParen(s, start) {
|
|
3335
|
+
let depth = 0;
|
|
3336
|
+
for (let i = start; i < s.length; i++) {
|
|
3337
|
+
const c = s[i];
|
|
3338
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3339
|
+
const close = skipString(s, i);
|
|
3340
|
+
if (close === null) return null;
|
|
3341
|
+
i = close;
|
|
3342
|
+
continue;
|
|
3343
|
+
}
|
|
3344
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3345
|
+
else if (c === "]" || c === "}") {
|
|
3346
|
+
if (--depth < 0) return null;
|
|
3347
|
+
} else if (c === ")") {
|
|
3348
|
+
if (depth === 0) return i;
|
|
3349
|
+
depth--;
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
return null;
|
|
3353
|
+
}
|
|
3354
|
+
function skipString(s, open) {
|
|
3355
|
+
const quote = s[open];
|
|
3356
|
+
for (let i = open + 1; i < s.length; i++) {
|
|
3357
|
+
if (s[i] === "\\") {
|
|
3358
|
+
i++;
|
|
3359
|
+
continue;
|
|
3360
|
+
}
|
|
3361
|
+
if (s[i] === quote) return i;
|
|
3362
|
+
}
|
|
3363
|
+
return null;
|
|
3364
|
+
}
|
|
3365
|
+
function splitTopLevel(inner) {
|
|
3366
|
+
const parts = [];
|
|
3367
|
+
let depth = 0;
|
|
3368
|
+
let angle = 0;
|
|
3369
|
+
let last = 0;
|
|
3370
|
+
for (let i = 0; i < inner.length; i++) {
|
|
3371
|
+
const c = inner[i];
|
|
3372
|
+
if (c === "=" && inner[i + 1] === ">") {
|
|
3373
|
+
i++;
|
|
3374
|
+
continue;
|
|
3375
|
+
}
|
|
3376
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3377
|
+
const close = skipString(inner, i);
|
|
3378
|
+
if (close === null) return null;
|
|
3379
|
+
i = close;
|
|
3380
|
+
continue;
|
|
3381
|
+
}
|
|
3382
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3383
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
3384
|
+
if (--depth < 0) return null;
|
|
3385
|
+
} else if (c === "<") angle++;
|
|
3386
|
+
else if (c === ">") {
|
|
3387
|
+
if (--angle < 0) return null;
|
|
3388
|
+
} else if (c === "," && depth === 0 && angle === 0) {
|
|
3389
|
+
parts.push(inner.slice(last, i));
|
|
3390
|
+
last = i + 1;
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
if (depth !== 0 || angle !== 0) return null;
|
|
3394
|
+
parts.push(inner.slice(last));
|
|
3395
|
+
return parts;
|
|
3396
|
+
}
|
|
3397
|
+
function isConfirmableParam(part) {
|
|
3398
|
+
const head = PARAM_HEAD_RE.exec(part);
|
|
3399
|
+
if (!head) return false;
|
|
3400
|
+
const rest = part.slice(head[0].length);
|
|
3401
|
+
if (rest === "") return true;
|
|
3402
|
+
if (rest[0] !== ":") return false;
|
|
3403
|
+
return !hasDefaultAssign(rest.slice(1));
|
|
3404
|
+
}
|
|
3405
|
+
function hasDefaultAssign(annotation) {
|
|
3406
|
+
for (let i = 0; i < annotation.length; i++) {
|
|
3407
|
+
if (annotation[i] !== "=") continue;
|
|
3408
|
+
if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
|
|
3409
|
+
i++;
|
|
3410
|
+
continue;
|
|
3411
|
+
}
|
|
3412
|
+
const prev = annotation[i - 1];
|
|
3413
|
+
if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
|
|
3414
|
+
return true;
|
|
3415
|
+
}
|
|
3416
|
+
return false;
|
|
3417
|
+
}
|
|
3418
|
+
function buildAnalysisSrc(def) {
|
|
3419
|
+
return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
|
|
3420
|
+
}
|
|
3421
|
+
var RESOLVER_REASONS = {
|
|
3422
|
+
"rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
|
|
3423
|
+
"arguments": "its body references `arguments`",
|
|
3424
|
+
"reassigned": "the binding it names is reassigned, so the function read here is not decidable",
|
|
3425
|
+
"not-a-function": "the binding it names is not a function declaration",
|
|
3426
|
+
"unresolved-import": "its module could not be resolved or parsed",
|
|
3427
|
+
"not-found": "the name did not resolve to any binding",
|
|
3428
|
+
"computed": "it is a computed expression",
|
|
3429
|
+
"foreign-source": "it is named inside an imported factory, whose offsets the entry-file resolver cannot index"
|
|
3430
|
+
};
|
|
3431
|
+
function unconfirmableReason(def, src) {
|
|
3432
|
+
const declared = def.buildArityUnresolved;
|
|
3433
|
+
if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
|
|
3434
|
+
const s = src.trim();
|
|
3435
|
+
const params = s.slice(0, s.indexOf(")") + 1);
|
|
3436
|
+
if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
|
|
3437
|
+
if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
|
|
3438
|
+
if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
|
|
3439
|
+
return "it names a binding this build could not resolve to a function declaration";
|
|
3440
|
+
}
|
|
3441
|
+
return "its parameter list could not be parsed";
|
|
3442
|
+
}
|
|
3443
|
+
function confirmedArityForDef(def) {
|
|
3444
|
+
if (def.buildArity !== void 0) return def.buildArity;
|
|
3445
|
+
const src = buildAnalysisSrc(def);
|
|
3446
|
+
const arity = confirmedBuildArity(src);
|
|
3447
|
+
if (arity !== null) return arity;
|
|
3448
|
+
const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
|
|
3449
|
+
recordDegradation({
|
|
3450
|
+
code: "build-arity-unconfirmed",
|
|
3451
|
+
severity: "warn",
|
|
3452
|
+
where: `node("${def.type ?? "<inferred>"}")`,
|
|
3453
|
+
subject,
|
|
3454
|
+
fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and clones \`_ctx.state\` on every match`,
|
|
3455
|
+
otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
|
|
3456
|
+
});
|
|
3457
|
+
return null;
|
|
3458
|
+
}
|
|
3225
3459
|
function buildReadsChildren(def) {
|
|
3226
3460
|
if (!def.build) return true;
|
|
3227
|
-
const
|
|
3228
|
-
const arity = confirmedBuildArity(src);
|
|
3461
|
+
const arity = confirmedArityForDef(def);
|
|
3229
3462
|
if (arity === null) return true;
|
|
3230
3463
|
return arity >= 1;
|
|
3231
3464
|
}
|
|
3232
3465
|
function buildReadsRaw(def) {
|
|
3233
3466
|
if (!def.build) return true;
|
|
3234
|
-
const
|
|
3235
|
-
const arity = confirmedBuildArity(src);
|
|
3467
|
+
const arity = confirmedArityForDef(def);
|
|
3236
3468
|
if (arity === null) return true;
|
|
3237
3469
|
return arity >= 4;
|
|
3238
3470
|
}
|
|
3239
3471
|
function buildReadsTrivia(def) {
|
|
3240
3472
|
if (!def.build) return true;
|
|
3241
|
-
const
|
|
3242
|
-
const arity = confirmedBuildArity(src);
|
|
3473
|
+
const arity = confirmedArityForDef(def);
|
|
3243
3474
|
if (arity === null) return true;
|
|
3244
3475
|
return arity >= 5;
|
|
3245
3476
|
}
|
|
3246
3477
|
function buildReadsState(def) {
|
|
3247
3478
|
if (!def.build) return true;
|
|
3248
|
-
const
|
|
3249
|
-
const arity = confirmedBuildArity(src);
|
|
3479
|
+
const arity = confirmedArityForDef(def);
|
|
3250
3480
|
if (arity === null) return true;
|
|
3251
3481
|
return arity >= 6;
|
|
3252
3482
|
}
|
|
@@ -3254,8 +3484,7 @@ function buildReadsState(def) {
|
|
|
3254
3484
|
// src/compiler/fields.ts
|
|
3255
3485
|
function buildReadsFields(def) {
|
|
3256
3486
|
if (!def.build) return true;
|
|
3257
|
-
const
|
|
3258
|
-
const arity = confirmedBuildArity(src);
|
|
3487
|
+
const arity = confirmedArityForDef(def);
|
|
3259
3488
|
if (arity === null) return true;
|
|
3260
3489
|
return arity >= 2;
|
|
3261
3490
|
}
|
|
@@ -3436,6 +3665,13 @@ function isCstChild(value) {
|
|
|
3436
3665
|
function missingInferredType() {
|
|
3437
3666
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
3438
3667
|
}
|
|
3668
|
+
function normalizeBuildArity(arity) {
|
|
3669
|
+
if (arity === void 0) return void 0;
|
|
3670
|
+
if (!Number.isInteger(arity) || arity < 0 || arity > 6) {
|
|
3671
|
+
throw new Error("node() buildArity must be an integer 0..6 (children, fields, span, rawChildren, triviaLog, state)");
|
|
3672
|
+
}
|
|
3673
|
+
return arity;
|
|
3674
|
+
}
|
|
3439
3675
|
function normalizeProject(project) {
|
|
3440
3676
|
if (project === void 0) return void 0;
|
|
3441
3677
|
if (!Number.isInteger(project) || project < 0) {
|
|
@@ -3471,13 +3707,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3471
3707
|
const captureTrivia = opts?.captureTrivia === true;
|
|
3472
3708
|
const trailingTrivia = opts?.trailingTrivia === true;
|
|
3473
3709
|
const tags = opts?.tags;
|
|
3710
|
+
const buildArity = normalizeBuildArity(opts?.buildArity);
|
|
3474
3711
|
if (unwrap && collapse) {
|
|
3475
3712
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
3476
3713
|
}
|
|
3477
3714
|
if (project !== void 0 && (unwrap || collapse)) {
|
|
3478
3715
|
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3479
3716
|
}
|
|
3480
|
-
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
|
|
3717
|
+
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
|
|
3481
3718
|
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3482
3719
|
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
3483
3720
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
@@ -3523,7 +3760,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3523
3760
|
const cstOutput = cstOutputHost(ctx.build);
|
|
3524
3761
|
const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
|
|
3525
3762
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
3526
|
-
const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
|
|
3763
|
+
const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : (cstOutput || !build && project === void 0) && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, hostState, tags) : build(children2, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
|
|
3527
3764
|
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
|
|
3528
3765
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
3529
3766
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3718,7 +3955,7 @@ function leaf(root, fn) {
|
|
|
3718
3955
|
}
|
|
3719
3956
|
|
|
3720
3957
|
// src/version.ts
|
|
3721
|
-
var PARSEMAN_VERSION = "0.
|
|
3958
|
+
var PARSEMAN_VERSION = "0.45.0";
|
|
3722
3959
|
|
|
3723
3960
|
// src/cst/host-mode.ts
|
|
3724
3961
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3738,346 +3975,11 @@ function assertHostModeCompatible(mode, build, hostBranchElided = true) {
|
|
|
3738
3975
|
}
|
|
3739
3976
|
|
|
3740
3977
|
// src/analysis/gating.ts
|
|
3741
|
-
var isAny = (fs2) => fs2.kind === "any";
|
|
3742
|
-
function intersects2(a, b) {
|
|
3743
|
-
if (a.kind === "any" || b.kind === "any") return true;
|
|
3744
|
-
if (a.kind === "empty" || b.kind === "empty") return false;
|
|
3745
|
-
for (const ra of a.ranges) for (const rb of b.ranges) if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
|
|
3746
|
-
return false;
|
|
3747
|
-
}
|
|
3748
|
-
function intersection(a, b) {
|
|
3749
|
-
if (a.kind === "any") return b;
|
|
3750
|
-
if (b.kind === "any") return a;
|
|
3751
|
-
if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
|
|
3752
|
-
const ranges = [];
|
|
3753
|
-
for (const ra of a.ranges) for (const rb of b.ranges) {
|
|
3754
|
-
const lo = Math.max(ra.lo, rb.lo);
|
|
3755
|
-
const hi = Math.min(ra.hi, rb.hi);
|
|
3756
|
-
if (lo <= hi) ranges.push({ lo, hi });
|
|
3757
|
-
}
|
|
3758
|
-
return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
|
|
3759
|
-
}
|
|
3760
|
-
function combine(sets) {
|
|
3761
|
-
let acc = { kind: "empty" };
|
|
3762
|
-
for (const s of sets) {
|
|
3763
|
-
if (s.kind === "any") return { kind: "any" };
|
|
3764
|
-
if (s.kind === "empty") continue;
|
|
3765
|
-
acc = acc.kind === "ranges" ? { kind: "ranges", ranges: [...acc.ranges, ...s.ranges] } : s;
|
|
3766
|
-
}
|
|
3767
|
-
return acc;
|
|
3768
|
-
}
|
|
3769
3978
|
var ch = (c) => c >= 32 && c < 127 ? `'${String.fromCharCode(c)}'` : `\\u${c}`;
|
|
3770
|
-
function firstSetToString(
|
|
3771
|
-
if (
|
|
3772
|
-
if (
|
|
3773
|
-
return
|
|
3774
|
-
}
|
|
3775
|
-
var ruleNameOf2 = (p) => p._ruleName;
|
|
3776
|
-
var SUGGESTIONS = {
|
|
3777
|
-
"broad-recognizer": "if this arm leads with a keyword regex, use word('kw', boundary) / keywords([...]) \u2014 they expose an EXACT, gating first-set and lower to the same charCodeAt scan. A genuine scanTo fallback is fine; accept it in the gating snapshot if intentional.",
|
|
3778
|
-
"leading-not": "let the arm lead with its actual consuming terminal (first-sets gate it automatically); keep not(...) only as a TRAILING boundary. Do not hand-roll not(not(...)) to fake gating \u2014 use peek(X), which is zero-width AND carries X first-set.",
|
|
3779
|
-
"nullable-prefix": "a leading optional/many lets a later, broad term start the arm. Split the empty case into its own arm, or gate on the prefix first char. A plain sepBy(item, sep) is ALSO nullable \u2014 pass { min: 1 } for a list that cannot be empty.",
|
|
3780
|
-
"cross-artifact-ref": "parseman >=0.32.0 resolves a g.Foo ref first-set at fuse time; if still ANY the target rule is itself ungated \u2014 analyze it and give it a concrete non-nullable lead.",
|
|
3781
|
-
"opaque-wrapper": "this wrapper (guard/withCtx/recover) contributes no first char; put a concrete leading terminal before it.",
|
|
3782
|
-
"ref-cycle": "a recursive ref resolved to ANY; ensure the recursion has a concrete terminal lead on the base case."
|
|
3783
|
-
};
|
|
3784
|
-
function classifyBroadArm(arm, resolve2) {
|
|
3785
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3786
|
-
const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
|
|
3787
|
-
const walk = (p) => {
|
|
3788
|
-
if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
|
|
3789
|
-
seen.add(p);
|
|
3790
|
-
const d = p._def;
|
|
3791
|
-
switch (d.tag) {
|
|
3792
|
-
case "literal":
|
|
3793
|
-
case "regex":
|
|
3794
|
-
case "keywords":
|
|
3795
|
-
return isAny(p._meta.firstSet) ? { cause: "broad-recognizer", detail: `broad recognizer (${d.tag})` } : null;
|
|
3796
|
-
case "not":
|
|
3797
|
-
return { cause: "leading-not", detail: "leading not(...) (first-set ANY)" };
|
|
3798
|
-
// peek() CARRIES its body's first-set, so it is only broad when the body is
|
|
3799
|
-
// (or the body is nullable) — walk in for the real cause.
|
|
3800
|
-
case "peek":
|
|
3801
|
-
return walk(d.parser);
|
|
3802
|
-
case "scanTo":
|
|
3803
|
-
return { cause: "broad-recognizer", detail: "scanTo (any first char)" };
|
|
3804
|
-
// `guard` (the `gate()` state predicate) has a genuinely-`any` first-set of
|
|
3805
|
-
// its own — it is the poison. `withCtx`/`recover` FORWARD their inner
|
|
3806
|
-
// first-set (see firstSetOf), so a broad result comes from the inner parser:
|
|
3807
|
-
// walk into it for a precise cause.
|
|
3808
|
-
case "guard":
|
|
3809
|
-
return { cause: "opaque-wrapper", detail: `opaque wrapper (${d.tag})` };
|
|
3810
|
-
// attempt/withCtx/recover FORWARD their inner first-set (transparent for
|
|
3811
|
-
// dispatch), so a broad result comes from the inner parser — walk into it.
|
|
3812
|
-
case "attempt":
|
|
3813
|
-
case "withCtx":
|
|
3814
|
-
case "recover":
|
|
3815
|
-
return walk(d.parser);
|
|
3816
|
-
case "lazy": {
|
|
3817
|
-
const name = p._ruleName;
|
|
3818
|
-
let target;
|
|
3819
|
-
try {
|
|
3820
|
-
target = d.thunk();
|
|
3821
|
-
} catch {
|
|
3822
|
-
const bound = name !== void 0 ? resolve2?.(name) : void 0;
|
|
3823
|
-
if (bound === void 0)
|
|
3824
|
-
return { cause: "cross-artifact-ref", detail: `unresolved ref${name ? ` g.${name}` : ""}`, unresolvedExternal: name !== void 0 };
|
|
3825
|
-
target = bound;
|
|
3826
|
-
}
|
|
3827
|
-
const inner = walk(target);
|
|
3828
|
-
if (name !== void 0) return inner ? relabel(inner, "cross-artifact-ref", `via ref g.${name} \u2192 ${inner.detail}`) : null;
|
|
3829
|
-
return inner;
|
|
3830
|
-
}
|
|
3831
|
-
case "optional":
|
|
3832
|
-
case "many": {
|
|
3833
|
-
const inner = walk(d.parser);
|
|
3834
|
-
return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
|
|
3835
|
-
}
|
|
3836
|
-
case "oneOrMore":
|
|
3837
|
-
case "transform":
|
|
3838
|
-
case "label":
|
|
3839
|
-
case "field":
|
|
3840
|
-
case "trivia":
|
|
3841
|
-
case "token":
|
|
3842
|
-
case "leaf":
|
|
3843
|
-
case "node":
|
|
3844
|
-
case "grammar":
|
|
3845
|
-
case "expect":
|
|
3846
|
-
return walk(d.parser);
|
|
3847
|
-
case "skip":
|
|
3848
|
-
return walk(d.main);
|
|
3849
|
-
case "sequence": {
|
|
3850
|
-
let sawNullablePrefix = false;
|
|
3851
|
-
for (const t of d.parsers) {
|
|
3852
|
-
if (t._def.tag === "not") {
|
|
3853
|
-
sawNullablePrefix = true;
|
|
3854
|
-
continue;
|
|
3855
|
-
}
|
|
3856
|
-
if (isAny(firstSetOf(t, /* @__PURE__ */ new Set(), resolve2))) {
|
|
3857
|
-
const inner = walk(t);
|
|
3858
|
-
if (sawNullablePrefix)
|
|
3859
|
-
return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
|
|
3860
|
-
return inner ?? { cause: "broad-recognizer", detail: "sequence leading term is broad" };
|
|
3861
|
-
}
|
|
3862
|
-
if (matchesEmpty(t, /* @__PURE__ */ new Set(), resolve2)) {
|
|
3863
|
-
sawNullablePrefix = true;
|
|
3864
|
-
continue;
|
|
3865
|
-
}
|
|
3866
|
-
return null;
|
|
3867
|
-
}
|
|
3868
|
-
return { cause: "broad-recognizer", detail: "sequence of only nullable/zero-width terms" };
|
|
3869
|
-
}
|
|
3870
|
-
case "choice": {
|
|
3871
|
-
for (const a of d.parsers) {
|
|
3872
|
-
const r = walk(a);
|
|
3873
|
-
if (r) return relabel(r, r.cause, `choice arm \u2192 ${r.detail}`);
|
|
3874
|
-
}
|
|
3875
|
-
return null;
|
|
3876
|
-
}
|
|
3877
|
-
case "dispatch":
|
|
3878
|
-
return walk(d.selector);
|
|
3879
|
-
default:
|
|
3880
|
-
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3881
|
-
}
|
|
3882
|
-
};
|
|
3883
|
-
return walk(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
|
|
3884
|
-
}
|
|
3885
|
-
function peelToLeading(arm) {
|
|
3886
|
-
let d = arm._def;
|
|
3887
|
-
let cur = arm;
|
|
3888
|
-
for (; ; ) {
|
|
3889
|
-
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label" || d.tag === "attempt") {
|
|
3890
|
-
cur = d.parser;
|
|
3891
|
-
d = cur._def;
|
|
3892
|
-
continue;
|
|
3893
|
-
}
|
|
3894
|
-
break;
|
|
3895
|
-
}
|
|
3896
|
-
if (d.tag === "sequence" && d.parsers.length >= 1) return d.parsers[0];
|
|
3897
|
-
return cur;
|
|
3898
|
-
}
|
|
3899
|
-
var KEYWORD_REGEX_RE = /^\^?[@#.-]?[A-Za-z][\w-]*(\(\?![^)]*\))?\$?$/;
|
|
3900
|
-
function detectAntiPatterns(rule, arms) {
|
|
3901
|
-
const out = [];
|
|
3902
|
-
arms.forEach((arm, i) => {
|
|
3903
|
-
const lead = peelToLeading(arm);
|
|
3904
|
-
const ld = lead._def;
|
|
3905
|
-
if (ld.tag === "not") {
|
|
3906
|
-
const inner = ld.parser;
|
|
3907
|
-
if (inner._def.tag === "not") {
|
|
3908
|
-
out.push({
|
|
3909
|
-
kind: "double-not",
|
|
3910
|
-
rule,
|
|
3911
|
-
armIndex: i,
|
|
3912
|
-
message: "not(not(...)) hand-rolls automatic first-char gating and MISCOMPILES among shared-first-char sibling arms (its first-set is ANY, poisoning dispatch). Prefer letting the arm lead with its consuming terminal; where a real positive lookahead IS needed, use peek(X) \u2014 zero-width like not(not(X)) but it CARRIES X's first-set, so the arm still dispatches."
|
|
3913
|
-
});
|
|
3914
|
-
} else {
|
|
3915
|
-
out.push({
|
|
3916
|
-
kind: "leading-not",
|
|
3917
|
-
rule,
|
|
3918
|
-
armIndex: i,
|
|
3919
|
-
message: "a leading not(...) on a choice arm hand-rolls gating and poisons the choice first-set (not() is ANY). Reorder so a consuming terminal leads; keep not(...) as a TRAILING boundary only."
|
|
3920
|
-
});
|
|
3921
|
-
}
|
|
3922
|
-
}
|
|
3923
|
-
if (ld.tag === "regex" && KEYWORD_REGEX_RE.test(ld.source)) {
|
|
3924
|
-
out.push({
|
|
3925
|
-
kind: "keyword-regex",
|
|
3926
|
-
rule,
|
|
3927
|
-
armIndex: i,
|
|
3928
|
-
message: `regex(/${ld.source}/) leads this arm but is a keyword \u2014 use word('\u2026', boundary) / keywords([\u2026]) for an EXACT resolvable first-set (they lower to the same charCodeAt scan).`
|
|
3929
|
-
});
|
|
3930
|
-
}
|
|
3931
|
-
});
|
|
3932
|
-
return out;
|
|
3933
|
-
}
|
|
3934
|
-
function analyzeGating(entry, opts) {
|
|
3935
|
-
return analyzeGatingRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3936
|
-
}
|
|
3937
|
-
function analyzeGatingRules(ruleMap, opts) {
|
|
3938
|
-
const raw = [];
|
|
3939
|
-
const antiPatterns = [];
|
|
3940
|
-
const unanalysable = [];
|
|
3941
|
-
const seenUnanalysable = /* @__PURE__ */ new Set();
|
|
3942
|
-
const visited = /* @__PURE__ */ new Set();
|
|
3943
|
-
const noteUnanalysable = (u) => {
|
|
3944
|
-
const key = `${u.rule}\0${u.kind}`;
|
|
3945
|
-
if (seenUnanalysable.has(key)) return;
|
|
3946
|
-
seenUnanalysable.add(key);
|
|
3947
|
-
unanalysable.push(u);
|
|
3948
|
-
};
|
|
3949
|
-
const visit = (p, enclosingRule) => {
|
|
3950
|
-
if (visited.has(p)) return;
|
|
3951
|
-
visited.add(p);
|
|
3952
|
-
const def = p?._def;
|
|
3953
|
-
if (def === null || typeof def !== "object") {
|
|
3954
|
-
noteUnanalysable(
|
|
3955
|
-
typeof p === "function" ? {
|
|
3956
|
-
rule: enclosingRule,
|
|
3957
|
-
kind: "fused-rule",
|
|
3958
|
-
reason: "fused rule function \u2014 a compose()/fuse result has no combinator graph. Analyze the composed grammar itself (analyzeGrammarGating) so the carried IR is re-lowered first."
|
|
3959
|
-
} : {
|
|
3960
|
-
rule: enclosingRule,
|
|
3961
|
-
kind: "not-a-combinator",
|
|
3962
|
-
reason: `value of type ${p === null ? "null" : typeof p} is not a combinator and carries no _def descriptor.`
|
|
3963
|
-
}
|
|
3964
|
-
);
|
|
3965
|
-
return;
|
|
3966
|
-
}
|
|
3967
|
-
const d = def;
|
|
3968
|
-
const rule = ruleNameOf2(p) ?? enclosingRule;
|
|
3969
|
-
if (d.tag === "choice") {
|
|
3970
|
-
raw.push({ g: analyzeChoice(p, d, rule, opts?.resolveRef), rule });
|
|
3971
|
-
antiPatterns.push(...detectAntiPatterns(rule, d.parsers));
|
|
3972
|
-
}
|
|
3973
|
-
const rec = d;
|
|
3974
|
-
const kids = [];
|
|
3975
|
-
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3976
|
-
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3977
|
-
if (rec[k]) kids.push(rec[k]);
|
|
3978
|
-
if (d.tag === "dispatch") {
|
|
3979
|
-
kids.push(d.selector);
|
|
3980
|
-
for (const c of d.cases) kids.push(c.parser);
|
|
3981
|
-
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3982
|
-
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3983
|
-
}
|
|
3984
|
-
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3985
|
-
if (d.tag === "lazy") {
|
|
3986
|
-
try {
|
|
3987
|
-
kids.push(d.thunk());
|
|
3988
|
-
} catch {
|
|
3989
|
-
}
|
|
3990
|
-
}
|
|
3991
|
-
for (const k of kids) visit(k, rule);
|
|
3992
|
-
};
|
|
3993
|
-
for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name);
|
|
3994
|
-
const perRule = /* @__PURE__ */ new Map();
|
|
3995
|
-
for (const r of raw) perRule.set(r.rule, (perRule.get(r.rule) ?? 0) + 1);
|
|
3996
|
-
const seenInRule = /* @__PURE__ */ new Map();
|
|
3997
|
-
const accept = new Set(opts?.accept ?? []);
|
|
3998
|
-
const usedAccept = /* @__PURE__ */ new Set();
|
|
3999
|
-
const choices = raw.map(({ g, rule }) => {
|
|
4000
|
-
const n = seenInRule.get(rule) ?? 0;
|
|
4001
|
-
seenInRule.set(rule, n + 1);
|
|
4002
|
-
const id = (perRule.get(rule) ?? 1) === 1 ? rule : `${rule}#${n}`;
|
|
4003
|
-
const isAccepted = g.gates === "no" && accept.has(id);
|
|
4004
|
-
if (isAccepted) usedAccept.add(id);
|
|
4005
|
-
return { ...g, id, accepted: isAccepted };
|
|
4006
|
-
});
|
|
4007
|
-
const gated = choices.filter((c) => c.gates === "yes").length;
|
|
4008
|
-
const recoverable = choices.filter((c) => c.gates === "recoverable").length;
|
|
4009
|
-
const ungated = choices.filter((c) => c.gates === "no" && !c.accepted && !c.deferred);
|
|
4010
|
-
const accepted = choices.filter((c) => c.gates === "no" && c.accepted);
|
|
4011
|
-
const deferred = choices.filter((c) => c.gates === "no" && !c.accepted && c.deferred);
|
|
4012
|
-
const acceptedUnused = [...accept].filter((id) => !usedAccept.has(id));
|
|
4013
|
-
return {
|
|
4014
|
-
totalChoices: choices.length,
|
|
4015
|
-
gated,
|
|
4016
|
-
recoverable,
|
|
4017
|
-
unanalysable,
|
|
4018
|
-
ungated,
|
|
4019
|
-
accepted,
|
|
4020
|
-
deferred,
|
|
4021
|
-
acceptedUnused,
|
|
4022
|
-
choices,
|
|
4023
|
-
antiPatterns
|
|
4024
|
-
};
|
|
4025
|
-
}
|
|
4026
|
-
function analyzeChoice(p, d, rule, resolve2) {
|
|
4027
|
-
const arms = d.parsers;
|
|
4028
|
-
const shallow = arms.map((a) => a._meta.firstSet);
|
|
4029
|
-
const deep = arms.map((a) => firstSetOf(a, /* @__PURE__ */ new Set(), resolve2));
|
|
4030
|
-
const anyArms = deep.map((fs2, index) => ({ fs: fs2, index })).filter((x) => isAny(x.fs)).map(({ index }) => {
|
|
4031
|
-
const { cause, detail, unresolvedExternal } = classifyBroadArm(arms[index], resolve2);
|
|
4032
|
-
return { index, cause, detail, shallowAnyOnly: false, unresolvedExternal: unresolvedExternal === true, suggestion: SUGGESTIONS[cause] };
|
|
4033
|
-
});
|
|
4034
|
-
const overlaps = [];
|
|
4035
|
-
for (let i = 0; i < deep.length; i++)
|
|
4036
|
-
for (let j = i + 1; j < deep.length; j++)
|
|
4037
|
-
if (!isAny(deep[i]) && !isAny(deep[j]) && intersects2(deep[i], deep[j]))
|
|
4038
|
-
overlaps.push({
|
|
4039
|
-
a: i,
|
|
4040
|
-
b: j,
|
|
4041
|
-
on: intersection(deep[i], deep[j]),
|
|
4042
|
-
suggestion: "arms share a first char \u2014 left-factor. parseman auto-detects the sharedPrefix strategy for bare sequences (choice.ts); make the arms bare sequences with a common leading terminal, or restructure."
|
|
4043
|
-
});
|
|
4044
|
-
let gates;
|
|
4045
|
-
if (d.disjoint) gates = "yes";
|
|
4046
|
-
else if (anyArms.length === 0 && overlaps.length === 0) gates = "recoverable";
|
|
4047
|
-
else gates = "no";
|
|
4048
|
-
const deferred = gates === "no" && overlaps.length === 0 && anyArms.length > 0 && anyArms.every((a) => a.unresolvedExternal);
|
|
4049
|
-
return {
|
|
4050
|
-
rule,
|
|
4051
|
-
strategy: d.strategy?.tag ?? "firstMatch",
|
|
4052
|
-
gates,
|
|
4053
|
-
deferred,
|
|
4054
|
-
combinedFirstSet: { shallow: combine(shallow), deep: combine(deep) },
|
|
4055
|
-
anyArms,
|
|
4056
|
-
overlaps
|
|
4057
|
-
};
|
|
4058
|
-
}
|
|
4059
|
-
function formatGatingWarnings(report) {
|
|
4060
|
-
const lines = [];
|
|
4061
|
-
if (report.unanalysable.length > 0) {
|
|
4062
|
-
lines.push(
|
|
4063
|
-
`parseman gating: ${report.unanalysable.length} rule(s) UNANALYSABLE \u2014 this report is PARTIAL (${report.totalChoices} choice(s) examined). An empty finding list below does NOT mean the grammar is clean.`
|
|
4064
|
-
);
|
|
4065
|
-
for (const u of report.unanalysable)
|
|
4066
|
-
lines.push(` \xB7 ${u.rule} [${u.kind}]: ${u.reason}`);
|
|
4067
|
-
}
|
|
4068
|
-
for (const c of report.ungated) {
|
|
4069
|
-
lines.push(`parseman gating: choice @ ${c.id} is UNGATED [${c.strategy}] \u2014 no first-char dispatch; every position speculatively enters doomed arms.`);
|
|
4070
|
-
for (const a of c.anyArms)
|
|
4071
|
-
lines.push(` \xB7 arm[${a.index}] first-set ANY (${a.cause}): ${a.detail}
|
|
4072
|
-
fix: ${a.suggestion}`);
|
|
4073
|
-
for (const o of c.overlaps)
|
|
4074
|
-
lines.push(` \xB7 arm[${o.a}] \u2229 arm[${o.b}] overlap on ${firstSetToString(o.on)}
|
|
4075
|
-
fix: ${o.suggestion}`);
|
|
4076
|
-
lines.push(` (intentional? accept it in the gating snapshot: { accept: ['${c.id}'] }.)`);
|
|
4077
|
-
}
|
|
4078
|
-
for (const ap of report.antiPatterns)
|
|
4079
|
-
lines.push(`parseman anti-pattern [${ap.kind}] @ ${ap.rule} arm[${ap.armIndex}]: ${ap.message}`);
|
|
4080
|
-
return lines;
|
|
3979
|
+
function firstSetToString(fs3) {
|
|
3980
|
+
if (fs3.kind === "any") return "ANY";
|
|
3981
|
+
if (fs3.kind === "empty") return "(empty)";
|
|
3982
|
+
return fs3.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
|
|
4081
3983
|
}
|
|
4082
3984
|
|
|
4083
3985
|
// src/analysis/duplication.ts
|
|
@@ -4120,7 +4022,7 @@ function childrenOf2(d) {
|
|
|
4120
4022
|
}
|
|
4121
4023
|
}
|
|
4122
4024
|
}
|
|
4123
|
-
var
|
|
4025
|
+
var ruleNameOf2 = (p) => p._ruleName;
|
|
4124
4026
|
var fnKey = (src, fn) => src ?? (typeof fn === "function" ? String(fn) : "");
|
|
4125
4027
|
function payloadKey(p, d) {
|
|
4126
4028
|
switch (d.tag) {
|
|
@@ -4131,7 +4033,7 @@ function payloadKey(p, d) {
|
|
|
4131
4033
|
case "keywords":
|
|
4132
4034
|
return `keywords\0${[...d.words].join("")}\0${d.caseInsensitive}\0${d.boundary ?? ""}`;
|
|
4133
4035
|
case "lazy": {
|
|
4134
|
-
const n =
|
|
4036
|
+
const n = ruleNameOf2(p);
|
|
4135
4037
|
return n === void 0 ? `ref\0#${anonId(p)}` : `ref\0${n}`;
|
|
4136
4038
|
}
|
|
4137
4039
|
case "label":
|
|
@@ -4200,7 +4102,7 @@ var Interner = class {
|
|
|
4200
4102
|
var MAX_RENDER = 160;
|
|
4201
4103
|
function render(p, depth = 3) {
|
|
4202
4104
|
const d = p._def;
|
|
4203
|
-
const name =
|
|
4105
|
+
const name = ruleNameOf2(p);
|
|
4204
4106
|
switch (d.tag) {
|
|
4205
4107
|
case "literal":
|
|
4206
4108
|
return `literal('${d.value}')`;
|
|
@@ -4388,7 +4290,7 @@ function keywordAlternationHazards(words, boundary) {
|
|
|
4388
4290
|
return out;
|
|
4389
4291
|
}
|
|
4390
4292
|
function analyzeDuplication(entry, opts) {
|
|
4391
|
-
return analyzeDuplicationRules([[
|
|
4293
|
+
return analyzeDuplicationRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
4392
4294
|
}
|
|
4393
4295
|
function assertAnalyzable(ruleMap) {
|
|
4394
4296
|
for (const [name, rule] of ruleMap) {
|
|
@@ -4426,11 +4328,11 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
4426
4328
|
return n;
|
|
4427
4329
|
};
|
|
4428
4330
|
const visited = /* @__PURE__ */ new Map();
|
|
4429
|
-
const visit = (p, rule,
|
|
4331
|
+
const visit = (p, rule, path3, enclosingNode, enclosingReducer) => {
|
|
4430
4332
|
if (visited.has(p)) return;
|
|
4431
4333
|
const d = p._def;
|
|
4432
|
-
const own =
|
|
4433
|
-
const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path:
|
|
4334
|
+
const own = ruleNameOf2(p);
|
|
4335
|
+
const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path: path3 };
|
|
4434
4336
|
visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
|
|
4435
4337
|
const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
|
|
4436
4338
|
const innerReducer = enclosingReducer || d.tag === "node" && (d.build !== void 0 || d.buildSrc !== void 0) || d.tag === "transform" || d.tag === "leaf";
|
|
@@ -4442,12 +4344,12 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
4442
4344
|
if (d.tag === "lazy") {
|
|
4443
4345
|
try {
|
|
4444
4346
|
const target = d.thunk();
|
|
4445
|
-
visit(target,
|
|
4347
|
+
visit(target, ruleNameOf2(target) ?? ruleNameOf2(p) ?? here.rule, "", null, false);
|
|
4446
4348
|
} catch {
|
|
4447
4349
|
}
|
|
4448
4350
|
}
|
|
4449
4351
|
};
|
|
4450
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
4352
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name, "", null, false);
|
|
4451
4353
|
const accept = new Set(opts?.accept ?? []);
|
|
4452
4354
|
const used = /* @__PURE__ */ new Set();
|
|
4453
4355
|
const keep = (f) => {
|
|
@@ -4464,10 +4366,10 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
4464
4366
|
const divergentNodes = findDivergentNodes(visited, shapeOf);
|
|
4465
4367
|
const structureLoss = findStructureLoss(visited, opts?.resolveRef);
|
|
4466
4368
|
const keywordRegexes = findKeywordRegexes(visited);
|
|
4467
|
-
const subsume = (
|
|
4369
|
+
const subsume = (fs3) => {
|
|
4468
4370
|
const covered = /* @__PURE__ */ new Set();
|
|
4469
4371
|
const surviving = /* @__PURE__ */ new Set();
|
|
4470
|
-
for (const f of [...
|
|
4372
|
+
for (const f of [...fs3].sort((a, b) => b.savings - a.savings)) {
|
|
4471
4373
|
if (f._members.every((m) => covered.has(m))) continue;
|
|
4472
4374
|
surviving.add(f.id);
|
|
4473
4375
|
for (const m of f._members) markSubtree(m, covered);
|
|
@@ -4590,10 +4492,10 @@ function findNearDuplicates(visited, interner, shapeOf, minSize) {
|
|
|
4590
4492
|
return out.sort((a, b) => b.savings - a.savings);
|
|
4591
4493
|
}
|
|
4592
4494
|
function findDivergentSlot(members, shapeOf) {
|
|
4593
|
-
const
|
|
4495
|
+
const path3 = [];
|
|
4594
4496
|
const defs = [];
|
|
4595
4497
|
let cur = [...members];
|
|
4596
|
-
for (let
|
|
4498
|
+
for (let guard = 0; guard < 64; guard++) {
|
|
4597
4499
|
const d0 = cur[0]._def;
|
|
4598
4500
|
const kidLists = cur.map((c) => childrenOf2(c._def));
|
|
4599
4501
|
const arity = kidLists[0].length;
|
|
@@ -4605,14 +4507,14 @@ function findDivergentSlot(members, shapeOf) {
|
|
|
4605
4507
|
}
|
|
4606
4508
|
if (diff.length !== 1) break;
|
|
4607
4509
|
const i = diff[0];
|
|
4608
|
-
|
|
4510
|
+
path3.push(i);
|
|
4609
4511
|
defs.push(d0);
|
|
4610
4512
|
cur = kidLists.map((k) => k[i]);
|
|
4611
4513
|
const nextArity = childrenOf2(cur[0]._def).length;
|
|
4612
4514
|
const samePayload = cur.every((c) => payloadKey(c, c._def) === payloadKey(cur[0], cur[0]._def));
|
|
4613
4515
|
if (!samePayload || nextArity === 0) break;
|
|
4614
4516
|
}
|
|
4615
|
-
if (
|
|
4517
|
+
if (path3.length === 0) return null;
|
|
4616
4518
|
let slotSize = 0;
|
|
4617
4519
|
const sizeOf = (p) => {
|
|
4618
4520
|
let n = 1;
|
|
@@ -4620,14 +4522,14 @@ function findDivergentSlot(members, shapeOf) {
|
|
|
4620
4522
|
return n;
|
|
4621
4523
|
};
|
|
4622
4524
|
for (const c of cur) slotSize = Math.max(slotSize, sizeOf(c));
|
|
4623
|
-
return { path:
|
|
4525
|
+
return { path: path3, defs, variants: cur, slotSize };
|
|
4624
4526
|
}
|
|
4625
|
-
function renderWithHole(p,
|
|
4626
|
-
if (depth ===
|
|
4527
|
+
function renderWithHole(p, path3, depth = 0) {
|
|
4528
|
+
if (depth === path3.length) return "\u2039slot\u203A";
|
|
4627
4529
|
const d = p._def;
|
|
4628
4530
|
const kids = childrenOf2(d);
|
|
4629
|
-
const idx =
|
|
4630
|
-
const parts = kids.map((k, i) => i === idx ? renderWithHole(k,
|
|
4531
|
+
const idx = path3[depth];
|
|
4532
|
+
const parts = kids.map((k, i) => i === idx ? renderWithHole(k, path3, depth + 1) : render(k, 2));
|
|
4631
4533
|
switch (d.tag) {
|
|
4632
4534
|
case "sequence":
|
|
4633
4535
|
return `sequence(${parts.join(", ")})`;
|
|
@@ -4831,13 +4733,13 @@ function findRegexClasses(visited) {
|
|
|
4831
4733
|
}
|
|
4832
4734
|
return out.sort((a, b) => Number(b.drifted) - Number(a.drifted) || b.count - a.count);
|
|
4833
4735
|
}
|
|
4834
|
-
function
|
|
4736
|
+
function intersects2(a, b) {
|
|
4835
4737
|
if (a.kind === "any" || b.kind === "any") return true;
|
|
4836
4738
|
if (a.kind === "empty" || b.kind === "empty") return false;
|
|
4837
4739
|
for (const ra of a.ranges) for (const rb of b.ranges) if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
|
|
4838
4740
|
return false;
|
|
4839
4741
|
}
|
|
4840
|
-
function
|
|
4742
|
+
function intersection(a, b) {
|
|
4841
4743
|
if (a.kind === "any") return b;
|
|
4842
4744
|
if (b.kind === "any") return a;
|
|
4843
4745
|
if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
|
|
@@ -4866,19 +4768,19 @@ function leadingRegex(arm) {
|
|
|
4866
4768
|
const t = termsOf(arm)[0];
|
|
4867
4769
|
return t !== void 0 && t._def.tag === "regex";
|
|
4868
4770
|
}
|
|
4869
|
-
function findOverlaps(visited, shapeOf,
|
|
4771
|
+
function findOverlaps(visited, shapeOf, resolve3) {
|
|
4870
4772
|
const out = [];
|
|
4871
4773
|
for (const v2 of visited.values()) {
|
|
4872
4774
|
const d = v2.d;
|
|
4873
4775
|
if (d.tag !== "choice") continue;
|
|
4874
4776
|
const arms = d.parsers;
|
|
4875
|
-
const
|
|
4777
|
+
const fs3 = arms.map((a) => firstSetOf(a, /* @__PURE__ */ new Set(), resolve3));
|
|
4876
4778
|
const strategy = d.strategy;
|
|
4877
4779
|
for (let i = 0; i < arms.length; i++) {
|
|
4878
4780
|
for (let j = i + 1; j < arms.length; j++) {
|
|
4879
|
-
const A =
|
|
4781
|
+
const A = fs3[i], B = fs3[j];
|
|
4880
4782
|
if (A.kind === "any" || B.kind === "any") continue;
|
|
4881
|
-
if (!
|
|
4783
|
+
if (!intersects2(A, B)) continue;
|
|
4882
4784
|
const ta = termsOf(arms[i]), tb = termsOf(arms[j]);
|
|
4883
4785
|
let shared = 0;
|
|
4884
4786
|
while (shared < ta.length && shared < tb.length && shapeOf(ta[shared]) === shapeOf(tb[shared])) shared++;
|
|
@@ -4890,7 +4792,7 @@ function findOverlaps(visited, shapeOf, resolve2) {
|
|
|
4890
4792
|
site: v2.site,
|
|
4891
4793
|
a: i,
|
|
4892
4794
|
b: j,
|
|
4893
|
-
on:
|
|
4795
|
+
on: intersection(A, B),
|
|
4894
4796
|
sharedLeadingTerms: shared,
|
|
4895
4797
|
sharedPrefix: shared > 0 ? clamp(ta.slice(0, shared).map((t) => render(t, 2)).join(", ")) : null,
|
|
4896
4798
|
handledByStrategy: handled,
|
|
@@ -5192,7 +5094,7 @@ function nestedNodeTypes(root, out, seen, isRoot) {
|
|
|
5192
5094
|
for (const k of childrenOf2(d)) nestedNodeTypes(k, out, seen, false);
|
|
5193
5095
|
}
|
|
5194
5096
|
var MAX_LOST_TYPES = 8;
|
|
5195
|
-
function findStructureLoss(visited,
|
|
5097
|
+
function findStructureLoss(visited, resolve3) {
|
|
5196
5098
|
const nestedCache = /* @__PURE__ */ new Map();
|
|
5197
5099
|
const nested = (p) => {
|
|
5198
5100
|
const hit = nestedCache.get(p);
|
|
@@ -5209,18 +5111,18 @@ function findStructureLoss(visited, resolve2) {
|
|
|
5209
5111
|
const arms = d.parsers;
|
|
5210
5112
|
const resolved = arms.map(resolveArm);
|
|
5211
5113
|
const nodeTypes = resolved.map(wrappingNodeType);
|
|
5212
|
-
const
|
|
5114
|
+
const fs3 = arms.map((a) => firstSetOf(a, /* @__PURE__ */ new Set(), resolve3));
|
|
5213
5115
|
for (let i = 0; i < arms.length; i++) {
|
|
5214
5116
|
if (d.gates[i] != null) continue;
|
|
5215
5117
|
const type = nodeTypes[i] ?? null;
|
|
5216
5118
|
if (type === null) continue;
|
|
5217
5119
|
if (nested(resolved[i]).size !== 0) continue;
|
|
5218
|
-
const A =
|
|
5120
|
+
const A = fs3[i];
|
|
5219
5121
|
if (A.kind === "any") continue;
|
|
5220
5122
|
for (let j = i + 1; j < arms.length; j++) {
|
|
5221
5123
|
if (nodeTypes[j] !== type) continue;
|
|
5222
|
-
const B =
|
|
5223
|
-
if (B.kind === "any" || !
|
|
5124
|
+
const B = fs3[j];
|
|
5125
|
+
if (B.kind === "any" || !intersects2(A, B)) continue;
|
|
5224
5126
|
const lost = nested(resolved[j]);
|
|
5225
5127
|
if (lost.size === 0) continue;
|
|
5226
5128
|
const lostNodeTypes = [...lost].sort();
|
|
@@ -5231,7 +5133,7 @@ function findStructureLoss(visited, resolve2) {
|
|
|
5231
5133
|
nodeType: type,
|
|
5232
5134
|
earlier: i,
|
|
5233
5135
|
later: j,
|
|
5234
|
-
on:
|
|
5136
|
+
on: intersection(A, B),
|
|
5235
5137
|
lostNodeTypes: lostNodeTypes.slice(0, MAX_LOST_TYPES),
|
|
5236
5138
|
earlierShape: clamp(render(resolved[i], 3)),
|
|
5237
5139
|
laterShape: clamp(render(resolved[j], 3)),
|
|
@@ -5489,11 +5391,11 @@ function buildBalancedInterior(open, close, skips) {
|
|
|
5489
5391
|
return combi;
|
|
5490
5392
|
}
|
|
5491
5393
|
function firstSetClassChars(c) {
|
|
5492
|
-
const
|
|
5493
|
-
if (
|
|
5494
|
-
if (
|
|
5394
|
+
const fs3 = c._meta.firstSet;
|
|
5395
|
+
if (fs3.kind === "empty") return [];
|
|
5396
|
+
if (fs3.kind !== "ranges") return null;
|
|
5495
5397
|
const out = [];
|
|
5496
|
-
for (const { lo, hi } of
|
|
5398
|
+
for (const { lo, hi } of fs3.ranges) {
|
|
5497
5399
|
if (hi - lo > 8) return null;
|
|
5498
5400
|
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
5499
5401
|
}
|
|
@@ -5507,13 +5409,13 @@ function escapeClassChar(ch2) {
|
|
|
5507
5409
|
function idPart(value) {
|
|
5508
5410
|
return encodeURIComponent(value);
|
|
5509
5411
|
}
|
|
5510
|
-
function dispatchArmIds(def,
|
|
5412
|
+
function dispatchArmIds(def, path3) {
|
|
5511
5413
|
const ids = [];
|
|
5512
|
-
for (const entry of def.cases) ids.push(`dispatch:${
|
|
5414
|
+
for (const entry of def.cases) ids.push(`dispatch:${path3}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5513
5415
|
for (const entry of def.matchers ?? []) {
|
|
5514
|
-
ids.push(`dispatch:${
|
|
5416
|
+
ids.push(`dispatch:${path3}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5515
5417
|
}
|
|
5516
|
-
if (def.otherwise) ids.push(`dispatch:${
|
|
5418
|
+
if (def.otherwise) ids.push(`dispatch:${path3}/otherwise`);
|
|
5517
5419
|
return ids;
|
|
5518
5420
|
}
|
|
5519
5421
|
function children(def, winners) {
|
|
@@ -5552,7 +5454,15 @@ function children(def, winners) {
|
|
|
5552
5454
|
let resolved;
|
|
5553
5455
|
try {
|
|
5554
5456
|
resolved = def.thunk();
|
|
5555
|
-
} catch {
|
|
5457
|
+
} catch (e) {
|
|
5458
|
+
recordDegradation({
|
|
5459
|
+
code: "coverage-definitions-unavailable",
|
|
5460
|
+
severity: "warn",
|
|
5461
|
+
where: "<lazy rule reference>",
|
|
5462
|
+
subject: `unresolvable reference (${e.message})`,
|
|
5463
|
+
fellBackTo: "the coverage walk stopped at this reference, so every definition below it is ABSENT from the denominator \u2014 which raises the reported ratio rather than lowering it",
|
|
5464
|
+
otherwise: "the referenced rule and its whole subtree would contribute definitions"
|
|
5465
|
+
});
|
|
5556
5466
|
return [];
|
|
5557
5467
|
}
|
|
5558
5468
|
const name = resolved._ruleName;
|
|
@@ -5582,7 +5492,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5582
5492
|
}
|
|
5583
5493
|
}
|
|
5584
5494
|
const seen = /* @__PURE__ */ new Set();
|
|
5585
|
-
const visit = (parser2,
|
|
5495
|
+
const visit = (parser2, path3) => {
|
|
5586
5496
|
if (seen.has(parser2)) return;
|
|
5587
5497
|
seen.add(parser2);
|
|
5588
5498
|
const rule = winnerNames.get(parser2) ?? parser2._ruleName;
|
|
@@ -5592,22 +5502,22 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5592
5502
|
rules2.set(parser2, id);
|
|
5593
5503
|
}
|
|
5594
5504
|
if (parser2._def.tag === "choice") {
|
|
5595
|
-
const ids = parser2._def.parsers.map((_, index) => `choice:${
|
|
5505
|
+
const ids = parser2._def.parsers.map((_, index) => `choice:${path3}/arm:${index}`);
|
|
5596
5506
|
choices.set(parser2, ids);
|
|
5597
5507
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
5598
5508
|
}
|
|
5599
5509
|
if (parser2._def.tag === "dispatch") {
|
|
5600
|
-
const ids = dispatchArmIds(parser2._def,
|
|
5510
|
+
const ids = dispatchArmIds(parser2._def, path3);
|
|
5601
5511
|
dispatches.set(parser2, ids);
|
|
5602
5512
|
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5603
5513
|
}
|
|
5604
|
-
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${
|
|
5514
|
+
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path3}`);
|
|
5605
5515
|
if (parser2._def.tag === "label") {
|
|
5606
|
-
const id = `label:${
|
|
5516
|
+
const id = `label:${path3}`;
|
|
5607
5517
|
labels.set(parser2, [id]);
|
|
5608
5518
|
definitions.set(id, { id, kind: "label" });
|
|
5609
5519
|
}
|
|
5610
|
-
children(parser2._def, winners).forEach((child, index) => visit(child, `${
|
|
5520
|
+
children(parser2._def, winners).forEach((child, index) => visit(child, `${path3}/${parser2._def.tag}:${index}`));
|
|
5611
5521
|
};
|
|
5612
5522
|
const roots = Array.isArray(entry) ? entry : [entry];
|
|
5613
5523
|
for (const root of roots) {
|
|
@@ -6379,10 +6289,10 @@ var ALT_SWITCH_MIN_CASES = 3;
|
|
|
6379
6289
|
function planAltSwitch(firsts) {
|
|
6380
6290
|
const cases = [];
|
|
6381
6291
|
let total = 0;
|
|
6382
|
-
for (const
|
|
6383
|
-
if (!
|
|
6292
|
+
for (const fs3 of firsts) {
|
|
6293
|
+
if (!fs3 || fs3.negated) return { kind: "if" };
|
|
6384
6294
|
const pts = [];
|
|
6385
|
-
for (const [lo, hi] of
|
|
6295
|
+
for (const [lo, hi] of fs3.ranges) {
|
|
6386
6296
|
if (hi - lo + 1 > ALT_SWITCH_RANGE_LIMIT) return { kind: "if" };
|
|
6387
6297
|
for (let cp = lo; cp <= hi; cp++) pts.push(cp);
|
|
6388
6298
|
}
|
|
@@ -6457,8 +6367,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
6457
6367
|
} else {
|
|
6458
6368
|
const c0 = codeAt(start, firstChar);
|
|
6459
6369
|
shape.arms.forEach((arm, k) => {
|
|
6460
|
-
const
|
|
6461
|
-
const cond =
|
|
6370
|
+
const fs3 = shape.firsts[k];
|
|
6371
|
+
const cond = fs3.negated ? `!(${classCond(c0, fs3.ranges)})` : `(${classCond(c0, fs3.ranges)})`;
|
|
6462
6372
|
const m = emitShapeMatch(arm, start, mint, `${ind2} `, firstChar);
|
|
6463
6373
|
lines.push(`${ind2}${k === 0 ? "if" : "else if"} (${start} < input.length && ${cond}) {`);
|
|
6464
6374
|
lines.push(...m.setup);
|
|
@@ -6875,27 +6785,53 @@ function emitScannableTerminal(shape, c) {
|
|
|
6875
6785
|
}
|
|
6876
6786
|
|
|
6877
6787
|
// src/compiler/inline-build.ts
|
|
6878
|
-
var
|
|
6788
|
+
var ANN = String.raw`\s*\??\s*(?::[^,)=]+)?`;
|
|
6789
|
+
var ANY_P = String.raw`\w+${ANN}`;
|
|
6790
|
+
var MK_BUILD_RE = new RegExp(
|
|
6791
|
+
String.raw`^\(\s*(\w+)${ANN}\s*,\s*${ANY_P}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*\)\s*=>\s*mk\s*\(\s*(['"])([^'"]+)\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
6792
|
+
);
|
|
6879
6793
|
function escapeRegExp(s) {
|
|
6880
6794
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6881
6795
|
}
|
|
6796
|
+
function identMkBuildRe(typeIdent) {
|
|
6797
|
+
return new RegExp(
|
|
6798
|
+
String.raw`^\(\s*(\w+)${ANN}\s*,\s*${ANY_P}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*\)\s*=>\s*(?:[\w$.]*\.)?mk\s*\(\s*${escapeRegExp(typeIdent)}\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
6799
|
+
);
|
|
6800
|
+
}
|
|
6882
6801
|
function looseMkBuildRe(type) {
|
|
6883
6802
|
return new RegExp(
|
|
6884
|
-
String.raw`^\(\s*(\w+)\s*,\s
|
|
6803
|
+
String.raw`^\(\s*(\w+)${ANN}\s*,\s*${ANY_P}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*\)\s*=>\s*.+\(\s*(['"])${escapeRegExp(type)}\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
6885
6804
|
);
|
|
6886
6805
|
}
|
|
6806
|
+
var LOOKS_LIKE_MK_RE = /=>\s*(?:[\w$.]*\.)?mk\s*\(/;
|
|
6887
6807
|
function analyzeMkInlineBuild(def) {
|
|
6888
6808
|
if (!def.build) return null;
|
|
6889
6809
|
if (def.type === void 0) return null;
|
|
6890
|
-
const src = (def
|
|
6810
|
+
const src = buildAnalysisSrc(def).trim();
|
|
6891
6811
|
const strict = src.match(MK_BUILD_RE);
|
|
6892
6812
|
if (strict) {
|
|
6893
6813
|
const mkType = strict[6];
|
|
6894
|
-
|
|
6814
|
+
if (mkType === def.type) return def.type;
|
|
6815
|
+
reportMkMiss(def.type, src, `it builds a "${mkType}" node, not "${def.type}"`);
|
|
6816
|
+
return null;
|
|
6895
6817
|
}
|
|
6896
6818
|
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
6819
|
+
if (def.typeSrc !== void 0 && identMkBuildRe(def.typeSrc).test(src)) return def.type;
|
|
6820
|
+
if (LOOKS_LIKE_MK_RE.test(src)) {
|
|
6821
|
+
reportMkMiss(def.type, src, "its parameter list or argument order does not match `(children, fields, span, rawChildren, triviaLog) => mk(type, children, rawChildren, span, triviaLog)`");
|
|
6822
|
+
}
|
|
6897
6823
|
return null;
|
|
6898
6824
|
}
|
|
6825
|
+
function reportMkMiss(type, src, why) {
|
|
6826
|
+
recordDegradation({
|
|
6827
|
+
code: "mk-inline-missed",
|
|
6828
|
+
severity: "warn",
|
|
6829
|
+
where: `node("${type}")`,
|
|
6830
|
+
subject: `build reducer \`${src.split("\n")[0].slice(0, 80)}\``,
|
|
6831
|
+
fellBackTo: `looks like an inline-\`mk\` builder but ${why}, so every match pays a \`_build[n](...)\` call instead of an inlined object literal`,
|
|
6832
|
+
otherwise: "the node object would be constructed at the call site with no call frame"
|
|
6833
|
+
});
|
|
6834
|
+
}
|
|
6899
6835
|
function emitInlineMkNodeExpr(type, chV, rawV, spanExpr, tlV) {
|
|
6900
6836
|
return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: ${spanExpr}, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
|
|
6901
6837
|
}
|
|
@@ -7078,7 +7014,30 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
7078
7014
|
seen.delete(p);
|
|
7079
7015
|
}
|
|
7080
7016
|
}
|
|
7017
|
+
function tern(cond, whenTrue, whenFalse) {
|
|
7018
|
+
if (cond === "false") return whenFalse;
|
|
7019
|
+
if (cond === "true") return whenTrue;
|
|
7020
|
+
return `${cond} ? ${whenTrue} : ${whenFalse}`;
|
|
7021
|
+
}
|
|
7022
|
+
function notGate(cond) {
|
|
7023
|
+
if (cond === "false") return "true";
|
|
7024
|
+
if (cond === "true") return "false";
|
|
7025
|
+
return `!(${cond})`;
|
|
7026
|
+
}
|
|
7027
|
+
function orGate(a, b) {
|
|
7028
|
+
if (a === "false") return b;
|
|
7029
|
+
if (b === "false") return a;
|
|
7030
|
+
if (a === "true" || b === "true") return "true";
|
|
7031
|
+
return `${a} || ${b}`;
|
|
7032
|
+
}
|
|
7033
|
+
function andGate(a, b) {
|
|
7034
|
+
if (a === "false" || b === "false") return "false";
|
|
7035
|
+
if (a === "true") return b;
|
|
7036
|
+
if (b === "true") return a;
|
|
7037
|
+
return `${a} && ${b}`;
|
|
7038
|
+
}
|
|
7081
7039
|
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 }";
|
|
7040
|
+
var RAW_ENTRY_DECL = "const _rawEntry = (v, input, s, e, span) => (typeof v === 'object' && v !== null && (v._tag === 'node' || v._tag === 'leaf' || v._tag === 'parseError')) ? v : { _tag: 'leaf', value: typeof v === 'string' ? v : (typeof v === 'object' && v !== null ? input.slice(s, e) : ''), span: span ?? { start: s, end: e } }";
|
|
7082
7041
|
var LINE_TRACK_DECL = "const _trackLines = (_ctx, input, start, end) => { const from = _ctx._lineScannedTo ?? 0; if (end <= from) return; for (let i = from; i < end; i++) if (input.charCodeAt(i) === 10) _ctx._lineStarts.push(i + 1); _ctx._lineScannedTo = end }";
|
|
7083
7042
|
var LINE_SPAN_DECL = "const _lineCol = (_ctx, offset) => { const starts = _ctx._lineStarts; let lo = 0, hi = starts.length - 1; while (lo < hi) { const mid = (lo + hi + 1) >> 1; if (starts[mid] <= offset) lo = mid; else hi = mid - 1 } return [lo + 1, offset - starts[lo] + 1] }\nconst _spanLines = (_ctx, start, end) => { const s = _lineCol(_ctx, start), e = _lineCol(_ctx, end); return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] } }";
|
|
7084
7043
|
var _loweringSink = null;
|
|
@@ -7090,6 +7049,27 @@ function endLoweringCapture() {
|
|
|
7090
7049
|
_loweringSink = null;
|
|
7091
7050
|
return misses;
|
|
7092
7051
|
}
|
|
7052
|
+
var _inlineCapSink = null;
|
|
7053
|
+
function beginInlineCapCapture() {
|
|
7054
|
+
_inlineCapSink = [];
|
|
7055
|
+
}
|
|
7056
|
+
function endInlineCapCapture() {
|
|
7057
|
+
const sites = _inlineCapSink ?? [];
|
|
7058
|
+
_inlineCapSink = null;
|
|
7059
|
+
return sites;
|
|
7060
|
+
}
|
|
7061
|
+
function formatInlineCapSites(sites, max) {
|
|
7062
|
+
if (sites.length === 0) return [];
|
|
7063
|
+
const byFn = /* @__PURE__ */ new Map();
|
|
7064
|
+
for (const s of sites) {
|
|
7065
|
+
const cur = byFn.get(s.fn);
|
|
7066
|
+
if (cur) {
|
|
7067
|
+
cur.count += 1;
|
|
7068
|
+
cur.nodes += s.nodes;
|
|
7069
|
+
} else byFn.set(s.fn, { count: 1, nodes: s.nodes });
|
|
7070
|
+
}
|
|
7071
|
+
return [...byFn].map(([fn, { count, nodes }]) => `[parseman] inline-cap ${fn}: inline budget of ${max} node(s) spent \u2014 ${count} single-use ref(s) totalling ~${nodes} node(s) became called functions instead of inline bodies. Raise it with maxInline (or PARSEMAN_MAX_INLINE) if this rule is hot.`);
|
|
7072
|
+
}
|
|
7093
7073
|
function hasSelectedRootTrivia(ctx) {
|
|
7094
7074
|
return ctx.rootTriviaClassified === true;
|
|
7095
7075
|
}
|
|
@@ -7373,10 +7353,10 @@ function ensureTriviaFn(ctx) {
|
|
|
7373
7353
|
function ensureTriviaCaptureFn(ctx) {
|
|
7374
7354
|
return ensureTriviaFn(ctx);
|
|
7375
7355
|
}
|
|
7376
|
-
function firstSetCond(codeVar,
|
|
7377
|
-
if (
|
|
7378
|
-
if (
|
|
7379
|
-
return
|
|
7356
|
+
function firstSetCond(codeVar, fs3) {
|
|
7357
|
+
if (fs3.kind === "any") return "true";
|
|
7358
|
+
if (fs3.kind === "empty") return "false";
|
|
7359
|
+
return fs3.ranges.map(
|
|
7380
7360
|
(r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
|
|
7381
7361
|
).join(" || ");
|
|
7382
7362
|
}
|
|
@@ -7389,10 +7369,10 @@ function planDisjointDispatch(parsers) {
|
|
|
7389
7369
|
const cases = [];
|
|
7390
7370
|
let total = 0;
|
|
7391
7371
|
for (const p of parsers) {
|
|
7392
|
-
const
|
|
7393
|
-
if (
|
|
7372
|
+
const fs3 = p._meta.firstSet;
|
|
7373
|
+
if (fs3.kind !== "ranges") return { kind: "if" };
|
|
7394
7374
|
const pts = [];
|
|
7395
|
-
for (const r of
|
|
7375
|
+
for (const r of fs3.ranges) {
|
|
7396
7376
|
if (r.hi - r.lo + 1 > SWITCH_RANGE_LIMIT) return { kind: "if" };
|
|
7397
7377
|
for (let cp = r.lo; cp <= r.hi; cp++) pts.push(cp);
|
|
7398
7378
|
}
|
|
@@ -7785,9 +7765,9 @@ function emitRegex(def, ctx, pos, canMatchNewline = true) {
|
|
|
7785
7765
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
7786
7766
|
return { stmts, valueVar: vv, endVar };
|
|
7787
7767
|
}
|
|
7788
|
-
function syncSentinelExpr(
|
|
7789
|
-
if (
|
|
7790
|
-
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(
|
|
7768
|
+
function syncSentinelExpr(fs3) {
|
|
7769
|
+
if (fs3.kind !== "ranges" || fs3.ranges.length === 0) return null;
|
|
7770
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs3.ranges)} })`;
|
|
7791
7771
|
}
|
|
7792
7772
|
function emitSeqValues(def, ctx, pos) {
|
|
7793
7773
|
const startV = v(ctx, "_start");
|
|
@@ -7801,8 +7781,8 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
7801
7781
|
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
7802
7782
|
const publishSync = (i) => {
|
|
7803
7783
|
if (!ctx.recovery) return "";
|
|
7804
|
-
const
|
|
7805
|
-
const ref2 = syncSentinelExpr(
|
|
7784
|
+
const fs3 = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
7785
|
+
const ref2 = syncSentinelExpr(fs3);
|
|
7806
7786
|
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
7807
7787
|
};
|
|
7808
7788
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
@@ -7838,9 +7818,11 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
7838
7818
|
const markLog = v(ctx, "_mklg");
|
|
7839
7819
|
const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
|
|
7840
7820
|
const scanEndV = v(ctx, "_sne");
|
|
7841
|
-
const
|
|
7821
|
+
const logV = v(ctx, "_tlg");
|
|
7822
|
+
const capArg = ctx.noHoist ? "0" : hasSelectedRootTrivia(ctx) ? `(${logV} !== undefined || _ctx._rootTriviaLog !== undefined) ? 2 : 0` : `${logV} !== undefined ? 2 : 0`;
|
|
7842
7823
|
stmts.push(
|
|
7843
|
-
`${ind(ctx)}const ${
|
|
7824
|
+
`${ind(ctx)}const ${logV} = _ctx._triviaLog`,
|
|
7825
|
+
`${ind(ctx)}const ${markLog} = ${logV} !== undefined ? ${logV}.length : 0`,
|
|
7844
7826
|
...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
|
|
7845
7827
|
`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
|
|
7846
7828
|
...emitLineTrack(ctx, curV, scanEndV)
|
|
@@ -7850,7 +7832,7 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
7850
7832
|
const endAfterV = v(ctx, "_sea");
|
|
7851
7833
|
stmts.push(
|
|
7852
7834
|
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
7853
|
-
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else { if (
|
|
7835
|
+
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else { if (${logV} !== undefined && ${logV}.length !== ${markLog}) ${logV}.length = ${markLog};${markRootLog ? ` if (_ctx._rootTriviaLog && _ctx._rootTriviaLog.length !== ${markRootLog}) _ctx._rootTriviaLog.length = ${markRootLog};` : ""} }`
|
|
7854
7836
|
);
|
|
7855
7837
|
valueVars.push(r2.valueVar);
|
|
7856
7838
|
continue;
|
|
@@ -7916,8 +7898,8 @@ function canMatchEmptyAtStart(p) {
|
|
|
7916
7898
|
}
|
|
7917
7899
|
}
|
|
7918
7900
|
function needsFirstSetGuard(p) {
|
|
7919
|
-
const
|
|
7920
|
-
return
|
|
7901
|
+
const fs3 = p._meta.firstSet;
|
|
7902
|
+
return fs3.kind !== "any" && !canMatchEmptyAtStart(p);
|
|
7921
7903
|
}
|
|
7922
7904
|
function coverageHit(ctx, id, offset = "_pos", end) {
|
|
7923
7905
|
return id === void 0 ? [] : [
|
|
@@ -8922,9 +8904,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
8922
8904
|
endVar: pos
|
|
8923
8905
|
};
|
|
8924
8906
|
}
|
|
8925
|
-
function emitRouted(ctx, pos) {
|
|
8907
|
+
function emitRouted(ctx, pos, def) {
|
|
8926
8908
|
const local = ctx.routedLocal;
|
|
8909
|
+
const fallback = def.fallback;
|
|
8927
8910
|
if (local !== void 0) {
|
|
8911
|
+
if (fallback !== void 0 && local.startVar !== pos) {
|
|
8912
|
+
return emitRoutedWithFallback(ctx, pos, fallback, {
|
|
8913
|
+
test: `${local.startVar} === ${pos}`,
|
|
8914
|
+
valExpr: local.valueVar,
|
|
8915
|
+
startExpr: local.startVar,
|
|
8916
|
+
endExpr: local.endVar
|
|
8917
|
+
});
|
|
8918
|
+
}
|
|
8928
8919
|
return {
|
|
8929
8920
|
stmts: [
|
|
8930
8921
|
...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
@@ -8935,9 +8926,19 @@ function emitRouted(ctx, pos) {
|
|
|
8935
8926
|
};
|
|
8936
8927
|
}
|
|
8937
8928
|
const item = v(ctx, "_rt");
|
|
8929
|
+
const read = `${ind(ctx)}const ${item} = _ctx._routed`;
|
|
8930
|
+
if (fallback !== void 0) {
|
|
8931
|
+
const r = emitRoutedWithFallback(ctx, pos, fallback, {
|
|
8932
|
+
test: `${item} !== undefined && ${item}.span.start === ${pos}`,
|
|
8933
|
+
valExpr: `${item}.value`,
|
|
8934
|
+
startExpr: `${item}.span.start`,
|
|
8935
|
+
endExpr: `${item}.span.end`
|
|
8936
|
+
});
|
|
8937
|
+
return { ...r, stmts: [read, ...r.stmts] };
|
|
8938
|
+
}
|
|
8938
8939
|
return {
|
|
8939
8940
|
stmts: [
|
|
8940
|
-
|
|
8941
|
+
read,
|
|
8941
8942
|
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8942
8943
|
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8943
8944
|
],
|
|
@@ -8945,6 +8946,30 @@ function emitRouted(ctx, pos) {
|
|
|
8945
8946
|
endVar: `${item}.span.end`
|
|
8946
8947
|
};
|
|
8947
8948
|
}
|
|
8949
|
+
function emitRoutedWithFallback(ctx, pos, fallback, routed2) {
|
|
8950
|
+
const valV = v(ctx, "_rtv");
|
|
8951
|
+
const endV = v(ctx, "_rte");
|
|
8952
|
+
const i = ind(ctx);
|
|
8953
|
+
ctx.indent++;
|
|
8954
|
+
const capture = emitLeafCapture(ctx, routed2.valExpr, routed2.startExpr, routed2.endExpr);
|
|
8955
|
+
const fb = emit(fallback, ctx, pos);
|
|
8956
|
+
const inner = ind(ctx);
|
|
8957
|
+
ctx.indent--;
|
|
8958
|
+
return {
|
|
8959
|
+
stmts: [
|
|
8960
|
+
`${i}let ${valV}, ${endV}`,
|
|
8961
|
+
`${i}if (${routed2.test}) {`,
|
|
8962
|
+
...capture,
|
|
8963
|
+
`${inner}${valV} = ${routed2.valExpr}; ${endV} = ${routed2.endExpr}`,
|
|
8964
|
+
`${i}} else {`,
|
|
8965
|
+
...fb.stmts,
|
|
8966
|
+
`${inner}${valV} = ${fb.valueVar}; ${endV} = ${fb.endVar}`,
|
|
8967
|
+
`${i}}`
|
|
8968
|
+
],
|
|
8969
|
+
valueVar: valV,
|
|
8970
|
+
endVar: endV
|
|
8971
|
+
};
|
|
8972
|
+
}
|
|
8948
8973
|
function escapeTokenLiteral(value) {
|
|
8949
8974
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
8950
8975
|
}
|
|
@@ -9126,22 +9151,16 @@ function emitNode(def, ctx, pos) {
|
|
|
9126
9151
|
const smk = structural ? v(ctx, "_smk") : null;
|
|
9127
9152
|
if (structural) ctx.needsHostReads = true;
|
|
9128
9153
|
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
9129
|
-
const
|
|
9130
|
-
const
|
|
9131
|
-
const profileRecognizer = recV;
|
|
9132
|
-
const profileCapture = capV;
|
|
9133
|
-
const cstMode = ctx.hostMode === "cst";
|
|
9134
|
-
const directCstV = !structural && !cstMode && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
9135
|
-
const directCstGate = directCstV === null ? "false" : profileCapture;
|
|
9154
|
+
const profileRecognizer = "false";
|
|
9155
|
+
const profileCapture = "false";
|
|
9136
9156
|
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
9137
9157
|
const chNeededExpr = def.unwrap || def.collapse ? "true" : `(_ctx._pmReadsCh ??= (_ctx.build === undefined || _ctx.build._parsemanReadsChildren !== false || _ctx.build._parsemanCstCollapse !== undefined))`;
|
|
9138
|
-
const chAlloc = def.unwrap || def.collapse ?
|
|
9139
|
-
const
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
|
|
9158
|
+
const chAlloc = def.unwrap || def.collapse ? tern(profileRecognizer, "undefined", "[]") : tern(profileRecognizer, "undefined", `${tern(orGate(profileCapture, chNeededExpr), "[]", "undefined")}`);
|
|
9159
|
+
const dcstAlloc = "undefined";
|
|
9160
|
+
const allocStmt = structural ? `${i}const ${capTLv} = ${andGate(notGate(profileRecognizer), orGate(profileCapture, structuralCapturesTrivia ? "true" : hostTriviaGate))}, ${capSTv} = ${andGate(notGate(orGate(profileRecognizer, profileCapture)), "(_ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6)))")}${capFv ? `, ${capFv} = ${andGate(notGate(profileRecognizer), orGate(profileCapture, "(_ctx.build !== undefined && _hostReads(_ctx.build, 2))"))}` : ""}
|
|
9161
|
+
${i}const ${chV} = ${chAlloc}, ${rawV} = ${tern(profileRecognizer, "undefined", "[]")}, ${tlV} = ${tern(profileRecognizer, "undefined", innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`)}` : capturesTrivia ? `${i}const ${capTLv} = ${notGate(profileRecognizer)}, ${chV} = ${tern(profileRecognizer, "undefined", capturesChildren ? "[]" : dcstAlloc)}, ${rawV} = ${tern(profileRecognizer, "undefined", capturesRaw ? "[]" : dcstAlloc)}, ${tlV} = ${tern(profileRecognizer, "undefined", "[]")}` : `${i}const ${chV} = ${tern(profileRecognizer, "undefined", capturesChildren ? "[]" : dcstAlloc)}, ${rawV} = ${tern(profileRecognizer, "undefined", capturesRaw ? "[]" : dcstAlloc)}`;
|
|
9143
9162
|
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
9144
|
-
const fieldsOn = structural ? capFv ?? "false" :
|
|
9163
|
+
const fieldsOn = structural ? capFv ?? "false" : tern(profileRecognizer, "false", capturesFields ? "true" : "false");
|
|
9145
9164
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
9146
9165
|
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
9147
9166
|
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
@@ -9150,7 +9169,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9150
9169
|
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}` : ""}` : "";
|
|
9151
9170
|
const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
|
|
9152
9171
|
const preGuard = [];
|
|
9153
|
-
if (!ctx.recovery && !ctx.coverage &&
|
|
9172
|
+
if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
|
|
9154
9173
|
const gcV = v(ctx, "_ngc");
|
|
9155
9174
|
const gExp = armStaticExpected(ctx, def.parser);
|
|
9156
9175
|
const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(ctx, gExp, pos);
|
|
@@ -9161,7 +9180,6 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9161
9180
|
}
|
|
9162
9181
|
const stmts = [
|
|
9163
9182
|
...preGuard,
|
|
9164
|
-
profHoist,
|
|
9165
9183
|
allocStmt,
|
|
9166
9184
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
9167
9185
|
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}${installTrivia}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
@@ -9178,21 +9196,13 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9178
9196
|
}
|
|
9179
9197
|
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}${restoreTrivia}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
9180
9198
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
9181
|
-
stmts.push(
|
|
9182
|
-
`${i}if (_ctx._pmProfile) {`,
|
|
9183
|
-
`${i} _ctx._pmProfile.nodes++`,
|
|
9184
|
-
`${i} if (${profileCapture}) {`,
|
|
9185
|
-
`${i} _ctx._pmProfile.childSlots += ${chV}.length; _ctx._pmProfile.rawSlots += ${rawV}.length; _ctx._pmProfile.triviaSlots += ${tlV}.length${fArr ? `; _ctx._pmProfile.fieldSlots += ${fArr} ? ${fArr}.length : 0` : ""}`,
|
|
9186
|
-
`${i} }`,
|
|
9187
|
-
`${i}}`
|
|
9188
|
-
);
|
|
9189
9199
|
let stV = "undefined";
|
|
9190
9200
|
if (structural) {
|
|
9191
9201
|
stV = v(ctx, "_nst");
|
|
9192
9202
|
stmts.push(`${i}const ${stV} = ${capSTv} && _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
9193
9203
|
} else if (clonesState) {
|
|
9194
9204
|
stV = v(ctx, "_nst");
|
|
9195
|
-
stmts.push(`${i}const ${stV} =
|
|
9205
|
+
stmts.push(`${i}const ${stV} = ${andGate(notGate(orGate(profileRecognizer, profileCapture)), "_ctx.state !== undefined")} ? Object.assign({}, _ctx.state) : undefined`);
|
|
9196
9206
|
}
|
|
9197
9207
|
if (sf && fArr) {
|
|
9198
9208
|
const fe = v(ctx, "_fe");
|
|
@@ -9216,19 +9226,22 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9216
9226
|
if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
|
|
9217
9227
|
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: ${nodeSpanV}, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, nodeSpanV, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV})`;
|
|
9218
9228
|
const hostBuildArgs = `${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV}${def.tags !== void 0 && def.tags.length > 0 ? `, ${JSON.stringify(def.tags)}` : ""}`;
|
|
9219
|
-
const hostBuildExpr = `_ctx.
|
|
9229
|
+
const hostBuildExpr = `_ctx.build(${hostBuildArgs})`;
|
|
9220
9230
|
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
|
|
9221
|
-
const
|
|
9231
|
+
const hostCollapses = structural || cstOut;
|
|
9232
|
+
const hostCollapseExpr = hostCollapses ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
|
|
9222
9233
|
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
9223
9234
|
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
9224
9235
|
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
);
|
|
9236
|
+
const ndGate = orGate(profileRecognizer, profileCapture);
|
|
9237
|
+
const recGate = notGate(profileRecognizer);
|
|
9238
|
+
const pushIndent = recGate === "true" ? i : `${i} `;
|
|
9239
|
+
const pushCh = `${pushIndent}if (${sc}) ${sc}.push(${ndV})`;
|
|
9240
|
+
ctx.needsRawEntry = true;
|
|
9241
|
+
const pushRaw = `${pushIndent}if (${sr}) ${sr}.push(_rawEntry(${ndV}, input, ${pos}, ${endVar}${ctx.lineTracking ? `, ${nodeSpanV}` : ""}))`;
|
|
9242
|
+
stmts.push(`${i}const ${ndV} = ${tern(ndGate, "undefined", `(${finalExpr})`)}`);
|
|
9243
|
+
if (recGate === "true") stmts.push(pushCh, pushRaw);
|
|
9244
|
+
else stmts.push(`${i}if (${recGate}) {`, pushCh, pushRaw, `${i}}`);
|
|
9232
9245
|
return { stmts, valueVar: ndV, endVar };
|
|
9233
9246
|
}
|
|
9234
9247
|
function emitRuntimeFallback(parser2, ctx, pos) {
|
|
@@ -9257,7 +9270,12 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9257
9270
|
} catch {
|
|
9258
9271
|
return emitRuntimeFallback(p, ctx, pos);
|
|
9259
9272
|
}
|
|
9260
|
-
|
|
9273
|
+
const cost = usage.sizes.get(resolved) ?? 1;
|
|
9274
|
+
if (cost <= ctx.inlineLeft) {
|
|
9275
|
+
ctx.inlineLeft -= cost;
|
|
9276
|
+
return emit(resolved, ctx, pos);
|
|
9277
|
+
}
|
|
9278
|
+
_inlineCapSink?.push({ fn: ctx.currentFnName ?? "<root>", nodes: cost });
|
|
9261
9279
|
}
|
|
9262
9280
|
if (!ctx.namedParsers.has(p)) {
|
|
9263
9281
|
const fnName2 = canonical2 ?? `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
@@ -9272,6 +9290,9 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9272
9290
|
const savedIndent = ctx.indent;
|
|
9273
9291
|
const savedFailLabel = ctx.failLabel;
|
|
9274
9292
|
const savedRecord = ctx.recordFail;
|
|
9293
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9294
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9295
|
+
ctx.currentFnName = fnName2;
|
|
9275
9296
|
const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
|
|
9276
9297
|
const savedActiveRule = ctx.activeCoverageRuleId;
|
|
9277
9298
|
const savedSuppressFailure = ctx.suppressCoverageFailure;
|
|
@@ -9286,6 +9307,8 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9286
9307
|
ctx.indent = savedIndent;
|
|
9287
9308
|
ctx.failLabel = savedFailLabel;
|
|
9288
9309
|
ctx.recordFail = savedRecord;
|
|
9310
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9311
|
+
ctx.currentFnName = savedFnName;
|
|
9289
9312
|
ctx.activeCoverageRuleId = savedActiveRule;
|
|
9290
9313
|
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
9291
9314
|
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
@@ -9380,6 +9403,9 @@ function emit(p, ctx, pos) {
|
|
|
9380
9403
|
const savedIndent = ctx.indent;
|
|
9381
9404
|
const savedFailLabel = ctx.failLabel;
|
|
9382
9405
|
const savedRecord = ctx.recordFail;
|
|
9406
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9407
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9408
|
+
ctx.currentFnName = fnName;
|
|
9383
9409
|
ctx.indent = 1;
|
|
9384
9410
|
ctx.failLabel = "_pfail";
|
|
9385
9411
|
ctx.recordFail = true;
|
|
@@ -9387,6 +9413,8 @@ function emit(p, ctx, pos) {
|
|
|
9387
9413
|
ctx.indent = savedIndent;
|
|
9388
9414
|
ctx.failLabel = savedFailLabel;
|
|
9389
9415
|
ctx.recordFail = savedRecord;
|
|
9416
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9417
|
+
ctx.currentFnName = savedFnName;
|
|
9390
9418
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
9391
9419
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
9392
9420
|
}
|
|
@@ -9580,7 +9608,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9580
9608
|
case "peek":
|
|
9581
9609
|
return emitPeek(def, ctx, pos);
|
|
9582
9610
|
case "routed":
|
|
9583
|
-
return emitRouted(ctx, pos);
|
|
9611
|
+
return emitRouted(ctx, pos, def);
|
|
9584
9612
|
case "node":
|
|
9585
9613
|
return emitNode(def, ctx, pos);
|
|
9586
9614
|
case "scanTo":
|
|
@@ -9615,6 +9643,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9615
9643
|
const savedIndent = ctx.indent;
|
|
9616
9644
|
const savedFailLabel = ctx.failLabel;
|
|
9617
9645
|
const savedRecord = ctx.recordFail;
|
|
9646
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9647
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9648
|
+
ctx.currentFnName = fnName;
|
|
9618
9649
|
ctx.indent = 1;
|
|
9619
9650
|
ctx.failLabel = "_pfail";
|
|
9620
9651
|
ctx.recordFail = true;
|
|
@@ -9622,6 +9653,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9622
9653
|
ctx.indent = savedIndent;
|
|
9623
9654
|
ctx.failLabel = savedFailLabel;
|
|
9624
9655
|
ctx.recordFail = savedRecord;
|
|
9656
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9657
|
+
ctx.currentFnName = savedFnName;
|
|
9625
9658
|
pushNamedFnDecl(ctx, fnName, innerR.stmts, innerR.valueVar, innerR.endVar);
|
|
9626
9659
|
}
|
|
9627
9660
|
const fn = ctx.namedParsers.get(innerParser);
|
|
@@ -9780,12 +9813,16 @@ function childrenOf3(def) {
|
|
|
9780
9813
|
return [def.parser, def.sentinel];
|
|
9781
9814
|
case "scanTo":
|
|
9782
9815
|
return [def.sentinel, ...def.skip];
|
|
9816
|
+
// A `routed()` fallback IS emitted at this site (emitRouted), so the usage
|
|
9817
|
+
// analysis must see the edge — otherwise a fallback shared by several routed()
|
|
9818
|
+
// sites is miscounted as single-use and inlined at each.
|
|
9819
|
+
case "routed":
|
|
9820
|
+
return def.fallback ? [def.fallback] : [];
|
|
9783
9821
|
case "lazy":
|
|
9784
9822
|
case "literal":
|
|
9785
9823
|
case "regex":
|
|
9786
9824
|
case "keywords":
|
|
9787
9825
|
case "guard":
|
|
9788
|
-
case "routed":
|
|
9789
9826
|
case "unknown":
|
|
9790
9827
|
return [];
|
|
9791
9828
|
}
|
|
@@ -9806,6 +9843,17 @@ function isHoistableTag(tag) {
|
|
|
9806
9843
|
return HOISTABLE_TAGS.has(tag);
|
|
9807
9844
|
}
|
|
9808
9845
|
var HOIST_MIN_SUBTREE = 3;
|
|
9846
|
+
var INLINE_MAX_NODES = 1e3;
|
|
9847
|
+
function resolveInlineMax(explicit) {
|
|
9848
|
+
if (explicit !== void 0) return explicit;
|
|
9849
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_MAX_INLINE : void 0;
|
|
9850
|
+
if (env !== void 0 && env !== "") {
|
|
9851
|
+
if (env === "off" || env === "infinity") return Infinity;
|
|
9852
|
+
const n = Number(env);
|
|
9853
|
+
if (Number.isFinite(n) && n >= 0) return n;
|
|
9854
|
+
}
|
|
9855
|
+
return INLINE_MAX_NODES;
|
|
9856
|
+
}
|
|
9809
9857
|
function analyzeLazyUsage(root) {
|
|
9810
9858
|
return analyzeLazyUsageMulti([root]);
|
|
9811
9859
|
}
|
|
@@ -9911,102 +9959,6 @@ function ruleDependencies(ruleMap) {
|
|
|
9911
9959
|
}
|
|
9912
9960
|
return deps;
|
|
9913
9961
|
}
|
|
9914
|
-
function resolveGatingLevel(opt) {
|
|
9915
|
-
const explicit = typeof opt === "string" ? opt : opt?.level;
|
|
9916
|
-
if (explicit !== void 0) return explicit;
|
|
9917
|
-
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_GATING : void 0;
|
|
9918
|
-
if (env === "off" || env === "warn" || env === "error") return env;
|
|
9919
|
-
return "warn";
|
|
9920
|
-
}
|
|
9921
|
-
function runGatingDiagnostic(combinator, opt) {
|
|
9922
|
-
return reportGating(opt, (o) => analyzeGating(combinator, o));
|
|
9923
|
-
}
|
|
9924
|
-
function runGatingDiagnosticRules(ruleMap, opt) {
|
|
9925
|
-
return reportGating(opt, (o) => analyzeGatingRules(ruleMap, o));
|
|
9926
|
-
}
|
|
9927
|
-
function runFusedGatingDiagnostic(getRuleMaps, opt, getOpaque) {
|
|
9928
|
-
if (resolveGatingLevel(opt) === "off") return void 0;
|
|
9929
|
-
const ruleMaps = getRuleMaps();
|
|
9930
|
-
const opaque = getOpaque?.() ?? [];
|
|
9931
|
-
const opaqueFindings = opaque.map((o) => ({
|
|
9932
|
-
rule: o.ruleNames.length > 0 ? o.ruleNames.join(", ") : `<artifact ${o.ns}>`,
|
|
9933
|
-
kind: "opaque-artifact",
|
|
9934
|
-
reason: `precompiled artifact "${o.ns}" carries compiled rule functions, not re-lowerable IR \u2014 its choices were not examined at this fuse.`
|
|
9935
|
-
}));
|
|
9936
|
-
if (!ruleMaps.some((map) => hasExternalRuleRef(map))) {
|
|
9937
|
-
if (opaqueFindings.length === 0) return void 0;
|
|
9938
|
-
return reportGating(opt, () => ({
|
|
9939
|
-
totalChoices: 0,
|
|
9940
|
-
gated: 0,
|
|
9941
|
-
recoverable: 0,
|
|
9942
|
-
unanalysable: opaqueFindings,
|
|
9943
|
-
ungated: [],
|
|
9944
|
-
accepted: [],
|
|
9945
|
-
deferred: [],
|
|
9946
|
-
acceptedUnused: [],
|
|
9947
|
-
choices: [],
|
|
9948
|
-
antiPatterns: []
|
|
9949
|
-
}));
|
|
9950
|
-
}
|
|
9951
|
-
const winners = /* @__PURE__ */ new Map();
|
|
9952
|
-
for (const map of ruleMaps) for (const [name, rule] of map) {
|
|
9953
|
-
if (rule._def.tag === "lazy") {
|
|
9954
|
-
try {
|
|
9955
|
-
rule._def.thunk();
|
|
9956
|
-
} catch {
|
|
9957
|
-
continue;
|
|
9958
|
-
}
|
|
9959
|
-
}
|
|
9960
|
-
winners.set(name, rule);
|
|
9961
|
-
}
|
|
9962
|
-
const entries = [...winners];
|
|
9963
|
-
return reportGating(opt, (o) => {
|
|
9964
|
-
const deferredHere = new Set(analyzeGatingRules(entries, o).deferred.map((c) => c.id));
|
|
9965
|
-
const fused = analyzeGatingRules(entries, { ...o, resolveRef: (name) => winners.get(name) });
|
|
9966
|
-
return {
|
|
9967
|
-
...fused,
|
|
9968
|
-
ungated: fused.ungated.filter((c) => deferredHere.has(c.id)),
|
|
9969
|
-
antiPatterns: [],
|
|
9970
|
-
unanalysable: [...fused.unanalysable, ...opaqueFindings]
|
|
9971
|
-
};
|
|
9972
|
-
});
|
|
9973
|
-
}
|
|
9974
|
-
function reportGating(opt, analyze) {
|
|
9975
|
-
const level = resolveGatingLevel(opt);
|
|
9976
|
-
if (level === "off") return void 0;
|
|
9977
|
-
const obj = opt !== null && typeof opt === "object" ? opt : void 0;
|
|
9978
|
-
const analyzeOpts = obj?.accept !== void 0 || obj?.entryName !== void 0 ? { ...obj.accept !== void 0 ? { accept: obj.accept } : {}, ...obj.entryName !== void 0 ? { entryName: obj.entryName } : {} } : void 0;
|
|
9979
|
-
let report;
|
|
9980
|
-
try {
|
|
9981
|
-
report = analyze(analyzeOpts);
|
|
9982
|
-
} catch (e) {
|
|
9983
|
-
const reason = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
|
|
9984
|
-
const failed = {
|
|
9985
|
-
totalChoices: 0,
|
|
9986
|
-
gated: 0,
|
|
9987
|
-
recoverable: 0,
|
|
9988
|
-
unanalysable: [{ rule: "<whole grammar>", kind: "not-a-combinator", reason: `gating analysis threw \u2014 ${reason}` }],
|
|
9989
|
-
ungated: [],
|
|
9990
|
-
accepted: [],
|
|
9991
|
-
deferred: [],
|
|
9992
|
-
acceptedUnused: [],
|
|
9993
|
-
choices: [],
|
|
9994
|
-
antiPatterns: []
|
|
9995
|
-
};
|
|
9996
|
-
const failLines = formatGatingWarnings(failed);
|
|
9997
|
-
if (level === "error") throw new Error(`parseman: gating analysis FAILED (no verdict available)
|
|
9998
|
-
${failLines.join("\n")}`);
|
|
9999
|
-
for (const l of failLines) console.warn(l);
|
|
10000
|
-
return failed;
|
|
10001
|
-
}
|
|
10002
|
-
const lines = formatGatingWarnings(report);
|
|
10003
|
-
if (lines.length > 0) {
|
|
10004
|
-
if (level === "error") throw new Error(`parseman: ${report.ungated.length} ungated hot choice(s) / ${report.antiPatterns.length} anti-pattern(s) / ${report.unanalysable.length} unanalysable rule(s)
|
|
10005
|
-
${lines.join("\n")}`);
|
|
10006
|
-
for (const l of lines) console.warn(l);
|
|
10007
|
-
}
|
|
10008
|
-
return report;
|
|
10009
|
-
}
|
|
10010
9962
|
function resolveDuplicationLevel(opt) {
|
|
10011
9963
|
const explicit = typeof opt === "string" ? opt : opt?.level;
|
|
10012
9964
|
if (explicit !== void 0) return explicit;
|
|
@@ -10049,7 +10001,17 @@ function runDuplicationDiagnosticRules(ruleMap, opt) {
|
|
|
10049
10001
|
return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
|
|
10050
10002
|
}
|
|
10051
10003
|
function compile(combinator, mapFnSources, opts) {
|
|
10052
|
-
const
|
|
10004
|
+
const drain = beginCompileDegradationDrain();
|
|
10005
|
+
let completed = false;
|
|
10006
|
+
try {
|
|
10007
|
+
const compiled = compileImpl(combinator, mapFnSources, opts);
|
|
10008
|
+
completed = true;
|
|
10009
|
+
return compiled;
|
|
10010
|
+
} finally {
|
|
10011
|
+
drain(completed);
|
|
10012
|
+
}
|
|
10013
|
+
}
|
|
10014
|
+
function compileImpl(combinator, mapFnSources, opts) {
|
|
10053
10015
|
runDuplicationDiagnostic(combinator, opts?.duplication);
|
|
10054
10016
|
markUnusedValues(combinator);
|
|
10055
10017
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
@@ -10057,9 +10019,12 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10057
10019
|
const grammarScanSkip = combinator._meta.grammarScanSkip;
|
|
10058
10020
|
const grammarHostMode = combinator._meta.grammarHostMode;
|
|
10059
10021
|
const grammarTrackLines = combinator._meta.grammarTrackLines;
|
|
10022
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10060
10023
|
const ctx = {
|
|
10061
10024
|
vars: 0,
|
|
10062
10025
|
indent: 1,
|
|
10026
|
+
inlineMax: _inlineMax,
|
|
10027
|
+
inlineLeft: _inlineMax,
|
|
10063
10028
|
regexDecls: [],
|
|
10064
10029
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10065
10030
|
expectedDecls: [],
|
|
@@ -10105,11 +10070,13 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10105
10070
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
10106
10071
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
10107
10072
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
10073
|
+
const rawEntryDecls = ctx.needsRawEntry ? [RAW_ENTRY_DECL] : [];
|
|
10108
10074
|
const lineTrackDecls = ctx.needsLineTrack ? [LINE_TRACK_DECL] : [];
|
|
10109
10075
|
const lineSpanDecls = ctx.needsLineSpan ? [LINE_SPAN_DECL] : [];
|
|
10110
10076
|
const source = [
|
|
10111
10077
|
...emptyTlDecls,
|
|
10112
10078
|
...hostReadsDecls,
|
|
10079
|
+
...rawEntryDecls,
|
|
10113
10080
|
...lineTrackDecls,
|
|
10114
10081
|
...lineSpanDecls,
|
|
10115
10082
|
...ctx.regexDecls,
|
|
@@ -10124,6 +10091,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10124
10091
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
10125
10092
|
...emptyTlDecls,
|
|
10126
10093
|
...hostReadsDecls,
|
|
10094
|
+
...rawEntryDecls,
|
|
10127
10095
|
...lineTrackDecls,
|
|
10128
10096
|
...lineSpanDecls,
|
|
10129
10097
|
...ctx.regexDecls,
|
|
@@ -10173,8 +10141,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10173
10141
|
const compiledMeta = {
|
|
10174
10142
|
source,
|
|
10175
10143
|
inlineExpression,
|
|
10176
|
-
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
10177
|
-
...gatingReport === void 0 ? {} : { gating: gatingReport }
|
|
10144
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
10178
10145
|
};
|
|
10179
10146
|
if (!ctx.lineTracking) {
|
|
10180
10147
|
return {
|
|
@@ -10239,7 +10206,6 @@ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels, ambien
|
|
|
10239
10206
|
return `Object.assign(${fnSource}, { _meta: {${labels === void 0 ? "" : ` triviaKindLabels: ${JSON.stringify(labels)},`}${classified === void 0 ? "" : " rootTriviaClassified: true,"} } })`;
|
|
10240
10207
|
}
|
|
10241
10208
|
function compileRuleMap(ruleMap, opts) {
|
|
10242
|
-
runGatingDiagnosticRules(ruleMap, opts?.gating);
|
|
10243
10209
|
runDuplicationDiagnosticRules(ruleMap, opts?.duplication);
|
|
10244
10210
|
for (const [, rule] of ruleMap) markUnusedValues(rule);
|
|
10245
10211
|
const coverageWinners = opts?.coverage ? Object.fromEntries(ruleMap.filter(([, rule]) => rule._def.tag !== "lazy")) : void 0;
|
|
@@ -10248,9 +10214,12 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
10248
10214
|
const grammarScanSkip = opts?.scanSkip ?? ruleMap.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
|
|
10249
10215
|
const grammarHostMode = opts?.hostMode ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
|
|
10250
10216
|
const grammarTrackLines = opts?.trackLines === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
|
|
10217
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10251
10218
|
const ctx = {
|
|
10252
10219
|
vars: 0,
|
|
10253
10220
|
indent: 1,
|
|
10221
|
+
inlineMax: _inlineMax,
|
|
10222
|
+
inlineLeft: _inlineMax,
|
|
10254
10223
|
regexDecls: [],
|
|
10255
10224
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10256
10225
|
expectedDecls: [],
|
|
@@ -10316,6 +10285,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
10316
10285
|
const hoistedDecls = [
|
|
10317
10286
|
ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "",
|
|
10318
10287
|
ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "",
|
|
10288
|
+
ctx.needsRawEntry ? ` ${RAW_ENTRY_DECL}` : "",
|
|
10319
10289
|
ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "",
|
|
10320
10290
|
ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "",
|
|
10321
10291
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
@@ -10388,7 +10358,6 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
10388
10358
|
}
|
|
10389
10359
|
function compileLinkable(ruleMapArg, ns, opts) {
|
|
10390
10360
|
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
10391
|
-
if (opts?.gating !== void 0) runGatingDiagnosticRules(ruleMapArg, opts.gating);
|
|
10392
10361
|
if (opts?.duplication !== void 0) runDuplicationDiagnosticRules(ruleMapArg, opts.duplication);
|
|
10393
10362
|
for (const [, rule] of ruleMapArg) markUnusedValues(rule);
|
|
10394
10363
|
const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
|
|
@@ -10407,9 +10376,12 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10407
10376
|
}
|
|
10408
10377
|
});
|
|
10409
10378
|
const nodeMeta = new Map(ruleMap.map(([name, rule]) => [name, collectGrammarReflection([[name, rule]], { followLazy: false })]));
|
|
10379
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10410
10380
|
const ctx = {
|
|
10411
10381
|
vars: 0,
|
|
10412
10382
|
indent: 1,
|
|
10383
|
+
inlineMax: _inlineMax,
|
|
10384
|
+
inlineLeft: _inlineMax,
|
|
10413
10385
|
regexDecls: [],
|
|
10414
10386
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10415
10387
|
expectedDecls: [],
|
|
@@ -10505,6 +10477,9 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10505
10477
|
}
|
|
10506
10478
|
}
|
|
10507
10479
|
const savedIndent = ctx.indent, savedFail = ctx.failLabel, savedRec = ctx.recordFail;
|
|
10480
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
10481
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
10482
|
+
ctx.currentFnName = fn;
|
|
10508
10483
|
ctx.indent = 1;
|
|
10509
10484
|
ctx.failLabel = "_pfail";
|
|
10510
10485
|
ctx.recordFail = true;
|
|
@@ -10520,6 +10495,8 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10520
10495
|
ctx.indent = savedIndent;
|
|
10521
10496
|
ctx.failLabel = savedFail;
|
|
10522
10497
|
ctx.recordFail = savedRec;
|
|
10498
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
10499
|
+
ctx.currentFnName = savedFnName;
|
|
10523
10500
|
const ruleId = ctx.coverage?.plan.rules.get(rule);
|
|
10524
10501
|
const stmts = ruleId === void 0 ? body.stmts : [
|
|
10525
10502
|
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
|
|
@@ -10604,6 +10581,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10604
10581
|
deps: ruleDependencies(ruleMap),
|
|
10605
10582
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
10606
10583
|
needsHostReads: !!ctx.needsHostReads,
|
|
10584
|
+
needsRawEntry: !!ctx.needsRawEntry,
|
|
10607
10585
|
hostMode: ctx.hostMode ?? "ast",
|
|
10608
10586
|
hostBranchElided: !!ctx.hostBranchElided,
|
|
10609
10587
|
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
@@ -10678,14 +10656,16 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootR
|
|
|
10678
10656
|
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
10679
10657
|
const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
|
|
10680
10658
|
const hostReadsDecl = ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "";
|
|
10659
|
+
const rawEntryDecl = ctx.needsRawEntry ? ` ${RAW_ENTRY_DECL}` : "";
|
|
10681
10660
|
const lineTrackDecl = ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "";
|
|
10682
10661
|
const lineSpanDecl = ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "";
|
|
10683
|
-
const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!lineTrackDecl || !!lineSpanDecl;
|
|
10662
|
+
const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!rawEntryDecl || !!lineTrackDecl || !!lineSpanDecl;
|
|
10684
10663
|
if (!needsWrapper) return innerFn;
|
|
10685
10664
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
10686
10665
|
const hoistedDecls = [
|
|
10687
10666
|
emptyTlDecl,
|
|
10688
10667
|
hostReadsDecl,
|
|
10668
|
+
rawEntryDecl,
|
|
10689
10669
|
lineTrackDecl,
|
|
10690
10670
|
lineSpanDecl,
|
|
10691
10671
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
@@ -10755,18 +10735,19 @@ function childrenOf4(def) {
|
|
|
10755
10735
|
return [def.main, def.skipped];
|
|
10756
10736
|
case "scanTo":
|
|
10757
10737
|
return [def.sentinel, ...def.skip];
|
|
10738
|
+
case "routed":
|
|
10739
|
+
return def.fallback ? [def.fallback] : [];
|
|
10758
10740
|
case "lazy":
|
|
10759
10741
|
case "literal":
|
|
10760
10742
|
case "regex":
|
|
10761
10743
|
case "keywords":
|
|
10762
|
-
case "routed":
|
|
10763
10744
|
case "guard":
|
|
10764
10745
|
case "recover":
|
|
10765
10746
|
case "unknown":
|
|
10766
10747
|
return [];
|
|
10767
10748
|
}
|
|
10768
10749
|
}
|
|
10769
|
-
var
|
|
10750
|
+
var ruleNameOf3 = (c) => c._ruleName;
|
|
10770
10751
|
function lazyTarget(c) {
|
|
10771
10752
|
if (c._def.tag !== "lazy") return null;
|
|
10772
10753
|
try {
|
|
@@ -10841,7 +10822,7 @@ function evalRuleMapIR(ir) {
|
|
|
10841
10822
|
l._def.fnSrc = src;
|
|
10842
10823
|
return l;
|
|
10843
10824
|
};
|
|
10844
|
-
const _nd = (type, child, src, opts, staticError) => {
|
|
10825
|
+
const _nd = (type, child, src, opts, staticError, sigSrc) => {
|
|
10845
10826
|
if (staticError !== void 0 && staticError.length > 0) {
|
|
10846
10827
|
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
10847
10828
|
}
|
|
@@ -10850,6 +10831,7 @@ function evalRuleMapIR(ir) {
|
|
|
10850
10831
|
}), opts);
|
|
10851
10832
|
n._def.buildSrc = src;
|
|
10852
10833
|
if (staticError !== void 0) n._def.buildStaticError = staticError;
|
|
10834
|
+
if (sigSrc !== void 0) n._def.buildSigSrc = sigSrc;
|
|
10853
10835
|
return n;
|
|
10854
10836
|
};
|
|
10855
10837
|
const _gch = (items) => {
|
|
@@ -11002,7 +10984,7 @@ var Serializer = class {
|
|
|
11002
10984
|
if (seen.has(c)) return;
|
|
11003
10985
|
seen.add(c);
|
|
11004
10986
|
if (c._def.tag === "lazy") {
|
|
11005
|
-
if (
|
|
10987
|
+
if (ruleNameOf3(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
|
|
11006
10988
|
const target = lazyTarget(c);
|
|
11007
10989
|
if (target) this.assertNoRuleRef(target, seen);
|
|
11008
10990
|
return;
|
|
@@ -11013,7 +10995,7 @@ var Serializer = class {
|
|
|
11013
10995
|
* its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
|
|
11014
10996
|
* `g[name]` ref — only the top-level entry is unwrapped. */
|
|
11015
10997
|
body(c) {
|
|
11016
|
-
return c._def.tag === "lazy" &&
|
|
10998
|
+
return c._def.tag === "lazy" && ruleNameOf3(c) !== void 0 ? lazyTarget(c) ?? c : c;
|
|
11017
10999
|
}
|
|
11018
11000
|
run() {
|
|
11019
11001
|
for (const [, c] of this.ruleMap) this.analyze(this.body(c), /* @__PURE__ */ new Set());
|
|
@@ -11055,7 +11037,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11055
11037
|
analyze(c, active) {
|
|
11056
11038
|
const def = c._def;
|
|
11057
11039
|
if (def.tag === "lazy") {
|
|
11058
|
-
if (
|
|
11040
|
+
if (ruleNameOf3(c) !== void 0) return;
|
|
11059
11041
|
const target = lazyTarget(c);
|
|
11060
11042
|
if (!target) throw new Unserializable("unresolved unnamed ref");
|
|
11061
11043
|
if (active.has(target)) {
|
|
@@ -11107,7 +11089,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11107
11089
|
const kid = (x) => this.ref(x, selfOf);
|
|
11108
11090
|
switch (def.tag) {
|
|
11109
11091
|
case "lazy": {
|
|
11110
|
-
const name = this.localRuleNames.get(c) ??
|
|
11092
|
+
const name = this.localRuleNames.get(c) ?? ruleNameOf3(c);
|
|
11111
11093
|
if (name !== void 0) return `g[${JSON.stringify(name)}]`;
|
|
11112
11094
|
const target = lazyTarget(c);
|
|
11113
11095
|
if (selfOf && target === selfOf.comb) return selfOf.var;
|
|
@@ -11162,7 +11144,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11162
11144
|
case "peek":
|
|
11163
11145
|
return `peek(${kid(def.parser)})`;
|
|
11164
11146
|
case "routed":
|
|
11165
|
-
return "routed()"
|
|
11147
|
+
return def.fallback === void 0 ? "routed()" : `routed(${kid(def.fallback)})`;
|
|
11166
11148
|
case "trivia":
|
|
11167
11149
|
return `trivia(${kid(def.parser)})`;
|
|
11168
11150
|
case "token":
|
|
@@ -11195,6 +11177,9 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11195
11177
|
...projectEntry === void 0 ? [] : [projectEntry],
|
|
11196
11178
|
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
11197
11179
|
...def.trailingTrivia ? ["trailingTrivia: true"] : [],
|
|
11180
|
+
// Declared or resolved arity. Carried so a re-lowered composed artifact does
|
|
11181
|
+
// not silently re-acquire the fail-open capture cost this module resolved away.
|
|
11182
|
+
...def.buildArity === void 0 ? [] : [`buildArity: ${def.buildArity}`],
|
|
11198
11183
|
...tagEntry === void 0 ? [] : [tagEntry]
|
|
11199
11184
|
];
|
|
11200
11185
|
const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
|
|
@@ -11203,8 +11188,14 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11203
11188
|
return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
|
|
11204
11189
|
}
|
|
11205
11190
|
if (def.buildSrc !== void 0) {
|
|
11206
|
-
const
|
|
11207
|
-
|
|
11191
|
+
const tail = [];
|
|
11192
|
+
if (def.buildStaticError !== void 0 || def.buildSigSrc !== void 0) {
|
|
11193
|
+
if (!opts) tail.push("undefined");
|
|
11194
|
+
tail.push(def.buildStaticError === void 0 ? "undefined" : JSON.stringify(def.buildStaticError));
|
|
11195
|
+
}
|
|
11196
|
+
if (def.buildSigSrc !== void 0) tail.push(JSON.stringify(def.buildSigSrc));
|
|
11197
|
+
const trailing = tail.length > 0 ? `, ${tail.join(", ")}` : "";
|
|
11198
|
+
return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${trailing})`;
|
|
11208
11199
|
}
|
|
11209
11200
|
return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
|
|
11210
11201
|
}
|
|
@@ -11292,12 +11283,14 @@ function fusedBody(pieces) {
|
|
|
11292
11283
|
const contributingPieces = [...contributing];
|
|
11293
11284
|
const needsEmptyTl = contributingPieces.some((p) => p.needsEmptyTl);
|
|
11294
11285
|
const needsHostReads = contributingPieces.some((p) => p.needsHostReads);
|
|
11286
|
+
const needsRawEntry = contributingPieces.some((p) => p.needsRawEntry);
|
|
11295
11287
|
const lines = [
|
|
11296
11288
|
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
11297
11289
|
"const _pfFail = {}",
|
|
11298
11290
|
"let _pfEnd",
|
|
11299
11291
|
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
11300
11292
|
...needsHostReads ? [HOST_READS_DECL] : [],
|
|
11293
|
+
...needsRawEntry ? [RAW_ENTRY_DECL] : [],
|
|
11301
11294
|
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
11302
11295
|
...new Set(contributingPieces.flatMap((p) => p.prelude)),
|
|
11303
11296
|
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
@@ -11331,8 +11324,8 @@ function fusedBody(pieces) {
|
|
|
11331
11324
|
for (const [k, p] of winner) {
|
|
11332
11325
|
const r = p.firstSetRecipes?.get(k);
|
|
11333
11326
|
if (r) recipes.set(k, r);
|
|
11334
|
-
const
|
|
11335
|
-
if (
|
|
11327
|
+
const fs3 = p.firstSets?.get(k);
|
|
11328
|
+
if (fs3) shallow.set(k, fs3);
|
|
11336
11329
|
const nu = p.nullable?.get(k);
|
|
11337
11330
|
if (nu !== void 0) nullable2.set(k, nu);
|
|
11338
11331
|
}
|
|
@@ -11355,9 +11348,9 @@ function fusedBody(pieces) {
|
|
|
11355
11348
|
for (let iter = 0; iter <= recipes.size; iter++) {
|
|
11356
11349
|
let changed = false;
|
|
11357
11350
|
for (const [k, r] of recipes) {
|
|
11358
|
-
const
|
|
11359
|
-
if (JSON.stringify(finalFS.get(k)) !== JSON.stringify(
|
|
11360
|
-
finalFS.set(k,
|
|
11351
|
+
const fs3 = resolveRecipe(r);
|
|
11352
|
+
if (JSON.stringify(finalFS.get(k)) !== JSON.stringify(fs3)) {
|
|
11353
|
+
finalFS.set(k, fs3);
|
|
11361
11354
|
changed = true;
|
|
11362
11355
|
}
|
|
11363
11356
|
}
|
|
@@ -11369,9 +11362,9 @@ function fusedBody(pieces) {
|
|
|
11369
11362
|
// matches every well-formed placeholder.
|
|
11370
11363
|
/\/\*@FS:([A-Za-z0-9_$]+):([A-Za-z0-9_$]+)@\*\/true/g,
|
|
11371
11364
|
(_m, name, codevar) => {
|
|
11372
|
-
const
|
|
11373
|
-
if (!
|
|
11374
|
-
return `(${firstSetCond(codevar,
|
|
11365
|
+
const fs3 = finalFS.get(name);
|
|
11366
|
+
if (!fs3 || fs3.kind === "any" || fs3.kind === "empty") return "true";
|
|
11367
|
+
return `(${firstSetCond(codevar, fs3)})`;
|
|
11375
11368
|
}
|
|
11376
11369
|
);
|
|
11377
11370
|
const env = {};
|
|
@@ -11403,17 +11396,6 @@ ${body}
|
|
|
11403
11396
|
function isIRPiece(p) {
|
|
11404
11397
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
11405
11398
|
}
|
|
11406
|
-
function once(fn) {
|
|
11407
|
-
let done = false;
|
|
11408
|
-
let value;
|
|
11409
|
-
return () => {
|
|
11410
|
-
if (!done) {
|
|
11411
|
-
value = fn();
|
|
11412
|
-
done = true;
|
|
11413
|
-
}
|
|
11414
|
-
return value;
|
|
11415
|
-
};
|
|
11416
|
-
}
|
|
11417
11399
|
function materializePiece(p, trivia2, captureTerminals = false, hostMode) {
|
|
11418
11400
|
if (!isIRPiece(p)) return p;
|
|
11419
11401
|
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
|
|
@@ -11445,8 +11427,22 @@ function gate(predicate) {
|
|
|
11445
11427
|
};
|
|
11446
11428
|
}
|
|
11447
11429
|
|
|
11448
|
-
// src/
|
|
11449
|
-
var {
|
|
11430
|
+
// src/functional/run.ts
|
|
11431
|
+
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
11432
|
+
var REMOVED_RUN_RESULT_FIELDS = [
|
|
11433
|
+
[
|
|
11434
|
+
"triviaMap",
|
|
11435
|
+
`It was a dense root-trivia index built on every parse; root trivia is now an OPT-IN sparse capture, because most grammars paid for an index they never read. Migration: name the trivia labels your grammar defines \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia\`, whose \`.index\` carries the labels and gap lookups \`triviaMap\` exposed.`
|
|
11436
|
+
],
|
|
11437
|
+
[
|
|
11438
|
+
"triviaLog",
|
|
11439
|
+
`It was the flat \`start, end[, kindIndex]\` log every other trivia view was derived from, and it is no longer allocated at all \u2014 not empty, absent. Migration: request the labels you need \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia.rows\`. Do NOT reuse a stride-2/3 reader: rows are a different width and a different unit (one row per SELECTED marker, not one per trivia chunk), so an old loop reads confidently wrong offsets rather than failing.`
|
|
11440
|
+
],
|
|
11441
|
+
[
|
|
11442
|
+
"triviaKindLabels",
|
|
11443
|
+
`It was already optional, so nothing ever flagged its disappearance \u2014 and \`triviaKindMask(undefined, \u2026)\` means "capture everything", so reading it now silently WIDENS capture instead of erroring. Migration: request labels \u2014 ${SELECT_EXAMPLE} \u2014 then the set you asked for is \`RunResult.rootTrivia.select\` and the resolved table is \`RunResult.rootTrivia.index.labels\`.`
|
|
11444
|
+
]
|
|
11445
|
+
];
|
|
11450
11446
|
|
|
11451
11447
|
// src/index.ts
|
|
11452
11448
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
@@ -11640,6 +11636,10 @@ function stripTsFromSource(node2, code) {
|
|
|
11640
11636
|
}
|
|
11641
11637
|
return out + code.slice(cur, end);
|
|
11642
11638
|
}
|
|
11639
|
+
var _reducers = null;
|
|
11640
|
+
function setReducerResolver(r) {
|
|
11641
|
+
_reducers = r;
|
|
11642
|
+
}
|
|
11643
11643
|
function isWordFactory(v2) {
|
|
11644
11644
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
11645
11645
|
}
|
|
@@ -11871,9 +11871,12 @@ function staticNodeOptionsFromValue(value) {
|
|
|
11871
11871
|
} else if (name === "tags") {
|
|
11872
11872
|
if (!Array.isArray(v2) || !v2.every((item) => typeof item === "string")) return STATIC_NODE_OPTIONS_FAILED;
|
|
11873
11873
|
opts.tags = v2;
|
|
11874
|
+
} else if (name === "buildArity") {
|
|
11875
|
+
if (typeof v2 !== "number" || !Number.isInteger(v2) || v2 < 0 || v2 > 6) return STATIC_NODE_OPTIONS_FAILED;
|
|
11876
|
+
opts.buildArity = v2;
|
|
11874
11877
|
}
|
|
11875
11878
|
}
|
|
11876
|
-
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 ? opts : void 0;
|
|
11879
|
+
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 || opts.buildArity !== void 0 ? opts : void 0;
|
|
11877
11880
|
}
|
|
11878
11881
|
function staticNodeOptions(expr, scope) {
|
|
11879
11882
|
const unwrapped = unwrapStaticExpr(expr);
|
|
@@ -11899,9 +11902,13 @@ function staticNodeOptions(expr, scope) {
|
|
|
11899
11902
|
const tags = staticStringArray(p.value, scope);
|
|
11900
11903
|
if (tags === void 0) return STATIC_NODE_OPTIONS_FAILED;
|
|
11901
11904
|
opts.tags = tags;
|
|
11905
|
+
} else if (name === "buildArity") {
|
|
11906
|
+
const arity = staticLiteralValue(p.value);
|
|
11907
|
+
if (typeof arity !== "number" || !Number.isInteger(arity) || arity < 0 || arity > 6) return STATIC_NODE_OPTIONS_FAILED;
|
|
11908
|
+
opts.buildArity = arity;
|
|
11902
11909
|
}
|
|
11903
11910
|
}
|
|
11904
|
-
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 ? opts : void 0;
|
|
11911
|
+
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 || opts.buildArity !== void 0 ? opts : void 0;
|
|
11905
11912
|
}
|
|
11906
11913
|
function exprToCombi(node2, scope, code, mfs) {
|
|
11907
11914
|
if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
|
|
@@ -11997,6 +12004,15 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
11997
12004
|
const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
|
|
11998
12005
|
if (combi._def.tag === "node" && buildSrc !== void 0) {
|
|
11999
12006
|
combi._def.buildSrc = buildSrc;
|
|
12007
|
+
if (explicitType !== void 0 && firstArg.type === "Identifier") {
|
|
12008
|
+
combi._def.typeSrc = firstArg.name;
|
|
12009
|
+
}
|
|
12010
|
+
const resolved = _reducers?.resolve(buildSrc, be.start, code);
|
|
12011
|
+
if (resolved) {
|
|
12012
|
+
if (resolved.src !== null) combi._def.buildSigSrc = resolved.src;
|
|
12013
|
+
if (combi._def.buildArity === void 0 && resolved.arity !== null) combi._def.buildArity = resolved.arity;
|
|
12014
|
+
if (resolved.reason !== void 0) combi._def.buildArityUnresolved = resolved.reason;
|
|
12015
|
+
}
|
|
12000
12016
|
const staticError = directBuilderUnsupportedBindings(buildSrc);
|
|
12001
12017
|
if (staticError.length > 0) combi._def.buildStaticError = staticError;
|
|
12002
12018
|
}
|
|
@@ -12414,9 +12430,9 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
12414
12430
|
r._ruleName = name;
|
|
12415
12431
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = name;
|
|
12416
12432
|
};
|
|
12417
|
-
const
|
|
12433
|
+
const ruleNameOf4 = (r) => r._ruleName;
|
|
12418
12434
|
const isNamedRuleRefForAnotherRule2 = (r, key) => {
|
|
12419
|
-
const name = r._def.tag === "lazy" ?
|
|
12435
|
+
const name = r._def.tag === "lazy" ? ruleNameOf4(r) : void 0;
|
|
12420
12436
|
return name !== void 0 && name !== key;
|
|
12421
12437
|
};
|
|
12422
12438
|
for (const key of keys) {
|
|
@@ -12507,6 +12523,367 @@ function referencesAny(node2, names, scope) {
|
|
|
12507
12523
|
return false;
|
|
12508
12524
|
}
|
|
12509
12525
|
|
|
12526
|
+
// src/plugin/reducer-resolver.ts
|
|
12527
|
+
var fs = __toESM(require("node:fs"), 1);
|
|
12528
|
+
var path = __toESM(require("node:path"), 1);
|
|
12529
|
+
var import_node_module = require("node:module");
|
|
12530
|
+
var import_oxc_parser2 = require("oxc-parser");
|
|
12531
|
+
var FUNCTION_TYPES = /* @__PURE__ */ new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
|
|
12532
|
+
var SCOPE_TYPES = /* @__PURE__ */ new Set([
|
|
12533
|
+
...FUNCTION_TYPES,
|
|
12534
|
+
"BlockStatement",
|
|
12535
|
+
"ForStatement",
|
|
12536
|
+
"ForInStatement",
|
|
12537
|
+
"ForOfStatement",
|
|
12538
|
+
"CatchClause",
|
|
12539
|
+
"ClassDeclaration",
|
|
12540
|
+
"ClassExpression",
|
|
12541
|
+
"StaticBlock"
|
|
12542
|
+
]);
|
|
12543
|
+
function newScope(start, end, parent, isFunction) {
|
|
12544
|
+
const s = { start, end, bindings: /* @__PURE__ */ new Map(), children: [], parent, isFunction };
|
|
12545
|
+
parent?.children.push(s);
|
|
12546
|
+
return s;
|
|
12547
|
+
}
|
|
12548
|
+
function patternNames(pat, out) {
|
|
12549
|
+
if (!pat || typeof pat !== "object") return;
|
|
12550
|
+
const n = pat;
|
|
12551
|
+
switch (n.type) {
|
|
12552
|
+
case "Identifier":
|
|
12553
|
+
out.push(n.name);
|
|
12554
|
+
return;
|
|
12555
|
+
case "AssignmentPattern":
|
|
12556
|
+
return patternNames(n.left, out);
|
|
12557
|
+
case "RestElement":
|
|
12558
|
+
return patternNames(n.argument, out);
|
|
12559
|
+
case "ArrayPattern":
|
|
12560
|
+
for (const el of n.elements ?? []) patternNames(el, out);
|
|
12561
|
+
return;
|
|
12562
|
+
case "ObjectPattern":
|
|
12563
|
+
for (const p of n.properties ?? []) patternNames(p.type === "RestElement" ? p.argument : p.value, out);
|
|
12564
|
+
return;
|
|
12565
|
+
// A TS parameter property / assignment target wrapper.
|
|
12566
|
+
case "TSParameterProperty":
|
|
12567
|
+
return patternNames(n.parameter, out);
|
|
12568
|
+
default:
|
|
12569
|
+
return;
|
|
12570
|
+
}
|
|
12571
|
+
}
|
|
12572
|
+
function declare(scope, name, b) {
|
|
12573
|
+
if (!scope.bindings.has(name)) scope.bindings.set(name, b);
|
|
12574
|
+
}
|
|
12575
|
+
function functionScope(scope) {
|
|
12576
|
+
let s = scope;
|
|
12577
|
+
while (!s.isFunction && s.parent) s = s.parent;
|
|
12578
|
+
return s;
|
|
12579
|
+
}
|
|
12580
|
+
function buildScopeTree(body, moduleEnd) {
|
|
12581
|
+
const root = newScope(0, moduleEnd, null, true);
|
|
12582
|
+
const declarePattern = (scope, pat, kind, init) => {
|
|
12583
|
+
const names = [];
|
|
12584
|
+
patternNames(pat, names);
|
|
12585
|
+
const target = kind === "var" ? functionScope(scope) : scope;
|
|
12586
|
+
for (const name of names) {
|
|
12587
|
+
declare(target, name, init !== void 0 && names.length === 1 ? { kind, init } : { kind });
|
|
12588
|
+
}
|
|
12589
|
+
};
|
|
12590
|
+
const walk = (n, scope) => {
|
|
12591
|
+
if (!n || typeof n !== "object") return;
|
|
12592
|
+
if (Array.isArray(n)) {
|
|
12593
|
+
for (const item of n) walk(item, scope);
|
|
12594
|
+
return;
|
|
12595
|
+
}
|
|
12596
|
+
const node2 = n;
|
|
12597
|
+
if (typeof node2.type !== "string") return;
|
|
12598
|
+
switch (node2.type) {
|
|
12599
|
+
case "VariableDeclaration": {
|
|
12600
|
+
const kind = node2.kind ?? "var";
|
|
12601
|
+
for (const d of node2.declarations ?? []) {
|
|
12602
|
+
declarePattern(scope, d.id, kind, d.init ?? void 0);
|
|
12603
|
+
}
|
|
12604
|
+
break;
|
|
12605
|
+
}
|
|
12606
|
+
case "FunctionDeclaration":
|
|
12607
|
+
if (node2.id) declare(functionScope(scope), node2.id.name, { kind: "function", init: node2 });
|
|
12608
|
+
break;
|
|
12609
|
+
case "ClassDeclaration":
|
|
12610
|
+
if (node2.id) declare(scope, node2.id.name, { kind: "class" });
|
|
12611
|
+
break;
|
|
12612
|
+
case "ImportDeclaration": {
|
|
12613
|
+
const specifier = node2.source?.value ?? "";
|
|
12614
|
+
for (const sp of node2.specifiers ?? []) {
|
|
12615
|
+
const local = sp.local?.name;
|
|
12616
|
+
if (!local) continue;
|
|
12617
|
+
const imported = sp.type === "ImportDefaultSpecifier" ? "default" : sp.type === "ImportNamespaceSpecifier" ? "*" : sp.imported?.name ?? local;
|
|
12618
|
+
declare(scope, local, { kind: "import", importRef: { specifier, imported } });
|
|
12619
|
+
}
|
|
12620
|
+
break;
|
|
12621
|
+
}
|
|
12622
|
+
default:
|
|
12623
|
+
break;
|
|
12624
|
+
}
|
|
12625
|
+
if (SCOPE_TYPES.has(node2.type)) {
|
|
12626
|
+
const isFn = FUNCTION_TYPES.has(node2.type);
|
|
12627
|
+
const inner = newScope(node2.start, node2.end, scope, isFn);
|
|
12628
|
+
if (isFn) {
|
|
12629
|
+
for (const p of node2.params ?? []) declarePattern(inner, p, "param");
|
|
12630
|
+
if (node2.type === "FunctionExpression" && node2.id) {
|
|
12631
|
+
declare(inner, node2.id.name, { kind: "function", init: node2 });
|
|
12632
|
+
}
|
|
12633
|
+
}
|
|
12634
|
+
if (node2.type === "CatchClause" && node2.param) declarePattern(inner, node2.param, "catch");
|
|
12635
|
+
for (const key of Object.keys(node2)) {
|
|
12636
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12637
|
+
walk(node2[key], inner);
|
|
12638
|
+
}
|
|
12639
|
+
return;
|
|
12640
|
+
}
|
|
12641
|
+
for (const key of Object.keys(node2)) {
|
|
12642
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12643
|
+
walk(node2[key], scope);
|
|
12644
|
+
}
|
|
12645
|
+
};
|
|
12646
|
+
for (const stmt of body) walk(stmt, root);
|
|
12647
|
+
return root;
|
|
12648
|
+
}
|
|
12649
|
+
function scopeAt(root, offset) {
|
|
12650
|
+
let cur = root;
|
|
12651
|
+
for (; ; ) {
|
|
12652
|
+
const next = cur.children.find((c) => offset >= c.start && offset <= c.end);
|
|
12653
|
+
if (!next) return cur;
|
|
12654
|
+
cur = next;
|
|
12655
|
+
}
|
|
12656
|
+
}
|
|
12657
|
+
function lookup(scope, name) {
|
|
12658
|
+
for (let s = scope; s; s = s.parent) {
|
|
12659
|
+
const b = s.bindings.get(name);
|
|
12660
|
+
if (b) return { binding: b, scope: s };
|
|
12661
|
+
}
|
|
12662
|
+
return null;
|
|
12663
|
+
}
|
|
12664
|
+
function markReassignments(body, root) {
|
|
12665
|
+
const walk = (n) => {
|
|
12666
|
+
if (!n || typeof n !== "object") return;
|
|
12667
|
+
if (Array.isArray(n)) {
|
|
12668
|
+
for (const item of n) walk(item);
|
|
12669
|
+
return;
|
|
12670
|
+
}
|
|
12671
|
+
const node2 = n;
|
|
12672
|
+
if (typeof node2.type !== "string") return;
|
|
12673
|
+
if (node2.type === "AssignmentExpression" || node2.type === "UpdateExpression") {
|
|
12674
|
+
const target = node2.type === "UpdateExpression" ? node2.argument : node2.left;
|
|
12675
|
+
const names = [];
|
|
12676
|
+
if (target) patternNames(target, names);
|
|
12677
|
+
for (const name of names) {
|
|
12678
|
+
const hit = lookup(scopeAt(root, node2.start), name);
|
|
12679
|
+
if (hit) hit.binding.reassigned = true;
|
|
12680
|
+
}
|
|
12681
|
+
}
|
|
12682
|
+
for (const key of Object.keys(node2)) {
|
|
12683
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12684
|
+
walk(node2[key]);
|
|
12685
|
+
}
|
|
12686
|
+
};
|
|
12687
|
+
for (const stmt of body) walk(stmt);
|
|
12688
|
+
}
|
|
12689
|
+
function functionArity(fn) {
|
|
12690
|
+
const params = fn.params ?? [];
|
|
12691
|
+
let count = 0;
|
|
12692
|
+
for (const p of params) {
|
|
12693
|
+
if (p.type === "RestElement") return { arity: null, reason: "rest-parameter" };
|
|
12694
|
+
if (p.type === "Identifier" && p.name === "this") continue;
|
|
12695
|
+
count++;
|
|
12696
|
+
}
|
|
12697
|
+
if (fn.type !== "ArrowFunctionExpression" && referencesArguments(fn.body)) {
|
|
12698
|
+
return { arity: null, reason: "arguments" };
|
|
12699
|
+
}
|
|
12700
|
+
return { arity: count };
|
|
12701
|
+
}
|
|
12702
|
+
function referencesArguments(n) {
|
|
12703
|
+
if (!n || typeof n !== "object") return false;
|
|
12704
|
+
if (Array.isArray(n)) return n.some(referencesArguments);
|
|
12705
|
+
const node2 = n;
|
|
12706
|
+
if (typeof node2.type !== "string") return false;
|
|
12707
|
+
if (node2.type === "Identifier" && node2.name === "arguments") return true;
|
|
12708
|
+
if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression") return false;
|
|
12709
|
+
for (const key of Object.keys(node2)) {
|
|
12710
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12711
|
+
if (referencesArguments(node2[key])) return true;
|
|
12712
|
+
}
|
|
12713
|
+
return false;
|
|
12714
|
+
}
|
|
12715
|
+
var _moduleCache = /* @__PURE__ */ new Map();
|
|
12716
|
+
function analyseModuleFile(file) {
|
|
12717
|
+
let mtimeMs;
|
|
12718
|
+
try {
|
|
12719
|
+
mtimeMs = fs.statSync(file).mtimeMs;
|
|
12720
|
+
} catch {
|
|
12721
|
+
return null;
|
|
12722
|
+
}
|
|
12723
|
+
const hit = _moduleCache.get(file);
|
|
12724
|
+
if (hit && hit.mtimeMs === mtimeMs) return hit.mod;
|
|
12725
|
+
let mod = null;
|
|
12726
|
+
try {
|
|
12727
|
+
const src = fs.readFileSync(file, "utf8");
|
|
12728
|
+
const r = (0, import_oxc_parser2.parseSync)(file, src);
|
|
12729
|
+
if (r.errors.length === 0) {
|
|
12730
|
+
const body = r.program.body;
|
|
12731
|
+
const scopes = buildScopeTree(body, src.length);
|
|
12732
|
+
markReassignments(body, scopes);
|
|
12733
|
+
mod = { file, src, body, scopes };
|
|
12734
|
+
}
|
|
12735
|
+
} catch {
|
|
12736
|
+
}
|
|
12737
|
+
_moduleCache.set(file, { mtimeMs, mod });
|
|
12738
|
+
return mod;
|
|
12739
|
+
}
|
|
12740
|
+
var SOURCE_EXTS = [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".jsx"];
|
|
12741
|
+
function resolveImport(fromFile, specifier) {
|
|
12742
|
+
if (specifier.startsWith(".") || path.isAbsolute(specifier)) {
|
|
12743
|
+
const base = path.resolve(path.dirname(fromFile), specifier);
|
|
12744
|
+
const ext = path.extname(base);
|
|
12745
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
12746
|
+
const candidates = [
|
|
12747
|
+
...ext ? [base] : [],
|
|
12748
|
+
// `./x.js` in TS source usually means `./x.ts`.
|
|
12749
|
+
...SOURCE_EXTS.map((e) => `${stem}${e}`),
|
|
12750
|
+
...SOURCE_EXTS.map((e) => path.join(base, `index${e}`))
|
|
12751
|
+
];
|
|
12752
|
+
for (const c of candidates) {
|
|
12753
|
+
try {
|
|
12754
|
+
if (fs.statSync(c).isFile()) return fs.realpathSync(c);
|
|
12755
|
+
} catch {
|
|
12756
|
+
}
|
|
12757
|
+
}
|
|
12758
|
+
return null;
|
|
12759
|
+
}
|
|
12760
|
+
try {
|
|
12761
|
+
return fs.realpathSync((0, import_node_module.createRequire)(fromFile).resolve(specifier));
|
|
12762
|
+
} catch {
|
|
12763
|
+
return null;
|
|
12764
|
+
}
|
|
12765
|
+
}
|
|
12766
|
+
function declarationBinds(decl, name) {
|
|
12767
|
+
if (decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration") {
|
|
12768
|
+
return decl.id?.name === name;
|
|
12769
|
+
}
|
|
12770
|
+
if (decl.type === "VariableDeclaration") {
|
|
12771
|
+
const names = [];
|
|
12772
|
+
for (const d of decl.declarations ?? []) patternNames(d.id, names);
|
|
12773
|
+
return names.includes(name);
|
|
12774
|
+
}
|
|
12775
|
+
return false;
|
|
12776
|
+
}
|
|
12777
|
+
function exportedBinding(mod, name, seen) {
|
|
12778
|
+
for (const stmt of mod.body) {
|
|
12779
|
+
if (stmt.type === "ExportDefaultDeclaration" && name === "default") {
|
|
12780
|
+
const d = stmt.declaration;
|
|
12781
|
+
if (FUNCTION_TYPES.has(d.type)) return { mod, binding: { kind: "const", init: d } };
|
|
12782
|
+
if (d.type === "Identifier") {
|
|
12783
|
+
const hit2 = lookup(mod.scopes, d.name);
|
|
12784
|
+
return hit2 ? { mod, binding: hit2.binding } : null;
|
|
12785
|
+
}
|
|
12786
|
+
return null;
|
|
12787
|
+
}
|
|
12788
|
+
if (stmt.type === "ExportNamedDeclaration") {
|
|
12789
|
+
const decl = stmt.declaration;
|
|
12790
|
+
if (decl && declarationBinds(decl, name)) {
|
|
12791
|
+
const hit2 = lookup(mod.scopes, name);
|
|
12792
|
+
if (hit2 && hit2.scope === mod.scopes) return { mod, binding: hit2.binding };
|
|
12793
|
+
}
|
|
12794
|
+
for (const sp of stmt.specifiers ?? []) {
|
|
12795
|
+
const exported = sp.exported?.name ?? "";
|
|
12796
|
+
if (exported !== name) continue;
|
|
12797
|
+
const local = sp.local?.name ?? exported;
|
|
12798
|
+
const from = stmt.source?.value;
|
|
12799
|
+
if (from !== void 0) return followReExport(mod, from, local, seen);
|
|
12800
|
+
const hit2 = lookup(mod.scopes, local);
|
|
12801
|
+
return hit2 ? { mod, binding: hit2.binding } : null;
|
|
12802
|
+
}
|
|
12803
|
+
}
|
|
12804
|
+
if (stmt.type === "ExportAllDeclaration" && !stmt.exported) {
|
|
12805
|
+
const from = stmt.source?.value;
|
|
12806
|
+
if (from === void 0) continue;
|
|
12807
|
+
const found = followReExport(mod, from, name, seen);
|
|
12808
|
+
if (found) return found;
|
|
12809
|
+
}
|
|
12810
|
+
}
|
|
12811
|
+
const hit = lookup(mod.scopes, name);
|
|
12812
|
+
return hit && hit.scope === mod.scopes ? { mod, binding: hit.binding } : null;
|
|
12813
|
+
}
|
|
12814
|
+
function followReExport(mod, specifier, name, seen) {
|
|
12815
|
+
const file = resolveImport(mod.file, specifier);
|
|
12816
|
+
if (!file || seen.has(`${file}\0${name}`)) return null;
|
|
12817
|
+
seen.add(`${file}\0${name}`);
|
|
12818
|
+
const next = analyseModuleFile(file);
|
|
12819
|
+
return next ? exportedBinding(next, name, seen) : null;
|
|
12820
|
+
}
|
|
12821
|
+
var MAX_HOPS = 12;
|
|
12822
|
+
var IDENT_RE = /^[A-Za-z_$][\w$]*$/;
|
|
12823
|
+
var MEMBER_RE = /^([A-Za-z_$][\w$]*)\s*\.\s*([A-Za-z_$][\w$]*)$/;
|
|
12824
|
+
function createReducerResolver(entryFile, body, src) {
|
|
12825
|
+
const scopes = buildScopeTree(body, src.length);
|
|
12826
|
+
markReassignments(body, scopes);
|
|
12827
|
+
const entry = { file: entryFile, src, body, scopes };
|
|
12828
|
+
const fromBinding = (mod, binding, memberName, hops, seen) => {
|
|
12829
|
+
if (hops > MAX_HOPS) return { arity: null, src: null, reason: "not-found" };
|
|
12830
|
+
if (binding.reassigned) return { arity: null, src: null, reason: "reassigned" };
|
|
12831
|
+
if (binding.kind === "param" || binding.kind === "catch" || binding.kind === "class") {
|
|
12832
|
+
return { arity: null, src: null, reason: "not-a-function" };
|
|
12833
|
+
}
|
|
12834
|
+
if (binding.kind === "import" && binding.importRef) {
|
|
12835
|
+
const { specifier, imported } = binding.importRef;
|
|
12836
|
+
if (imported === "*" && memberName === void 0) return { arity: null, src: null, reason: "not-a-function" };
|
|
12837
|
+
const file = resolveImport(mod.file, specifier);
|
|
12838
|
+
if (!file) return { arity: null, src: null, reason: "unresolved-import" };
|
|
12839
|
+
const next = analyseModuleFile(file);
|
|
12840
|
+
if (!next) return { arity: null, src: null, reason: "unresolved-import" };
|
|
12841
|
+
const wanted = imported === "*" ? memberName : imported;
|
|
12842
|
+
if (wanted === void 0) return { arity: null, src: null, reason: "not-a-function" };
|
|
12843
|
+
const found = exportedBinding(next, wanted, seen);
|
|
12844
|
+
if (!found) return { arity: null, src: null, reason: "not-found" };
|
|
12845
|
+
return fromBinding(found.mod, found.binding, void 0, hops + 1, seen);
|
|
12846
|
+
}
|
|
12847
|
+
const init = binding.init;
|
|
12848
|
+
if (!init) return { arity: null, src: null, reason: "not-a-function" };
|
|
12849
|
+
if (init.type === "Identifier") {
|
|
12850
|
+
const hit = lookup(scopeAt(mod.scopes, init.start), init.name);
|
|
12851
|
+
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12852
|
+
return fromBinding(mod, hit.binding, void 0, hops + 1, seen);
|
|
12853
|
+
}
|
|
12854
|
+
if (init.type === "ComputedMemberExpression" || init.computed === true && init.type.endsWith("MemberExpression")) {
|
|
12855
|
+
return { arity: null, src: null, reason: "computed" };
|
|
12856
|
+
}
|
|
12857
|
+
if (init.type === "StaticMemberExpression" || init.type === "MemberExpression") {
|
|
12858
|
+
const obj = init.object;
|
|
12859
|
+
const prop = init.property;
|
|
12860
|
+
if (obj?.type === "Identifier" && prop?.type === "Identifier") {
|
|
12861
|
+
const hit = lookup(scopeAt(mod.scopes, init.start), obj.name);
|
|
12862
|
+
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12863
|
+
return fromBinding(mod, hit.binding, prop.name, hops + 1, seen);
|
|
12864
|
+
}
|
|
12865
|
+
return { arity: null, src: null, reason: "computed" };
|
|
12866
|
+
}
|
|
12867
|
+
if (!FUNCTION_TYPES.has(init.type)) return { arity: null, src: null, reason: "not-a-function" };
|
|
12868
|
+
const { arity, reason } = functionArity(init);
|
|
12869
|
+
return { arity, src: mod.src.slice(init.start, init.end), ...reason ? { reason } : {} };
|
|
12870
|
+
};
|
|
12871
|
+
return {
|
|
12872
|
+
resolve(exprSrc, offset, offsetSrc) {
|
|
12873
|
+
const text = exprSrc.trim();
|
|
12874
|
+
const ident = IDENT_RE.test(text) ? text : null;
|
|
12875
|
+
const member = ident ? null : MEMBER_RE.exec(text);
|
|
12876
|
+
if (!ident && !member) return null;
|
|
12877
|
+
if (offsetSrc !== src) return { arity: null, src: null, reason: "foreign-source" };
|
|
12878
|
+
const name = ident ?? member[1];
|
|
12879
|
+
const memberName = ident ? void 0 : member[2];
|
|
12880
|
+
const hit = lookup(scopeAt(scopes, offset), name);
|
|
12881
|
+
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12882
|
+
return fromBinding(entry, hit.binding, memberName, 0, /* @__PURE__ */ new Set());
|
|
12883
|
+
}
|
|
12884
|
+
};
|
|
12885
|
+
}
|
|
12886
|
+
|
|
12510
12887
|
// src/plugin/index.ts
|
|
12511
12888
|
var import_node_crypto = require("node:crypto");
|
|
12512
12889
|
var PARSEMAN_MODULE = "parseman";
|
|
@@ -12532,37 +12909,37 @@ function getCompiledResolver() {
|
|
|
12532
12909
|
}
|
|
12533
12910
|
var PRIVATE_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts"]);
|
|
12534
12911
|
function nearestPackageRoot(file) {
|
|
12535
|
-
let dir =
|
|
12912
|
+
let dir = path2.dirname(file);
|
|
12536
12913
|
for (; ; ) {
|
|
12537
12914
|
try {
|
|
12538
|
-
if (
|
|
12915
|
+
if (fs2.statSync(path2.join(dir, "package.json")).isFile()) return fs2.realpathSync(dir);
|
|
12539
12916
|
} catch {
|
|
12540
12917
|
}
|
|
12541
|
-
const parent =
|
|
12918
|
+
const parent = path2.dirname(dir);
|
|
12542
12919
|
if (parent === dir) return null;
|
|
12543
12920
|
dir = parent;
|
|
12544
12921
|
}
|
|
12545
12922
|
}
|
|
12546
12923
|
function isWithinPackageRoot(file, root) {
|
|
12547
|
-
const relative2 =
|
|
12548
|
-
return relative2 !== ".." && !relative2.startsWith(`..${
|
|
12924
|
+
const relative2 = path2.relative(root, file);
|
|
12925
|
+
return relative2 !== ".." && !relative2.startsWith(`..${path2.sep}`) && !path2.isAbsolute(relative2);
|
|
12549
12926
|
}
|
|
12550
12927
|
function resolvePrivateSourceModule(from, specifier) {
|
|
12551
|
-
if (!specifier.startsWith(".") && !
|
|
12928
|
+
if (!specifier.startsWith(".") && !path2.isAbsolute(specifier)) return null;
|
|
12552
12929
|
const packageRoot = nearestPackageRoot(from);
|
|
12553
12930
|
if (!packageRoot) return null;
|
|
12554
|
-
const base =
|
|
12555
|
-
const ext =
|
|
12931
|
+
const base = path2.resolve(path2.dirname(from), specifier);
|
|
12932
|
+
const ext = path2.extname(base);
|
|
12556
12933
|
const candidates = [
|
|
12557
12934
|
base,
|
|
12558
12935
|
...ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base.slice(0, -ext.length)}${next}`) : [],
|
|
12559
12936
|
...!ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base}${next}`) : [],
|
|
12560
|
-
...!ext ? ["index.ts", "index.tsx", "index.mts", "index.cts"].map((next) =>
|
|
12937
|
+
...!ext ? ["index.ts", "index.tsx", "index.mts", "index.cts"].map((next) => path2.join(base, next)) : []
|
|
12561
12938
|
];
|
|
12562
12939
|
for (const candidate of candidates) {
|
|
12563
12940
|
try {
|
|
12564
|
-
if (!
|
|
12565
|
-
const real =
|
|
12941
|
+
if (!fs2.statSync(candidate).isFile()) continue;
|
|
12942
|
+
const real = fs2.realpathSync(candidate);
|
|
12566
12943
|
if (isWithinPackageRoot(real, packageRoot)) return real;
|
|
12567
12944
|
} catch {
|
|
12568
12945
|
}
|
|
@@ -12570,7 +12947,7 @@ function resolvePrivateSourceModule(from, specifier) {
|
|
|
12570
12947
|
return null;
|
|
12571
12948
|
}
|
|
12572
12949
|
function resolveGrammarModule(from, specifier) {
|
|
12573
|
-
if (PRIVATE_SOURCE_EXTENSIONS.has(
|
|
12950
|
+
if (PRIVATE_SOURCE_EXTENSIONS.has(path2.extname(specifier))) {
|
|
12574
12951
|
const file2 = resolvePrivateSourceModule(from, specifier);
|
|
12575
12952
|
return file2 ? { file: file2, source: true } : null;
|
|
12576
12953
|
}
|
|
@@ -12591,7 +12968,7 @@ var _moduleParseCache = /* @__PURE__ */ new Map();
|
|
|
12591
12968
|
function parseModuleCached(filePath) {
|
|
12592
12969
|
let mtimeMs;
|
|
12593
12970
|
try {
|
|
12594
|
-
mtimeMs =
|
|
12971
|
+
mtimeMs = fs2.statSync(filePath).mtimeMs;
|
|
12595
12972
|
} catch {
|
|
12596
12973
|
return null;
|
|
12597
12974
|
}
|
|
@@ -12599,8 +12976,8 @@ function parseModuleCached(filePath) {
|
|
|
12599
12976
|
if (hit && hit.mtimeMs === mtimeMs) return hit.parsed;
|
|
12600
12977
|
let parsed = null;
|
|
12601
12978
|
try {
|
|
12602
|
-
const src =
|
|
12603
|
-
const r = (0,
|
|
12979
|
+
const src = fs2.readFileSync(filePath, "utf8");
|
|
12980
|
+
const r = (0, import_oxc_parser3.parseSync)(filePath, src);
|
|
12604
12981
|
if (r.errors.length === 0) parsed = { body: r.program.body, src };
|
|
12605
12982
|
} catch {
|
|
12606
12983
|
}
|
|
@@ -12728,7 +13105,7 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
12728
13105
|
if (_sourceLowering.has(file)) return null;
|
|
12729
13106
|
let mtimeMs;
|
|
12730
13107
|
try {
|
|
12731
|
-
mtimeMs =
|
|
13108
|
+
mtimeMs = fs2.statSync(file).mtimeMs;
|
|
12732
13109
|
} catch {
|
|
12733
13110
|
return null;
|
|
12734
13111
|
}
|
|
@@ -12738,10 +13115,10 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
12738
13115
|
_sourceLowering.add(file);
|
|
12739
13116
|
let parsedModule = null;
|
|
12740
13117
|
try {
|
|
12741
|
-
const source =
|
|
13118
|
+
const source = fs2.readFileSync(file, "utf8");
|
|
12742
13119
|
const transformed = transformMacro(source, file, moduleAliases, warnUnloweredRegex, recovery);
|
|
12743
13120
|
if (!transformed || transformed.warnings.length > 0) return null;
|
|
12744
|
-
const parsed = (0,
|
|
13121
|
+
const parsed = (0, import_oxc_parser3.parseSync)(file, transformed.code);
|
|
12745
13122
|
parsedModule = parsed.errors.length === 0 ? { body: parsed.program.body, src: transformed.code } : null;
|
|
12746
13123
|
return parsedModule;
|
|
12747
13124
|
} catch {
|
|
@@ -12752,9 +13129,20 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
12752
13129
|
}
|
|
12753
13130
|
}
|
|
12754
13131
|
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false, grammarCoverage = false) {
|
|
13132
|
+
const depth = degradationCaptureDepth();
|
|
13133
|
+
try {
|
|
13134
|
+
return transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recovery, grammarCoverage);
|
|
13135
|
+
} finally {
|
|
13136
|
+
setReducerResolver(null);
|
|
13137
|
+
endLoweringCapture();
|
|
13138
|
+
endInlineCapCapture();
|
|
13139
|
+
for (const d of unwindDegradationCapture(depth)) console.warn(formatDegradation(d));
|
|
13140
|
+
}
|
|
13141
|
+
}
|
|
13142
|
+
function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recovery, grammarCoverage) {
|
|
12755
13143
|
let result;
|
|
12756
13144
|
try {
|
|
12757
|
-
result = (0,
|
|
13145
|
+
result = (0, import_oxc_parser3.parseSync)(id, code);
|
|
12758
13146
|
} catch {
|
|
12759
13147
|
return null;
|
|
12760
13148
|
}
|
|
@@ -12811,6 +13199,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
12811
13199
|
}
|
|
12812
13200
|
}
|
|
12813
13201
|
}
|
|
13202
|
+
setReducerResolver(createReducerResolver(id, body, code));
|
|
12814
13203
|
const topLevelFunction = (moduleBody, name) => {
|
|
12815
13204
|
for (const st of moduleBody) {
|
|
12816
13205
|
const decl = st.type === "ExportNamedDeclaration" ? st.declaration : st;
|
|
@@ -12910,6 +13299,8 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
12910
13299
|
const replacements = [];
|
|
12911
13300
|
const warnings = [];
|
|
12912
13301
|
beginLoweringCapture();
|
|
13302
|
+
beginInlineCapCapture();
|
|
13303
|
+
beginDegradationCapture();
|
|
12913
13304
|
let anyUnresolved = false;
|
|
12914
13305
|
let keepMacroImport = false;
|
|
12915
13306
|
let runtimeComposeFallback = false;
|
|
@@ -13025,7 +13416,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13025
13416
|
const mapLit = (m, stripVals = false) => `new Map([${[...m].map(
|
|
13026
13417
|
([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(stripVals && typeof v2 === "string" ? stripIndent(v2) : v2)}]`
|
|
13027
13418
|
).join(", ")}])`;
|
|
13028
|
-
return `{ v: ${JSON.stringify(p.v)}, 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)}, nullable: ${p.nullable ? mapLit(p.nullable) : "new Map()"}, firstSetRecipes: ${p.firstSetRecipes ? mapLit(p.firstSetRecipes) : "new Map()"}, deps: ${mapLit(p.deps)}, nodeMeta: ${mapLit(p.nodeMeta)}, hostMode: ${JSON.stringify(p.hostMode ?? "ast")}, hostBranchElided: ${p.hostBranchElided === true}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, hasDirectBuilders: ${p.hasDirectBuilders === true}, isRecognitionOnly: ${p.isRecognitionOnly === true}, mfFns: [], buildFns: [] }`;
|
|
13419
|
+
return `{ v: ${JSON.stringify(p.v)}, 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)}, nullable: ${p.nullable ? mapLit(p.nullable) : "new Map()"}, firstSetRecipes: ${p.firstSetRecipes ? mapLit(p.firstSetRecipes) : "new Map()"}, deps: ${mapLit(p.deps)}, nodeMeta: ${mapLit(p.nodeMeta)}, hostMode: ${JSON.stringify(p.hostMode ?? "ast")}, hostBranchElided: ${p.hostBranchElided === true}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, needsRawEntry: ${p.needsRawEntry}, hasDirectBuilders: ${p.hasDirectBuilders === true}, isRecognitionOnly: ${p.isRecognitionOnly === true}, mfFns: [], buildFns: [] }`;
|
|
13029
13420
|
};
|
|
13030
13421
|
const isSpread = (it) => "__spreadLocal" in it;
|
|
13031
13422
|
const isIR = (it) => "ir" in it && !("ruleFns" in it);
|
|
@@ -13036,9 +13427,19 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13036
13427
|
const withHostMode = (grammarExpr, mode, elided) => `/* @__PURE__ */ (m => { for (const k of Object.keys(m)) { Object.defineProperty(m[k], Symbol.for('parseman.fusedHostMode'), { value: ${JSON.stringify(mode)}, enumerable: false }); Object.defineProperty(m[k], Symbol.for('parseman.fusedHostElided'), { value: ${JSON.stringify(elided)}, enumerable: false }) } Object.defineProperty(m, Symbol.for('parseman.fusedHostMode'), { value: ${JSON.stringify(mode)}, enumerable: false }); Object.defineProperty(m, Symbol.for('parseman.fusedHostElided'), { value: ${JSON.stringify(elided)}, enumerable: false }); return m })(${grammarExpr})`;
|
|
13037
13428
|
const withGrammarReflection = (grammarExpr, reflection) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.grammarReflection'), { value: ${grammarReflectionSource(reflection)}, enumerable: false })`;
|
|
13038
13429
|
const withCoverageDefinitions = (grammarExpr, definitions) => !grammarCoverage ? grammarExpr : `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.grammarCoverageDefinitions'), { value: Object.freeze(${JSON.stringify(definitions)}.map(Object.freeze)), enumerable: false })`;
|
|
13039
|
-
const emittedCoverageDefinitions = (source) => {
|
|
13430
|
+
const emittedCoverageDefinitions = (source, where) => {
|
|
13040
13431
|
const ids = /* @__PURE__ */ new Set();
|
|
13041
13432
|
for (const match of source.matchAll(/id:\s*"([^"]+)"/g)) ids.add(match[1]);
|
|
13433
|
+
if (grammarCoverage && ids.size === 0) {
|
|
13434
|
+
recordDegradation({
|
|
13435
|
+
code: "coverage-definitions-unavailable",
|
|
13436
|
+
severity: "warn",
|
|
13437
|
+
where,
|
|
13438
|
+
subject: "generated coverage hooks",
|
|
13439
|
+
fellBackTo: "no coverage definitions could be read out of the generated source, so the grammar carries an EMPTY definition set \u2014 which is no measurement, not full coverage",
|
|
13440
|
+
otherwise: "the emitted hook IDs would form the coverage denominator"
|
|
13441
|
+
});
|
|
13442
|
+
}
|
|
13042
13443
|
return [...ids].sort().map((id2) => ({
|
|
13043
13444
|
id: id2,
|
|
13044
13445
|
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : id2.startsWith("dispatch:") ? "dispatch-arm" : "choice-arm"
|
|
@@ -13107,26 +13508,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13107
13508
|
}
|
|
13108
13509
|
return out;
|
|
13109
13510
|
};
|
|
13110
|
-
const carriedRuleMapsDetailed = (items) => {
|
|
13111
|
-
const maps = [];
|
|
13112
|
-
const opaque = [];
|
|
13113
|
-
const add = (it) => {
|
|
13114
|
-
if (isIR(it)) {
|
|
13115
|
-
maps.push(evalRuleMapIR(it.ir));
|
|
13116
|
-
return;
|
|
13117
|
-
}
|
|
13118
|
-
const o = it;
|
|
13119
|
-
opaque.push({
|
|
13120
|
-
ns: o.ns ?? "<unknown>",
|
|
13121
|
-
ruleNames: o.ruleFns instanceof Map ? [...o.ruleFns.keys()] : []
|
|
13122
|
-
});
|
|
13123
|
-
};
|
|
13124
|
-
for (const it of items) {
|
|
13125
|
-
if (isSpread(it)) for (const p of importedPieces(it.__spreadLocal) ?? []) add(p);
|
|
13126
|
-
else add(it);
|
|
13127
|
-
}
|
|
13128
|
-
return { maps, opaque };
|
|
13129
|
-
};
|
|
13130
13511
|
const materializeLeafCoverage = (items, localRules, localNs, composing, captureTerminals = false) => {
|
|
13131
13512
|
const sources = [];
|
|
13132
13513
|
const add = (item) => {
|
|
@@ -13277,12 +13658,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13277
13658
|
carried.push(...r.carried);
|
|
13278
13659
|
importedFactories.push(...r.importedFactories ?? []);
|
|
13279
13660
|
}
|
|
13280
|
-
const detailed = once(() => carriedRuleMapsDetailed(carried));
|
|
13281
|
-
runFusedGatingDiagnostic(
|
|
13282
|
-
() => detailed().maps,
|
|
13283
|
-
void 0,
|
|
13284
|
-
() => detailed().opaque
|
|
13285
|
-
);
|
|
13286
13661
|
const pieces = materializeCarried(carried, composing, false, cHostMode);
|
|
13287
13662
|
try {
|
|
13288
13663
|
return {
|
|
@@ -13339,12 +13714,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13339
13714
|
}
|
|
13340
13715
|
try {
|
|
13341
13716
|
const localNs = nsFor(`composeLeaf${init.start}`);
|
|
13342
|
-
const detailedLeaf = once(() => carriedRuleMapsDetailed(carried));
|
|
13343
|
-
runFusedGatingDiagnostic(
|
|
13344
|
-
() => [...detailedLeaf().maps, [...localRules]],
|
|
13345
|
-
void 0,
|
|
13346
|
-
() => detailedLeaf().opaque
|
|
13347
|
-
);
|
|
13348
13717
|
const plainLocalPiece = compileLinkable([...localRules], localNs, { ...composing ? { trivia: composing } : {}, ...localScanSkip ? { scanSkip: localScanSkip } : {}, recovery });
|
|
13349
13718
|
if (!plainLocalPiece) {
|
|
13350
13719
|
warn(init.start, "composeLeaf(): local rules could not be statically compiled");
|
|
@@ -13362,7 +13731,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13362
13731
|
}
|
|
13363
13732
|
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
|
|
13364
13733
|
return {
|
|
13365
|
-
replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)),
|
|
13734
|
+
replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement, `${id} composeLeaf()`)),
|
|
13366
13735
|
...importedFactories.length ? { importedFactories } : {}
|
|
13367
13736
|
};
|
|
13368
13737
|
} catch (e) {
|
|
@@ -13442,7 +13811,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13442
13811
|
const refEntry = scope.get(varName);
|
|
13443
13812
|
const refCombi = refEntry?.combi ?? null;
|
|
13444
13813
|
if (refCombi) {
|
|
13445
|
-
const compiled2 = compile(refCombi, void 0, { recovery, coverage: grammarCoverage
|
|
13814
|
+
const compiled2 = compile(refCombi, void 0, { recovery, coverage: grammarCoverage });
|
|
13446
13815
|
if (compiled2.inlineExpression === null) {
|
|
13447
13816
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
13448
13817
|
continue;
|
|
@@ -13473,7 +13842,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13473
13842
|
const source = compiledRules.replacement ?? code.slice(init.start, init.end);
|
|
13474
13843
|
let replacement = withCoverageDefinitions(
|
|
13475
13844
|
source,
|
|
13476
|
-
compiledRules.coverageDefinitions?.length ? compiledRules.coverageDefinitions : emittedCoverageDefinitions(source)
|
|
13845
|
+
compiledRules.coverageDefinitions?.length ? compiledRules.coverageDefinitions : emittedCoverageDefinitions(source, `${id} rules()`)
|
|
13477
13846
|
);
|
|
13478
13847
|
if (compiledRules.replacement !== null) {
|
|
13479
13848
|
replacement = withHostMode(replacement, compiledRules.hostMode, compiledRules.hostBranchElided);
|
|
@@ -13498,7 +13867,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13498
13867
|
localComposedCarried.set(varName, fused.carried);
|
|
13499
13868
|
if (fused.trivia) localComposedTrivia.set(varName, fused.trivia);
|
|
13500
13869
|
const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.carried) : fused.replacement;
|
|
13501
|
-
replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) });
|
|
13870
|
+
replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement, `${id} compose()`)) });
|
|
13502
13871
|
markUsedImportedFactories(fused.importedFactories);
|
|
13503
13872
|
continue;
|
|
13504
13873
|
}
|
|
@@ -13549,7 +13918,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13549
13918
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
13550
13919
|
continue;
|
|
13551
13920
|
}
|
|
13552
|
-
const compiled = compile(parser2, void 0, { recovery, coverage: grammarCoverage
|
|
13921
|
+
const compiled = compile(parser2, void 0, { recovery, coverage: grammarCoverage });
|
|
13553
13922
|
if (compiled.inlineExpression === null) {
|
|
13554
13923
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
13555
13924
|
continue;
|
|
@@ -13675,12 +14044,23 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13675
14044
|
`
|
|
13676
14045
|
);
|
|
13677
14046
|
}
|
|
14047
|
+
for (const line of formatInlineCapSites(endInlineCapCapture(), resolveInlineMax())) warnings.push(`${id}: ${line}`);
|
|
13678
14048
|
const unlowered = endLoweringCapture();
|
|
13679
14049
|
if (warnUnloweredRegex) {
|
|
13680
14050
|
for (const src of unlowered) {
|
|
13681
14051
|
warnings.push(`${id}: regex ${src} did not lower to a fast charCodeAt scan (RegExp.exec fallback)`);
|
|
13682
14052
|
}
|
|
13683
14053
|
}
|
|
14054
|
+
setReducerResolver(null);
|
|
14055
|
+
const degradations = endDegradationCapture();
|
|
14056
|
+
if (degradations.length > 0) {
|
|
14057
|
+
const lines = formatDegradations(degradations);
|
|
14058
|
+
if (resolveDegradationLevel() === "error") {
|
|
14059
|
+
throw new Error(`parseman: ${degradations.length} degraded compilation path(s) in ${id}
|
|
14060
|
+
${lines.join("\n")}`);
|
|
14061
|
+
}
|
|
14062
|
+
for (const l of lines) warnings.push(`${id}: ${l}`);
|
|
14063
|
+
}
|
|
13684
14064
|
return {
|
|
13685
14065
|
code: ms.toString(),
|
|
13686
14066
|
map: ms.generateMap({ hires: true }),
|