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.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// src/plugin/index.ts
|
|
2
|
-
import * as
|
|
3
|
-
import * as
|
|
2
|
+
import * as fs2 from "node:fs";
|
|
3
|
+
import * as path2 from "node:path";
|
|
4
4
|
import { createUnplugin } from "unplugin";
|
|
5
|
-
import { parseSync as
|
|
5
|
+
import { parseSync as parseSync3 } from "oxc-parser";
|
|
6
6
|
import { ResolverFactory } from "oxc-resolver";
|
|
7
7
|
import MagicString from "magic-string";
|
|
8
8
|
|
|
9
9
|
// src/combinators/first-set.ts
|
|
10
|
-
function resolveNamedRef(p,
|
|
11
|
-
if (
|
|
10
|
+
function resolveNamedRef(p, resolve3) {
|
|
11
|
+
if (resolve3 === void 0) return void 0;
|
|
12
12
|
const name = p._ruleName;
|
|
13
|
-
return name === void 0 ? void 0 :
|
|
13
|
+
return name === void 0 ? void 0 : resolve3(name);
|
|
14
14
|
}
|
|
15
15
|
function union(a, b) {
|
|
16
16
|
if (a.kind === "any" || b.kind === "any") return { kind: "any" };
|
|
@@ -32,12 +32,12 @@ function fromChar(code) {
|
|
|
32
32
|
return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
|
|
33
33
|
}
|
|
34
34
|
function startsFirstSet(combinator, input, pos) {
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
37
|
-
if (
|
|
35
|
+
const fs3 = combinator._meta.firstSet;
|
|
36
|
+
if (fs3.kind === "any") return true;
|
|
37
|
+
if (fs3.kind === "empty") return false;
|
|
38
38
|
const code = input.codePointAt(pos);
|
|
39
39
|
if (code === void 0) return false;
|
|
40
|
-
for (const r of
|
|
40
|
+
for (const r of fs3.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
43
|
function fromRange(lo, hi) {
|
|
@@ -49,18 +49,19 @@ function any() {
|
|
|
49
49
|
function empty() {
|
|
50
50
|
return { kind: "empty" };
|
|
51
51
|
}
|
|
52
|
-
function matchesEmpty(p, seen = /* @__PURE__ */ new Set(),
|
|
52
|
+
function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve3) {
|
|
53
53
|
if (seen.has(p)) return true;
|
|
54
54
|
seen.add(p);
|
|
55
|
-
const me = (c) => matchesEmpty(c, seen,
|
|
55
|
+
const me = (c) => matchesEmpty(c, seen, resolve3);
|
|
56
56
|
const d = p._def;
|
|
57
57
|
switch (d.tag) {
|
|
58
58
|
case "literal":
|
|
59
59
|
return d.value.length === 0;
|
|
60
60
|
case "keywords":
|
|
61
61
|
return false;
|
|
62
|
+
// The routed token itself is the selector's match, never empty; a fallback can be.
|
|
62
63
|
case "routed":
|
|
63
|
-
return false;
|
|
64
|
+
return d.fallback === void 0 ? false : me(d.fallback);
|
|
64
65
|
case "regex":
|
|
65
66
|
try {
|
|
66
67
|
const m = new RegExp(d.source).exec("");
|
|
@@ -106,7 +107,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
106
107
|
try {
|
|
107
108
|
return me(d.thunk());
|
|
108
109
|
} catch {
|
|
109
|
-
const t = resolveNamedRef(p,
|
|
110
|
+
const t = resolveNamedRef(p, resolve3);
|
|
110
111
|
return t ? me(t) : true;
|
|
111
112
|
}
|
|
112
113
|
default:
|
|
@@ -132,29 +133,29 @@ function narrowBy(acc, constraint) {
|
|
|
132
133
|
}
|
|
133
134
|
return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
|
|
134
135
|
}
|
|
135
|
-
function applyAssertion(
|
|
136
|
-
if (assertion === null) return
|
|
137
|
-
if (
|
|
138
|
-
return narrowBy(
|
|
136
|
+
function applyAssertion(fs3, assertion) {
|
|
137
|
+
if (assertion === null) return fs3;
|
|
138
|
+
if (fs3.kind === "empty") return assertion;
|
|
139
|
+
return narrowBy(fs3, assertion) ?? fs3;
|
|
139
140
|
}
|
|
140
141
|
function sequenceFirstSet(parsers) {
|
|
141
|
-
let
|
|
142
|
+
let fs3 = empty();
|
|
142
143
|
let assertion = null;
|
|
143
144
|
for (const p of parsers) {
|
|
144
145
|
if (isPositiveLookahead(p)) {
|
|
145
146
|
assertion = narrowBy(assertion, p._meta.firstSet);
|
|
146
147
|
continue;
|
|
147
148
|
}
|
|
148
|
-
if (!isZeroWidthAssertion(p))
|
|
149
|
-
if (!matchesEmpty(p)) return applyAssertion(
|
|
149
|
+
if (!isZeroWidthAssertion(p)) fs3 = union(fs3, p._meta.firstSet);
|
|
150
|
+
if (!matchesEmpty(p)) return applyAssertion(fs3, assertion);
|
|
150
151
|
}
|
|
151
|
-
return applyAssertion(
|
|
152
|
+
return applyAssertion(fs3, assertion);
|
|
152
153
|
}
|
|
153
|
-
function firstSetOf(p, seen = /* @__PURE__ */ new Set(),
|
|
154
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve3) {
|
|
154
155
|
if (seen.has(p)) return any();
|
|
155
156
|
seen.add(p);
|
|
156
|
-
const
|
|
157
|
-
const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(),
|
|
157
|
+
const fs3 = (c) => firstSetOf(c, seen, resolve3);
|
|
158
|
+
const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve3);
|
|
158
159
|
const d = p._def;
|
|
159
160
|
switch (d.tag) {
|
|
160
161
|
case "literal":
|
|
@@ -163,17 +164,17 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
163
164
|
return p._meta.firstSet;
|
|
164
165
|
// terminals: no refs, cached set is exact
|
|
165
166
|
case "dispatch":
|
|
166
|
-
return
|
|
167
|
+
return fs3(d.selector);
|
|
167
168
|
case "lazy":
|
|
168
169
|
try {
|
|
169
|
-
return
|
|
170
|
+
return fs3(d.thunk());
|
|
170
171
|
} catch {
|
|
171
|
-
const t = resolveNamedRef(p,
|
|
172
|
-
return t ?
|
|
172
|
+
const t = resolveNamedRef(p, resolve3);
|
|
173
|
+
return t ? fs3(t) : any();
|
|
173
174
|
}
|
|
174
175
|
case "choice": {
|
|
175
176
|
let out = empty();
|
|
176
|
-
for (const arm of d.parsers) out = union(out,
|
|
177
|
+
for (const arm of d.parsers) out = union(out, fs3(arm));
|
|
177
178
|
return out;
|
|
178
179
|
}
|
|
179
180
|
case "sequence": {
|
|
@@ -181,17 +182,17 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
181
182
|
let assertion = null;
|
|
182
183
|
for (const term of d.parsers) {
|
|
183
184
|
if (isPositiveLookahead(term)) {
|
|
184
|
-
assertion = narrowBy(assertion,
|
|
185
|
+
assertion = narrowBy(assertion, fs3(term));
|
|
185
186
|
continue;
|
|
186
187
|
}
|
|
187
|
-
if (!isZeroWidthAssertion(term)) out = union(out,
|
|
188
|
+
if (!isZeroWidthAssertion(term)) out = union(out, fs3(term));
|
|
188
189
|
if (!empties(term)) return applyAssertion(out, assertion);
|
|
189
190
|
}
|
|
190
191
|
return applyAssertion(out, assertion);
|
|
191
192
|
}
|
|
192
193
|
case "peek": {
|
|
193
194
|
const inner = d.parser;
|
|
194
|
-
return empties(inner) ? any() :
|
|
195
|
+
return empties(inner) ? any() : fs3(inner);
|
|
195
196
|
}
|
|
196
197
|
case "oneOrMore":
|
|
197
198
|
case "many":
|
|
@@ -204,12 +205,12 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
|
|
|
204
205
|
case "node":
|
|
205
206
|
case "grammar":
|
|
206
207
|
case "expect":
|
|
207
|
-
return
|
|
208
|
+
return fs3(d.parser);
|
|
208
209
|
case "sepBy":
|
|
209
|
-
return
|
|
210
|
+
return fs3(d.parser);
|
|
210
211
|
// both min 0 and min 1 start with the item
|
|
211
212
|
case "skip":
|
|
212
|
-
return
|
|
213
|
+
return fs3(d.main);
|
|
213
214
|
default:
|
|
214
215
|
return p._meta.firstSet;
|
|
215
216
|
}
|
|
@@ -680,13 +681,13 @@ function shortScanner(source, flags) {
|
|
|
680
681
|
return minOne && end === pos ? null : end;
|
|
681
682
|
};
|
|
682
683
|
}
|
|
683
|
-
function asciiCaseFold(
|
|
684
|
-
if (
|
|
685
|
-
const ranges =
|
|
684
|
+
function asciiCaseFold(fs3) {
|
|
685
|
+
if (fs3.kind !== "ranges") return fs3;
|
|
686
|
+
const ranges = fs3.ranges.map((r) => ({ lo: r.lo, hi: r.hi }));
|
|
686
687
|
const add = (lo, hi) => {
|
|
687
688
|
if (lo <= hi) ranges.push({ lo, hi });
|
|
688
689
|
};
|
|
689
|
-
for (const r of
|
|
690
|
+
for (const r of fs3.ranges) {
|
|
690
691
|
const uLo = Math.max(r.lo, 65), uHi = Math.min(r.hi, 90);
|
|
691
692
|
add(uLo + 32, uHi + 32);
|
|
692
693
|
const lLo = Math.max(r.lo, 97), lHi = Math.min(r.hi, 122);
|
|
@@ -744,9 +745,9 @@ function charNode(set, nl) {
|
|
|
744
745
|
return { t: "char", set, nl };
|
|
745
746
|
}
|
|
746
747
|
function rangesToSet(ranges) {
|
|
747
|
-
let
|
|
748
|
-
for (const [lo, hi] of ranges)
|
|
749
|
-
return
|
|
748
|
+
let fs3 = empty();
|
|
749
|
+
for (const [lo, hi] of ranges) fs3 = union(fs3, fromRange(lo, hi));
|
|
750
|
+
return fs3;
|
|
750
751
|
}
|
|
751
752
|
function rangesHaveNewline(ranges) {
|
|
752
753
|
return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
|
|
@@ -952,17 +953,17 @@ function firstSet(n) {
|
|
|
952
953
|
case "rep":
|
|
953
954
|
return firstSet(n.node);
|
|
954
955
|
case "alt": {
|
|
955
|
-
let
|
|
956
|
-
for (const arm of n.arms)
|
|
957
|
-
return
|
|
956
|
+
let fs3 = empty();
|
|
957
|
+
for (const arm of n.arms) fs3 = union(fs3, firstSet(arm));
|
|
958
|
+
return fs3;
|
|
958
959
|
}
|
|
959
960
|
case "seq": {
|
|
960
|
-
let
|
|
961
|
+
let fs3 = empty();
|
|
961
962
|
for (const part of n.parts) {
|
|
962
|
-
|
|
963
|
+
fs3 = union(fs3, firstSet(part));
|
|
963
964
|
if (!nullable(part)) break;
|
|
964
965
|
}
|
|
965
|
-
return
|
|
966
|
+
return fs3;
|
|
966
967
|
}
|
|
967
968
|
}
|
|
968
969
|
}
|
|
@@ -1637,12 +1638,12 @@ function orSentinel(a, b) {
|
|
|
1637
1638
|
}
|
|
1638
1639
|
};
|
|
1639
1640
|
}
|
|
1640
|
-
function firstSetSentinel(
|
|
1641
|
-
if (
|
|
1642
|
-
const ranges =
|
|
1641
|
+
function firstSetSentinel(fs3) {
|
|
1642
|
+
if (fs3.kind !== "ranges" || fs3.ranges.length === 0) return null;
|
|
1643
|
+
const ranges = fs3.ranges;
|
|
1643
1644
|
return {
|
|
1644
1645
|
_tag: "firstSetSentinel",
|
|
1645
|
-
_meta: { firstSet:
|
|
1646
|
+
_meta: { firstSet: fs3, canMatchNewline: false, isTrivia: false },
|
|
1646
1647
|
_def: { tag: "unknown" },
|
|
1647
1648
|
parse(input, pos) {
|
|
1648
1649
|
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
@@ -1684,11 +1685,11 @@ function sequence(...parsers) {
|
|
|
1684
1685
|
let followSentinels;
|
|
1685
1686
|
function parseTolerant(input, pos, ctx) {
|
|
1686
1687
|
followSentinels ??= parsers.map((_, i) => {
|
|
1687
|
-
const
|
|
1688
|
+
const fs3 = parsers.slice(i + 1).reduce(
|
|
1688
1689
|
(acc, p) => union(acc, firstSetOf(p)),
|
|
1689
1690
|
{ kind: "empty" }
|
|
1690
1691
|
);
|
|
1691
|
-
return firstSetSentinel(
|
|
1692
|
+
return firstSetSentinel(fs3);
|
|
1692
1693
|
});
|
|
1693
1694
|
const values = def.valueUnused ? void 0 : [];
|
|
1694
1695
|
let cur = pos;
|
|
@@ -1831,8 +1832,11 @@ function derive(c, seen) {
|
|
|
1831
1832
|
case "not":
|
|
1832
1833
|
case "peek":
|
|
1833
1834
|
return deriveExpected2(def.parser);
|
|
1835
|
+
// A bare routed() can only fail as "there is no routed token here". With a
|
|
1836
|
+
// fallback, THAT is the branch that can fail, so its expectations are the useful
|
|
1837
|
+
// ones — the routed path either succeeds or is not taken.
|
|
1834
1838
|
case "routed":
|
|
1835
|
-
return ["routed()"];
|
|
1839
|
+
return def.fallback === void 0 ? ["routed()"] : deriveExpected2(def.fallback);
|
|
1836
1840
|
case "lazy": {
|
|
1837
1841
|
const name = c._ruleName;
|
|
1838
1842
|
if (seen.has(c)) return name ? [name] : [];
|
|
@@ -2019,7 +2023,7 @@ function detectStrategy(parsers) {
|
|
|
2019
2023
|
function bareLeadingTermKey(term) {
|
|
2020
2024
|
const d = term._def;
|
|
2021
2025
|
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
2022
|
-
if (d.tag === "regex") return `R:${d.source
|
|
2026
|
+
if (d.tag === "regex") return `R:${JSON.stringify([d.source, d.flags])}`;
|
|
2023
2027
|
return null;
|
|
2024
2028
|
}
|
|
2025
2029
|
function detectSharedPrefix(parsers) {
|
|
@@ -2135,10 +2139,10 @@ function codesToFirstSet(codes) {
|
|
|
2135
2139
|
ranges.push({ lo, hi });
|
|
2136
2140
|
return { kind: "ranges", ranges };
|
|
2137
2141
|
}
|
|
2138
|
-
function inFirstSet(code,
|
|
2139
|
-
if (
|
|
2140
|
-
if (
|
|
2141
|
-
for (const r of
|
|
2142
|
+
function inFirstSet(code, fs3) {
|
|
2143
|
+
if (fs3.kind === "any") return true;
|
|
2144
|
+
if (fs3.kind === "empty") return false;
|
|
2145
|
+
for (const r of fs3.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
2142
2146
|
return false;
|
|
2143
2147
|
}
|
|
2144
2148
|
function areDisjoint(sets) {
|
|
@@ -2151,9 +2155,9 @@ function areDisjoint(sets) {
|
|
|
2151
2155
|
function buildAsciiDispatch(parsers) {
|
|
2152
2156
|
const table = Array(128).fill(-1);
|
|
2153
2157
|
for (let i = 0; i < parsers.length; i++) {
|
|
2154
|
-
const
|
|
2155
|
-
if (
|
|
2156
|
-
for (const { lo, hi } of
|
|
2158
|
+
const fs3 = parsers[i]._meta.firstSet;
|
|
2159
|
+
if (fs3.kind !== "ranges") continue;
|
|
2160
|
+
for (const { lo, hi } of fs3.ranges) {
|
|
2157
2161
|
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
2158
2162
|
table[code] = i;
|
|
2159
2163
|
}
|
|
@@ -2274,17 +2278,21 @@ function when(key, parser2, opts = {}) {
|
|
|
2274
2278
|
function otherwise(parser2) {
|
|
2275
2279
|
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2276
2280
|
}
|
|
2277
|
-
function routed() {
|
|
2281
|
+
function routed(fallback) {
|
|
2278
2282
|
return {
|
|
2279
2283
|
_tag: "routed",
|
|
2280
|
-
_meta: {
|
|
2281
|
-
|
|
2284
|
+
_meta: {
|
|
2285
|
+
// The routed token is whatever the selector matched, so the first set stays
|
|
2286
|
+
// `any` even with a fallback — `any` already subsumes the fallback's.
|
|
2287
|
+
firstSet: { kind: "any" },
|
|
2288
|
+
canMatchNewline: fallback?._meta.canMatchNewline ?? false,
|
|
2289
|
+
isTrivia: false
|
|
2290
|
+
},
|
|
2291
|
+
_def: fallback === void 0 ? { tag: "routed" } : { tag: "routed", fallback },
|
|
2282
2292
|
parse(_input, pos, ctx) {
|
|
2283
2293
|
const item = ctx._routed;
|
|
2284
|
-
if (item === void 0) {
|
|
2285
|
-
|
|
2286
|
-
}
|
|
2287
|
-
if (pos !== item.span.start) {
|
|
2294
|
+
if (item === void 0 || pos !== item.span.start) {
|
|
2295
|
+
if (fallback !== void 0) return fallback.parse(_input, pos, ctx);
|
|
2288
2296
|
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2289
2297
|
}
|
|
2290
2298
|
if (cstCaptureActive(ctx)) {
|
|
@@ -2791,12 +2799,12 @@ function markUnusedValues(root) {
|
|
|
2791
2799
|
}
|
|
2792
2800
|
};
|
|
2793
2801
|
const resolveRoot = (c) => {
|
|
2794
|
-
const
|
|
2802
|
+
const guard = /* @__PURE__ */ new Set();
|
|
2795
2803
|
let cur = c;
|
|
2796
|
-
while (!
|
|
2804
|
+
while (!guard.has(cur)) {
|
|
2797
2805
|
const d = cur._def;
|
|
2798
2806
|
if (d.tag !== "lazy") return cur;
|
|
2799
|
-
|
|
2807
|
+
guard.add(cur);
|
|
2800
2808
|
try {
|
|
2801
2809
|
cur = d.thunk();
|
|
2802
2810
|
} catch {
|
|
@@ -2938,10 +2946,11 @@ function childrenOf(def) {
|
|
|
2938
2946
|
return [def.main, def.skipped];
|
|
2939
2947
|
case "scanTo":
|
|
2940
2948
|
return [def.sentinel, ...def.skip];
|
|
2949
|
+
case "routed":
|
|
2950
|
+
return def.fallback ? [def.fallback] : [];
|
|
2941
2951
|
case "literal":
|
|
2942
2952
|
case "regex":
|
|
2943
2953
|
case "keywords":
|
|
2944
|
-
case "routed":
|
|
2945
2954
|
case "guard":
|
|
2946
2955
|
case "lazy":
|
|
2947
2956
|
case "unknown":
|
|
@@ -3164,54 +3173,275 @@ function peek(combinator) {
|
|
|
3164
3173
|
};
|
|
3165
3174
|
}
|
|
3166
3175
|
|
|
3176
|
+
// src/compiler/degradation.ts
|
|
3177
|
+
function formatDegradation(d) {
|
|
3178
|
+
return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
|
|
3179
|
+
}
|
|
3180
|
+
var DETAIL_CAP = 8;
|
|
3181
|
+
function formatDegradations(list) {
|
|
3182
|
+
const byCode = /* @__PURE__ */ new Map();
|
|
3183
|
+
for (const d of list) {
|
|
3184
|
+
const bucket = byCode.get(d.code);
|
|
3185
|
+
if (bucket) bucket.push(d);
|
|
3186
|
+
else byCode.set(d.code, [d]);
|
|
3187
|
+
}
|
|
3188
|
+
const out = [];
|
|
3189
|
+
for (const [code, items] of byCode) {
|
|
3190
|
+
for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
|
|
3191
|
+
if (items.length > DETAIL_CAP) {
|
|
3192
|
+
out.push(
|
|
3193
|
+
`[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.`
|
|
3194
|
+
);
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
return out;
|
|
3198
|
+
}
|
|
3199
|
+
var _sinks = [];
|
|
3200
|
+
function beginDegradationCapture() {
|
|
3201
|
+
_sinks.push(/* @__PURE__ */ new Map());
|
|
3202
|
+
}
|
|
3203
|
+
function endDegradationCapture() {
|
|
3204
|
+
const sink = _sinks.pop();
|
|
3205
|
+
return sink ? [...sink.values()] : [];
|
|
3206
|
+
}
|
|
3207
|
+
function degradationCaptureDepth() {
|
|
3208
|
+
return _sinks.length;
|
|
3209
|
+
}
|
|
3210
|
+
function unwindDegradationCapture(depth) {
|
|
3211
|
+
const found = [];
|
|
3212
|
+
while (_sinks.length > depth) {
|
|
3213
|
+
const sink = _sinks.pop();
|
|
3214
|
+
found.unshift(...sink.values());
|
|
3215
|
+
}
|
|
3216
|
+
return found;
|
|
3217
|
+
}
|
|
3218
|
+
function resolveDegradationLevel(explicit) {
|
|
3219
|
+
if (explicit !== void 0) return explicit;
|
|
3220
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
|
|
3221
|
+
if (env === "off" || env === "warn" || env === "error") return env;
|
|
3222
|
+
return "warn";
|
|
3223
|
+
}
|
|
3224
|
+
function degradationKey(d) {
|
|
3225
|
+
return JSON.stringify([d.code, d.where, d.subject]);
|
|
3226
|
+
}
|
|
3227
|
+
function recordDegradation(d) {
|
|
3228
|
+
const level = resolveDegradationLevel();
|
|
3229
|
+
if (level === "off") return;
|
|
3230
|
+
const key = degradationKey(d);
|
|
3231
|
+
const sink = _sinks[_sinks.length - 1];
|
|
3232
|
+
if (sink) {
|
|
3233
|
+
if (!sink.has(key)) sink.set(key, d);
|
|
3234
|
+
return;
|
|
3235
|
+
}
|
|
3236
|
+
if (_immediate.has(key)) return;
|
|
3237
|
+
_immediate.add(key);
|
|
3238
|
+
if (level === "error") throw new Error(`parseman: degraded compilation path
|
|
3239
|
+
${formatDegradation(d)}`);
|
|
3240
|
+
console.warn(formatDegradation(d));
|
|
3241
|
+
}
|
|
3242
|
+
var _immediate = /* @__PURE__ */ new Set();
|
|
3243
|
+
function beginCompileDegradationDrain() {
|
|
3244
|
+
if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
|
|
3245
|
+
};
|
|
3246
|
+
const depth = degradationCaptureDepth();
|
|
3247
|
+
beginDegradationCapture();
|
|
3248
|
+
return (report) => {
|
|
3249
|
+
const found = unwindDegradationCapture(depth);
|
|
3250
|
+
if (!report || found.length === 0) return;
|
|
3251
|
+
const fresh = found.filter((d) => {
|
|
3252
|
+
const k = degradationKey(d);
|
|
3253
|
+
if (_immediate.has(k)) return false;
|
|
3254
|
+
_immediate.add(k);
|
|
3255
|
+
return true;
|
|
3256
|
+
});
|
|
3257
|
+
if (fresh.length === 0) return;
|
|
3258
|
+
const lines = formatDegradations(fresh);
|
|
3259
|
+
if (resolveDegradationLevel() === "error") {
|
|
3260
|
+
throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
|
|
3261
|
+
${lines.join("\n")}`);
|
|
3262
|
+
}
|
|
3263
|
+
for (const l of lines) console.warn(l);
|
|
3264
|
+
};
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3167
3267
|
// src/compiler/build-arity.ts
|
|
3168
3268
|
function cstOutputHost(build) {
|
|
3169
3269
|
return build?._parsemanCstOutput === true;
|
|
3170
3270
|
}
|
|
3171
|
-
var
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
|
|
3271
|
+
var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
|
|
3272
|
+
var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
|
|
3273
|
+
var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
|
|
3274
|
+
var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
|
|
3176
3275
|
function confirmedBuildArity(src) {
|
|
3177
3276
|
const s = src.trim();
|
|
3178
|
-
|
|
3179
|
-
if (
|
|
3180
|
-
if (
|
|
3181
|
-
const inner = (
|
|
3182
|
-
if (inner ===
|
|
3183
|
-
|
|
3277
|
+
if (NATIVE_CODE_RE.test(s)) return null;
|
|
3278
|
+
if (/\barguments\b/.test(s)) return null;
|
|
3279
|
+
if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
|
|
3280
|
+
const inner = paramListText(s);
|
|
3281
|
+
if (inner === null) return null;
|
|
3282
|
+
if (inner.trim() === "") return 0;
|
|
3283
|
+
const parts = splitTopLevel(inner);
|
|
3284
|
+
if (parts === null) return null;
|
|
3184
3285
|
for (const part of parts) {
|
|
3185
|
-
if (!
|
|
3286
|
+
if (!isConfirmableParam(part.trim())) return null;
|
|
3186
3287
|
}
|
|
3187
|
-
if (/\barguments\b/.test(s)) return null;
|
|
3188
3288
|
return parts.length;
|
|
3189
3289
|
}
|
|
3290
|
+
function paramListText(s) {
|
|
3291
|
+
const open = PARAM_LIST_OPEN_RE.exec(s);
|
|
3292
|
+
if (!open) return null;
|
|
3293
|
+
const start = open[0].length;
|
|
3294
|
+
const end = matchingParen(s, start);
|
|
3295
|
+
if (end === null) return null;
|
|
3296
|
+
if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
|
|
3297
|
+
return s.slice(start, end);
|
|
3298
|
+
}
|
|
3299
|
+
function matchingParen(s, start) {
|
|
3300
|
+
let depth = 0;
|
|
3301
|
+
for (let i = start; i < s.length; i++) {
|
|
3302
|
+
const c = s[i];
|
|
3303
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3304
|
+
const close = skipString(s, i);
|
|
3305
|
+
if (close === null) return null;
|
|
3306
|
+
i = close;
|
|
3307
|
+
continue;
|
|
3308
|
+
}
|
|
3309
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3310
|
+
else if (c === "]" || c === "}") {
|
|
3311
|
+
if (--depth < 0) return null;
|
|
3312
|
+
} else if (c === ")") {
|
|
3313
|
+
if (depth === 0) return i;
|
|
3314
|
+
depth--;
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
return null;
|
|
3318
|
+
}
|
|
3319
|
+
function skipString(s, open) {
|
|
3320
|
+
const quote = s[open];
|
|
3321
|
+
for (let i = open + 1; i < s.length; i++) {
|
|
3322
|
+
if (s[i] === "\\") {
|
|
3323
|
+
i++;
|
|
3324
|
+
continue;
|
|
3325
|
+
}
|
|
3326
|
+
if (s[i] === quote) return i;
|
|
3327
|
+
}
|
|
3328
|
+
return null;
|
|
3329
|
+
}
|
|
3330
|
+
function splitTopLevel(inner) {
|
|
3331
|
+
const parts = [];
|
|
3332
|
+
let depth = 0;
|
|
3333
|
+
let angle = 0;
|
|
3334
|
+
let last = 0;
|
|
3335
|
+
for (let i = 0; i < inner.length; i++) {
|
|
3336
|
+
const c = inner[i];
|
|
3337
|
+
if (c === "=" && inner[i + 1] === ">") {
|
|
3338
|
+
i++;
|
|
3339
|
+
continue;
|
|
3340
|
+
}
|
|
3341
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3342
|
+
const close = skipString(inner, i);
|
|
3343
|
+
if (close === null) return null;
|
|
3344
|
+
i = close;
|
|
3345
|
+
continue;
|
|
3346
|
+
}
|
|
3347
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3348
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
3349
|
+
if (--depth < 0) return null;
|
|
3350
|
+
} else if (c === "<") angle++;
|
|
3351
|
+
else if (c === ">") {
|
|
3352
|
+
if (--angle < 0) return null;
|
|
3353
|
+
} else if (c === "," && depth === 0 && angle === 0) {
|
|
3354
|
+
parts.push(inner.slice(last, i));
|
|
3355
|
+
last = i + 1;
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
if (depth !== 0 || angle !== 0) return null;
|
|
3359
|
+
parts.push(inner.slice(last));
|
|
3360
|
+
return parts;
|
|
3361
|
+
}
|
|
3362
|
+
function isConfirmableParam(part) {
|
|
3363
|
+
const head = PARAM_HEAD_RE.exec(part);
|
|
3364
|
+
if (!head) return false;
|
|
3365
|
+
const rest = part.slice(head[0].length);
|
|
3366
|
+
if (rest === "") return true;
|
|
3367
|
+
if (rest[0] !== ":") return false;
|
|
3368
|
+
return !hasDefaultAssign(rest.slice(1));
|
|
3369
|
+
}
|
|
3370
|
+
function hasDefaultAssign(annotation) {
|
|
3371
|
+
for (let i = 0; i < annotation.length; i++) {
|
|
3372
|
+
if (annotation[i] !== "=") continue;
|
|
3373
|
+
if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
|
|
3374
|
+
i++;
|
|
3375
|
+
continue;
|
|
3376
|
+
}
|
|
3377
|
+
const prev = annotation[i - 1];
|
|
3378
|
+
if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
|
|
3379
|
+
return true;
|
|
3380
|
+
}
|
|
3381
|
+
return false;
|
|
3382
|
+
}
|
|
3383
|
+
function buildAnalysisSrc(def) {
|
|
3384
|
+
return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
|
|
3385
|
+
}
|
|
3386
|
+
var RESOLVER_REASONS = {
|
|
3387
|
+
"rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
|
|
3388
|
+
"arguments": "its body references `arguments`",
|
|
3389
|
+
"reassigned": "the binding it names is reassigned, so the function read here is not decidable",
|
|
3390
|
+
"not-a-function": "the binding it names is not a function declaration",
|
|
3391
|
+
"unresolved-import": "its module could not be resolved or parsed",
|
|
3392
|
+
"not-found": "the name did not resolve to any binding",
|
|
3393
|
+
"computed": "it is a computed expression",
|
|
3394
|
+
"foreign-source": "it is named inside an imported factory, whose offsets the entry-file resolver cannot index"
|
|
3395
|
+
};
|
|
3396
|
+
function unconfirmableReason(def, src) {
|
|
3397
|
+
const declared = def.buildArityUnresolved;
|
|
3398
|
+
if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
|
|
3399
|
+
const s = src.trim();
|
|
3400
|
+
const params = s.slice(0, s.indexOf(")") + 1);
|
|
3401
|
+
if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
|
|
3402
|
+
if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
|
|
3403
|
+
if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
|
|
3404
|
+
return "it names a binding this build could not resolve to a function declaration";
|
|
3405
|
+
}
|
|
3406
|
+
return "its parameter list could not be parsed";
|
|
3407
|
+
}
|
|
3408
|
+
function confirmedArityForDef(def) {
|
|
3409
|
+
if (def.buildArity !== void 0) return def.buildArity;
|
|
3410
|
+
const src = buildAnalysisSrc(def);
|
|
3411
|
+
const arity = confirmedBuildArity(src);
|
|
3412
|
+
if (arity !== null) return arity;
|
|
3413
|
+
const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
|
|
3414
|
+
recordDegradation({
|
|
3415
|
+
code: "build-arity-unconfirmed",
|
|
3416
|
+
severity: "warn",
|
|
3417
|
+
where: `node("${def.type ?? "<inferred>"}")`,
|
|
3418
|
+
subject,
|
|
3419
|
+
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`,
|
|
3420
|
+
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"
|
|
3421
|
+
});
|
|
3422
|
+
return null;
|
|
3423
|
+
}
|
|
3190
3424
|
function buildReadsChildren(def) {
|
|
3191
3425
|
if (!def.build) return true;
|
|
3192
|
-
const
|
|
3193
|
-
const arity = confirmedBuildArity(src);
|
|
3426
|
+
const arity = confirmedArityForDef(def);
|
|
3194
3427
|
if (arity === null) return true;
|
|
3195
3428
|
return arity >= 1;
|
|
3196
3429
|
}
|
|
3197
3430
|
function buildReadsRaw(def) {
|
|
3198
3431
|
if (!def.build) return true;
|
|
3199
|
-
const
|
|
3200
|
-
const arity = confirmedBuildArity(src);
|
|
3432
|
+
const arity = confirmedArityForDef(def);
|
|
3201
3433
|
if (arity === null) return true;
|
|
3202
3434
|
return arity >= 4;
|
|
3203
3435
|
}
|
|
3204
3436
|
function buildReadsTrivia(def) {
|
|
3205
3437
|
if (!def.build) return true;
|
|
3206
|
-
const
|
|
3207
|
-
const arity = confirmedBuildArity(src);
|
|
3438
|
+
const arity = confirmedArityForDef(def);
|
|
3208
3439
|
if (arity === null) return true;
|
|
3209
3440
|
return arity >= 5;
|
|
3210
3441
|
}
|
|
3211
3442
|
function buildReadsState(def) {
|
|
3212
3443
|
if (!def.build) return true;
|
|
3213
|
-
const
|
|
3214
|
-
const arity = confirmedBuildArity(src);
|
|
3444
|
+
const arity = confirmedArityForDef(def);
|
|
3215
3445
|
if (arity === null) return true;
|
|
3216
3446
|
return arity >= 6;
|
|
3217
3447
|
}
|
|
@@ -3219,8 +3449,7 @@ function buildReadsState(def) {
|
|
|
3219
3449
|
// src/compiler/fields.ts
|
|
3220
3450
|
function buildReadsFields(def) {
|
|
3221
3451
|
if (!def.build) return true;
|
|
3222
|
-
const
|
|
3223
|
-
const arity = confirmedBuildArity(src);
|
|
3452
|
+
const arity = confirmedArityForDef(def);
|
|
3224
3453
|
if (arity === null) return true;
|
|
3225
3454
|
return arity >= 2;
|
|
3226
3455
|
}
|
|
@@ -3401,6 +3630,13 @@ function isCstChild(value) {
|
|
|
3401
3630
|
function missingInferredType() {
|
|
3402
3631
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
3403
3632
|
}
|
|
3633
|
+
function normalizeBuildArity(arity) {
|
|
3634
|
+
if (arity === void 0) return void 0;
|
|
3635
|
+
if (!Number.isInteger(arity) || arity < 0 || arity > 6) {
|
|
3636
|
+
throw new Error("node() buildArity must be an integer 0..6 (children, fields, span, rawChildren, triviaLog, state)");
|
|
3637
|
+
}
|
|
3638
|
+
return arity;
|
|
3639
|
+
}
|
|
3404
3640
|
function normalizeProject(project) {
|
|
3405
3641
|
if (project === void 0) return void 0;
|
|
3406
3642
|
if (!Number.isInteger(project) || project < 0) {
|
|
@@ -3436,13 +3672,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3436
3672
|
const captureTrivia = opts?.captureTrivia === true;
|
|
3437
3673
|
const trailingTrivia = opts?.trailingTrivia === true;
|
|
3438
3674
|
const tags = opts?.tags;
|
|
3675
|
+
const buildArity = normalizeBuildArity(opts?.buildArity);
|
|
3439
3676
|
if (unwrap && collapse) {
|
|
3440
3677
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
3441
3678
|
}
|
|
3442
3679
|
if (project !== void 0 && (unwrap || collapse)) {
|
|
3443
3680
|
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3444
3681
|
}
|
|
3445
|
-
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;
|
|
3682
|
+
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;
|
|
3446
3683
|
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3447
3684
|
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
3448
3685
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
@@ -3488,7 +3725,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3488
3725
|
const cstOutput = cstOutputHost(ctx.build);
|
|
3489
3726
|
const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
|
|
3490
3727
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
3491
|
-
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 };
|
|
3728
|
+
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 };
|
|
3492
3729
|
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 };
|
|
3493
3730
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
3494
3731
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3683,7 +3920,7 @@ function leaf(root, fn) {
|
|
|
3683
3920
|
}
|
|
3684
3921
|
|
|
3685
3922
|
// src/version.ts
|
|
3686
|
-
var PARSEMAN_VERSION = "0.
|
|
3923
|
+
var PARSEMAN_VERSION = "0.45.0";
|
|
3687
3924
|
|
|
3688
3925
|
// src/cst/host-mode.ts
|
|
3689
3926
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -3703,346 +3940,11 @@ function assertHostModeCompatible(mode, build, hostBranchElided = true) {
|
|
|
3703
3940
|
}
|
|
3704
3941
|
|
|
3705
3942
|
// src/analysis/gating.ts
|
|
3706
|
-
var isAny = (fs2) => fs2.kind === "any";
|
|
3707
|
-
function intersects2(a, b) {
|
|
3708
|
-
if (a.kind === "any" || b.kind === "any") return true;
|
|
3709
|
-
if (a.kind === "empty" || b.kind === "empty") return false;
|
|
3710
|
-
for (const ra of a.ranges) for (const rb of b.ranges) if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
|
|
3711
|
-
return false;
|
|
3712
|
-
}
|
|
3713
|
-
function intersection(a, b) {
|
|
3714
|
-
if (a.kind === "any") return b;
|
|
3715
|
-
if (b.kind === "any") return a;
|
|
3716
|
-
if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
|
|
3717
|
-
const ranges = [];
|
|
3718
|
-
for (const ra of a.ranges) for (const rb of b.ranges) {
|
|
3719
|
-
const lo = Math.max(ra.lo, rb.lo);
|
|
3720
|
-
const hi = Math.min(ra.hi, rb.hi);
|
|
3721
|
-
if (lo <= hi) ranges.push({ lo, hi });
|
|
3722
|
-
}
|
|
3723
|
-
return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
|
|
3724
|
-
}
|
|
3725
|
-
function combine(sets) {
|
|
3726
|
-
let acc = { kind: "empty" };
|
|
3727
|
-
for (const s of sets) {
|
|
3728
|
-
if (s.kind === "any") return { kind: "any" };
|
|
3729
|
-
if (s.kind === "empty") continue;
|
|
3730
|
-
acc = acc.kind === "ranges" ? { kind: "ranges", ranges: [...acc.ranges, ...s.ranges] } : s;
|
|
3731
|
-
}
|
|
3732
|
-
return acc;
|
|
3733
|
-
}
|
|
3734
3943
|
var ch = (c) => c >= 32 && c < 127 ? `'${String.fromCharCode(c)}'` : `\\u${c}`;
|
|
3735
|
-
function firstSetToString(
|
|
3736
|
-
if (
|
|
3737
|
-
if (
|
|
3738
|
-
return
|
|
3739
|
-
}
|
|
3740
|
-
var ruleNameOf2 = (p) => p._ruleName;
|
|
3741
|
-
var SUGGESTIONS = {
|
|
3742
|
-
"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.",
|
|
3743
|
-
"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.",
|
|
3744
|
-
"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.",
|
|
3745
|
-
"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.",
|
|
3746
|
-
"opaque-wrapper": "this wrapper (guard/withCtx/recover) contributes no first char; put a concrete leading terminal before it.",
|
|
3747
|
-
"ref-cycle": "a recursive ref resolved to ANY; ensure the recursion has a concrete terminal lead on the base case."
|
|
3748
|
-
};
|
|
3749
|
-
function classifyBroadArm(arm, resolve2) {
|
|
3750
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3751
|
-
const relabel = (inner, cause, detail) => ({ cause, detail, ...inner?.unresolvedExternal ? { unresolvedExternal: true } : {} });
|
|
3752
|
-
const walk = (p) => {
|
|
3753
|
-
if (seen.has(p)) return { cause: "ref-cycle", detail: "ref cycle" };
|
|
3754
|
-
seen.add(p);
|
|
3755
|
-
const d = p._def;
|
|
3756
|
-
switch (d.tag) {
|
|
3757
|
-
case "literal":
|
|
3758
|
-
case "regex":
|
|
3759
|
-
case "keywords":
|
|
3760
|
-
return isAny(p._meta.firstSet) ? { cause: "broad-recognizer", detail: `broad recognizer (${d.tag})` } : null;
|
|
3761
|
-
case "not":
|
|
3762
|
-
return { cause: "leading-not", detail: "leading not(...) (first-set ANY)" };
|
|
3763
|
-
// peek() CARRIES its body's first-set, so it is only broad when the body is
|
|
3764
|
-
// (or the body is nullable) — walk in for the real cause.
|
|
3765
|
-
case "peek":
|
|
3766
|
-
return walk(d.parser);
|
|
3767
|
-
case "scanTo":
|
|
3768
|
-
return { cause: "broad-recognizer", detail: "scanTo (any first char)" };
|
|
3769
|
-
// `guard` (the `gate()` state predicate) has a genuinely-`any` first-set of
|
|
3770
|
-
// its own — it is the poison. `withCtx`/`recover` FORWARD their inner
|
|
3771
|
-
// first-set (see firstSetOf), so a broad result comes from the inner parser:
|
|
3772
|
-
// walk into it for a precise cause.
|
|
3773
|
-
case "guard":
|
|
3774
|
-
return { cause: "opaque-wrapper", detail: `opaque wrapper (${d.tag})` };
|
|
3775
|
-
// attempt/withCtx/recover FORWARD their inner first-set (transparent for
|
|
3776
|
-
// dispatch), so a broad result comes from the inner parser — walk into it.
|
|
3777
|
-
case "attempt":
|
|
3778
|
-
case "withCtx":
|
|
3779
|
-
case "recover":
|
|
3780
|
-
return walk(d.parser);
|
|
3781
|
-
case "lazy": {
|
|
3782
|
-
const name = p._ruleName;
|
|
3783
|
-
let target;
|
|
3784
|
-
try {
|
|
3785
|
-
target = d.thunk();
|
|
3786
|
-
} catch {
|
|
3787
|
-
const bound = name !== void 0 ? resolve2?.(name) : void 0;
|
|
3788
|
-
if (bound === void 0)
|
|
3789
|
-
return { cause: "cross-artifact-ref", detail: `unresolved ref${name ? ` g.${name}` : ""}`, unresolvedExternal: name !== void 0 };
|
|
3790
|
-
target = bound;
|
|
3791
|
-
}
|
|
3792
|
-
const inner = walk(target);
|
|
3793
|
-
if (name !== void 0) return inner ? relabel(inner, "cross-artifact-ref", `via ref g.${name} \u2192 ${inner.detail}`) : null;
|
|
3794
|
-
return inner;
|
|
3795
|
-
}
|
|
3796
|
-
case "optional":
|
|
3797
|
-
case "many": {
|
|
3798
|
-
const inner = walk(d.parser);
|
|
3799
|
-
return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
|
|
3800
|
-
}
|
|
3801
|
-
case "oneOrMore":
|
|
3802
|
-
case "transform":
|
|
3803
|
-
case "label":
|
|
3804
|
-
case "field":
|
|
3805
|
-
case "trivia":
|
|
3806
|
-
case "token":
|
|
3807
|
-
case "leaf":
|
|
3808
|
-
case "node":
|
|
3809
|
-
case "grammar":
|
|
3810
|
-
case "expect":
|
|
3811
|
-
return walk(d.parser);
|
|
3812
|
-
case "skip":
|
|
3813
|
-
return walk(d.main);
|
|
3814
|
-
case "sequence": {
|
|
3815
|
-
let sawNullablePrefix = false;
|
|
3816
|
-
for (const t of d.parsers) {
|
|
3817
|
-
if (t._def.tag === "not") {
|
|
3818
|
-
sawNullablePrefix = true;
|
|
3819
|
-
continue;
|
|
3820
|
-
}
|
|
3821
|
-
if (isAny(firstSetOf(t, /* @__PURE__ */ new Set(), resolve2))) {
|
|
3822
|
-
const inner = walk(t);
|
|
3823
|
-
if (sawNullablePrefix)
|
|
3824
|
-
return relabel(inner, "nullable-prefix", inner ? `nullable prefix \u2192 ${inner.detail}` : "nullable prefix to broad term");
|
|
3825
|
-
return inner ?? { cause: "broad-recognizer", detail: "sequence leading term is broad" };
|
|
3826
|
-
}
|
|
3827
|
-
if (matchesEmpty(t, /* @__PURE__ */ new Set(), resolve2)) {
|
|
3828
|
-
sawNullablePrefix = true;
|
|
3829
|
-
continue;
|
|
3830
|
-
}
|
|
3831
|
-
return null;
|
|
3832
|
-
}
|
|
3833
|
-
return { cause: "broad-recognizer", detail: "sequence of only nullable/zero-width terms" };
|
|
3834
|
-
}
|
|
3835
|
-
case "choice": {
|
|
3836
|
-
for (const a of d.parsers) {
|
|
3837
|
-
const r = walk(a);
|
|
3838
|
-
if (r) return relabel(r, r.cause, `choice arm \u2192 ${r.detail}`);
|
|
3839
|
-
}
|
|
3840
|
-
return null;
|
|
3841
|
-
}
|
|
3842
|
-
case "dispatch":
|
|
3843
|
-
return walk(d.selector);
|
|
3844
|
-
default:
|
|
3845
|
-
return { cause: "broad-recognizer", detail: `unmodeled construct (${d.tag})` };
|
|
3846
|
-
}
|
|
3847
|
-
};
|
|
3848
|
-
return walk(arm) ?? { cause: "broad-recognizer", detail: "broad (cause not localized)" };
|
|
3849
|
-
}
|
|
3850
|
-
function peelToLeading(arm) {
|
|
3851
|
-
let d = arm._def;
|
|
3852
|
-
let cur = arm;
|
|
3853
|
-
for (; ; ) {
|
|
3854
|
-
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label" || d.tag === "attempt") {
|
|
3855
|
-
cur = d.parser;
|
|
3856
|
-
d = cur._def;
|
|
3857
|
-
continue;
|
|
3858
|
-
}
|
|
3859
|
-
break;
|
|
3860
|
-
}
|
|
3861
|
-
if (d.tag === "sequence" && d.parsers.length >= 1) return d.parsers[0];
|
|
3862
|
-
return cur;
|
|
3863
|
-
}
|
|
3864
|
-
var KEYWORD_REGEX_RE = /^\^?[@#.-]?[A-Za-z][\w-]*(\(\?![^)]*\))?\$?$/;
|
|
3865
|
-
function detectAntiPatterns(rule, arms) {
|
|
3866
|
-
const out = [];
|
|
3867
|
-
arms.forEach((arm, i) => {
|
|
3868
|
-
const lead = peelToLeading(arm);
|
|
3869
|
-
const ld = lead._def;
|
|
3870
|
-
if (ld.tag === "not") {
|
|
3871
|
-
const inner = ld.parser;
|
|
3872
|
-
if (inner._def.tag === "not") {
|
|
3873
|
-
out.push({
|
|
3874
|
-
kind: "double-not",
|
|
3875
|
-
rule,
|
|
3876
|
-
armIndex: i,
|
|
3877
|
-
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."
|
|
3878
|
-
});
|
|
3879
|
-
} else {
|
|
3880
|
-
out.push({
|
|
3881
|
-
kind: "leading-not",
|
|
3882
|
-
rule,
|
|
3883
|
-
armIndex: i,
|
|
3884
|
-
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."
|
|
3885
|
-
});
|
|
3886
|
-
}
|
|
3887
|
-
}
|
|
3888
|
-
if (ld.tag === "regex" && KEYWORD_REGEX_RE.test(ld.source)) {
|
|
3889
|
-
out.push({
|
|
3890
|
-
kind: "keyword-regex",
|
|
3891
|
-
rule,
|
|
3892
|
-
armIndex: i,
|
|
3893
|
-
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).`
|
|
3894
|
-
});
|
|
3895
|
-
}
|
|
3896
|
-
});
|
|
3897
|
-
return out;
|
|
3898
|
-
}
|
|
3899
|
-
function analyzeGating(entry, opts) {
|
|
3900
|
-
return analyzeGatingRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
3901
|
-
}
|
|
3902
|
-
function analyzeGatingRules(ruleMap, opts) {
|
|
3903
|
-
const raw = [];
|
|
3904
|
-
const antiPatterns = [];
|
|
3905
|
-
const unanalysable = [];
|
|
3906
|
-
const seenUnanalysable = /* @__PURE__ */ new Set();
|
|
3907
|
-
const visited = /* @__PURE__ */ new Set();
|
|
3908
|
-
const noteUnanalysable = (u) => {
|
|
3909
|
-
const key = `${u.rule}\0${u.kind}`;
|
|
3910
|
-
if (seenUnanalysable.has(key)) return;
|
|
3911
|
-
seenUnanalysable.add(key);
|
|
3912
|
-
unanalysable.push(u);
|
|
3913
|
-
};
|
|
3914
|
-
const visit = (p, enclosingRule) => {
|
|
3915
|
-
if (visited.has(p)) return;
|
|
3916
|
-
visited.add(p);
|
|
3917
|
-
const def = p?._def;
|
|
3918
|
-
if (def === null || typeof def !== "object") {
|
|
3919
|
-
noteUnanalysable(
|
|
3920
|
-
typeof p === "function" ? {
|
|
3921
|
-
rule: enclosingRule,
|
|
3922
|
-
kind: "fused-rule",
|
|
3923
|
-
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."
|
|
3924
|
-
} : {
|
|
3925
|
-
rule: enclosingRule,
|
|
3926
|
-
kind: "not-a-combinator",
|
|
3927
|
-
reason: `value of type ${p === null ? "null" : typeof p} is not a combinator and carries no _def descriptor.`
|
|
3928
|
-
}
|
|
3929
|
-
);
|
|
3930
|
-
return;
|
|
3931
|
-
}
|
|
3932
|
-
const d = def;
|
|
3933
|
-
const rule = ruleNameOf2(p) ?? enclosingRule;
|
|
3934
|
-
if (d.tag === "choice") {
|
|
3935
|
-
raw.push({ g: analyzeChoice(p, d, rule, opts?.resolveRef), rule });
|
|
3936
|
-
antiPatterns.push(...detectAntiPatterns(rule, d.parsers));
|
|
3937
|
-
}
|
|
3938
|
-
const rec = d;
|
|
3939
|
-
const kids = [];
|
|
3940
|
-
if (Array.isArray(rec.parsers)) kids.push(...rec.parsers);
|
|
3941
|
-
for (const k of ["parser", "main", "skipped", "separator", "sentinel"])
|
|
3942
|
-
if (rec[k]) kids.push(rec[k]);
|
|
3943
|
-
if (d.tag === "dispatch") {
|
|
3944
|
-
kids.push(d.selector);
|
|
3945
|
-
for (const c of d.cases) kids.push(c.parser);
|
|
3946
|
-
if (d.matchers) for (const c of d.matchers) kids.push(c.parser);
|
|
3947
|
-
if (d.otherwise !== void 0) kids.push(d.otherwise);
|
|
3948
|
-
}
|
|
3949
|
-
if (Array.isArray(rec.skip)) kids.push(...rec.skip);
|
|
3950
|
-
if (d.tag === "lazy") {
|
|
3951
|
-
try {
|
|
3952
|
-
kids.push(d.thunk());
|
|
3953
|
-
} catch {
|
|
3954
|
-
}
|
|
3955
|
-
}
|
|
3956
|
-
for (const k of kids) visit(k, rule);
|
|
3957
|
-
};
|
|
3958
|
-
for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name);
|
|
3959
|
-
const perRule = /* @__PURE__ */ new Map();
|
|
3960
|
-
for (const r of raw) perRule.set(r.rule, (perRule.get(r.rule) ?? 0) + 1);
|
|
3961
|
-
const seenInRule = /* @__PURE__ */ new Map();
|
|
3962
|
-
const accept = new Set(opts?.accept ?? []);
|
|
3963
|
-
const usedAccept = /* @__PURE__ */ new Set();
|
|
3964
|
-
const choices = raw.map(({ g, rule }) => {
|
|
3965
|
-
const n = seenInRule.get(rule) ?? 0;
|
|
3966
|
-
seenInRule.set(rule, n + 1);
|
|
3967
|
-
const id = (perRule.get(rule) ?? 1) === 1 ? rule : `${rule}#${n}`;
|
|
3968
|
-
const isAccepted = g.gates === "no" && accept.has(id);
|
|
3969
|
-
if (isAccepted) usedAccept.add(id);
|
|
3970
|
-
return { ...g, id, accepted: isAccepted };
|
|
3971
|
-
});
|
|
3972
|
-
const gated = choices.filter((c) => c.gates === "yes").length;
|
|
3973
|
-
const recoverable = choices.filter((c) => c.gates === "recoverable").length;
|
|
3974
|
-
const ungated = choices.filter((c) => c.gates === "no" && !c.accepted && !c.deferred);
|
|
3975
|
-
const accepted = choices.filter((c) => c.gates === "no" && c.accepted);
|
|
3976
|
-
const deferred = choices.filter((c) => c.gates === "no" && !c.accepted && c.deferred);
|
|
3977
|
-
const acceptedUnused = [...accept].filter((id) => !usedAccept.has(id));
|
|
3978
|
-
return {
|
|
3979
|
-
totalChoices: choices.length,
|
|
3980
|
-
gated,
|
|
3981
|
-
recoverable,
|
|
3982
|
-
unanalysable,
|
|
3983
|
-
ungated,
|
|
3984
|
-
accepted,
|
|
3985
|
-
deferred,
|
|
3986
|
-
acceptedUnused,
|
|
3987
|
-
choices,
|
|
3988
|
-
antiPatterns
|
|
3989
|
-
};
|
|
3990
|
-
}
|
|
3991
|
-
function analyzeChoice(p, d, rule, resolve2) {
|
|
3992
|
-
const arms = d.parsers;
|
|
3993
|
-
const shallow = arms.map((a) => a._meta.firstSet);
|
|
3994
|
-
const deep = arms.map((a) => firstSetOf(a, /* @__PURE__ */ new Set(), resolve2));
|
|
3995
|
-
const anyArms = deep.map((fs2, index) => ({ fs: fs2, index })).filter((x) => isAny(x.fs)).map(({ index }) => {
|
|
3996
|
-
const { cause, detail, unresolvedExternal } = classifyBroadArm(arms[index], resolve2);
|
|
3997
|
-
return { index, cause, detail, shallowAnyOnly: false, unresolvedExternal: unresolvedExternal === true, suggestion: SUGGESTIONS[cause] };
|
|
3998
|
-
});
|
|
3999
|
-
const overlaps = [];
|
|
4000
|
-
for (let i = 0; i < deep.length; i++)
|
|
4001
|
-
for (let j = i + 1; j < deep.length; j++)
|
|
4002
|
-
if (!isAny(deep[i]) && !isAny(deep[j]) && intersects2(deep[i], deep[j]))
|
|
4003
|
-
overlaps.push({
|
|
4004
|
-
a: i,
|
|
4005
|
-
b: j,
|
|
4006
|
-
on: intersection(deep[i], deep[j]),
|
|
4007
|
-
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."
|
|
4008
|
-
});
|
|
4009
|
-
let gates;
|
|
4010
|
-
if (d.disjoint) gates = "yes";
|
|
4011
|
-
else if (anyArms.length === 0 && overlaps.length === 0) gates = "recoverable";
|
|
4012
|
-
else gates = "no";
|
|
4013
|
-
const deferred = gates === "no" && overlaps.length === 0 && anyArms.length > 0 && anyArms.every((a) => a.unresolvedExternal);
|
|
4014
|
-
return {
|
|
4015
|
-
rule,
|
|
4016
|
-
strategy: d.strategy?.tag ?? "firstMatch",
|
|
4017
|
-
gates,
|
|
4018
|
-
deferred,
|
|
4019
|
-
combinedFirstSet: { shallow: combine(shallow), deep: combine(deep) },
|
|
4020
|
-
anyArms,
|
|
4021
|
-
overlaps
|
|
4022
|
-
};
|
|
4023
|
-
}
|
|
4024
|
-
function formatGatingWarnings(report) {
|
|
4025
|
-
const lines = [];
|
|
4026
|
-
if (report.unanalysable.length > 0) {
|
|
4027
|
-
lines.push(
|
|
4028
|
-
`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.`
|
|
4029
|
-
);
|
|
4030
|
-
for (const u of report.unanalysable)
|
|
4031
|
-
lines.push(` \xB7 ${u.rule} [${u.kind}]: ${u.reason}`);
|
|
4032
|
-
}
|
|
4033
|
-
for (const c of report.ungated) {
|
|
4034
|
-
lines.push(`parseman gating: choice @ ${c.id} is UNGATED [${c.strategy}] \u2014 no first-char dispatch; every position speculatively enters doomed arms.`);
|
|
4035
|
-
for (const a of c.anyArms)
|
|
4036
|
-
lines.push(` \xB7 arm[${a.index}] first-set ANY (${a.cause}): ${a.detail}
|
|
4037
|
-
fix: ${a.suggestion}`);
|
|
4038
|
-
for (const o of c.overlaps)
|
|
4039
|
-
lines.push(` \xB7 arm[${o.a}] \u2229 arm[${o.b}] overlap on ${firstSetToString(o.on)}
|
|
4040
|
-
fix: ${o.suggestion}`);
|
|
4041
|
-
lines.push(` (intentional? accept it in the gating snapshot: { accept: ['${c.id}'] }.)`);
|
|
4042
|
-
}
|
|
4043
|
-
for (const ap of report.antiPatterns)
|
|
4044
|
-
lines.push(`parseman anti-pattern [${ap.kind}] @ ${ap.rule} arm[${ap.armIndex}]: ${ap.message}`);
|
|
4045
|
-
return lines;
|
|
3944
|
+
function firstSetToString(fs3) {
|
|
3945
|
+
if (fs3.kind === "any") return "ANY";
|
|
3946
|
+
if (fs3.kind === "empty") return "(empty)";
|
|
3947
|
+
return fs3.ranges.map((r) => r.lo === r.hi ? ch(r.lo) : `${ch(r.lo)}-${ch(r.hi)}`).join(",");
|
|
4046
3948
|
}
|
|
4047
3949
|
|
|
4048
3950
|
// src/analysis/duplication.ts
|
|
@@ -4085,7 +3987,7 @@ function childrenOf2(d) {
|
|
|
4085
3987
|
}
|
|
4086
3988
|
}
|
|
4087
3989
|
}
|
|
4088
|
-
var
|
|
3990
|
+
var ruleNameOf2 = (p) => p._ruleName;
|
|
4089
3991
|
var fnKey = (src, fn) => src ?? (typeof fn === "function" ? String(fn) : "");
|
|
4090
3992
|
function payloadKey(p, d) {
|
|
4091
3993
|
switch (d.tag) {
|
|
@@ -4096,7 +3998,7 @@ function payloadKey(p, d) {
|
|
|
4096
3998
|
case "keywords":
|
|
4097
3999
|
return `keywords\0${[...d.words].join("")}\0${d.caseInsensitive}\0${d.boundary ?? ""}`;
|
|
4098
4000
|
case "lazy": {
|
|
4099
|
-
const n =
|
|
4001
|
+
const n = ruleNameOf2(p);
|
|
4100
4002
|
return n === void 0 ? `ref\0#${anonId(p)}` : `ref\0${n}`;
|
|
4101
4003
|
}
|
|
4102
4004
|
case "label":
|
|
@@ -4165,7 +4067,7 @@ var Interner = class {
|
|
|
4165
4067
|
var MAX_RENDER = 160;
|
|
4166
4068
|
function render(p, depth = 3) {
|
|
4167
4069
|
const d = p._def;
|
|
4168
|
-
const name =
|
|
4070
|
+
const name = ruleNameOf2(p);
|
|
4169
4071
|
switch (d.tag) {
|
|
4170
4072
|
case "literal":
|
|
4171
4073
|
return `literal('${d.value}')`;
|
|
@@ -4353,7 +4255,7 @@ function keywordAlternationHazards(words, boundary) {
|
|
|
4353
4255
|
return out;
|
|
4354
4256
|
}
|
|
4355
4257
|
function analyzeDuplication(entry, opts) {
|
|
4356
|
-
return analyzeDuplicationRules([[
|
|
4258
|
+
return analyzeDuplicationRules([[ruleNameOf2(entry) ?? opts?.entryName ?? "<entry>", entry]], opts);
|
|
4357
4259
|
}
|
|
4358
4260
|
function assertAnalyzable(ruleMap) {
|
|
4359
4261
|
for (const [name, rule] of ruleMap) {
|
|
@@ -4391,11 +4293,11 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
4391
4293
|
return n;
|
|
4392
4294
|
};
|
|
4393
4295
|
const visited = /* @__PURE__ */ new Map();
|
|
4394
|
-
const visit = (p, rule,
|
|
4296
|
+
const visit = (p, rule, path3, enclosingNode, enclosingReducer) => {
|
|
4395
4297
|
if (visited.has(p)) return;
|
|
4396
4298
|
const d = p._def;
|
|
4397
|
-
const own =
|
|
4398
|
-
const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path:
|
|
4299
|
+
const own = ruleNameOf2(p);
|
|
4300
|
+
const here = own !== void 0 && own !== rule ? { rule: own, path: "" } : { rule, path: path3 };
|
|
4399
4301
|
visited.set(p, { p, d, site: here, shape: shapeOf(p), size: sizeOf(p), enclosingNode, enclosingReducer });
|
|
4400
4302
|
const inner = d.tag === "node" ? d.type ?? "(anonymous)" : enclosingNode;
|
|
4401
4303
|
const innerReducer = enclosingReducer || d.tag === "node" && (d.build !== void 0 || d.buildSrc !== void 0) || d.tag === "transform" || d.tag === "leaf";
|
|
@@ -4407,12 +4309,12 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
4407
4309
|
if (d.tag === "lazy") {
|
|
4408
4310
|
try {
|
|
4409
4311
|
const target = d.thunk();
|
|
4410
|
-
visit(target,
|
|
4312
|
+
visit(target, ruleNameOf2(target) ?? ruleNameOf2(p) ?? here.rule, "", null, false);
|
|
4411
4313
|
} catch {
|
|
4412
4314
|
}
|
|
4413
4315
|
}
|
|
4414
4316
|
};
|
|
4415
|
-
for (const [name, root] of ruleMap) visit(root,
|
|
4317
|
+
for (const [name, root] of ruleMap) visit(root, ruleNameOf2(root) ?? name, "", null, false);
|
|
4416
4318
|
const accept = new Set(opts?.accept ?? []);
|
|
4417
4319
|
const used = /* @__PURE__ */ new Set();
|
|
4418
4320
|
const keep = (f) => {
|
|
@@ -4429,10 +4331,10 @@ function analyzeDuplicationRules(ruleMap, opts) {
|
|
|
4429
4331
|
const divergentNodes = findDivergentNodes(visited, shapeOf);
|
|
4430
4332
|
const structureLoss = findStructureLoss(visited, opts?.resolveRef);
|
|
4431
4333
|
const keywordRegexes = findKeywordRegexes(visited);
|
|
4432
|
-
const subsume = (
|
|
4334
|
+
const subsume = (fs3) => {
|
|
4433
4335
|
const covered = /* @__PURE__ */ new Set();
|
|
4434
4336
|
const surviving = /* @__PURE__ */ new Set();
|
|
4435
|
-
for (const f of [...
|
|
4337
|
+
for (const f of [...fs3].sort((a, b) => b.savings - a.savings)) {
|
|
4436
4338
|
if (f._members.every((m) => covered.has(m))) continue;
|
|
4437
4339
|
surviving.add(f.id);
|
|
4438
4340
|
for (const m of f._members) markSubtree(m, covered);
|
|
@@ -4555,10 +4457,10 @@ function findNearDuplicates(visited, interner, shapeOf, minSize) {
|
|
|
4555
4457
|
return out.sort((a, b) => b.savings - a.savings);
|
|
4556
4458
|
}
|
|
4557
4459
|
function findDivergentSlot(members, shapeOf) {
|
|
4558
|
-
const
|
|
4460
|
+
const path3 = [];
|
|
4559
4461
|
const defs = [];
|
|
4560
4462
|
let cur = [...members];
|
|
4561
|
-
for (let
|
|
4463
|
+
for (let guard = 0; guard < 64; guard++) {
|
|
4562
4464
|
const d0 = cur[0]._def;
|
|
4563
4465
|
const kidLists = cur.map((c) => childrenOf2(c._def));
|
|
4564
4466
|
const arity = kidLists[0].length;
|
|
@@ -4570,14 +4472,14 @@ function findDivergentSlot(members, shapeOf) {
|
|
|
4570
4472
|
}
|
|
4571
4473
|
if (diff.length !== 1) break;
|
|
4572
4474
|
const i = diff[0];
|
|
4573
|
-
|
|
4475
|
+
path3.push(i);
|
|
4574
4476
|
defs.push(d0);
|
|
4575
4477
|
cur = kidLists.map((k) => k[i]);
|
|
4576
4478
|
const nextArity = childrenOf2(cur[0]._def).length;
|
|
4577
4479
|
const samePayload = cur.every((c) => payloadKey(c, c._def) === payloadKey(cur[0], cur[0]._def));
|
|
4578
4480
|
if (!samePayload || nextArity === 0) break;
|
|
4579
4481
|
}
|
|
4580
|
-
if (
|
|
4482
|
+
if (path3.length === 0) return null;
|
|
4581
4483
|
let slotSize = 0;
|
|
4582
4484
|
const sizeOf = (p) => {
|
|
4583
4485
|
let n = 1;
|
|
@@ -4585,14 +4487,14 @@ function findDivergentSlot(members, shapeOf) {
|
|
|
4585
4487
|
return n;
|
|
4586
4488
|
};
|
|
4587
4489
|
for (const c of cur) slotSize = Math.max(slotSize, sizeOf(c));
|
|
4588
|
-
return { path:
|
|
4490
|
+
return { path: path3, defs, variants: cur, slotSize };
|
|
4589
4491
|
}
|
|
4590
|
-
function renderWithHole(p,
|
|
4591
|
-
if (depth ===
|
|
4492
|
+
function renderWithHole(p, path3, depth = 0) {
|
|
4493
|
+
if (depth === path3.length) return "\u2039slot\u203A";
|
|
4592
4494
|
const d = p._def;
|
|
4593
4495
|
const kids = childrenOf2(d);
|
|
4594
|
-
const idx =
|
|
4595
|
-
const parts = kids.map((k, i) => i === idx ? renderWithHole(k,
|
|
4496
|
+
const idx = path3[depth];
|
|
4497
|
+
const parts = kids.map((k, i) => i === idx ? renderWithHole(k, path3, depth + 1) : render(k, 2));
|
|
4596
4498
|
switch (d.tag) {
|
|
4597
4499
|
case "sequence":
|
|
4598
4500
|
return `sequence(${parts.join(", ")})`;
|
|
@@ -4796,13 +4698,13 @@ function findRegexClasses(visited) {
|
|
|
4796
4698
|
}
|
|
4797
4699
|
return out.sort((a, b) => Number(b.drifted) - Number(a.drifted) || b.count - a.count);
|
|
4798
4700
|
}
|
|
4799
|
-
function
|
|
4701
|
+
function intersects2(a, b) {
|
|
4800
4702
|
if (a.kind === "any" || b.kind === "any") return true;
|
|
4801
4703
|
if (a.kind === "empty" || b.kind === "empty") return false;
|
|
4802
4704
|
for (const ra of a.ranges) for (const rb of b.ranges) if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
|
|
4803
4705
|
return false;
|
|
4804
4706
|
}
|
|
4805
|
-
function
|
|
4707
|
+
function intersection(a, b) {
|
|
4806
4708
|
if (a.kind === "any") return b;
|
|
4807
4709
|
if (b.kind === "any") return a;
|
|
4808
4710
|
if (a.kind === "empty" || b.kind === "empty") return { kind: "empty" };
|
|
@@ -4831,19 +4733,19 @@ function leadingRegex(arm) {
|
|
|
4831
4733
|
const t = termsOf(arm)[0];
|
|
4832
4734
|
return t !== void 0 && t._def.tag === "regex";
|
|
4833
4735
|
}
|
|
4834
|
-
function findOverlaps(visited, shapeOf,
|
|
4736
|
+
function findOverlaps(visited, shapeOf, resolve3) {
|
|
4835
4737
|
const out = [];
|
|
4836
4738
|
for (const v2 of visited.values()) {
|
|
4837
4739
|
const d = v2.d;
|
|
4838
4740
|
if (d.tag !== "choice") continue;
|
|
4839
4741
|
const arms = d.parsers;
|
|
4840
|
-
const
|
|
4742
|
+
const fs3 = arms.map((a) => firstSetOf(a, /* @__PURE__ */ new Set(), resolve3));
|
|
4841
4743
|
const strategy = d.strategy;
|
|
4842
4744
|
for (let i = 0; i < arms.length; i++) {
|
|
4843
4745
|
for (let j = i + 1; j < arms.length; j++) {
|
|
4844
|
-
const A =
|
|
4746
|
+
const A = fs3[i], B = fs3[j];
|
|
4845
4747
|
if (A.kind === "any" || B.kind === "any") continue;
|
|
4846
|
-
if (!
|
|
4748
|
+
if (!intersects2(A, B)) continue;
|
|
4847
4749
|
const ta = termsOf(arms[i]), tb = termsOf(arms[j]);
|
|
4848
4750
|
let shared = 0;
|
|
4849
4751
|
while (shared < ta.length && shared < tb.length && shapeOf(ta[shared]) === shapeOf(tb[shared])) shared++;
|
|
@@ -4855,7 +4757,7 @@ function findOverlaps(visited, shapeOf, resolve2) {
|
|
|
4855
4757
|
site: v2.site,
|
|
4856
4758
|
a: i,
|
|
4857
4759
|
b: j,
|
|
4858
|
-
on:
|
|
4760
|
+
on: intersection(A, B),
|
|
4859
4761
|
sharedLeadingTerms: shared,
|
|
4860
4762
|
sharedPrefix: shared > 0 ? clamp(ta.slice(0, shared).map((t) => render(t, 2)).join(", ")) : null,
|
|
4861
4763
|
handledByStrategy: handled,
|
|
@@ -5157,7 +5059,7 @@ function nestedNodeTypes(root, out, seen, isRoot) {
|
|
|
5157
5059
|
for (const k of childrenOf2(d)) nestedNodeTypes(k, out, seen, false);
|
|
5158
5060
|
}
|
|
5159
5061
|
var MAX_LOST_TYPES = 8;
|
|
5160
|
-
function findStructureLoss(visited,
|
|
5062
|
+
function findStructureLoss(visited, resolve3) {
|
|
5161
5063
|
const nestedCache = /* @__PURE__ */ new Map();
|
|
5162
5064
|
const nested = (p) => {
|
|
5163
5065
|
const hit = nestedCache.get(p);
|
|
@@ -5174,18 +5076,18 @@ function findStructureLoss(visited, resolve2) {
|
|
|
5174
5076
|
const arms = d.parsers;
|
|
5175
5077
|
const resolved = arms.map(resolveArm);
|
|
5176
5078
|
const nodeTypes = resolved.map(wrappingNodeType);
|
|
5177
|
-
const
|
|
5079
|
+
const fs3 = arms.map((a) => firstSetOf(a, /* @__PURE__ */ new Set(), resolve3));
|
|
5178
5080
|
for (let i = 0; i < arms.length; i++) {
|
|
5179
5081
|
if (d.gates[i] != null) continue;
|
|
5180
5082
|
const type = nodeTypes[i] ?? null;
|
|
5181
5083
|
if (type === null) continue;
|
|
5182
5084
|
if (nested(resolved[i]).size !== 0) continue;
|
|
5183
|
-
const A =
|
|
5085
|
+
const A = fs3[i];
|
|
5184
5086
|
if (A.kind === "any") continue;
|
|
5185
5087
|
for (let j = i + 1; j < arms.length; j++) {
|
|
5186
5088
|
if (nodeTypes[j] !== type) continue;
|
|
5187
|
-
const B =
|
|
5188
|
-
if (B.kind === "any" || !
|
|
5089
|
+
const B = fs3[j];
|
|
5090
|
+
if (B.kind === "any" || !intersects2(A, B)) continue;
|
|
5189
5091
|
const lost = nested(resolved[j]);
|
|
5190
5092
|
if (lost.size === 0) continue;
|
|
5191
5093
|
const lostNodeTypes = [...lost].sort();
|
|
@@ -5196,7 +5098,7 @@ function findStructureLoss(visited, resolve2) {
|
|
|
5196
5098
|
nodeType: type,
|
|
5197
5099
|
earlier: i,
|
|
5198
5100
|
later: j,
|
|
5199
|
-
on:
|
|
5101
|
+
on: intersection(A, B),
|
|
5200
5102
|
lostNodeTypes: lostNodeTypes.slice(0, MAX_LOST_TYPES),
|
|
5201
5103
|
earlierShape: clamp(render(resolved[i], 3)),
|
|
5202
5104
|
laterShape: clamp(render(resolved[j], 3)),
|
|
@@ -5454,11 +5356,11 @@ function buildBalancedInterior(open, close, skips) {
|
|
|
5454
5356
|
return combi;
|
|
5455
5357
|
}
|
|
5456
5358
|
function firstSetClassChars(c) {
|
|
5457
|
-
const
|
|
5458
|
-
if (
|
|
5459
|
-
if (
|
|
5359
|
+
const fs3 = c._meta.firstSet;
|
|
5360
|
+
if (fs3.kind === "empty") return [];
|
|
5361
|
+
if (fs3.kind !== "ranges") return null;
|
|
5460
5362
|
const out = [];
|
|
5461
|
-
for (const { lo, hi } of
|
|
5363
|
+
for (const { lo, hi } of fs3.ranges) {
|
|
5462
5364
|
if (hi - lo > 8) return null;
|
|
5463
5365
|
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
5464
5366
|
}
|
|
@@ -5472,13 +5374,13 @@ function escapeClassChar(ch2) {
|
|
|
5472
5374
|
function idPart(value) {
|
|
5473
5375
|
return encodeURIComponent(value);
|
|
5474
5376
|
}
|
|
5475
|
-
function dispatchArmIds(def,
|
|
5377
|
+
function dispatchArmIds(def, path3) {
|
|
5476
5378
|
const ids = [];
|
|
5477
|
-
for (const entry of def.cases) ids.push(`dispatch:${
|
|
5379
|
+
for (const entry of def.cases) ids.push(`dispatch:${path3}/when:${entry.keys.map(idPart).join("|")}`);
|
|
5478
5380
|
for (const entry of def.matchers ?? []) {
|
|
5479
|
-
ids.push(`dispatch:${
|
|
5381
|
+
ids.push(`dispatch:${path3}/matcher:${entry.kind}:${idPart(entry.value)}${entry.kind === "matches" && entry.flags ? `:${idPart(entry.flags)}` : ""}`);
|
|
5480
5382
|
}
|
|
5481
|
-
if (def.otherwise) ids.push(`dispatch:${
|
|
5383
|
+
if (def.otherwise) ids.push(`dispatch:${path3}/otherwise`);
|
|
5482
5384
|
return ids;
|
|
5483
5385
|
}
|
|
5484
5386
|
function children(def, winners) {
|
|
@@ -5517,7 +5419,15 @@ function children(def, winners) {
|
|
|
5517
5419
|
let resolved;
|
|
5518
5420
|
try {
|
|
5519
5421
|
resolved = def.thunk();
|
|
5520
|
-
} catch {
|
|
5422
|
+
} catch (e) {
|
|
5423
|
+
recordDegradation({
|
|
5424
|
+
code: "coverage-definitions-unavailable",
|
|
5425
|
+
severity: "warn",
|
|
5426
|
+
where: "<lazy rule reference>",
|
|
5427
|
+
subject: `unresolvable reference (${e.message})`,
|
|
5428
|
+
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",
|
|
5429
|
+
otherwise: "the referenced rule and its whole subtree would contribute definitions"
|
|
5430
|
+
});
|
|
5521
5431
|
return [];
|
|
5522
5432
|
}
|
|
5523
5433
|
const name = resolved._ruleName;
|
|
@@ -5547,7 +5457,7 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5547
5457
|
}
|
|
5548
5458
|
}
|
|
5549
5459
|
const seen = /* @__PURE__ */ new Set();
|
|
5550
|
-
const visit = (parser2,
|
|
5460
|
+
const visit = (parser2, path3) => {
|
|
5551
5461
|
if (seen.has(parser2)) return;
|
|
5552
5462
|
seen.add(parser2);
|
|
5553
5463
|
const rule = winnerNames.get(parser2) ?? parser2._ruleName;
|
|
@@ -5557,22 +5467,22 @@ function buildGrammarPlan(entry, winners) {
|
|
|
5557
5467
|
rules2.set(parser2, id);
|
|
5558
5468
|
}
|
|
5559
5469
|
if (parser2._def.tag === "choice") {
|
|
5560
|
-
const ids = parser2._def.parsers.map((_, index) => `choice:${
|
|
5470
|
+
const ids = parser2._def.parsers.map((_, index) => `choice:${path3}/arm:${index}`);
|
|
5561
5471
|
choices.set(parser2, ids);
|
|
5562
5472
|
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
5563
5473
|
}
|
|
5564
5474
|
if (parser2._def.tag === "dispatch") {
|
|
5565
|
-
const ids = dispatchArmIds(parser2._def,
|
|
5475
|
+
const ids = dispatchArmIds(parser2._def, path3);
|
|
5566
5476
|
dispatches.set(parser2, ids);
|
|
5567
5477
|
ids.forEach((id) => definitions.set(id, { id, kind: "dispatch-arm" }));
|
|
5568
5478
|
}
|
|
5569
|
-
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${
|
|
5479
|
+
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path3}`);
|
|
5570
5480
|
if (parser2._def.tag === "label") {
|
|
5571
|
-
const id = `label:${
|
|
5481
|
+
const id = `label:${path3}`;
|
|
5572
5482
|
labels.set(parser2, [id]);
|
|
5573
5483
|
definitions.set(id, { id, kind: "label" });
|
|
5574
5484
|
}
|
|
5575
|
-
children(parser2._def, winners).forEach((child, index) => visit(child, `${
|
|
5485
|
+
children(parser2._def, winners).forEach((child, index) => visit(child, `${path3}/${parser2._def.tag}:${index}`));
|
|
5576
5486
|
};
|
|
5577
5487
|
const roots = Array.isArray(entry) ? entry : [entry];
|
|
5578
5488
|
for (const root of roots) {
|
|
@@ -6344,10 +6254,10 @@ var ALT_SWITCH_MIN_CASES = 3;
|
|
|
6344
6254
|
function planAltSwitch(firsts) {
|
|
6345
6255
|
const cases = [];
|
|
6346
6256
|
let total = 0;
|
|
6347
|
-
for (const
|
|
6348
|
-
if (!
|
|
6257
|
+
for (const fs3 of firsts) {
|
|
6258
|
+
if (!fs3 || fs3.negated) return { kind: "if" };
|
|
6349
6259
|
const pts = [];
|
|
6350
|
-
for (const [lo, hi] of
|
|
6260
|
+
for (const [lo, hi] of fs3.ranges) {
|
|
6351
6261
|
if (hi - lo + 1 > ALT_SWITCH_RANGE_LIMIT) return { kind: "if" };
|
|
6352
6262
|
for (let cp = lo; cp <= hi; cp++) pts.push(cp);
|
|
6353
6263
|
}
|
|
@@ -6422,8 +6332,8 @@ function emitShapeMatch(shape, start, mint, ind2, firstChar) {
|
|
|
6422
6332
|
} else {
|
|
6423
6333
|
const c0 = codeAt(start, firstChar);
|
|
6424
6334
|
shape.arms.forEach((arm, k) => {
|
|
6425
|
-
const
|
|
6426
|
-
const cond =
|
|
6335
|
+
const fs3 = shape.firsts[k];
|
|
6336
|
+
const cond = fs3.negated ? `!(${classCond(c0, fs3.ranges)})` : `(${classCond(c0, fs3.ranges)})`;
|
|
6427
6337
|
const m = emitShapeMatch(arm, start, mint, `${ind2} `, firstChar);
|
|
6428
6338
|
lines.push(`${ind2}${k === 0 ? "if" : "else if"} (${start} < input.length && ${cond}) {`);
|
|
6429
6339
|
lines.push(...m.setup);
|
|
@@ -6840,27 +6750,53 @@ function emitScannableTerminal(shape, c) {
|
|
|
6840
6750
|
}
|
|
6841
6751
|
|
|
6842
6752
|
// src/compiler/inline-build.ts
|
|
6843
|
-
var
|
|
6753
|
+
var ANN = String.raw`\s*\??\s*(?::[^,)=]+)?`;
|
|
6754
|
+
var ANY_P = String.raw`\w+${ANN}`;
|
|
6755
|
+
var MK_BUILD_RE = new RegExp(
|
|
6756
|
+
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*$`
|
|
6757
|
+
);
|
|
6844
6758
|
function escapeRegExp(s) {
|
|
6845
6759
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6846
6760
|
}
|
|
6761
|
+
function identMkBuildRe(typeIdent) {
|
|
6762
|
+
return new RegExp(
|
|
6763
|
+
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*$`
|
|
6764
|
+
);
|
|
6765
|
+
}
|
|
6847
6766
|
function looseMkBuildRe(type) {
|
|
6848
6767
|
return new RegExp(
|
|
6849
|
-
String.raw`^\(\s*(\w+)\s*,\s
|
|
6768
|
+
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*$`
|
|
6850
6769
|
);
|
|
6851
6770
|
}
|
|
6771
|
+
var LOOKS_LIKE_MK_RE = /=>\s*(?:[\w$.]*\.)?mk\s*\(/;
|
|
6852
6772
|
function analyzeMkInlineBuild(def) {
|
|
6853
6773
|
if (!def.build) return null;
|
|
6854
6774
|
if (def.type === void 0) return null;
|
|
6855
|
-
const src = (def
|
|
6775
|
+
const src = buildAnalysisSrc(def).trim();
|
|
6856
6776
|
const strict = src.match(MK_BUILD_RE);
|
|
6857
6777
|
if (strict) {
|
|
6858
6778
|
const mkType = strict[6];
|
|
6859
|
-
|
|
6779
|
+
if (mkType === def.type) return def.type;
|
|
6780
|
+
reportMkMiss(def.type, src, `it builds a "${mkType}" node, not "${def.type}"`);
|
|
6781
|
+
return null;
|
|
6860
6782
|
}
|
|
6861
6783
|
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
6784
|
+
if (def.typeSrc !== void 0 && identMkBuildRe(def.typeSrc).test(src)) return def.type;
|
|
6785
|
+
if (LOOKS_LIKE_MK_RE.test(src)) {
|
|
6786
|
+
reportMkMiss(def.type, src, "its parameter list or argument order does not match `(children, fields, span, rawChildren, triviaLog) => mk(type, children, rawChildren, span, triviaLog)`");
|
|
6787
|
+
}
|
|
6862
6788
|
return null;
|
|
6863
6789
|
}
|
|
6790
|
+
function reportMkMiss(type, src, why) {
|
|
6791
|
+
recordDegradation({
|
|
6792
|
+
code: "mk-inline-missed",
|
|
6793
|
+
severity: "warn",
|
|
6794
|
+
where: `node("${type}")`,
|
|
6795
|
+
subject: `build reducer \`${src.split("\n")[0].slice(0, 80)}\``,
|
|
6796
|
+
fellBackTo: `looks like an inline-\`mk\` builder but ${why}, so every match pays a \`_build[n](...)\` call instead of an inlined object literal`,
|
|
6797
|
+
otherwise: "the node object would be constructed at the call site with no call frame"
|
|
6798
|
+
});
|
|
6799
|
+
}
|
|
6864
6800
|
function emitInlineMkNodeExpr(type, chV, rawV, spanExpr, tlV) {
|
|
6865
6801
|
return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: ${spanExpr}, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
|
|
6866
6802
|
}
|
|
@@ -7043,7 +6979,30 @@ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
7043
6979
|
seen.delete(p);
|
|
7044
6980
|
}
|
|
7045
6981
|
}
|
|
6982
|
+
function tern(cond, whenTrue, whenFalse) {
|
|
6983
|
+
if (cond === "false") return whenFalse;
|
|
6984
|
+
if (cond === "true") return whenTrue;
|
|
6985
|
+
return `${cond} ? ${whenTrue} : ${whenFalse}`;
|
|
6986
|
+
}
|
|
6987
|
+
function notGate(cond) {
|
|
6988
|
+
if (cond === "false") return "true";
|
|
6989
|
+
if (cond === "true") return "false";
|
|
6990
|
+
return `!(${cond})`;
|
|
6991
|
+
}
|
|
6992
|
+
function orGate(a, b) {
|
|
6993
|
+
if (a === "false") return b;
|
|
6994
|
+
if (b === "false") return a;
|
|
6995
|
+
if (a === "true" || b === "true") return "true";
|
|
6996
|
+
return `${a} || ${b}`;
|
|
6997
|
+
}
|
|
6998
|
+
function andGate(a, b) {
|
|
6999
|
+
if (a === "false" || b === "false") return "false";
|
|
7000
|
+
if (a === "true") return b;
|
|
7001
|
+
if (b === "true") return a;
|
|
7002
|
+
return `${a} && ${b}`;
|
|
7003
|
+
}
|
|
7046
7004
|
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 }";
|
|
7005
|
+
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 } }";
|
|
7047
7006
|
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 }";
|
|
7048
7007
|
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] } }";
|
|
7049
7008
|
var _loweringSink = null;
|
|
@@ -7055,6 +7014,27 @@ function endLoweringCapture() {
|
|
|
7055
7014
|
_loweringSink = null;
|
|
7056
7015
|
return misses;
|
|
7057
7016
|
}
|
|
7017
|
+
var _inlineCapSink = null;
|
|
7018
|
+
function beginInlineCapCapture() {
|
|
7019
|
+
_inlineCapSink = [];
|
|
7020
|
+
}
|
|
7021
|
+
function endInlineCapCapture() {
|
|
7022
|
+
const sites = _inlineCapSink ?? [];
|
|
7023
|
+
_inlineCapSink = null;
|
|
7024
|
+
return sites;
|
|
7025
|
+
}
|
|
7026
|
+
function formatInlineCapSites(sites, max) {
|
|
7027
|
+
if (sites.length === 0) return [];
|
|
7028
|
+
const byFn = /* @__PURE__ */ new Map();
|
|
7029
|
+
for (const s of sites) {
|
|
7030
|
+
const cur = byFn.get(s.fn);
|
|
7031
|
+
if (cur) {
|
|
7032
|
+
cur.count += 1;
|
|
7033
|
+
cur.nodes += s.nodes;
|
|
7034
|
+
} else byFn.set(s.fn, { count: 1, nodes: s.nodes });
|
|
7035
|
+
}
|
|
7036
|
+
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.`);
|
|
7037
|
+
}
|
|
7058
7038
|
function hasSelectedRootTrivia(ctx) {
|
|
7059
7039
|
return ctx.rootTriviaClassified === true;
|
|
7060
7040
|
}
|
|
@@ -7338,10 +7318,10 @@ function ensureTriviaFn(ctx) {
|
|
|
7338
7318
|
function ensureTriviaCaptureFn(ctx) {
|
|
7339
7319
|
return ensureTriviaFn(ctx);
|
|
7340
7320
|
}
|
|
7341
|
-
function firstSetCond(codeVar,
|
|
7342
|
-
if (
|
|
7343
|
-
if (
|
|
7344
|
-
return
|
|
7321
|
+
function firstSetCond(codeVar, fs3) {
|
|
7322
|
+
if (fs3.kind === "any") return "true";
|
|
7323
|
+
if (fs3.kind === "empty") return "false";
|
|
7324
|
+
return fs3.ranges.map(
|
|
7345
7325
|
(r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
|
|
7346
7326
|
).join(" || ");
|
|
7347
7327
|
}
|
|
@@ -7354,10 +7334,10 @@ function planDisjointDispatch(parsers) {
|
|
|
7354
7334
|
const cases = [];
|
|
7355
7335
|
let total = 0;
|
|
7356
7336
|
for (const p of parsers) {
|
|
7357
|
-
const
|
|
7358
|
-
if (
|
|
7337
|
+
const fs3 = p._meta.firstSet;
|
|
7338
|
+
if (fs3.kind !== "ranges") return { kind: "if" };
|
|
7359
7339
|
const pts = [];
|
|
7360
|
-
for (const r of
|
|
7340
|
+
for (const r of fs3.ranges) {
|
|
7361
7341
|
if (r.hi - r.lo + 1 > SWITCH_RANGE_LIMIT) return { kind: "if" };
|
|
7362
7342
|
for (let cp = r.lo; cp <= r.hi; cp++) pts.push(cp);
|
|
7363
7343
|
}
|
|
@@ -7750,9 +7730,9 @@ function emitRegex(def, ctx, pos, canMatchNewline = true) {
|
|
|
7750
7730
|
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
7751
7731
|
return { stmts, valueVar: vv, endVar };
|
|
7752
7732
|
}
|
|
7753
|
-
function syncSentinelExpr(
|
|
7754
|
-
if (
|
|
7755
|
-
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(
|
|
7733
|
+
function syncSentinelExpr(fs3) {
|
|
7734
|
+
if (fs3.kind !== "ranges" || fs3.ranges.length === 0) return null;
|
|
7735
|
+
return `_ctx._rec.sentinel({ kind: 'ranges', ranges: ${JSON.stringify(fs3.ranges)} })`;
|
|
7756
7736
|
}
|
|
7757
7737
|
function emitSeqValues(def, ctx, pos) {
|
|
7758
7738
|
const startV = v(ctx, "_start");
|
|
@@ -7766,8 +7746,8 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
7766
7746
|
if (ctx.recovery) stmts.push(`${ind(ctx)}const ${syncInV} = _ctx._sync`);
|
|
7767
7747
|
const publishSync = (i) => {
|
|
7768
7748
|
if (!ctx.recovery) return "";
|
|
7769
|
-
const
|
|
7770
|
-
const ref2 = syncSentinelExpr(
|
|
7749
|
+
const fs3 = def.parsers.slice(i + 1).reduce((acc, p) => union(acc, firstSetOf(p)), { kind: "empty" });
|
|
7750
|
+
const ref2 = syncSentinelExpr(fs3);
|
|
7771
7751
|
return `${ind(ctx)}if (_ctx._tolerant) _ctx._sync = ${ref2 ?? syncInV}`;
|
|
7772
7752
|
};
|
|
7773
7753
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
@@ -7803,9 +7783,11 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
7803
7783
|
const markLog = v(ctx, "_mklg");
|
|
7804
7784
|
const markRootLog = hasSelectedRootTrivia(ctx) ? v(ctx, "_mkrlg") : null;
|
|
7805
7785
|
const scanEndV = v(ctx, "_sne");
|
|
7806
|
-
const
|
|
7786
|
+
const logV = v(ctx, "_tlg");
|
|
7787
|
+
const capArg = ctx.noHoist ? "0" : hasSelectedRootTrivia(ctx) ? `(${logV} !== undefined || _ctx._rootTriviaLog !== undefined) ? 2 : 0` : `${logV} !== undefined ? 2 : 0`;
|
|
7807
7788
|
stmts.push(
|
|
7808
|
-
`${ind(ctx)}const ${
|
|
7789
|
+
`${ind(ctx)}const ${logV} = _ctx._triviaLog`,
|
|
7790
|
+
`${ind(ctx)}const ${markLog} = ${logV} !== undefined ? ${logV}.length : 0`,
|
|
7809
7791
|
...markRootLog ? [`${ind(ctx)}const ${markRootLog} = _ctx._rootTriviaLog ? _ctx._rootTriviaLog.length : 0`] : [],
|
|
7810
7792
|
`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`,
|
|
7811
7793
|
...emitLineTrack(ctx, curV, scanEndV)
|
|
@@ -7815,7 +7797,7 @@ function emitSeqValues(def, ctx, pos) {
|
|
|
7815
7797
|
const endAfterV = v(ctx, "_sea");
|
|
7816
7798
|
stmts.push(
|
|
7817
7799
|
`${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
|
|
7818
|
-
`${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else { if (
|
|
7800
|
+
`${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};` : ""} }`
|
|
7819
7801
|
);
|
|
7820
7802
|
valueVars.push(r2.valueVar);
|
|
7821
7803
|
continue;
|
|
@@ -7881,8 +7863,8 @@ function canMatchEmptyAtStart(p) {
|
|
|
7881
7863
|
}
|
|
7882
7864
|
}
|
|
7883
7865
|
function needsFirstSetGuard(p) {
|
|
7884
|
-
const
|
|
7885
|
-
return
|
|
7866
|
+
const fs3 = p._meta.firstSet;
|
|
7867
|
+
return fs3.kind !== "any" && !canMatchEmptyAtStart(p);
|
|
7886
7868
|
}
|
|
7887
7869
|
function coverageHit(ctx, id, offset = "_pos", end) {
|
|
7888
7870
|
return id === void 0 ? [] : [
|
|
@@ -8887,9 +8869,18 @@ function emitPeek(def, ctx, pos) {
|
|
|
8887
8869
|
endVar: pos
|
|
8888
8870
|
};
|
|
8889
8871
|
}
|
|
8890
|
-
function emitRouted(ctx, pos) {
|
|
8872
|
+
function emitRouted(ctx, pos, def) {
|
|
8891
8873
|
const local = ctx.routedLocal;
|
|
8874
|
+
const fallback = def.fallback;
|
|
8892
8875
|
if (local !== void 0) {
|
|
8876
|
+
if (fallback !== void 0 && local.startVar !== pos) {
|
|
8877
|
+
return emitRoutedWithFallback(ctx, pos, fallback, {
|
|
8878
|
+
test: `${local.startVar} === ${pos}`,
|
|
8879
|
+
valExpr: local.valueVar,
|
|
8880
|
+
startExpr: local.startVar,
|
|
8881
|
+
endExpr: local.endVar
|
|
8882
|
+
});
|
|
8883
|
+
}
|
|
8893
8884
|
return {
|
|
8894
8885
|
stmts: [
|
|
8895
8886
|
...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
@@ -8900,9 +8891,19 @@ function emitRouted(ctx, pos) {
|
|
|
8900
8891
|
};
|
|
8901
8892
|
}
|
|
8902
8893
|
const item = v(ctx, "_rt");
|
|
8894
|
+
const read = `${ind(ctx)}const ${item} = _ctx._routed`;
|
|
8895
|
+
if (fallback !== void 0) {
|
|
8896
|
+
const r = emitRoutedWithFallback(ctx, pos, fallback, {
|
|
8897
|
+
test: `${item} !== undefined && ${item}.span.start === ${pos}`,
|
|
8898
|
+
valExpr: `${item}.value`,
|
|
8899
|
+
startExpr: `${item}.span.start`,
|
|
8900
|
+
endExpr: `${item}.span.end`
|
|
8901
|
+
});
|
|
8902
|
+
return { ...r, stmts: [read, ...r.stmts] };
|
|
8903
|
+
}
|
|
8903
8904
|
return {
|
|
8904
8905
|
stmts: [
|
|
8905
|
-
|
|
8906
|
+
read,
|
|
8906
8907
|
...emitIfFail(ctx, `${item} === undefined || ${item}.span.start !== ${pos}`, failBody(ctx, '"routed()"', pos)),
|
|
8907
8908
|
...emitLeafCapture(ctx, `${item}.value`, `${item}.span.start`, `${item}.span.end`)
|
|
8908
8909
|
],
|
|
@@ -8910,6 +8911,30 @@ function emitRouted(ctx, pos) {
|
|
|
8910
8911
|
endVar: `${item}.span.end`
|
|
8911
8912
|
};
|
|
8912
8913
|
}
|
|
8914
|
+
function emitRoutedWithFallback(ctx, pos, fallback, routed2) {
|
|
8915
|
+
const valV = v(ctx, "_rtv");
|
|
8916
|
+
const endV = v(ctx, "_rte");
|
|
8917
|
+
const i = ind(ctx);
|
|
8918
|
+
ctx.indent++;
|
|
8919
|
+
const capture = emitLeafCapture(ctx, routed2.valExpr, routed2.startExpr, routed2.endExpr);
|
|
8920
|
+
const fb = emit(fallback, ctx, pos);
|
|
8921
|
+
const inner = ind(ctx);
|
|
8922
|
+
ctx.indent--;
|
|
8923
|
+
return {
|
|
8924
|
+
stmts: [
|
|
8925
|
+
`${i}let ${valV}, ${endV}`,
|
|
8926
|
+
`${i}if (${routed2.test}) {`,
|
|
8927
|
+
...capture,
|
|
8928
|
+
`${inner}${valV} = ${routed2.valExpr}; ${endV} = ${routed2.endExpr}`,
|
|
8929
|
+
`${i}} else {`,
|
|
8930
|
+
...fb.stmts,
|
|
8931
|
+
`${inner}${valV} = ${fb.valueVar}; ${endV} = ${fb.endVar}`,
|
|
8932
|
+
`${i}}`
|
|
8933
|
+
],
|
|
8934
|
+
valueVar: valV,
|
|
8935
|
+
endVar: endV
|
|
8936
|
+
};
|
|
8937
|
+
}
|
|
8913
8938
|
function escapeTokenLiteral(value) {
|
|
8914
8939
|
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
8915
8940
|
}
|
|
@@ -9091,22 +9116,16 @@ function emitNode(def, ctx, pos) {
|
|
|
9091
9116
|
const smk = structural ? v(ctx, "_smk") : null;
|
|
9092
9117
|
if (structural) ctx.needsHostReads = true;
|
|
9093
9118
|
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
9094
|
-
const
|
|
9095
|
-
const
|
|
9096
|
-
const profileRecognizer = recV;
|
|
9097
|
-
const profileCapture = capV;
|
|
9098
|
-
const cstMode = ctx.hostMode === "cst";
|
|
9099
|
-
const directCstV = !structural && !cstMode && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
9100
|
-
const directCstGate = directCstV === null ? "false" : profileCapture;
|
|
9119
|
+
const profileRecognizer = "false";
|
|
9120
|
+
const profileCapture = "false";
|
|
9101
9121
|
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
9102
9122
|
const chNeededExpr = def.unwrap || def.collapse ? "true" : `(_ctx._pmReadsCh ??= (_ctx.build === undefined || _ctx.build._parsemanReadsChildren !== false || _ctx.build._parsemanCstCollapse !== undefined))`;
|
|
9103
|
-
const chAlloc = def.unwrap || def.collapse ?
|
|
9104
|
-
const
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
|
|
9123
|
+
const chAlloc = def.unwrap || def.collapse ? tern(profileRecognizer, "undefined", "[]") : tern(profileRecognizer, "undefined", `${tern(orGate(profileCapture, chNeededExpr), "[]", "undefined")}`);
|
|
9124
|
+
const dcstAlloc = "undefined";
|
|
9125
|
+
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))"))}` : ""}
|
|
9126
|
+
${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)}`;
|
|
9108
9127
|
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
9109
|
-
const fieldsOn = structural ? capFv ?? "false" :
|
|
9128
|
+
const fieldsOn = structural ? capFv ?? "false" : tern(profileRecognizer, "false", capturesFields ? "true" : "false");
|
|
9110
9129
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
9111
9130
|
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
9112
9131
|
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
@@ -9115,7 +9134,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9115
9134
|
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}` : ""}` : "";
|
|
9116
9135
|
const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
|
|
9117
9136
|
const preGuard = [];
|
|
9118
|
-
if (!ctx.recovery && !ctx.coverage &&
|
|
9137
|
+
if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
|
|
9119
9138
|
const gcV = v(ctx, "_ngc");
|
|
9120
9139
|
const gExp = armStaticExpected(ctx, def.parser);
|
|
9121
9140
|
const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(ctx, gExp, pos);
|
|
@@ -9126,7 +9145,6 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9126
9145
|
}
|
|
9127
9146
|
const stmts = [
|
|
9128
9147
|
...preGuard,
|
|
9129
|
-
profHoist,
|
|
9130
9148
|
allocStmt,
|
|
9131
9149
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
9132
9150
|
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}${installTrivia}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
@@ -9143,21 +9161,13 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9143
9161
|
}
|
|
9144
9162
|
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}${restoreTrivia}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
9145
9163
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
9146
|
-
stmts.push(
|
|
9147
|
-
`${i}if (_ctx._pmProfile) {`,
|
|
9148
|
-
`${i} _ctx._pmProfile.nodes++`,
|
|
9149
|
-
`${i} if (${profileCapture}) {`,
|
|
9150
|
-
`${i} _ctx._pmProfile.childSlots += ${chV}.length; _ctx._pmProfile.rawSlots += ${rawV}.length; _ctx._pmProfile.triviaSlots += ${tlV}.length${fArr ? `; _ctx._pmProfile.fieldSlots += ${fArr} ? ${fArr}.length : 0` : ""}`,
|
|
9151
|
-
`${i} }`,
|
|
9152
|
-
`${i}}`
|
|
9153
|
-
);
|
|
9154
9164
|
let stV = "undefined";
|
|
9155
9165
|
if (structural) {
|
|
9156
9166
|
stV = v(ctx, "_nst");
|
|
9157
9167
|
stmts.push(`${i}const ${stV} = ${capSTv} && _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
9158
9168
|
} else if (clonesState) {
|
|
9159
9169
|
stV = v(ctx, "_nst");
|
|
9160
|
-
stmts.push(`${i}const ${stV} =
|
|
9170
|
+
stmts.push(`${i}const ${stV} = ${andGate(notGate(orGate(profileRecognizer, profileCapture)), "_ctx.state !== undefined")} ? Object.assign({}, _ctx.state) : undefined`);
|
|
9161
9171
|
}
|
|
9162
9172
|
if (sf && fArr) {
|
|
9163
9173
|
const fe = v(ctx, "_fe");
|
|
@@ -9181,19 +9191,22 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
|
|
|
9181
9191
|
if (ctx.lineTracking) stmts.push(`${i}const ${nodeSpanV} = ${nodeSpanExpr}`);
|
|
9182
9192
|
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})`;
|
|
9183
9193
|
const hostBuildArgs = `${JSON.stringify(def.type)}, ${chV}, ${fObj}, ${nodeSpanV}, ${rawV}, ${tlV}, ${stV}${def.tags !== void 0 && def.tags.length > 0 ? `, ${JSON.stringify(def.tags)}` : ""}`;
|
|
9184
|
-
const hostBuildExpr = `_ctx.
|
|
9194
|
+
const hostBuildExpr = `_ctx.build(${hostBuildArgs})`;
|
|
9185
9195
|
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
|
|
9186
|
-
const
|
|
9196
|
+
const hostCollapses = structural || cstOut;
|
|
9197
|
+
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;
|
|
9187
9198
|
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
9188
9199
|
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
9189
9200
|
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
);
|
|
9201
|
+
const ndGate = orGate(profileRecognizer, profileCapture);
|
|
9202
|
+
const recGate = notGate(profileRecognizer);
|
|
9203
|
+
const pushIndent = recGate === "true" ? i : `${i} `;
|
|
9204
|
+
const pushCh = `${pushIndent}if (${sc}) ${sc}.push(${ndV})`;
|
|
9205
|
+
ctx.needsRawEntry = true;
|
|
9206
|
+
const pushRaw = `${pushIndent}if (${sr}) ${sr}.push(_rawEntry(${ndV}, input, ${pos}, ${endVar}${ctx.lineTracking ? `, ${nodeSpanV}` : ""}))`;
|
|
9207
|
+
stmts.push(`${i}const ${ndV} = ${tern(ndGate, "undefined", `(${finalExpr})`)}`);
|
|
9208
|
+
if (recGate === "true") stmts.push(pushCh, pushRaw);
|
|
9209
|
+
else stmts.push(`${i}if (${recGate}) {`, pushCh, pushRaw, `${i}}`);
|
|
9197
9210
|
return { stmts, valueVar: ndV, endVar };
|
|
9198
9211
|
}
|
|
9199
9212
|
function emitRuntimeFallback(parser2, ctx, pos) {
|
|
@@ -9222,7 +9235,12 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9222
9235
|
} catch {
|
|
9223
9236
|
return emitRuntimeFallback(p, ctx, pos);
|
|
9224
9237
|
}
|
|
9225
|
-
|
|
9238
|
+
const cost = usage.sizes.get(resolved) ?? 1;
|
|
9239
|
+
if (cost <= ctx.inlineLeft) {
|
|
9240
|
+
ctx.inlineLeft -= cost;
|
|
9241
|
+
return emit(resolved, ctx, pos);
|
|
9242
|
+
}
|
|
9243
|
+
_inlineCapSink?.push({ fn: ctx.currentFnName ?? "<root>", nodes: cost });
|
|
9226
9244
|
}
|
|
9227
9245
|
if (!ctx.namedParsers.has(p)) {
|
|
9228
9246
|
const fnName2 = canonical2 ?? `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
@@ -9237,6 +9255,9 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9237
9255
|
const savedIndent = ctx.indent;
|
|
9238
9256
|
const savedFailLabel = ctx.failLabel;
|
|
9239
9257
|
const savedRecord = ctx.recordFail;
|
|
9258
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9259
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9260
|
+
ctx.currentFnName = fnName2;
|
|
9240
9261
|
const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
|
|
9241
9262
|
const savedActiveRule = ctx.activeCoverageRuleId;
|
|
9242
9263
|
const savedSuppressFailure = ctx.suppressCoverageFailure;
|
|
@@ -9251,6 +9272,8 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
9251
9272
|
ctx.indent = savedIndent;
|
|
9252
9273
|
ctx.failLabel = savedFailLabel;
|
|
9253
9274
|
ctx.recordFail = savedRecord;
|
|
9275
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9276
|
+
ctx.currentFnName = savedFnName;
|
|
9254
9277
|
ctx.activeCoverageRuleId = savedActiveRule;
|
|
9255
9278
|
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
9256
9279
|
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
@@ -9345,6 +9368,9 @@ function emit(p, ctx, pos) {
|
|
|
9345
9368
|
const savedIndent = ctx.indent;
|
|
9346
9369
|
const savedFailLabel = ctx.failLabel;
|
|
9347
9370
|
const savedRecord = ctx.recordFail;
|
|
9371
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9372
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9373
|
+
ctx.currentFnName = fnName;
|
|
9348
9374
|
ctx.indent = 1;
|
|
9349
9375
|
ctx.failLabel = "_pfail";
|
|
9350
9376
|
ctx.recordFail = true;
|
|
@@ -9352,6 +9378,8 @@ function emit(p, ctx, pos) {
|
|
|
9352
9378
|
ctx.indent = savedIndent;
|
|
9353
9379
|
ctx.failLabel = savedFailLabel;
|
|
9354
9380
|
ctx.recordFail = savedRecord;
|
|
9381
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9382
|
+
ctx.currentFnName = savedFnName;
|
|
9355
9383
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
9356
9384
|
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
9357
9385
|
}
|
|
@@ -9545,7 +9573,7 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9545
9573
|
case "peek":
|
|
9546
9574
|
return emitPeek(def, ctx, pos);
|
|
9547
9575
|
case "routed":
|
|
9548
|
-
return emitRouted(ctx, pos);
|
|
9576
|
+
return emitRouted(ctx, pos, def);
|
|
9549
9577
|
case "node":
|
|
9550
9578
|
return emitNode(def, ctx, pos);
|
|
9551
9579
|
case "scanTo":
|
|
@@ -9580,6 +9608,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9580
9608
|
const savedIndent = ctx.indent;
|
|
9581
9609
|
const savedFailLabel = ctx.failLabel;
|
|
9582
9610
|
const savedRecord = ctx.recordFail;
|
|
9611
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
9612
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
9613
|
+
ctx.currentFnName = fnName;
|
|
9583
9614
|
ctx.indent = 1;
|
|
9584
9615
|
ctx.failLabel = "_pfail";
|
|
9585
9616
|
ctx.recordFail = true;
|
|
@@ -9587,6 +9618,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
9587
9618
|
ctx.indent = savedIndent;
|
|
9588
9619
|
ctx.failLabel = savedFailLabel;
|
|
9589
9620
|
ctx.recordFail = savedRecord;
|
|
9621
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
9622
|
+
ctx.currentFnName = savedFnName;
|
|
9590
9623
|
pushNamedFnDecl(ctx, fnName, innerR.stmts, innerR.valueVar, innerR.endVar);
|
|
9591
9624
|
}
|
|
9592
9625
|
const fn = ctx.namedParsers.get(innerParser);
|
|
@@ -9745,12 +9778,16 @@ function childrenOf3(def) {
|
|
|
9745
9778
|
return [def.parser, def.sentinel];
|
|
9746
9779
|
case "scanTo":
|
|
9747
9780
|
return [def.sentinel, ...def.skip];
|
|
9781
|
+
// A `routed()` fallback IS emitted at this site (emitRouted), so the usage
|
|
9782
|
+
// analysis must see the edge — otherwise a fallback shared by several routed()
|
|
9783
|
+
// sites is miscounted as single-use and inlined at each.
|
|
9784
|
+
case "routed":
|
|
9785
|
+
return def.fallback ? [def.fallback] : [];
|
|
9748
9786
|
case "lazy":
|
|
9749
9787
|
case "literal":
|
|
9750
9788
|
case "regex":
|
|
9751
9789
|
case "keywords":
|
|
9752
9790
|
case "guard":
|
|
9753
|
-
case "routed":
|
|
9754
9791
|
case "unknown":
|
|
9755
9792
|
return [];
|
|
9756
9793
|
}
|
|
@@ -9771,6 +9808,17 @@ function isHoistableTag(tag) {
|
|
|
9771
9808
|
return HOISTABLE_TAGS.has(tag);
|
|
9772
9809
|
}
|
|
9773
9810
|
var HOIST_MIN_SUBTREE = 3;
|
|
9811
|
+
var INLINE_MAX_NODES = 1e3;
|
|
9812
|
+
function resolveInlineMax(explicit) {
|
|
9813
|
+
if (explicit !== void 0) return explicit;
|
|
9814
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_MAX_INLINE : void 0;
|
|
9815
|
+
if (env !== void 0 && env !== "") {
|
|
9816
|
+
if (env === "off" || env === "infinity") return Infinity;
|
|
9817
|
+
const n = Number(env);
|
|
9818
|
+
if (Number.isFinite(n) && n >= 0) return n;
|
|
9819
|
+
}
|
|
9820
|
+
return INLINE_MAX_NODES;
|
|
9821
|
+
}
|
|
9774
9822
|
function analyzeLazyUsage(root) {
|
|
9775
9823
|
return analyzeLazyUsageMulti([root]);
|
|
9776
9824
|
}
|
|
@@ -9876,102 +9924,6 @@ function ruleDependencies(ruleMap) {
|
|
|
9876
9924
|
}
|
|
9877
9925
|
return deps;
|
|
9878
9926
|
}
|
|
9879
|
-
function resolveGatingLevel(opt) {
|
|
9880
|
-
const explicit = typeof opt === "string" ? opt : opt?.level;
|
|
9881
|
-
if (explicit !== void 0) return explicit;
|
|
9882
|
-
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_GATING : void 0;
|
|
9883
|
-
if (env === "off" || env === "warn" || env === "error") return env;
|
|
9884
|
-
return "warn";
|
|
9885
|
-
}
|
|
9886
|
-
function runGatingDiagnostic(combinator, opt) {
|
|
9887
|
-
return reportGating(opt, (o) => analyzeGating(combinator, o));
|
|
9888
|
-
}
|
|
9889
|
-
function runGatingDiagnosticRules(ruleMap, opt) {
|
|
9890
|
-
return reportGating(opt, (o) => analyzeGatingRules(ruleMap, o));
|
|
9891
|
-
}
|
|
9892
|
-
function runFusedGatingDiagnostic(getRuleMaps, opt, getOpaque) {
|
|
9893
|
-
if (resolveGatingLevel(opt) === "off") return void 0;
|
|
9894
|
-
const ruleMaps = getRuleMaps();
|
|
9895
|
-
const opaque = getOpaque?.() ?? [];
|
|
9896
|
-
const opaqueFindings = opaque.map((o) => ({
|
|
9897
|
-
rule: o.ruleNames.length > 0 ? o.ruleNames.join(", ") : `<artifact ${o.ns}>`,
|
|
9898
|
-
kind: "opaque-artifact",
|
|
9899
|
-
reason: `precompiled artifact "${o.ns}" carries compiled rule functions, not re-lowerable IR \u2014 its choices were not examined at this fuse.`
|
|
9900
|
-
}));
|
|
9901
|
-
if (!ruleMaps.some((map) => hasExternalRuleRef(map))) {
|
|
9902
|
-
if (opaqueFindings.length === 0) return void 0;
|
|
9903
|
-
return reportGating(opt, () => ({
|
|
9904
|
-
totalChoices: 0,
|
|
9905
|
-
gated: 0,
|
|
9906
|
-
recoverable: 0,
|
|
9907
|
-
unanalysable: opaqueFindings,
|
|
9908
|
-
ungated: [],
|
|
9909
|
-
accepted: [],
|
|
9910
|
-
deferred: [],
|
|
9911
|
-
acceptedUnused: [],
|
|
9912
|
-
choices: [],
|
|
9913
|
-
antiPatterns: []
|
|
9914
|
-
}));
|
|
9915
|
-
}
|
|
9916
|
-
const winners = /* @__PURE__ */ new Map();
|
|
9917
|
-
for (const map of ruleMaps) for (const [name, rule] of map) {
|
|
9918
|
-
if (rule._def.tag === "lazy") {
|
|
9919
|
-
try {
|
|
9920
|
-
rule._def.thunk();
|
|
9921
|
-
} catch {
|
|
9922
|
-
continue;
|
|
9923
|
-
}
|
|
9924
|
-
}
|
|
9925
|
-
winners.set(name, rule);
|
|
9926
|
-
}
|
|
9927
|
-
const entries = [...winners];
|
|
9928
|
-
return reportGating(opt, (o) => {
|
|
9929
|
-
const deferredHere = new Set(analyzeGatingRules(entries, o).deferred.map((c) => c.id));
|
|
9930
|
-
const fused = analyzeGatingRules(entries, { ...o, resolveRef: (name) => winners.get(name) });
|
|
9931
|
-
return {
|
|
9932
|
-
...fused,
|
|
9933
|
-
ungated: fused.ungated.filter((c) => deferredHere.has(c.id)),
|
|
9934
|
-
antiPatterns: [],
|
|
9935
|
-
unanalysable: [...fused.unanalysable, ...opaqueFindings]
|
|
9936
|
-
};
|
|
9937
|
-
});
|
|
9938
|
-
}
|
|
9939
|
-
function reportGating(opt, analyze) {
|
|
9940
|
-
const level = resolveGatingLevel(opt);
|
|
9941
|
-
if (level === "off") return void 0;
|
|
9942
|
-
const obj = opt !== null && typeof opt === "object" ? opt : void 0;
|
|
9943
|
-
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;
|
|
9944
|
-
let report;
|
|
9945
|
-
try {
|
|
9946
|
-
report = analyze(analyzeOpts);
|
|
9947
|
-
} catch (e) {
|
|
9948
|
-
const reason = e instanceof Error ? `${e.name}: ${e.message}` : String(e);
|
|
9949
|
-
const failed = {
|
|
9950
|
-
totalChoices: 0,
|
|
9951
|
-
gated: 0,
|
|
9952
|
-
recoverable: 0,
|
|
9953
|
-
unanalysable: [{ rule: "<whole grammar>", kind: "not-a-combinator", reason: `gating analysis threw \u2014 ${reason}` }],
|
|
9954
|
-
ungated: [],
|
|
9955
|
-
accepted: [],
|
|
9956
|
-
deferred: [],
|
|
9957
|
-
acceptedUnused: [],
|
|
9958
|
-
choices: [],
|
|
9959
|
-
antiPatterns: []
|
|
9960
|
-
};
|
|
9961
|
-
const failLines = formatGatingWarnings(failed);
|
|
9962
|
-
if (level === "error") throw new Error(`parseman: gating analysis FAILED (no verdict available)
|
|
9963
|
-
${failLines.join("\n")}`);
|
|
9964
|
-
for (const l of failLines) console.warn(l);
|
|
9965
|
-
return failed;
|
|
9966
|
-
}
|
|
9967
|
-
const lines = formatGatingWarnings(report);
|
|
9968
|
-
if (lines.length > 0) {
|
|
9969
|
-
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)
|
|
9970
|
-
${lines.join("\n")}`);
|
|
9971
|
-
for (const l of lines) console.warn(l);
|
|
9972
|
-
}
|
|
9973
|
-
return report;
|
|
9974
|
-
}
|
|
9975
9927
|
function resolveDuplicationLevel(opt) {
|
|
9976
9928
|
const explicit = typeof opt === "string" ? opt : opt?.level;
|
|
9977
9929
|
if (explicit !== void 0) return explicit;
|
|
@@ -10014,7 +9966,17 @@ function runDuplicationDiagnosticRules(ruleMap, opt) {
|
|
|
10014
9966
|
return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
|
|
10015
9967
|
}
|
|
10016
9968
|
function compile(combinator, mapFnSources, opts) {
|
|
10017
|
-
const
|
|
9969
|
+
const drain = beginCompileDegradationDrain();
|
|
9970
|
+
let completed = false;
|
|
9971
|
+
try {
|
|
9972
|
+
const compiled = compileImpl(combinator, mapFnSources, opts);
|
|
9973
|
+
completed = true;
|
|
9974
|
+
return compiled;
|
|
9975
|
+
} finally {
|
|
9976
|
+
drain(completed);
|
|
9977
|
+
}
|
|
9978
|
+
}
|
|
9979
|
+
function compileImpl(combinator, mapFnSources, opts) {
|
|
10018
9980
|
runDuplicationDiagnostic(combinator, opts?.duplication);
|
|
10019
9981
|
markUnusedValues(combinator);
|
|
10020
9982
|
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
@@ -10022,9 +9984,12 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10022
9984
|
const grammarScanSkip = combinator._meta.grammarScanSkip;
|
|
10023
9985
|
const grammarHostMode = combinator._meta.grammarHostMode;
|
|
10024
9986
|
const grammarTrackLines = combinator._meta.grammarTrackLines;
|
|
9987
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10025
9988
|
const ctx = {
|
|
10026
9989
|
vars: 0,
|
|
10027
9990
|
indent: 1,
|
|
9991
|
+
inlineMax: _inlineMax,
|
|
9992
|
+
inlineLeft: _inlineMax,
|
|
10028
9993
|
regexDecls: [],
|
|
10029
9994
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10030
9995
|
expectedDecls: [],
|
|
@@ -10070,11 +10035,13 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10070
10035
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
10071
10036
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
10072
10037
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
10038
|
+
const rawEntryDecls = ctx.needsRawEntry ? [RAW_ENTRY_DECL] : [];
|
|
10073
10039
|
const lineTrackDecls = ctx.needsLineTrack ? [LINE_TRACK_DECL] : [];
|
|
10074
10040
|
const lineSpanDecls = ctx.needsLineSpan ? [LINE_SPAN_DECL] : [];
|
|
10075
10041
|
const source = [
|
|
10076
10042
|
...emptyTlDecls,
|
|
10077
10043
|
...hostReadsDecls,
|
|
10044
|
+
...rawEntryDecls,
|
|
10078
10045
|
...lineTrackDecls,
|
|
10079
10046
|
...lineSpanDecls,
|
|
10080
10047
|
...ctx.regexDecls,
|
|
@@ -10089,6 +10056,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10089
10056
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
10090
10057
|
...emptyTlDecls,
|
|
10091
10058
|
...hostReadsDecls,
|
|
10059
|
+
...rawEntryDecls,
|
|
10092
10060
|
...lineTrackDecls,
|
|
10093
10061
|
...lineSpanDecls,
|
|
10094
10062
|
...ctx.regexDecls,
|
|
@@ -10138,8 +10106,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
10138
10106
|
const compiledMeta = {
|
|
10139
10107
|
source,
|
|
10140
10108
|
inlineExpression,
|
|
10141
|
-
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
10142
|
-
...gatingReport === void 0 ? {} : { gating: gatingReport }
|
|
10109
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
10143
10110
|
};
|
|
10144
10111
|
if (!ctx.lineTracking) {
|
|
10145
10112
|
return {
|
|
@@ -10204,7 +10171,6 @@ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels, ambien
|
|
|
10204
10171
|
return `Object.assign(${fnSource}, { _meta: {${labels === void 0 ? "" : ` triviaKindLabels: ${JSON.stringify(labels)},`}${classified === void 0 ? "" : " rootTriviaClassified: true,"} } })`;
|
|
10205
10172
|
}
|
|
10206
10173
|
function compileRuleMap(ruleMap, opts) {
|
|
10207
|
-
runGatingDiagnosticRules(ruleMap, opts?.gating);
|
|
10208
10174
|
runDuplicationDiagnosticRules(ruleMap, opts?.duplication);
|
|
10209
10175
|
for (const [, rule] of ruleMap) markUnusedValues(rule);
|
|
10210
10176
|
const coverageWinners = opts?.coverage ? Object.fromEntries(ruleMap.filter(([, rule]) => rule._def.tag !== "lazy")) : void 0;
|
|
@@ -10213,9 +10179,12 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
10213
10179
|
const grammarScanSkip = opts?.scanSkip ?? ruleMap.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
|
|
10214
10180
|
const grammarHostMode = opts?.hostMode ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
|
|
10215
10181
|
const grammarTrackLines = opts?.trackLines === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
|
|
10182
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10216
10183
|
const ctx = {
|
|
10217
10184
|
vars: 0,
|
|
10218
10185
|
indent: 1,
|
|
10186
|
+
inlineMax: _inlineMax,
|
|
10187
|
+
inlineLeft: _inlineMax,
|
|
10219
10188
|
regexDecls: [],
|
|
10220
10189
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10221
10190
|
expectedDecls: [],
|
|
@@ -10281,6 +10250,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
10281
10250
|
const hoistedDecls = [
|
|
10282
10251
|
ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "",
|
|
10283
10252
|
ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "",
|
|
10253
|
+
ctx.needsRawEntry ? ` ${RAW_ENTRY_DECL}` : "",
|
|
10284
10254
|
ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "",
|
|
10285
10255
|
ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "",
|
|
10286
10256
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
@@ -10353,7 +10323,6 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
10353
10323
|
}
|
|
10354
10324
|
function compileLinkable(ruleMapArg, ns, opts) {
|
|
10355
10325
|
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
10356
|
-
if (opts?.gating !== void 0) runGatingDiagnosticRules(ruleMapArg, opts.gating);
|
|
10357
10326
|
if (opts?.duplication !== void 0) runDuplicationDiagnosticRules(ruleMapArg, opts.duplication);
|
|
10358
10327
|
for (const [, rule] of ruleMapArg) markUnusedValues(rule);
|
|
10359
10328
|
const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
|
|
@@ -10372,9 +10341,12 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10372
10341
|
}
|
|
10373
10342
|
});
|
|
10374
10343
|
const nodeMeta = new Map(ruleMap.map(([name, rule]) => [name, collectGrammarReflection([[name, rule]], { followLazy: false })]));
|
|
10344
|
+
const _inlineMax = resolveInlineMax(opts?.maxInline);
|
|
10375
10345
|
const ctx = {
|
|
10376
10346
|
vars: 0,
|
|
10377
10347
|
indent: 1,
|
|
10348
|
+
inlineMax: _inlineMax,
|
|
10349
|
+
inlineLeft: _inlineMax,
|
|
10378
10350
|
regexDecls: [],
|
|
10379
10351
|
regexMap: /* @__PURE__ */ new Map(),
|
|
10380
10352
|
expectedDecls: [],
|
|
@@ -10470,6 +10442,9 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10470
10442
|
}
|
|
10471
10443
|
}
|
|
10472
10444
|
const savedIndent = ctx.indent, savedFail = ctx.failLabel, savedRec = ctx.recordFail;
|
|
10445
|
+
const savedInlineLeft = ctx.inlineLeft, savedFnName = ctx.currentFnName;
|
|
10446
|
+
ctx.inlineLeft = ctx.inlineMax;
|
|
10447
|
+
ctx.currentFnName = fn;
|
|
10473
10448
|
ctx.indent = 1;
|
|
10474
10449
|
ctx.failLabel = "_pfail";
|
|
10475
10450
|
ctx.recordFail = true;
|
|
@@ -10485,6 +10460,8 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10485
10460
|
ctx.indent = savedIndent;
|
|
10486
10461
|
ctx.failLabel = savedFail;
|
|
10487
10462
|
ctx.recordFail = savedRec;
|
|
10463
|
+
ctx.inlineLeft = savedInlineLeft;
|
|
10464
|
+
ctx.currentFnName = savedFnName;
|
|
10488
10465
|
const ruleId = ctx.coverage?.plan.rules.get(rule);
|
|
10489
10466
|
const stmts = ruleId === void 0 ? body.stmts : [
|
|
10490
10467
|
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
|
|
@@ -10569,6 +10546,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
10569
10546
|
deps: ruleDependencies(ruleMap),
|
|
10570
10547
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
10571
10548
|
needsHostReads: !!ctx.needsHostReads,
|
|
10549
|
+
needsRawEntry: !!ctx.needsRawEntry,
|
|
10572
10550
|
hostMode: ctx.hostMode ?? "ast",
|
|
10573
10551
|
hostBranchElided: !!ctx.hostBranchElided,
|
|
10574
10552
|
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
@@ -10643,14 +10621,16 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootR
|
|
|
10643
10621
|
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
10644
10622
|
const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
|
|
10645
10623
|
const hostReadsDecl = ctx.needsHostReads ? ` ${HOST_READS_DECL}` : "";
|
|
10624
|
+
const rawEntryDecl = ctx.needsRawEntry ? ` ${RAW_ENTRY_DECL}` : "";
|
|
10646
10625
|
const lineTrackDecl = ctx.needsLineTrack ? ` ${LINE_TRACK_DECL}` : "";
|
|
10647
10626
|
const lineSpanDecl = ctx.needsLineSpan ? ` ${LINE_SPAN_DECL}` : "";
|
|
10648
|
-
const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!lineTrackDecl || !!lineSpanDecl;
|
|
10627
|
+
const needsWrapper = ctx.regexDecls.length > 0 || ctx.expectedDecls.length > 0 || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl || !!hostReadsDecl || !!rawEntryDecl || !!lineTrackDecl || !!lineSpanDecl;
|
|
10649
10628
|
if (!needsWrapper) return innerFn;
|
|
10650
10629
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
10651
10630
|
const hoistedDecls = [
|
|
10652
10631
|
emptyTlDecl,
|
|
10653
10632
|
hostReadsDecl,
|
|
10633
|
+
rawEntryDecl,
|
|
10654
10634
|
lineTrackDecl,
|
|
10655
10635
|
lineSpanDecl,
|
|
10656
10636
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
@@ -10720,18 +10700,19 @@ function childrenOf4(def) {
|
|
|
10720
10700
|
return [def.main, def.skipped];
|
|
10721
10701
|
case "scanTo":
|
|
10722
10702
|
return [def.sentinel, ...def.skip];
|
|
10703
|
+
case "routed":
|
|
10704
|
+
return def.fallback ? [def.fallback] : [];
|
|
10723
10705
|
case "lazy":
|
|
10724
10706
|
case "literal":
|
|
10725
10707
|
case "regex":
|
|
10726
10708
|
case "keywords":
|
|
10727
|
-
case "routed":
|
|
10728
10709
|
case "guard":
|
|
10729
10710
|
case "recover":
|
|
10730
10711
|
case "unknown":
|
|
10731
10712
|
return [];
|
|
10732
10713
|
}
|
|
10733
10714
|
}
|
|
10734
|
-
var
|
|
10715
|
+
var ruleNameOf3 = (c) => c._ruleName;
|
|
10735
10716
|
function lazyTarget(c) {
|
|
10736
10717
|
if (c._def.tag !== "lazy") return null;
|
|
10737
10718
|
try {
|
|
@@ -10806,7 +10787,7 @@ function evalRuleMapIR(ir) {
|
|
|
10806
10787
|
l._def.fnSrc = src;
|
|
10807
10788
|
return l;
|
|
10808
10789
|
};
|
|
10809
|
-
const _nd = (type, child, src, opts, staticError) => {
|
|
10790
|
+
const _nd = (type, child, src, opts, staticError, sigSrc) => {
|
|
10810
10791
|
if (staticError !== void 0 && staticError.length > 0) {
|
|
10811
10792
|
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
10812
10793
|
}
|
|
@@ -10815,6 +10796,7 @@ function evalRuleMapIR(ir) {
|
|
|
10815
10796
|
}), opts);
|
|
10816
10797
|
n._def.buildSrc = src;
|
|
10817
10798
|
if (staticError !== void 0) n._def.buildStaticError = staticError;
|
|
10799
|
+
if (sigSrc !== void 0) n._def.buildSigSrc = sigSrc;
|
|
10818
10800
|
return n;
|
|
10819
10801
|
};
|
|
10820
10802
|
const _gch = (items) => {
|
|
@@ -10967,7 +10949,7 @@ var Serializer = class {
|
|
|
10967
10949
|
if (seen.has(c)) return;
|
|
10968
10950
|
seen.add(c);
|
|
10969
10951
|
if (c._def.tag === "lazy") {
|
|
10970
|
-
if (
|
|
10952
|
+
if (ruleNameOf3(c) !== void 0) throw new Unserializable("scanSkip unit references a grammar rule");
|
|
10971
10953
|
const target = lazyTarget(c);
|
|
10972
10954
|
if (target) this.assertNoRuleRef(target, seen);
|
|
10973
10955
|
return;
|
|
@@ -10978,7 +10960,7 @@ var Serializer = class {
|
|
|
10978
10960
|
* its target (compileLinkable unwraps the same way). A ref INSIDE a body stays a
|
|
10979
10961
|
* `g[name]` ref — only the top-level entry is unwrapped. */
|
|
10980
10962
|
body(c) {
|
|
10981
|
-
return c._def.tag === "lazy" &&
|
|
10963
|
+
return c._def.tag === "lazy" && ruleNameOf3(c) !== void 0 ? lazyTarget(c) ?? c : c;
|
|
10982
10964
|
}
|
|
10983
10965
|
run() {
|
|
10984
10966
|
for (const [, c] of this.ruleMap) this.analyze(this.body(c), /* @__PURE__ */ new Set());
|
|
@@ -11020,7 +11002,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11020
11002
|
analyze(c, active) {
|
|
11021
11003
|
const def = c._def;
|
|
11022
11004
|
if (def.tag === "lazy") {
|
|
11023
|
-
if (
|
|
11005
|
+
if (ruleNameOf3(c) !== void 0) return;
|
|
11024
11006
|
const target = lazyTarget(c);
|
|
11025
11007
|
if (!target) throw new Unserializable("unresolved unnamed ref");
|
|
11026
11008
|
if (active.has(target)) {
|
|
@@ -11072,7 +11054,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11072
11054
|
const kid = (x) => this.ref(x, selfOf);
|
|
11073
11055
|
switch (def.tag) {
|
|
11074
11056
|
case "lazy": {
|
|
11075
|
-
const name = this.localRuleNames.get(c) ??
|
|
11057
|
+
const name = this.localRuleNames.get(c) ?? ruleNameOf3(c);
|
|
11076
11058
|
if (name !== void 0) return `g[${JSON.stringify(name)}]`;
|
|
11077
11059
|
const target = lazyTarget(c);
|
|
11078
11060
|
if (selfOf && target === selfOf.comb) return selfOf.var;
|
|
@@ -11127,7 +11109,7 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11127
11109
|
case "peek":
|
|
11128
11110
|
return `peek(${kid(def.parser)})`;
|
|
11129
11111
|
case "routed":
|
|
11130
|
-
return "routed()"
|
|
11112
|
+
return def.fallback === void 0 ? "routed()" : `routed(${kid(def.fallback)})`;
|
|
11131
11113
|
case "trivia":
|
|
11132
11114
|
return `trivia(${kid(def.parser)})`;
|
|
11133
11115
|
case "token":
|
|
@@ -11160,6 +11142,9 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11160
11142
|
...projectEntry === void 0 ? [] : [projectEntry],
|
|
11161
11143
|
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
11162
11144
|
...def.trailingTrivia ? ["trailingTrivia: true"] : [],
|
|
11145
|
+
// Declared or resolved arity. Carried so a re-lowered composed artifact does
|
|
11146
|
+
// not silently re-acquire the fail-open capture cost this module resolved away.
|
|
11147
|
+
...def.buildArity === void 0 ? [] : [`buildArity: ${def.buildArity}`],
|
|
11163
11148
|
...tagEntry === void 0 ? [] : [tagEntry]
|
|
11164
11149
|
];
|
|
11165
11150
|
const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
|
|
@@ -11168,8 +11153,14 @@ ${outerDecls.map((d) => " " + d).join("\n")}
|
|
|
11168
11153
|
return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
|
|
11169
11154
|
}
|
|
11170
11155
|
if (def.buildSrc !== void 0) {
|
|
11171
|
-
const
|
|
11172
|
-
|
|
11156
|
+
const tail = [];
|
|
11157
|
+
if (def.buildStaticError !== void 0 || def.buildSigSrc !== void 0) {
|
|
11158
|
+
if (!opts) tail.push("undefined");
|
|
11159
|
+
tail.push(def.buildStaticError === void 0 ? "undefined" : JSON.stringify(def.buildStaticError));
|
|
11160
|
+
}
|
|
11161
|
+
if (def.buildSigSrc !== void 0) tail.push(JSON.stringify(def.buildSigSrc));
|
|
11162
|
+
const trailing = tail.length > 0 ? `, ${tail.join(", ")}` : "";
|
|
11163
|
+
return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${trailing})`;
|
|
11173
11164
|
}
|
|
11174
11165
|
return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
|
|
11175
11166
|
}
|
|
@@ -11257,12 +11248,14 @@ function fusedBody(pieces) {
|
|
|
11257
11248
|
const contributingPieces = [...contributing];
|
|
11258
11249
|
const needsEmptyTl = contributingPieces.some((p) => p.needsEmptyTl);
|
|
11259
11250
|
const needsHostReads = contributingPieces.some((p) => p.needsHostReads);
|
|
11251
|
+
const needsRawEntry = contributingPieces.some((p) => p.needsRawEntry);
|
|
11260
11252
|
const lines = [
|
|
11261
11253
|
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
11262
11254
|
"const _pfFail = {}",
|
|
11263
11255
|
"let _pfEnd",
|
|
11264
11256
|
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
11265
11257
|
...needsHostReads ? [HOST_READS_DECL] : [],
|
|
11258
|
+
...needsRawEntry ? [RAW_ENTRY_DECL] : [],
|
|
11266
11259
|
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
11267
11260
|
...new Set(contributingPieces.flatMap((p) => p.prelude)),
|
|
11268
11261
|
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
@@ -11296,8 +11289,8 @@ function fusedBody(pieces) {
|
|
|
11296
11289
|
for (const [k, p] of winner) {
|
|
11297
11290
|
const r = p.firstSetRecipes?.get(k);
|
|
11298
11291
|
if (r) recipes.set(k, r);
|
|
11299
|
-
const
|
|
11300
|
-
if (
|
|
11292
|
+
const fs3 = p.firstSets?.get(k);
|
|
11293
|
+
if (fs3) shallow.set(k, fs3);
|
|
11301
11294
|
const nu = p.nullable?.get(k);
|
|
11302
11295
|
if (nu !== void 0) nullable2.set(k, nu);
|
|
11303
11296
|
}
|
|
@@ -11320,9 +11313,9 @@ function fusedBody(pieces) {
|
|
|
11320
11313
|
for (let iter = 0; iter <= recipes.size; iter++) {
|
|
11321
11314
|
let changed = false;
|
|
11322
11315
|
for (const [k, r] of recipes) {
|
|
11323
|
-
const
|
|
11324
|
-
if (JSON.stringify(finalFS.get(k)) !== JSON.stringify(
|
|
11325
|
-
finalFS.set(k,
|
|
11316
|
+
const fs3 = resolveRecipe(r);
|
|
11317
|
+
if (JSON.stringify(finalFS.get(k)) !== JSON.stringify(fs3)) {
|
|
11318
|
+
finalFS.set(k, fs3);
|
|
11326
11319
|
changed = true;
|
|
11327
11320
|
}
|
|
11328
11321
|
}
|
|
@@ -11334,9 +11327,9 @@ function fusedBody(pieces) {
|
|
|
11334
11327
|
// matches every well-formed placeholder.
|
|
11335
11328
|
/\/\*@FS:([A-Za-z0-9_$]+):([A-Za-z0-9_$]+)@\*\/true/g,
|
|
11336
11329
|
(_m, name, codevar) => {
|
|
11337
|
-
const
|
|
11338
|
-
if (!
|
|
11339
|
-
return `(${firstSetCond(codevar,
|
|
11330
|
+
const fs3 = finalFS.get(name);
|
|
11331
|
+
if (!fs3 || fs3.kind === "any" || fs3.kind === "empty") return "true";
|
|
11332
|
+
return `(${firstSetCond(codevar, fs3)})`;
|
|
11340
11333
|
}
|
|
11341
11334
|
);
|
|
11342
11335
|
const env = {};
|
|
@@ -11368,17 +11361,6 @@ ${body}
|
|
|
11368
11361
|
function isIRPiece(p) {
|
|
11369
11362
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
11370
11363
|
}
|
|
11371
|
-
function once(fn) {
|
|
11372
|
-
let done = false;
|
|
11373
|
-
let value;
|
|
11374
|
-
return () => {
|
|
11375
|
-
if (!done) {
|
|
11376
|
-
value = fn();
|
|
11377
|
-
done = true;
|
|
11378
|
-
}
|
|
11379
|
-
return value;
|
|
11380
|
-
};
|
|
11381
|
-
}
|
|
11382
11364
|
function materializePiece(p, trivia2, captureTerminals = false, hostMode) {
|
|
11383
11365
|
if (!isIRPiece(p)) return p;
|
|
11384
11366
|
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
|
|
@@ -11410,8 +11392,22 @@ function gate(predicate) {
|
|
|
11410
11392
|
};
|
|
11411
11393
|
}
|
|
11412
11394
|
|
|
11413
|
-
// src/
|
|
11414
|
-
var {
|
|
11395
|
+
// src/functional/run.ts
|
|
11396
|
+
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
11397
|
+
var REMOVED_RUN_RESULT_FIELDS = [
|
|
11398
|
+
[
|
|
11399
|
+
"triviaMap",
|
|
11400
|
+
`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.`
|
|
11401
|
+
],
|
|
11402
|
+
[
|
|
11403
|
+
"triviaLog",
|
|
11404
|
+
`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.`
|
|
11405
|
+
],
|
|
11406
|
+
[
|
|
11407
|
+
"triviaKindLabels",
|
|
11408
|
+
`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\`.`
|
|
11409
|
+
]
|
|
11410
|
+
];
|
|
11415
11411
|
|
|
11416
11412
|
// src/index.ts
|
|
11417
11413
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
@@ -11605,6 +11601,10 @@ function stripTsFromSource(node2, code) {
|
|
|
11605
11601
|
}
|
|
11606
11602
|
return out + code.slice(cur, end);
|
|
11607
11603
|
}
|
|
11604
|
+
var _reducers = null;
|
|
11605
|
+
function setReducerResolver(r) {
|
|
11606
|
+
_reducers = r;
|
|
11607
|
+
}
|
|
11608
11608
|
function isWordFactory(v2) {
|
|
11609
11609
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
11610
11610
|
}
|
|
@@ -11836,9 +11836,12 @@ function staticNodeOptionsFromValue(value) {
|
|
|
11836
11836
|
} else if (name === "tags") {
|
|
11837
11837
|
if (!Array.isArray(v2) || !v2.every((item) => typeof item === "string")) return STATIC_NODE_OPTIONS_FAILED;
|
|
11838
11838
|
opts.tags = v2;
|
|
11839
|
+
} else if (name === "buildArity") {
|
|
11840
|
+
if (typeof v2 !== "number" || !Number.isInteger(v2) || v2 < 0 || v2 > 6) return STATIC_NODE_OPTIONS_FAILED;
|
|
11841
|
+
opts.buildArity = v2;
|
|
11839
11842
|
}
|
|
11840
11843
|
}
|
|
11841
|
-
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 ? opts : void 0;
|
|
11844
|
+
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 || opts.buildArity !== void 0 ? opts : void 0;
|
|
11842
11845
|
}
|
|
11843
11846
|
function staticNodeOptions(expr, scope) {
|
|
11844
11847
|
const unwrapped = unwrapStaticExpr(expr);
|
|
@@ -11864,9 +11867,13 @@ function staticNodeOptions(expr, scope) {
|
|
|
11864
11867
|
const tags = staticStringArray(p.value, scope);
|
|
11865
11868
|
if (tags === void 0) return STATIC_NODE_OPTIONS_FAILED;
|
|
11866
11869
|
opts.tags = tags;
|
|
11870
|
+
} else if (name === "buildArity") {
|
|
11871
|
+
const arity = staticLiteralValue(p.value);
|
|
11872
|
+
if (typeof arity !== "number" || !Number.isInteger(arity) || arity < 0 || arity > 6) return STATIC_NODE_OPTIONS_FAILED;
|
|
11873
|
+
opts.buildArity = arity;
|
|
11867
11874
|
}
|
|
11868
11875
|
}
|
|
11869
|
-
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 ? opts : void 0;
|
|
11876
|
+
return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia || opts.tags !== void 0 || opts.buildArity !== void 0 ? opts : void 0;
|
|
11870
11877
|
}
|
|
11871
11878
|
function exprToCombi(node2, scope, code, mfs) {
|
|
11872
11879
|
if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
|
|
@@ -11962,6 +11969,15 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
11962
11969
|
const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
|
|
11963
11970
|
if (combi._def.tag === "node" && buildSrc !== void 0) {
|
|
11964
11971
|
combi._def.buildSrc = buildSrc;
|
|
11972
|
+
if (explicitType !== void 0 && firstArg.type === "Identifier") {
|
|
11973
|
+
combi._def.typeSrc = firstArg.name;
|
|
11974
|
+
}
|
|
11975
|
+
const resolved = _reducers?.resolve(buildSrc, be.start, code);
|
|
11976
|
+
if (resolved) {
|
|
11977
|
+
if (resolved.src !== null) combi._def.buildSigSrc = resolved.src;
|
|
11978
|
+
if (combi._def.buildArity === void 0 && resolved.arity !== null) combi._def.buildArity = resolved.arity;
|
|
11979
|
+
if (resolved.reason !== void 0) combi._def.buildArityUnresolved = resolved.reason;
|
|
11980
|
+
}
|
|
11965
11981
|
const staticError = directBuilderUnsupportedBindings(buildSrc);
|
|
11966
11982
|
if (staticError.length > 0) combi._def.buildStaticError = staticError;
|
|
11967
11983
|
}
|
|
@@ -12379,9 +12395,9 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
12379
12395
|
r._ruleName = name;
|
|
12380
12396
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = name;
|
|
12381
12397
|
};
|
|
12382
|
-
const
|
|
12398
|
+
const ruleNameOf4 = (r) => r._ruleName;
|
|
12383
12399
|
const isNamedRuleRefForAnotherRule2 = (r, key) => {
|
|
12384
|
-
const name = r._def.tag === "lazy" ?
|
|
12400
|
+
const name = r._def.tag === "lazy" ? ruleNameOf4(r) : void 0;
|
|
12385
12401
|
return name !== void 0 && name !== key;
|
|
12386
12402
|
};
|
|
12387
12403
|
for (const key of keys) {
|
|
@@ -12472,6 +12488,367 @@ function referencesAny(node2, names, scope) {
|
|
|
12472
12488
|
return false;
|
|
12473
12489
|
}
|
|
12474
12490
|
|
|
12491
|
+
// src/plugin/reducer-resolver.ts
|
|
12492
|
+
import * as fs from "node:fs";
|
|
12493
|
+
import * as path from "node:path";
|
|
12494
|
+
import { createRequire } from "node:module";
|
|
12495
|
+
import { parseSync as parseSync2 } from "oxc-parser";
|
|
12496
|
+
var FUNCTION_TYPES = /* @__PURE__ */ new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
|
|
12497
|
+
var SCOPE_TYPES = /* @__PURE__ */ new Set([
|
|
12498
|
+
...FUNCTION_TYPES,
|
|
12499
|
+
"BlockStatement",
|
|
12500
|
+
"ForStatement",
|
|
12501
|
+
"ForInStatement",
|
|
12502
|
+
"ForOfStatement",
|
|
12503
|
+
"CatchClause",
|
|
12504
|
+
"ClassDeclaration",
|
|
12505
|
+
"ClassExpression",
|
|
12506
|
+
"StaticBlock"
|
|
12507
|
+
]);
|
|
12508
|
+
function newScope(start, end, parent, isFunction) {
|
|
12509
|
+
const s = { start, end, bindings: /* @__PURE__ */ new Map(), children: [], parent, isFunction };
|
|
12510
|
+
parent?.children.push(s);
|
|
12511
|
+
return s;
|
|
12512
|
+
}
|
|
12513
|
+
function patternNames(pat, out) {
|
|
12514
|
+
if (!pat || typeof pat !== "object") return;
|
|
12515
|
+
const n = pat;
|
|
12516
|
+
switch (n.type) {
|
|
12517
|
+
case "Identifier":
|
|
12518
|
+
out.push(n.name);
|
|
12519
|
+
return;
|
|
12520
|
+
case "AssignmentPattern":
|
|
12521
|
+
return patternNames(n.left, out);
|
|
12522
|
+
case "RestElement":
|
|
12523
|
+
return patternNames(n.argument, out);
|
|
12524
|
+
case "ArrayPattern":
|
|
12525
|
+
for (const el of n.elements ?? []) patternNames(el, out);
|
|
12526
|
+
return;
|
|
12527
|
+
case "ObjectPattern":
|
|
12528
|
+
for (const p of n.properties ?? []) patternNames(p.type === "RestElement" ? p.argument : p.value, out);
|
|
12529
|
+
return;
|
|
12530
|
+
// A TS parameter property / assignment target wrapper.
|
|
12531
|
+
case "TSParameterProperty":
|
|
12532
|
+
return patternNames(n.parameter, out);
|
|
12533
|
+
default:
|
|
12534
|
+
return;
|
|
12535
|
+
}
|
|
12536
|
+
}
|
|
12537
|
+
function declare(scope, name, b) {
|
|
12538
|
+
if (!scope.bindings.has(name)) scope.bindings.set(name, b);
|
|
12539
|
+
}
|
|
12540
|
+
function functionScope(scope) {
|
|
12541
|
+
let s = scope;
|
|
12542
|
+
while (!s.isFunction && s.parent) s = s.parent;
|
|
12543
|
+
return s;
|
|
12544
|
+
}
|
|
12545
|
+
function buildScopeTree(body, moduleEnd) {
|
|
12546
|
+
const root = newScope(0, moduleEnd, null, true);
|
|
12547
|
+
const declarePattern = (scope, pat, kind, init) => {
|
|
12548
|
+
const names = [];
|
|
12549
|
+
patternNames(pat, names);
|
|
12550
|
+
const target = kind === "var" ? functionScope(scope) : scope;
|
|
12551
|
+
for (const name of names) {
|
|
12552
|
+
declare(target, name, init !== void 0 && names.length === 1 ? { kind, init } : { kind });
|
|
12553
|
+
}
|
|
12554
|
+
};
|
|
12555
|
+
const walk = (n, scope) => {
|
|
12556
|
+
if (!n || typeof n !== "object") return;
|
|
12557
|
+
if (Array.isArray(n)) {
|
|
12558
|
+
for (const item of n) walk(item, scope);
|
|
12559
|
+
return;
|
|
12560
|
+
}
|
|
12561
|
+
const node2 = n;
|
|
12562
|
+
if (typeof node2.type !== "string") return;
|
|
12563
|
+
switch (node2.type) {
|
|
12564
|
+
case "VariableDeclaration": {
|
|
12565
|
+
const kind = node2.kind ?? "var";
|
|
12566
|
+
for (const d of node2.declarations ?? []) {
|
|
12567
|
+
declarePattern(scope, d.id, kind, d.init ?? void 0);
|
|
12568
|
+
}
|
|
12569
|
+
break;
|
|
12570
|
+
}
|
|
12571
|
+
case "FunctionDeclaration":
|
|
12572
|
+
if (node2.id) declare(functionScope(scope), node2.id.name, { kind: "function", init: node2 });
|
|
12573
|
+
break;
|
|
12574
|
+
case "ClassDeclaration":
|
|
12575
|
+
if (node2.id) declare(scope, node2.id.name, { kind: "class" });
|
|
12576
|
+
break;
|
|
12577
|
+
case "ImportDeclaration": {
|
|
12578
|
+
const specifier = node2.source?.value ?? "";
|
|
12579
|
+
for (const sp of node2.specifiers ?? []) {
|
|
12580
|
+
const local = sp.local?.name;
|
|
12581
|
+
if (!local) continue;
|
|
12582
|
+
const imported = sp.type === "ImportDefaultSpecifier" ? "default" : sp.type === "ImportNamespaceSpecifier" ? "*" : sp.imported?.name ?? local;
|
|
12583
|
+
declare(scope, local, { kind: "import", importRef: { specifier, imported } });
|
|
12584
|
+
}
|
|
12585
|
+
break;
|
|
12586
|
+
}
|
|
12587
|
+
default:
|
|
12588
|
+
break;
|
|
12589
|
+
}
|
|
12590
|
+
if (SCOPE_TYPES.has(node2.type)) {
|
|
12591
|
+
const isFn = FUNCTION_TYPES.has(node2.type);
|
|
12592
|
+
const inner = newScope(node2.start, node2.end, scope, isFn);
|
|
12593
|
+
if (isFn) {
|
|
12594
|
+
for (const p of node2.params ?? []) declarePattern(inner, p, "param");
|
|
12595
|
+
if (node2.type === "FunctionExpression" && node2.id) {
|
|
12596
|
+
declare(inner, node2.id.name, { kind: "function", init: node2 });
|
|
12597
|
+
}
|
|
12598
|
+
}
|
|
12599
|
+
if (node2.type === "CatchClause" && node2.param) declarePattern(inner, node2.param, "catch");
|
|
12600
|
+
for (const key of Object.keys(node2)) {
|
|
12601
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12602
|
+
walk(node2[key], inner);
|
|
12603
|
+
}
|
|
12604
|
+
return;
|
|
12605
|
+
}
|
|
12606
|
+
for (const key of Object.keys(node2)) {
|
|
12607
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12608
|
+
walk(node2[key], scope);
|
|
12609
|
+
}
|
|
12610
|
+
};
|
|
12611
|
+
for (const stmt of body) walk(stmt, root);
|
|
12612
|
+
return root;
|
|
12613
|
+
}
|
|
12614
|
+
function scopeAt(root, offset) {
|
|
12615
|
+
let cur = root;
|
|
12616
|
+
for (; ; ) {
|
|
12617
|
+
const next = cur.children.find((c) => offset >= c.start && offset <= c.end);
|
|
12618
|
+
if (!next) return cur;
|
|
12619
|
+
cur = next;
|
|
12620
|
+
}
|
|
12621
|
+
}
|
|
12622
|
+
function lookup(scope, name) {
|
|
12623
|
+
for (let s = scope; s; s = s.parent) {
|
|
12624
|
+
const b = s.bindings.get(name);
|
|
12625
|
+
if (b) return { binding: b, scope: s };
|
|
12626
|
+
}
|
|
12627
|
+
return null;
|
|
12628
|
+
}
|
|
12629
|
+
function markReassignments(body, root) {
|
|
12630
|
+
const walk = (n) => {
|
|
12631
|
+
if (!n || typeof n !== "object") return;
|
|
12632
|
+
if (Array.isArray(n)) {
|
|
12633
|
+
for (const item of n) walk(item);
|
|
12634
|
+
return;
|
|
12635
|
+
}
|
|
12636
|
+
const node2 = n;
|
|
12637
|
+
if (typeof node2.type !== "string") return;
|
|
12638
|
+
if (node2.type === "AssignmentExpression" || node2.type === "UpdateExpression") {
|
|
12639
|
+
const target = node2.type === "UpdateExpression" ? node2.argument : node2.left;
|
|
12640
|
+
const names = [];
|
|
12641
|
+
if (target) patternNames(target, names);
|
|
12642
|
+
for (const name of names) {
|
|
12643
|
+
const hit = lookup(scopeAt(root, node2.start), name);
|
|
12644
|
+
if (hit) hit.binding.reassigned = true;
|
|
12645
|
+
}
|
|
12646
|
+
}
|
|
12647
|
+
for (const key of Object.keys(node2)) {
|
|
12648
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12649
|
+
walk(node2[key]);
|
|
12650
|
+
}
|
|
12651
|
+
};
|
|
12652
|
+
for (const stmt of body) walk(stmt);
|
|
12653
|
+
}
|
|
12654
|
+
function functionArity(fn) {
|
|
12655
|
+
const params = fn.params ?? [];
|
|
12656
|
+
let count = 0;
|
|
12657
|
+
for (const p of params) {
|
|
12658
|
+
if (p.type === "RestElement") return { arity: null, reason: "rest-parameter" };
|
|
12659
|
+
if (p.type === "Identifier" && p.name === "this") continue;
|
|
12660
|
+
count++;
|
|
12661
|
+
}
|
|
12662
|
+
if (fn.type !== "ArrowFunctionExpression" && referencesArguments(fn.body)) {
|
|
12663
|
+
return { arity: null, reason: "arguments" };
|
|
12664
|
+
}
|
|
12665
|
+
return { arity: count };
|
|
12666
|
+
}
|
|
12667
|
+
function referencesArguments(n) {
|
|
12668
|
+
if (!n || typeof n !== "object") return false;
|
|
12669
|
+
if (Array.isArray(n)) return n.some(referencesArguments);
|
|
12670
|
+
const node2 = n;
|
|
12671
|
+
if (typeof node2.type !== "string") return false;
|
|
12672
|
+
if (node2.type === "Identifier" && node2.name === "arguments") return true;
|
|
12673
|
+
if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression") return false;
|
|
12674
|
+
for (const key of Object.keys(node2)) {
|
|
12675
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12676
|
+
if (referencesArguments(node2[key])) return true;
|
|
12677
|
+
}
|
|
12678
|
+
return false;
|
|
12679
|
+
}
|
|
12680
|
+
var _moduleCache = /* @__PURE__ */ new Map();
|
|
12681
|
+
function analyseModuleFile(file) {
|
|
12682
|
+
let mtimeMs;
|
|
12683
|
+
try {
|
|
12684
|
+
mtimeMs = fs.statSync(file).mtimeMs;
|
|
12685
|
+
} catch {
|
|
12686
|
+
return null;
|
|
12687
|
+
}
|
|
12688
|
+
const hit = _moduleCache.get(file);
|
|
12689
|
+
if (hit && hit.mtimeMs === mtimeMs) return hit.mod;
|
|
12690
|
+
let mod = null;
|
|
12691
|
+
try {
|
|
12692
|
+
const src = fs.readFileSync(file, "utf8");
|
|
12693
|
+
const r = parseSync2(file, src);
|
|
12694
|
+
if (r.errors.length === 0) {
|
|
12695
|
+
const body = r.program.body;
|
|
12696
|
+
const scopes = buildScopeTree(body, src.length);
|
|
12697
|
+
markReassignments(body, scopes);
|
|
12698
|
+
mod = { file, src, body, scopes };
|
|
12699
|
+
}
|
|
12700
|
+
} catch {
|
|
12701
|
+
}
|
|
12702
|
+
_moduleCache.set(file, { mtimeMs, mod });
|
|
12703
|
+
return mod;
|
|
12704
|
+
}
|
|
12705
|
+
var SOURCE_EXTS = [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".jsx"];
|
|
12706
|
+
function resolveImport(fromFile, specifier) {
|
|
12707
|
+
if (specifier.startsWith(".") || path.isAbsolute(specifier)) {
|
|
12708
|
+
const base = path.resolve(path.dirname(fromFile), specifier);
|
|
12709
|
+
const ext = path.extname(base);
|
|
12710
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
12711
|
+
const candidates = [
|
|
12712
|
+
...ext ? [base] : [],
|
|
12713
|
+
// `./x.js` in TS source usually means `./x.ts`.
|
|
12714
|
+
...SOURCE_EXTS.map((e) => `${stem}${e}`),
|
|
12715
|
+
...SOURCE_EXTS.map((e) => path.join(base, `index${e}`))
|
|
12716
|
+
];
|
|
12717
|
+
for (const c of candidates) {
|
|
12718
|
+
try {
|
|
12719
|
+
if (fs.statSync(c).isFile()) return fs.realpathSync(c);
|
|
12720
|
+
} catch {
|
|
12721
|
+
}
|
|
12722
|
+
}
|
|
12723
|
+
return null;
|
|
12724
|
+
}
|
|
12725
|
+
try {
|
|
12726
|
+
return fs.realpathSync(createRequire(fromFile).resolve(specifier));
|
|
12727
|
+
} catch {
|
|
12728
|
+
return null;
|
|
12729
|
+
}
|
|
12730
|
+
}
|
|
12731
|
+
function declarationBinds(decl, name) {
|
|
12732
|
+
if (decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration") {
|
|
12733
|
+
return decl.id?.name === name;
|
|
12734
|
+
}
|
|
12735
|
+
if (decl.type === "VariableDeclaration") {
|
|
12736
|
+
const names = [];
|
|
12737
|
+
for (const d of decl.declarations ?? []) patternNames(d.id, names);
|
|
12738
|
+
return names.includes(name);
|
|
12739
|
+
}
|
|
12740
|
+
return false;
|
|
12741
|
+
}
|
|
12742
|
+
function exportedBinding(mod, name, seen) {
|
|
12743
|
+
for (const stmt of mod.body) {
|
|
12744
|
+
if (stmt.type === "ExportDefaultDeclaration" && name === "default") {
|
|
12745
|
+
const d = stmt.declaration;
|
|
12746
|
+
if (FUNCTION_TYPES.has(d.type)) return { mod, binding: { kind: "const", init: d } };
|
|
12747
|
+
if (d.type === "Identifier") {
|
|
12748
|
+
const hit2 = lookup(mod.scopes, d.name);
|
|
12749
|
+
return hit2 ? { mod, binding: hit2.binding } : null;
|
|
12750
|
+
}
|
|
12751
|
+
return null;
|
|
12752
|
+
}
|
|
12753
|
+
if (stmt.type === "ExportNamedDeclaration") {
|
|
12754
|
+
const decl = stmt.declaration;
|
|
12755
|
+
if (decl && declarationBinds(decl, name)) {
|
|
12756
|
+
const hit2 = lookup(mod.scopes, name);
|
|
12757
|
+
if (hit2 && hit2.scope === mod.scopes) return { mod, binding: hit2.binding };
|
|
12758
|
+
}
|
|
12759
|
+
for (const sp of stmt.specifiers ?? []) {
|
|
12760
|
+
const exported = sp.exported?.name ?? "";
|
|
12761
|
+
if (exported !== name) continue;
|
|
12762
|
+
const local = sp.local?.name ?? exported;
|
|
12763
|
+
const from = stmt.source?.value;
|
|
12764
|
+
if (from !== void 0) return followReExport(mod, from, local, seen);
|
|
12765
|
+
const hit2 = lookup(mod.scopes, local);
|
|
12766
|
+
return hit2 ? { mod, binding: hit2.binding } : null;
|
|
12767
|
+
}
|
|
12768
|
+
}
|
|
12769
|
+
if (stmt.type === "ExportAllDeclaration" && !stmt.exported) {
|
|
12770
|
+
const from = stmt.source?.value;
|
|
12771
|
+
if (from === void 0) continue;
|
|
12772
|
+
const found = followReExport(mod, from, name, seen);
|
|
12773
|
+
if (found) return found;
|
|
12774
|
+
}
|
|
12775
|
+
}
|
|
12776
|
+
const hit = lookup(mod.scopes, name);
|
|
12777
|
+
return hit && hit.scope === mod.scopes ? { mod, binding: hit.binding } : null;
|
|
12778
|
+
}
|
|
12779
|
+
function followReExport(mod, specifier, name, seen) {
|
|
12780
|
+
const file = resolveImport(mod.file, specifier);
|
|
12781
|
+
if (!file || seen.has(`${file}\0${name}`)) return null;
|
|
12782
|
+
seen.add(`${file}\0${name}`);
|
|
12783
|
+
const next = analyseModuleFile(file);
|
|
12784
|
+
return next ? exportedBinding(next, name, seen) : null;
|
|
12785
|
+
}
|
|
12786
|
+
var MAX_HOPS = 12;
|
|
12787
|
+
var IDENT_RE = /^[A-Za-z_$][\w$]*$/;
|
|
12788
|
+
var MEMBER_RE = /^([A-Za-z_$][\w$]*)\s*\.\s*([A-Za-z_$][\w$]*)$/;
|
|
12789
|
+
function createReducerResolver(entryFile, body, src) {
|
|
12790
|
+
const scopes = buildScopeTree(body, src.length);
|
|
12791
|
+
markReassignments(body, scopes);
|
|
12792
|
+
const entry = { file: entryFile, src, body, scopes };
|
|
12793
|
+
const fromBinding = (mod, binding, memberName, hops, seen) => {
|
|
12794
|
+
if (hops > MAX_HOPS) return { arity: null, src: null, reason: "not-found" };
|
|
12795
|
+
if (binding.reassigned) return { arity: null, src: null, reason: "reassigned" };
|
|
12796
|
+
if (binding.kind === "param" || binding.kind === "catch" || binding.kind === "class") {
|
|
12797
|
+
return { arity: null, src: null, reason: "not-a-function" };
|
|
12798
|
+
}
|
|
12799
|
+
if (binding.kind === "import" && binding.importRef) {
|
|
12800
|
+
const { specifier, imported } = binding.importRef;
|
|
12801
|
+
if (imported === "*" && memberName === void 0) return { arity: null, src: null, reason: "not-a-function" };
|
|
12802
|
+
const file = resolveImport(mod.file, specifier);
|
|
12803
|
+
if (!file) return { arity: null, src: null, reason: "unresolved-import" };
|
|
12804
|
+
const next = analyseModuleFile(file);
|
|
12805
|
+
if (!next) return { arity: null, src: null, reason: "unresolved-import" };
|
|
12806
|
+
const wanted = imported === "*" ? memberName : imported;
|
|
12807
|
+
if (wanted === void 0) return { arity: null, src: null, reason: "not-a-function" };
|
|
12808
|
+
const found = exportedBinding(next, wanted, seen);
|
|
12809
|
+
if (!found) return { arity: null, src: null, reason: "not-found" };
|
|
12810
|
+
return fromBinding(found.mod, found.binding, void 0, hops + 1, seen);
|
|
12811
|
+
}
|
|
12812
|
+
const init = binding.init;
|
|
12813
|
+
if (!init) return { arity: null, src: null, reason: "not-a-function" };
|
|
12814
|
+
if (init.type === "Identifier") {
|
|
12815
|
+
const hit = lookup(scopeAt(mod.scopes, init.start), init.name);
|
|
12816
|
+
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12817
|
+
return fromBinding(mod, hit.binding, void 0, hops + 1, seen);
|
|
12818
|
+
}
|
|
12819
|
+
if (init.type === "ComputedMemberExpression" || init.computed === true && init.type.endsWith("MemberExpression")) {
|
|
12820
|
+
return { arity: null, src: null, reason: "computed" };
|
|
12821
|
+
}
|
|
12822
|
+
if (init.type === "StaticMemberExpression" || init.type === "MemberExpression") {
|
|
12823
|
+
const obj = init.object;
|
|
12824
|
+
const prop = init.property;
|
|
12825
|
+
if (obj?.type === "Identifier" && prop?.type === "Identifier") {
|
|
12826
|
+
const hit = lookup(scopeAt(mod.scopes, init.start), obj.name);
|
|
12827
|
+
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12828
|
+
return fromBinding(mod, hit.binding, prop.name, hops + 1, seen);
|
|
12829
|
+
}
|
|
12830
|
+
return { arity: null, src: null, reason: "computed" };
|
|
12831
|
+
}
|
|
12832
|
+
if (!FUNCTION_TYPES.has(init.type)) return { arity: null, src: null, reason: "not-a-function" };
|
|
12833
|
+
const { arity, reason } = functionArity(init);
|
|
12834
|
+
return { arity, src: mod.src.slice(init.start, init.end), ...reason ? { reason } : {} };
|
|
12835
|
+
};
|
|
12836
|
+
return {
|
|
12837
|
+
resolve(exprSrc, offset, offsetSrc) {
|
|
12838
|
+
const text = exprSrc.trim();
|
|
12839
|
+
const ident = IDENT_RE.test(text) ? text : null;
|
|
12840
|
+
const member = ident ? null : MEMBER_RE.exec(text);
|
|
12841
|
+
if (!ident && !member) return null;
|
|
12842
|
+
if (offsetSrc !== src) return { arity: null, src: null, reason: "foreign-source" };
|
|
12843
|
+
const name = ident ?? member[1];
|
|
12844
|
+
const memberName = ident ? void 0 : member[2];
|
|
12845
|
+
const hit = lookup(scopeAt(scopes, offset), name);
|
|
12846
|
+
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12847
|
+
return fromBinding(entry, hit.binding, memberName, 0, /* @__PURE__ */ new Set());
|
|
12848
|
+
}
|
|
12849
|
+
};
|
|
12850
|
+
}
|
|
12851
|
+
|
|
12475
12852
|
// src/plugin/index.ts
|
|
12476
12853
|
import { createHash } from "node:crypto";
|
|
12477
12854
|
var PARSEMAN_MODULE = "parseman";
|
|
@@ -12497,37 +12874,37 @@ function getCompiledResolver() {
|
|
|
12497
12874
|
}
|
|
12498
12875
|
var PRIVATE_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts"]);
|
|
12499
12876
|
function nearestPackageRoot(file) {
|
|
12500
|
-
let dir =
|
|
12877
|
+
let dir = path2.dirname(file);
|
|
12501
12878
|
for (; ; ) {
|
|
12502
12879
|
try {
|
|
12503
|
-
if (
|
|
12880
|
+
if (fs2.statSync(path2.join(dir, "package.json")).isFile()) return fs2.realpathSync(dir);
|
|
12504
12881
|
} catch {
|
|
12505
12882
|
}
|
|
12506
|
-
const parent =
|
|
12883
|
+
const parent = path2.dirname(dir);
|
|
12507
12884
|
if (parent === dir) return null;
|
|
12508
12885
|
dir = parent;
|
|
12509
12886
|
}
|
|
12510
12887
|
}
|
|
12511
12888
|
function isWithinPackageRoot(file, root) {
|
|
12512
|
-
const relative2 =
|
|
12513
|
-
return relative2 !== ".." && !relative2.startsWith(`..${
|
|
12889
|
+
const relative2 = path2.relative(root, file);
|
|
12890
|
+
return relative2 !== ".." && !relative2.startsWith(`..${path2.sep}`) && !path2.isAbsolute(relative2);
|
|
12514
12891
|
}
|
|
12515
12892
|
function resolvePrivateSourceModule(from, specifier) {
|
|
12516
|
-
if (!specifier.startsWith(".") && !
|
|
12893
|
+
if (!specifier.startsWith(".") && !path2.isAbsolute(specifier)) return null;
|
|
12517
12894
|
const packageRoot = nearestPackageRoot(from);
|
|
12518
12895
|
if (!packageRoot) return null;
|
|
12519
|
-
const base =
|
|
12520
|
-
const ext =
|
|
12896
|
+
const base = path2.resolve(path2.dirname(from), specifier);
|
|
12897
|
+
const ext = path2.extname(base);
|
|
12521
12898
|
const candidates = [
|
|
12522
12899
|
base,
|
|
12523
12900
|
...ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base.slice(0, -ext.length)}${next}`) : [],
|
|
12524
12901
|
...!ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base}${next}`) : [],
|
|
12525
|
-
...!ext ? ["index.ts", "index.tsx", "index.mts", "index.cts"].map((next) =>
|
|
12902
|
+
...!ext ? ["index.ts", "index.tsx", "index.mts", "index.cts"].map((next) => path2.join(base, next)) : []
|
|
12526
12903
|
];
|
|
12527
12904
|
for (const candidate of candidates) {
|
|
12528
12905
|
try {
|
|
12529
|
-
if (!
|
|
12530
|
-
const real =
|
|
12906
|
+
if (!fs2.statSync(candidate).isFile()) continue;
|
|
12907
|
+
const real = fs2.realpathSync(candidate);
|
|
12531
12908
|
if (isWithinPackageRoot(real, packageRoot)) return real;
|
|
12532
12909
|
} catch {
|
|
12533
12910
|
}
|
|
@@ -12535,7 +12912,7 @@ function resolvePrivateSourceModule(from, specifier) {
|
|
|
12535
12912
|
return null;
|
|
12536
12913
|
}
|
|
12537
12914
|
function resolveGrammarModule(from, specifier) {
|
|
12538
|
-
if (PRIVATE_SOURCE_EXTENSIONS.has(
|
|
12915
|
+
if (PRIVATE_SOURCE_EXTENSIONS.has(path2.extname(specifier))) {
|
|
12539
12916
|
const file2 = resolvePrivateSourceModule(from, specifier);
|
|
12540
12917
|
return file2 ? { file: file2, source: true } : null;
|
|
12541
12918
|
}
|
|
@@ -12556,7 +12933,7 @@ var _moduleParseCache = /* @__PURE__ */ new Map();
|
|
|
12556
12933
|
function parseModuleCached(filePath) {
|
|
12557
12934
|
let mtimeMs;
|
|
12558
12935
|
try {
|
|
12559
|
-
mtimeMs =
|
|
12936
|
+
mtimeMs = fs2.statSync(filePath).mtimeMs;
|
|
12560
12937
|
} catch {
|
|
12561
12938
|
return null;
|
|
12562
12939
|
}
|
|
@@ -12564,8 +12941,8 @@ function parseModuleCached(filePath) {
|
|
|
12564
12941
|
if (hit && hit.mtimeMs === mtimeMs) return hit.parsed;
|
|
12565
12942
|
let parsed = null;
|
|
12566
12943
|
try {
|
|
12567
|
-
const src =
|
|
12568
|
-
const r =
|
|
12944
|
+
const src = fs2.readFileSync(filePath, "utf8");
|
|
12945
|
+
const r = parseSync3(filePath, src);
|
|
12569
12946
|
if (r.errors.length === 0) parsed = { body: r.program.body, src };
|
|
12570
12947
|
} catch {
|
|
12571
12948
|
}
|
|
@@ -12693,7 +13070,7 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
12693
13070
|
if (_sourceLowering.has(file)) return null;
|
|
12694
13071
|
let mtimeMs;
|
|
12695
13072
|
try {
|
|
12696
|
-
mtimeMs =
|
|
13073
|
+
mtimeMs = fs2.statSync(file).mtimeMs;
|
|
12697
13074
|
} catch {
|
|
12698
13075
|
return null;
|
|
12699
13076
|
}
|
|
@@ -12703,10 +13080,10 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
12703
13080
|
_sourceLowering.add(file);
|
|
12704
13081
|
let parsedModule = null;
|
|
12705
13082
|
try {
|
|
12706
|
-
const source =
|
|
13083
|
+
const source = fs2.readFileSync(file, "utf8");
|
|
12707
13084
|
const transformed = transformMacro(source, file, moduleAliases, warnUnloweredRegex, recovery);
|
|
12708
13085
|
if (!transformed || transformed.warnings.length > 0) return null;
|
|
12709
|
-
const parsed =
|
|
13086
|
+
const parsed = parseSync3(file, transformed.code);
|
|
12710
13087
|
parsedModule = parsed.errors.length === 0 ? { body: parsed.program.body, src: transformed.code } : null;
|
|
12711
13088
|
return parsedModule;
|
|
12712
13089
|
} catch {
|
|
@@ -12717,9 +13094,20 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
12717
13094
|
}
|
|
12718
13095
|
}
|
|
12719
13096
|
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false, grammarCoverage = false) {
|
|
13097
|
+
const depth = degradationCaptureDepth();
|
|
13098
|
+
try {
|
|
13099
|
+
return transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recovery, grammarCoverage);
|
|
13100
|
+
} finally {
|
|
13101
|
+
setReducerResolver(null);
|
|
13102
|
+
endLoweringCapture();
|
|
13103
|
+
endInlineCapCapture();
|
|
13104
|
+
for (const d of unwindDegradationCapture(depth)) console.warn(formatDegradation(d));
|
|
13105
|
+
}
|
|
13106
|
+
}
|
|
13107
|
+
function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recovery, grammarCoverage) {
|
|
12720
13108
|
let result;
|
|
12721
13109
|
try {
|
|
12722
|
-
result =
|
|
13110
|
+
result = parseSync3(id, code);
|
|
12723
13111
|
} catch {
|
|
12724
13112
|
return null;
|
|
12725
13113
|
}
|
|
@@ -12776,6 +13164,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
12776
13164
|
}
|
|
12777
13165
|
}
|
|
12778
13166
|
}
|
|
13167
|
+
setReducerResolver(createReducerResolver(id, body, code));
|
|
12779
13168
|
const topLevelFunction = (moduleBody, name) => {
|
|
12780
13169
|
for (const st of moduleBody) {
|
|
12781
13170
|
const decl = st.type === "ExportNamedDeclaration" ? st.declaration : st;
|
|
@@ -12875,6 +13264,8 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
12875
13264
|
const replacements = [];
|
|
12876
13265
|
const warnings = [];
|
|
12877
13266
|
beginLoweringCapture();
|
|
13267
|
+
beginInlineCapCapture();
|
|
13268
|
+
beginDegradationCapture();
|
|
12878
13269
|
let anyUnresolved = false;
|
|
12879
13270
|
let keepMacroImport = false;
|
|
12880
13271
|
let runtimeComposeFallback = false;
|
|
@@ -12990,7 +13381,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
12990
13381
|
const mapLit = (m, stripVals = false) => `new Map([${[...m].map(
|
|
12991
13382
|
([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(stripVals && typeof v2 === "string" ? stripIndent(v2) : v2)}]`
|
|
12992
13383
|
).join(", ")}])`;
|
|
12993
|
-
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: [] }`;
|
|
13384
|
+
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: [] }`;
|
|
12994
13385
|
};
|
|
12995
13386
|
const isSpread = (it) => "__spreadLocal" in it;
|
|
12996
13387
|
const isIR = (it) => "ir" in it && !("ruleFns" in it);
|
|
@@ -13001,9 +13392,19 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13001
13392
|
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})`;
|
|
13002
13393
|
const withGrammarReflection = (grammarExpr, reflection) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.grammarReflection'), { value: ${grammarReflectionSource(reflection)}, enumerable: false })`;
|
|
13003
13394
|
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 })`;
|
|
13004
|
-
const emittedCoverageDefinitions = (source) => {
|
|
13395
|
+
const emittedCoverageDefinitions = (source, where) => {
|
|
13005
13396
|
const ids = /* @__PURE__ */ new Set();
|
|
13006
13397
|
for (const match of source.matchAll(/id:\s*"([^"]+)"/g)) ids.add(match[1]);
|
|
13398
|
+
if (grammarCoverage && ids.size === 0) {
|
|
13399
|
+
recordDegradation({
|
|
13400
|
+
code: "coverage-definitions-unavailable",
|
|
13401
|
+
severity: "warn",
|
|
13402
|
+
where,
|
|
13403
|
+
subject: "generated coverage hooks",
|
|
13404
|
+
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",
|
|
13405
|
+
otherwise: "the emitted hook IDs would form the coverage denominator"
|
|
13406
|
+
});
|
|
13407
|
+
}
|
|
13007
13408
|
return [...ids].sort().map((id2) => ({
|
|
13008
13409
|
id: id2,
|
|
13009
13410
|
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : id2.startsWith("dispatch:") ? "dispatch-arm" : "choice-arm"
|
|
@@ -13072,26 +13473,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13072
13473
|
}
|
|
13073
13474
|
return out;
|
|
13074
13475
|
};
|
|
13075
|
-
const carriedRuleMapsDetailed = (items) => {
|
|
13076
|
-
const maps = [];
|
|
13077
|
-
const opaque = [];
|
|
13078
|
-
const add = (it) => {
|
|
13079
|
-
if (isIR(it)) {
|
|
13080
|
-
maps.push(evalRuleMapIR(it.ir));
|
|
13081
|
-
return;
|
|
13082
|
-
}
|
|
13083
|
-
const o = it;
|
|
13084
|
-
opaque.push({
|
|
13085
|
-
ns: o.ns ?? "<unknown>",
|
|
13086
|
-
ruleNames: o.ruleFns instanceof Map ? [...o.ruleFns.keys()] : []
|
|
13087
|
-
});
|
|
13088
|
-
};
|
|
13089
|
-
for (const it of items) {
|
|
13090
|
-
if (isSpread(it)) for (const p of importedPieces(it.__spreadLocal) ?? []) add(p);
|
|
13091
|
-
else add(it);
|
|
13092
|
-
}
|
|
13093
|
-
return { maps, opaque };
|
|
13094
|
-
};
|
|
13095
13476
|
const materializeLeafCoverage = (items, localRules, localNs, composing, captureTerminals = false) => {
|
|
13096
13477
|
const sources = [];
|
|
13097
13478
|
const add = (item) => {
|
|
@@ -13242,12 +13623,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13242
13623
|
carried.push(...r.carried);
|
|
13243
13624
|
importedFactories.push(...r.importedFactories ?? []);
|
|
13244
13625
|
}
|
|
13245
|
-
const detailed = once(() => carriedRuleMapsDetailed(carried));
|
|
13246
|
-
runFusedGatingDiagnostic(
|
|
13247
|
-
() => detailed().maps,
|
|
13248
|
-
void 0,
|
|
13249
|
-
() => detailed().opaque
|
|
13250
|
-
);
|
|
13251
13626
|
const pieces = materializeCarried(carried, composing, false, cHostMode);
|
|
13252
13627
|
try {
|
|
13253
13628
|
return {
|
|
@@ -13304,12 +13679,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13304
13679
|
}
|
|
13305
13680
|
try {
|
|
13306
13681
|
const localNs = nsFor(`composeLeaf${init.start}`);
|
|
13307
|
-
const detailedLeaf = once(() => carriedRuleMapsDetailed(carried));
|
|
13308
|
-
runFusedGatingDiagnostic(
|
|
13309
|
-
() => [...detailedLeaf().maps, [...localRules]],
|
|
13310
|
-
void 0,
|
|
13311
|
-
() => detailedLeaf().opaque
|
|
13312
|
-
);
|
|
13313
13682
|
const plainLocalPiece = compileLinkable([...localRules], localNs, { ...composing ? { trivia: composing } : {}, ...localScanSkip ? { scanSkip: localScanSkip } : {}, recovery });
|
|
13314
13683
|
if (!plainLocalPiece) {
|
|
13315
13684
|
warn(init.start, "composeLeaf(): local rules could not be statically compiled");
|
|
@@ -13327,7 +13696,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13327
13696
|
}
|
|
13328
13697
|
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
|
|
13329
13698
|
return {
|
|
13330
|
-
replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)),
|
|
13699
|
+
replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement, `${id} composeLeaf()`)),
|
|
13331
13700
|
...importedFactories.length ? { importedFactories } : {}
|
|
13332
13701
|
};
|
|
13333
13702
|
} catch (e) {
|
|
@@ -13407,7 +13776,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13407
13776
|
const refEntry = scope.get(varName);
|
|
13408
13777
|
const refCombi = refEntry?.combi ?? null;
|
|
13409
13778
|
if (refCombi) {
|
|
13410
|
-
const compiled2 = compile(refCombi, void 0, { recovery, coverage: grammarCoverage
|
|
13779
|
+
const compiled2 = compile(refCombi, void 0, { recovery, coverage: grammarCoverage });
|
|
13411
13780
|
if (compiled2.inlineExpression === null) {
|
|
13412
13781
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
13413
13782
|
continue;
|
|
@@ -13438,7 +13807,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13438
13807
|
const source = compiledRules.replacement ?? code.slice(init.start, init.end);
|
|
13439
13808
|
let replacement = withCoverageDefinitions(
|
|
13440
13809
|
source,
|
|
13441
|
-
compiledRules.coverageDefinitions?.length ? compiledRules.coverageDefinitions : emittedCoverageDefinitions(source)
|
|
13810
|
+
compiledRules.coverageDefinitions?.length ? compiledRules.coverageDefinitions : emittedCoverageDefinitions(source, `${id} rules()`)
|
|
13442
13811
|
);
|
|
13443
13812
|
if (compiledRules.replacement !== null) {
|
|
13444
13813
|
replacement = withHostMode(replacement, compiledRules.hostMode, compiledRules.hostBranchElided);
|
|
@@ -13463,7 +13832,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13463
13832
|
localComposedCarried.set(varName, fused.carried);
|
|
13464
13833
|
if (fused.trivia) localComposedTrivia.set(varName, fused.trivia);
|
|
13465
13834
|
const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.carried) : fused.replacement;
|
|
13466
|
-
replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) });
|
|
13835
|
+
replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement, `${id} compose()`)) });
|
|
13467
13836
|
markUsedImportedFactories(fused.importedFactories);
|
|
13468
13837
|
continue;
|
|
13469
13838
|
}
|
|
@@ -13514,7 +13883,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13514
13883
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
13515
13884
|
continue;
|
|
13516
13885
|
}
|
|
13517
|
-
const compiled = compile(parser2, void 0, { recovery, coverage: grammarCoverage
|
|
13886
|
+
const compiled = compile(parser2, void 0, { recovery, coverage: grammarCoverage });
|
|
13518
13887
|
if (compiled.inlineExpression === null) {
|
|
13519
13888
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
13520
13889
|
continue;
|
|
@@ -13640,12 +14009,23 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13640
14009
|
`
|
|
13641
14010
|
);
|
|
13642
14011
|
}
|
|
14012
|
+
for (const line of formatInlineCapSites(endInlineCapCapture(), resolveInlineMax())) warnings.push(`${id}: ${line}`);
|
|
13643
14013
|
const unlowered = endLoweringCapture();
|
|
13644
14014
|
if (warnUnloweredRegex) {
|
|
13645
14015
|
for (const src of unlowered) {
|
|
13646
14016
|
warnings.push(`${id}: regex ${src} did not lower to a fast charCodeAt scan (RegExp.exec fallback)`);
|
|
13647
14017
|
}
|
|
13648
14018
|
}
|
|
14019
|
+
setReducerResolver(null);
|
|
14020
|
+
const degradations = endDegradationCapture();
|
|
14021
|
+
if (degradations.length > 0) {
|
|
14022
|
+
const lines = formatDegradations(degradations);
|
|
14023
|
+
if (resolveDegradationLevel() === "error") {
|
|
14024
|
+
throw new Error(`parseman: ${degradations.length} degraded compilation path(s) in ${id}
|
|
14025
|
+
${lines.join("\n")}`);
|
|
14026
|
+
}
|
|
14027
|
+
for (const l of lines) warnings.push(`${id}: ${l}`);
|
|
14028
|
+
}
|
|
13649
14029
|
return {
|
|
13650
14030
|
code: ms.toString(),
|
|
13651
14031
|
map: ms.generateMap({ hires: true }),
|