parseman 0.27.1 → 0.28.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/README.md +1 -1
- package/dist/combinators/attempt.d.ts +8 -0
- package/dist/combinators/attempt.d.ts.map +1 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/combinators/token.d.ts +12 -0
- package/dist/combinators/token.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts +8 -4
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +12 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts +19 -0
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -0
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +12 -1
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts +68 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/functional/run.d.ts +13 -0
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +816 -77
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +816 -77
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +4 -1
- package/dist/language-service/index.cjs.map +2 -2
- package/dist/language-service/index.js +4 -1
- package/dist/language-service/index.js.map +2 -2
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +786 -113
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts +4 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +786 -113
- package/dist/plugin/index.js.map +4 -4
- package/dist/spec/index.cjs +3 -0
- package/dist/spec/index.cjs.map +2 -2
- package/dist/spec/index.js +3 -0
- package/dist/spec/index.js.map +2 -2
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -35,6 +35,7 @@ __export(plugin_exports, {
|
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(plugin_exports);
|
|
37
37
|
var fs = __toESM(require("node:fs"), 1);
|
|
38
|
+
var path = __toESM(require("node:path"), 1);
|
|
38
39
|
var import_unplugin = require("unplugin");
|
|
39
40
|
var import_oxc_parser2 = require("oxc-parser");
|
|
40
41
|
var import_oxc_resolver = require("oxc-resolver");
|
|
@@ -101,6 +102,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
101
102
|
case "label":
|
|
102
103
|
case "trivia":
|
|
103
104
|
case "token":
|
|
105
|
+
case "leaf":
|
|
104
106
|
case "expect":
|
|
105
107
|
case "withCtx":
|
|
106
108
|
case "node":
|
|
@@ -164,6 +166,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
164
166
|
case "label":
|
|
165
167
|
case "trivia":
|
|
166
168
|
case "token":
|
|
169
|
+
case "leaf":
|
|
167
170
|
case "node":
|
|
168
171
|
case "grammar":
|
|
169
172
|
case "expect":
|
|
@@ -269,10 +272,10 @@ function beginCstNodeCapture(ctx) {
|
|
|
269
272
|
}
|
|
270
273
|
function finishCstBuf(buf) {
|
|
271
274
|
if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
|
|
272
|
-
const
|
|
275
|
+
const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
|
|
273
276
|
const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
|
|
274
277
|
const triviaLog = buf.tl ?? EMPTY_TL;
|
|
275
|
-
return { children, rawChildren, triviaLog };
|
|
278
|
+
return { children: children2, rawChildren, triviaLog };
|
|
276
279
|
}
|
|
277
280
|
function endCstNodeCapture(ctx, saved) {
|
|
278
281
|
const materialized = finishCstBuf(ctx._cstBuf);
|
|
@@ -284,8 +287,8 @@ function endCstNodeCapture(ctx, saved) {
|
|
|
284
287
|
ctx.captureTrivia = saved.cap;
|
|
285
288
|
return materialized;
|
|
286
289
|
}
|
|
287
|
-
function pushCstLeaf(ctx,
|
|
288
|
-
pushCstChild(ctx,
|
|
290
|
+
function pushCstLeaf(ctx, leaf2) {
|
|
291
|
+
pushCstChild(ctx, leaf2, leaf2);
|
|
289
292
|
}
|
|
290
293
|
function pushCstChild(ctx, built, rawEntry) {
|
|
291
294
|
const b = ctx._cstBuf;
|
|
@@ -1015,10 +1018,13 @@ function deriveExpected(c) {
|
|
|
1015
1018
|
return def.parsers.flatMap(deriveExpected);
|
|
1016
1019
|
case "sequence":
|
|
1017
1020
|
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1021
|
+
case "attempt":
|
|
1022
|
+
return deriveExpected(def.parser);
|
|
1018
1023
|
case "node":
|
|
1019
1024
|
case "grammar":
|
|
1020
1025
|
case "trivia":
|
|
1021
1026
|
case "token":
|
|
1027
|
+
case "leaf":
|
|
1022
1028
|
case "optional":
|
|
1023
1029
|
case "many":
|
|
1024
1030
|
case "oneOrMore":
|
|
@@ -1793,6 +1799,24 @@ function sequence(...parsers) {
|
|
|
1793
1799
|
};
|
|
1794
1800
|
}
|
|
1795
1801
|
|
|
1802
|
+
// src/combinators/attempt.ts
|
|
1803
|
+
function attempt(parser2) {
|
|
1804
|
+
return {
|
|
1805
|
+
_tag: "attempt",
|
|
1806
|
+
_meta: parser2._meta,
|
|
1807
|
+
_def: { tag: "attempt", parser: parser2 },
|
|
1808
|
+
parse(input, pos, ctx) {
|
|
1809
|
+
const mark = saveCstMark(ctx);
|
|
1810
|
+
const log = ctx._triviaLog?.length;
|
|
1811
|
+
const result = parser2.parse(input, pos, ctx);
|
|
1812
|
+
if (result.ok) return result;
|
|
1813
|
+
rollbackCstCapture(ctx, mark);
|
|
1814
|
+
if (log !== void 0 && ctx._triviaLog) ctx._triviaLog.length = log;
|
|
1815
|
+
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
1816
|
+
}
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1796
1820
|
// src/combinators/repeat.ts
|
|
1797
1821
|
function repItem(combinator, input, cur, ctx) {
|
|
1798
1822
|
const mark = saveTriviaMark(ctx);
|
|
@@ -1968,19 +1992,19 @@ function sepBy(combinator, separator) {
|
|
|
1968
1992
|
sepPos = advanceTrivia(input, cur, ctx);
|
|
1969
1993
|
}
|
|
1970
1994
|
}
|
|
1971
|
-
const
|
|
1972
|
-
if (!
|
|
1995
|
+
const sep2 = separator.parse(input, sepPos, ctx);
|
|
1996
|
+
if (!sep2.ok) {
|
|
1973
1997
|
rollbackTrivia(ctx, loopMark);
|
|
1974
1998
|
break;
|
|
1975
1999
|
}
|
|
1976
|
-
let nextPos =
|
|
2000
|
+
let nextPos = sep2.span.end;
|
|
1977
2001
|
if (ctx.trivia) {
|
|
1978
2002
|
if (needsDeferredTriviaCommit(ctx)) {
|
|
1979
|
-
const scan = scanTrivia(input,
|
|
2003
|
+
const scan = scanTrivia(input, sep2.span.end, ctx);
|
|
1980
2004
|
scan.commit();
|
|
1981
2005
|
nextPos = scan.end;
|
|
1982
2006
|
} else {
|
|
1983
|
-
nextPos = advanceTrivia(input,
|
|
2007
|
+
nextPos = advanceTrivia(input, sep2.span.end, ctx);
|
|
1984
2008
|
}
|
|
1985
2009
|
}
|
|
1986
2010
|
const next = combinator.parse(input, nextPos, ctx);
|
|
@@ -2065,10 +2089,14 @@ function markUnusedValues(root) {
|
|
|
2065
2089
|
case "label":
|
|
2066
2090
|
case "trivia":
|
|
2067
2091
|
case "token":
|
|
2092
|
+
case "attempt":
|
|
2068
2093
|
case "withCtx":
|
|
2069
2094
|
case "expect":
|
|
2070
2095
|
visit(def.parser, consumed);
|
|
2071
2096
|
return;
|
|
2097
|
+
case "leaf":
|
|
2098
|
+
visit(def.parser, true);
|
|
2099
|
+
return;
|
|
2072
2100
|
case "lazy":
|
|
2073
2101
|
return;
|
|
2074
2102
|
default:
|
|
@@ -2191,6 +2219,20 @@ function confirmedBuildArity(src) {
|
|
|
2191
2219
|
if (/\barguments\b/.test(s)) return null;
|
|
2192
2220
|
return parts.length;
|
|
2193
2221
|
}
|
|
2222
|
+
function buildReadsChildren(def) {
|
|
2223
|
+
if (!def.build) return true;
|
|
2224
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2225
|
+
const arity = confirmedBuildArity(src);
|
|
2226
|
+
if (arity === null) return true;
|
|
2227
|
+
return arity >= 1;
|
|
2228
|
+
}
|
|
2229
|
+
function buildReadsRaw(def) {
|
|
2230
|
+
if (!def.build) return true;
|
|
2231
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2232
|
+
const arity = confirmedBuildArity(src);
|
|
2233
|
+
if (arity === null) return true;
|
|
2234
|
+
return arity >= 4;
|
|
2235
|
+
}
|
|
2194
2236
|
function buildReadsTrivia(def) {
|
|
2195
2237
|
if (!def.build) return true;
|
|
2196
2238
|
const src = def.buildSrc ?? def.build.toString();
|
|
@@ -2246,9 +2288,11 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2246
2288
|
case "many":
|
|
2247
2289
|
case "oneOrMore":
|
|
2248
2290
|
case "optional":
|
|
2291
|
+
case "attempt":
|
|
2249
2292
|
case "transform":
|
|
2250
2293
|
case "trivia":
|
|
2251
2294
|
case "token":
|
|
2295
|
+
case "leaf":
|
|
2252
2296
|
case "label":
|
|
2253
2297
|
case "expect":
|
|
2254
2298
|
case "withCtx":
|
|
@@ -2281,9 +2325,11 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2281
2325
|
case "keywords":
|
|
2282
2326
|
case "guard":
|
|
2283
2327
|
case "token":
|
|
2328
|
+
case "leaf":
|
|
2284
2329
|
return false;
|
|
2285
2330
|
// Transparent single-child wrappers: recurse.
|
|
2286
2331
|
case "optional":
|
|
2332
|
+
case "attempt":
|
|
2287
2333
|
case "transform":
|
|
2288
2334
|
case "trivia":
|
|
2289
2335
|
case "label":
|
|
@@ -2330,6 +2376,7 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2330
2376
|
case "many":
|
|
2331
2377
|
case "oneOrMore":
|
|
2332
2378
|
case "optional":
|
|
2379
|
+
case "attempt":
|
|
2333
2380
|
case "transform":
|
|
2334
2381
|
case "trivia":
|
|
2335
2382
|
case "token":
|
|
@@ -2339,6 +2386,10 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2339
2386
|
case "withCtx":
|
|
2340
2387
|
case "not":
|
|
2341
2388
|
return parserEnablesTriviaCapture(d.parser, seen);
|
|
2389
|
+
// leaf() clears the inner CST/trivia collector and publishes only its own
|
|
2390
|
+
// terminal result. An inner parser() capture cannot reach this node.
|
|
2391
|
+
case "leaf":
|
|
2392
|
+
return false;
|
|
2342
2393
|
case "lazy": {
|
|
2343
2394
|
try {
|
|
2344
2395
|
return parserEnablesTriviaCapture(d.thunk(), seen);
|
|
@@ -2417,12 +2468,12 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2417
2468
|
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
2418
2469
|
ctx._fields = savedFields;
|
|
2419
2470
|
ctx._triviaCaptureMask = savedMask;
|
|
2420
|
-
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2471
|
+
const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2421
2472
|
if (!r.ok) return r;
|
|
2422
2473
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2423
2474
|
const nodeType = def.type ?? missingInferredType();
|
|
2424
2475
|
const cstOutput = ctx.build?._parsemanCstOutput === true;
|
|
2425
|
-
const built = unwrap &&
|
|
2476
|
+
const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
|
|
2426
2477
|
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: r.span };
|
|
2427
2478
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2428
2479
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -2628,6 +2679,141 @@ function token(root) {
|
|
|
2628
2679
|
}
|
|
2629
2680
|
};
|
|
2630
2681
|
}
|
|
2682
|
+
function leaf(root, fn) {
|
|
2683
|
+
const meta = {
|
|
2684
|
+
firstSet: root._meta.firstSet,
|
|
2685
|
+
canMatchNewline: root._meta.canMatchNewline,
|
|
2686
|
+
isTrivia: false
|
|
2687
|
+
};
|
|
2688
|
+
return {
|
|
2689
|
+
_tag: "leaf",
|
|
2690
|
+
_meta: meta,
|
|
2691
|
+
_def: { tag: "leaf", parser: root, fn },
|
|
2692
|
+
parse(input, pos, ctx) {
|
|
2693
|
+
const savedBuf = ctx._cstBuf;
|
|
2694
|
+
const savedChildren = ctx._cstChildren;
|
|
2695
|
+
const savedLeaves = ctx._cstLeaves;
|
|
2696
|
+
const savedRaw = ctx._cstRawChildren;
|
|
2697
|
+
const savedTriviaLog = ctx._cstTriviaLog;
|
|
2698
|
+
const savedOuterTriviaLog = ctx._triviaLog;
|
|
2699
|
+
const wasCapturing = cstCaptureActive(ctx);
|
|
2700
|
+
ctx._cstBuf = void 0;
|
|
2701
|
+
ctx._cstChildren = void 0;
|
|
2702
|
+
ctx._cstLeaves = void 0;
|
|
2703
|
+
ctx._cstRawChildren = void 0;
|
|
2704
|
+
ctx._cstTriviaLog = void 0;
|
|
2705
|
+
delete ctx._triviaLog;
|
|
2706
|
+
let result;
|
|
2707
|
+
try {
|
|
2708
|
+
result = root.parse(input, pos, ctx);
|
|
2709
|
+
} finally {
|
|
2710
|
+
ctx._cstBuf = savedBuf;
|
|
2711
|
+
ctx._cstChildren = savedChildren;
|
|
2712
|
+
ctx._cstLeaves = savedLeaves;
|
|
2713
|
+
ctx._cstRawChildren = savedRaw;
|
|
2714
|
+
ctx._cstTriviaLog = savedTriviaLog;
|
|
2715
|
+
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
2716
|
+
else ctx._triviaLog = savedOuterTriviaLog;
|
|
2717
|
+
}
|
|
2718
|
+
if (!result.ok) return result;
|
|
2719
|
+
const value = fn(result.value, result.span);
|
|
2720
|
+
if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span: result.span });
|
|
2721
|
+
return { ok: true, value, span: result.span };
|
|
2722
|
+
}
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/compiler/grammar-coverage-ids.ts
|
|
2727
|
+
function children(def, winners) {
|
|
2728
|
+
switch (def.tag) {
|
|
2729
|
+
case "sequence":
|
|
2730
|
+
case "choice":
|
|
2731
|
+
return def.parsers;
|
|
2732
|
+
case "many":
|
|
2733
|
+
case "oneOrMore":
|
|
2734
|
+
case "optional":
|
|
2735
|
+
case "attempt":
|
|
2736
|
+
case "transform":
|
|
2737
|
+
case "trivia":
|
|
2738
|
+
case "token":
|
|
2739
|
+
case "leaf":
|
|
2740
|
+
case "label":
|
|
2741
|
+
case "field":
|
|
2742
|
+
case "grammar":
|
|
2743
|
+
case "not":
|
|
2744
|
+
case "node":
|
|
2745
|
+
case "guard":
|
|
2746
|
+
case "withCtx":
|
|
2747
|
+
case "recover":
|
|
2748
|
+
case "expect":
|
|
2749
|
+
return "parser" in def ? [def.parser] : [];
|
|
2750
|
+
case "sepBy":
|
|
2751
|
+
return [def.parser, def.separator];
|
|
2752
|
+
case "skip":
|
|
2753
|
+
return [def.main, def.skipped];
|
|
2754
|
+
case "scanTo":
|
|
2755
|
+
return [def.sentinel, ...def.skip];
|
|
2756
|
+
case "lazy": {
|
|
2757
|
+
let resolved;
|
|
2758
|
+
try {
|
|
2759
|
+
resolved = def.thunk();
|
|
2760
|
+
} catch {
|
|
2761
|
+
return [];
|
|
2762
|
+
}
|
|
2763
|
+
const name = resolved._ruleName;
|
|
2764
|
+
return name && winners?.[name] ? [winners[name]] : [resolved];
|
|
2765
|
+
}
|
|
2766
|
+
default:
|
|
2767
|
+
return [];
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
function buildGrammarPlan(entry, winners) {
|
|
2771
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
2772
|
+
const choices = /* @__PURE__ */ new WeakMap();
|
|
2773
|
+
const attempts = /* @__PURE__ */ new WeakMap();
|
|
2774
|
+
const labels = /* @__PURE__ */ new WeakMap();
|
|
2775
|
+
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
2776
|
+
const winnerNames = /* @__PURE__ */ new Map();
|
|
2777
|
+
if (winners) {
|
|
2778
|
+
for (const [name, winner] of Object.entries(winners)) {
|
|
2779
|
+
winnerNames.set(winner, name);
|
|
2780
|
+
if (winner._def.tag === "lazy") {
|
|
2781
|
+
try {
|
|
2782
|
+
winnerNames.set(winner._def.thunk(), name);
|
|
2783
|
+
} catch {
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2789
|
+
const visit = (parser2, path2) => {
|
|
2790
|
+
if (seen.has(parser2)) return;
|
|
2791
|
+
seen.add(parser2);
|
|
2792
|
+
const rule = winnerNames.get(parser2) ?? parser2._ruleName;
|
|
2793
|
+
if (rule && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
|
|
2794
|
+
const id = `rule:${rule}`;
|
|
2795
|
+
definitions.set(id, { id, kind: "rule" });
|
|
2796
|
+
rules2.set(parser2, id);
|
|
2797
|
+
}
|
|
2798
|
+
if (parser2._def.tag === "choice") {
|
|
2799
|
+
const ids = parser2._def.parsers.map((_, index) => `choice:${path2}/arm:${index}`);
|
|
2800
|
+
choices.set(parser2, ids);
|
|
2801
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
2802
|
+
}
|
|
2803
|
+
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path2}`);
|
|
2804
|
+
if (parser2._def.tag === "label") {
|
|
2805
|
+
const id = `label:${path2}`;
|
|
2806
|
+
labels.set(parser2, [id]);
|
|
2807
|
+
definitions.set(id, { id, kind: "label" });
|
|
2808
|
+
}
|
|
2809
|
+
children(parser2._def, winners).forEach((child, index) => visit(child, `${path2}/${parser2._def.tag}:${index}`));
|
|
2810
|
+
};
|
|
2811
|
+
const roots = Array.isArray(entry) ? entry : [entry];
|
|
2812
|
+
for (const root of roots) {
|
|
2813
|
+
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
2814
|
+
}
|
|
2815
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
2816
|
+
}
|
|
2631
2817
|
|
|
2632
2818
|
// src/compiler/scannable-run.ts
|
|
2633
2819
|
var BACKSLASH = 92;
|
|
@@ -4020,21 +4206,23 @@ function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
|
4020
4206
|
}
|
|
4021
4207
|
function failBody(ctx, expected, posExpr) {
|
|
4022
4208
|
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
4209
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
4023
4210
|
if (ctx.failLabel) {
|
|
4024
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4025
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
4211
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4212
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
|
|
4026
4213
|
}
|
|
4027
|
-
return probe + failReturn(expected, posExpr);
|
|
4214
|
+
return probe + trace + failReturn(expected, posExpr);
|
|
4028
4215
|
}
|
|
4029
4216
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
4030
4217
|
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
4218
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
4031
4219
|
if (ctx.failLabel) {
|
|
4032
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4220
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4033
4221
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
4034
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
4222
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
|
|
4035
4223
|
}
|
|
4036
|
-
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4037
|
-
return probe + failReturnArr(expectedArr, posExpr);
|
|
4224
|
+
if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4225
|
+
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
4038
4226
|
}
|
|
4039
4227
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
4040
4228
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4069,7 +4257,7 @@ var NAMED_FN_END = "_pfEnd";
|
|
|
4069
4257
|
function namedFnPrelude() {
|
|
4070
4258
|
return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
|
|
4071
4259
|
}
|
|
4072
|
-
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
4260
|
+
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar, failureRuleId) {
|
|
4073
4261
|
ctx.namedFnDecls.push([
|
|
4074
4262
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
4075
4263
|
` _pfail: {`,
|
|
@@ -4077,6 +4265,7 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
|
4077
4265
|
` ${NAMED_FN_END} = ${endVar}`,
|
|
4078
4266
|
` return ${valueVar}`,
|
|
4079
4267
|
` }`,
|
|
4268
|
+
...failureRuleId === void 0 ? [] : [` _ctx._grammarTrace?.write({ id: ${JSON.stringify(failureRuleId)}, phase: 'failure', offset: _ctx._fe ?? _pos })`],
|
|
4080
4269
|
` return ${NAMED_FN_FAIL}`,
|
|
4081
4270
|
`}`
|
|
4082
4271
|
].join("\n"));
|
|
@@ -4238,6 +4427,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4238
4427
|
case "not":
|
|
4239
4428
|
case "trivia":
|
|
4240
4429
|
case "token":
|
|
4430
|
+
case "leaf":
|
|
4241
4431
|
case "scanTo":
|
|
4242
4432
|
case "unknown":
|
|
4243
4433
|
return false;
|
|
@@ -4249,6 +4439,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4249
4439
|
// nothing committed remains.
|
|
4250
4440
|
case "choice":
|
|
4251
4441
|
return false;
|
|
4442
|
+
case "attempt":
|
|
4443
|
+
return false;
|
|
4252
4444
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
4253
4445
|
case "optional":
|
|
4254
4446
|
case "many":
|
|
@@ -4301,6 +4493,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4301
4493
|
case "keywords":
|
|
4302
4494
|
case "node":
|
|
4303
4495
|
case "token":
|
|
4496
|
+
case "leaf":
|
|
4304
4497
|
return true;
|
|
4305
4498
|
case "not":
|
|
4306
4499
|
case "guard":
|
|
@@ -4315,6 +4508,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4315
4508
|
case "many":
|
|
4316
4509
|
case "oneOrMore":
|
|
4317
4510
|
case "optional":
|
|
4511
|
+
case "attempt":
|
|
4318
4512
|
case "transform":
|
|
4319
4513
|
case "label":
|
|
4320
4514
|
case "field":
|
|
@@ -4656,35 +4850,55 @@ function needsFirstSetGuard(p) {
|
|
|
4656
4850
|
const fs2 = p._meta.firstSet;
|
|
4657
4851
|
return fs2.kind !== "any" && !canMatchEmptyAtStart(p);
|
|
4658
4852
|
}
|
|
4659
|
-
function
|
|
4660
|
-
|
|
4853
|
+
function coverageHit(ctx, id, offset = "_pos", end) {
|
|
4854
|
+
return id === void 0 ? [] : [
|
|
4855
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`,
|
|
4856
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'selected', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`,
|
|
4857
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`
|
|
4858
|
+
];
|
|
4859
|
+
}
|
|
4860
|
+
function coverageAttempt(ctx, id, offset) {
|
|
4861
|
+
return id === void 0 ? [] : [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'attempt', offset: ${offset} })`];
|
|
4862
|
+
}
|
|
4863
|
+
function coverageFailureBacktrack(ctx, id, failureOffset, startOffset) {
|
|
4864
|
+
return id === void 0 ? [] : [
|
|
4865
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'failure', offset: ${failureOffset} })`,
|
|
4866
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'backtrack', offset: ${startOffset} })`
|
|
4867
|
+
];
|
|
4868
|
+
}
|
|
4869
|
+
function emitDisjointArm(p, ctx, pos, valV, endV, coverageId) {
|
|
4870
|
+
if (failsAtStart(p) && coverageId === void 0) {
|
|
4661
4871
|
const r = emit(p, ctx, pos);
|
|
4662
|
-
return [...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}
|
|
4872
|
+
return [...coverageAttempt(ctx, coverageId, pos), ...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`, ...coverageHit(ctx, coverageId, pos, r.endVar)];
|
|
4663
4873
|
}
|
|
4664
4874
|
const { stmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
|
|
4665
4875
|
return [
|
|
4876
|
+
...coverageAttempt(ctx, coverageId, pos),
|
|
4666
4877
|
...stmts,
|
|
4667
|
-
...emitIfFail(ctx, `!${okVar}`, failArrBody(ctx, "_ctx._fx", pos, false)),
|
|
4878
|
+
...emitIfFail(ctx, `!${okVar}`, `${coverageFailureBacktrack(ctx, coverageId, "_ctx._fe", pos).join("; ")}; ${failArrBody(ctx, "_ctx._fx", pos, false)}`),
|
|
4668
4879
|
`${ind(ctx)}${valV} = ${valVar}`,
|
|
4669
|
-
`${ind(ctx)}${endV} = ${endVar}
|
|
4880
|
+
`${ind(ctx)}${endV} = ${endVar}`,
|
|
4881
|
+
...coverageHit(ctx, coverageId, pos, endVar)
|
|
4670
4882
|
];
|
|
4671
4883
|
}
|
|
4672
|
-
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4884
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageId) {
|
|
4673
4885
|
const p = def.parsers[i];
|
|
4674
4886
|
const gate = def.gates[i];
|
|
4675
|
-
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4887
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV, coverageId);
|
|
4676
4888
|
const gateIdx = ctx.mapFns.length;
|
|
4677
4889
|
ctx.mapFns.push(gate);
|
|
4678
4890
|
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4679
4891
|
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4680
4892
|
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4681
4893
|
ctx.indent++;
|
|
4682
|
-
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4894
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV, coverageId));
|
|
4683
4895
|
ctx.indent--;
|
|
4684
4896
|
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4685
4897
|
return stmts;
|
|
4686
4898
|
}
|
|
4687
|
-
function emitChoice(def, ctx, pos) {
|
|
4899
|
+
function emitChoice(parser2, def, ctx, pos) {
|
|
4900
|
+
const coverageIds = ctx.coverage?.plan.choices.get(parser2);
|
|
4901
|
+
const coverageBase = coverageIds?.[0]?.slice(0, -1);
|
|
4688
4902
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4689
4903
|
if (def.disjoint) {
|
|
4690
4904
|
const codeV = v(ctx, "_code");
|
|
@@ -4703,7 +4917,7 @@ function emitChoice(def, ctx, pos) {
|
|
|
4703
4917
|
stmts.push(`${ind(ctx)}{`);
|
|
4704
4918
|
ctx.indent++;
|
|
4705
4919
|
stmts.push(
|
|
4706
|
-
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
4920
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]),
|
|
4707
4921
|
`${ind(ctx)}break`
|
|
4708
4922
|
);
|
|
4709
4923
|
ctx.indent--;
|
|
@@ -4722,16 +4936,16 @@ function emitChoice(def, ctx, pos) {
|
|
|
4722
4936
|
first = false;
|
|
4723
4937
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4724
4938
|
ctx.indent++;
|
|
4725
|
-
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
4939
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]));
|
|
4726
4940
|
ctx.indent--;
|
|
4727
4941
|
stmts.push(`${ind(ctx)}}`);
|
|
4728
4942
|
}
|
|
4729
4943
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4730
4944
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4731
4945
|
}
|
|
4732
|
-
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
|
|
4946
|
+
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
4733
4947
|
}
|
|
4734
|
-
function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
4948
|
+
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
4735
4949
|
const superParser = def.parsers[superIndex];
|
|
4736
4950
|
const regexDef = getCoreRegexDef(superParser);
|
|
4737
4951
|
const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
@@ -4747,10 +4961,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4747
4961
|
const endV = v(ctx, "_ge");
|
|
4748
4962
|
const valV = v(ctx, "_gcv");
|
|
4749
4963
|
const regexExpected = JSON.stringify(deriveExpected(superParser));
|
|
4964
|
+
const superCoverageId = coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`;
|
|
4750
4965
|
const stmts = [
|
|
4966
|
+
...coverageAttempt(ctx, superCoverageId, pos),
|
|
4751
4967
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
4752
4968
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
4753
|
-
...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, regexExpected, pos)),
|
|
4969
|
+
...emitIfFail(ctx, `${matchV} === null`, `${coverageFailureBacktrack(ctx, superCoverageId, pos, pos).join("; ")}; ${failArrBody(ctx, regexExpected, pos)}`),
|
|
4754
4970
|
`${ind(ctx)}const ${wordV} = ${matchV}[0]`,
|
|
4755
4971
|
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
|
|
4756
4972
|
`${ind(ctx)}let ${valV}`
|
|
@@ -4766,8 +4982,9 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4766
4982
|
stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
|
|
4767
4983
|
ctx.indent++;
|
|
4768
4984
|
const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
|
|
4985
|
+
stmts.push(...coverageFailureBacktrack(ctx, superCoverageId, pos, pos));
|
|
4769
4986
|
stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
|
|
4770
|
-
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}
|
|
4987
|
+
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endV));
|
|
4771
4988
|
ctx.indent--;
|
|
4772
4989
|
stmts.push(`${ind(ctx)}}`);
|
|
4773
4990
|
}
|
|
@@ -4775,12 +4992,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4775
4992
|
const regexKw = first ? "if" : "else";
|
|
4776
4993
|
stmts.push(`${ind(ctx)}${regexKw} {`);
|
|
4777
4994
|
ctx.indent++;
|
|
4778
|
-
stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}
|
|
4995
|
+
stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`, pos, endV));
|
|
4779
4996
|
ctx.indent--;
|
|
4780
4997
|
stmts.push(`${ind(ctx)}}`);
|
|
4781
4998
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4782
4999
|
}
|
|
4783
|
-
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
5000
|
+
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, coverageBase) {
|
|
4784
5001
|
const valV = v(ctx, "_llv");
|
|
4785
5002
|
const endV = v(ctx, "_lle");
|
|
4786
5003
|
const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
|
|
@@ -4797,10 +5014,12 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4797
5014
|
ctx.indent++;
|
|
4798
5015
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
4799
5016
|
stmts.push(
|
|
5017
|
+
...coverageAttempt(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos),
|
|
4800
5018
|
...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
|
|
4801
5019
|
...tR.stmts,
|
|
4802
5020
|
`${ind(ctx)}${valV} = ${tR.valueVar}`,
|
|
4803
|
-
`${ind(ctx)}${endV} = ${litEnd}
|
|
5021
|
+
`${ind(ctx)}${endV} = ${litEnd}`,
|
|
5022
|
+
...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos, litEnd)
|
|
4804
5023
|
);
|
|
4805
5024
|
ctx.indent--;
|
|
4806
5025
|
stmts.push(`${ind(ctx)}}`);
|
|
@@ -4808,16 +5027,18 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4808
5027
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4809
5028
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4810
5029
|
}
|
|
4811
|
-
function emitFirstMatch(def, ctx, pos) {
|
|
5030
|
+
function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
4812
5031
|
const resValV = v(ctx, "_crv");
|
|
4813
5032
|
const resEndV = v(ctx, "_cre");
|
|
4814
5033
|
const resOkV = v(ctx, "_crok");
|
|
4815
5034
|
const codeV = v(ctx, "_chcode");
|
|
4816
5035
|
const slots = def.parsers.map(() => v(ctx, "_cfx"));
|
|
5036
|
+
const autoRejectedV = coverageBase === void 0 ? void 0 : v(ctx, "_carej");
|
|
4817
5037
|
const ind0 = ind(ctx);
|
|
4818
5038
|
const stmts = [
|
|
4819
5039
|
`${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`,
|
|
4820
5040
|
`${ind0}let ${slots.join(", ")}`,
|
|
5041
|
+
...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
|
|
4821
5042
|
`${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
|
|
4822
5043
|
];
|
|
4823
5044
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
@@ -4853,6 +5074,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4853
5074
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4854
5075
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
4855
5076
|
ctx.indent += fsGuard ? 2 : 1;
|
|
5077
|
+
if (coverageBase !== void 0) stmts.push(`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'attempt', offset: ${pos} })`);
|
|
4856
5078
|
if (markLeaves) {
|
|
4857
5079
|
stmts.push(
|
|
4858
5080
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
@@ -4875,13 +5097,21 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4875
5097
|
stmts.push(`${ind(ctx)} ${resValV} = ${valVar}`);
|
|
4876
5098
|
stmts.push(`${ind(ctx)} ${resEndV} = ${endVar}`);
|
|
4877
5099
|
stmts.push(`${ind(ctx)} ${resOkV} = true`);
|
|
5100
|
+
if (autoRejectedV !== void 0) {
|
|
5101
|
+
stmts.push(`${ind(ctx)} for (const _rejectedId of ${autoRejectedV}) { _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'failure', offset: ${pos} }); _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'backtrack', offset: ${pos} }) }`);
|
|
5102
|
+
}
|
|
5103
|
+
stmts.push(...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endVar));
|
|
4878
5104
|
stmts.push(`${ind(ctx)} }`);
|
|
5105
|
+
if (autoRejectedV !== void 0) {
|
|
5106
|
+
stmts.push(`${ind(ctx)} else { ${autoRejectedV}.push(${JSON.stringify(`${coverageBase}${i}`)}) }`);
|
|
5107
|
+
}
|
|
4879
5108
|
stmts.push(`${ind(ctx)}}`);
|
|
4880
|
-
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot} }`);
|
|
5109
|
+
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}; ${coverageBase === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} });`} }`);
|
|
4881
5110
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
4882
5111
|
} else {
|
|
4883
|
-
|
|
4884
|
-
stmts.push(`${ind(ctx)}
|
|
5112
|
+
const rejectedFlush = autoRejectedV === void 0 ? "" : `; for (const _rejectedId of ${autoRejectedV}) { _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'failure', offset: ${pos} }); _ctx._grammarTrace?.write({ id: _rejectedId, phase: 'backtrack', offset: ${pos} }) }`;
|
|
5113
|
+
stmts.push(`${ind(ctx)}if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true${coverageBase === void 0 ? "" : `${rejectedFlush}; _ctx._grammarCoverage?.(${JSON.stringify(`${coverageBase}${i}`)}); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'selected', offset: ${pos}, end: ${endVar} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'success', offset: ${pos}, end: ${endVar} })`} }`);
|
|
5114
|
+
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot}${rollback ? `; ${rollback}` : ""}${coverageBase === void 0 ? "" : `; _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'failure', offset: ${atStart ? pos : "_ctx._fe"} }); _ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'backtrack', offset: ${pos} })`} }`);
|
|
4885
5115
|
}
|
|
4886
5116
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
4887
5117
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -4891,12 +5121,12 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4891
5121
|
stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
|
|
4892
5122
|
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
4893
5123
|
}
|
|
4894
|
-
function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
5124
|
+
function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
|
|
4895
5125
|
if (strategy.tag === "greedyClassify")
|
|
4896
|
-
return emitGreedyClassify(def, strategy.superIndex, ctx, pos);
|
|
5126
|
+
return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
|
|
4897
5127
|
if (strategy.tag === "literalsLongestFirst")
|
|
4898
|
-
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
4899
|
-
return emitFirstMatch(def, ctx, pos);
|
|
5128
|
+
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
|
|
5129
|
+
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
4900
5130
|
}
|
|
4901
5131
|
function pushMapFn(ctx, fn, src) {
|
|
4902
5132
|
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
@@ -5014,6 +5244,27 @@ function emitOptional(def, ctx, pos) {
|
|
|
5014
5244
|
];
|
|
5015
5245
|
return { stmts, valueVar: valV, endVar: endV };
|
|
5016
5246
|
}
|
|
5247
|
+
function emitAttempt(p, def, ctx, pos) {
|
|
5248
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5249
|
+
const leaves = v(ctx, "_atl");
|
|
5250
|
+
const raw = v(ctx, "_atr");
|
|
5251
|
+
const trivia2 = v(ctx, "_att");
|
|
5252
|
+
const log = v(ctx, "_atg");
|
|
5253
|
+
const fields = v(ctx, "_atf");
|
|
5254
|
+
const errors = v(ctx, "_ate");
|
|
5255
|
+
const rollback = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${trivia2}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${log}; if (_ctx._fields) _ctx._fields.length = ${fields}; if (_ctx._errors) _ctx._errors.length = ${errors}`;
|
|
5256
|
+
const traceId = ctx.coverage?.plan.attempts.get(p);
|
|
5257
|
+
const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
|
|
5258
|
+
return {
|
|
5259
|
+
stmts: [
|
|
5260
|
+
`${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${trivia2} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`,
|
|
5261
|
+
...inner.stmts,
|
|
5262
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
5263
|
+
],
|
|
5264
|
+
valueVar: inner.valVar,
|
|
5265
|
+
endVar: inner.endVar
|
|
5266
|
+
};
|
|
5267
|
+
}
|
|
5017
5268
|
function emitSepBy(_p, def, ctx, pos) {
|
|
5018
5269
|
const arrV = v(ctx, "_arr");
|
|
5019
5270
|
const curV = v(ctx, "_cur");
|
|
@@ -5259,11 +5510,11 @@ function tokenNullableRegex(def) {
|
|
|
5259
5510
|
}
|
|
5260
5511
|
if (inner.tag === "sepBy") {
|
|
5261
5512
|
const item = tokenSequenceSource(inner.parser);
|
|
5262
|
-
const
|
|
5263
|
-
if (!item || !
|
|
5264
|
-
const combined = combineTokenRegexSources([item,
|
|
5513
|
+
const sep2 = tokenSequenceSource(inner.separator);
|
|
5514
|
+
if (!item || !sep2) return null;
|
|
5515
|
+
const combined = combineTokenRegexSources([item, sep2]);
|
|
5265
5516
|
if (!combined) return null;
|
|
5266
|
-
return { tag: "regex", source: `(?:${item.source}(?:${
|
|
5517
|
+
return { tag: "regex", source: `(?:${item.source}(?:${sep2.source}${item.source})*)?`, flags: combined.flags };
|
|
5267
5518
|
}
|
|
5268
5519
|
return null;
|
|
5269
5520
|
}
|
|
@@ -5304,6 +5555,36 @@ function emitToken(def, ctx, pos) {
|
|
|
5304
5555
|
endVar: inner.endVar
|
|
5305
5556
|
};
|
|
5306
5557
|
}
|
|
5558
|
+
function emitLeaf(def, ctx, pos) {
|
|
5559
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5560
|
+
const i = ind(ctx);
|
|
5561
|
+
const sc = v(ctx, "_leafCh");
|
|
5562
|
+
const sl = v(ctx, "_leafLv");
|
|
5563
|
+
const sr = v(ctx, "_leafRaw");
|
|
5564
|
+
const stl = v(ctx, "_leafTl");
|
|
5565
|
+
const sol = v(ctx, "_leafLog");
|
|
5566
|
+
const sb = v(ctx, "_leafBuf");
|
|
5567
|
+
const rawV = v(ctx, "_leafRawValue");
|
|
5568
|
+
const valV = v(ctx, "_leaf");
|
|
5569
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
5570
|
+
return {
|
|
5571
|
+
stmts: [
|
|
5572
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
|
|
5573
|
+
`${i}_ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
|
|
5574
|
+
`${i}try {`,
|
|
5575
|
+
...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
|
|
5576
|
+
`${i}} finally {`,
|
|
5577
|
+
`${i} _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
|
|
5578
|
+
`${i}}`,
|
|
5579
|
+
...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
|
|
5580
|
+
`${i}const ${rawV} = ${inner.valVar}`,
|
|
5581
|
+
`${i}const ${valV} = ${mfRef(ctx)}[${fnIdx}](${rawV}, { start: ${pos}, end: ${inner.endVar} })`,
|
|
5582
|
+
...emitLeafCapture(ctx, valV, pos, inner.endVar)
|
|
5583
|
+
],
|
|
5584
|
+
valueVar: valV,
|
|
5585
|
+
endVar: inner.endVar
|
|
5586
|
+
};
|
|
5587
|
+
}
|
|
5307
5588
|
function emitNode(def, ctx, pos) {
|
|
5308
5589
|
if (def.type === void 0) {
|
|
5309
5590
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -5319,6 +5600,8 @@ function emitNode(def, ctx, pos) {
|
|
|
5319
5600
|
const i = ind(ctx);
|
|
5320
5601
|
const capturesTrivia = mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
|
|
5321
5602
|
const clonesState = !structural && buildReadsState(def);
|
|
5603
|
+
const capturesChildren = !structural && (mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
|
|
5604
|
+
const capturesRaw = !structural && (mkType !== null || buildReadsRaw(def));
|
|
5322
5605
|
const hasFields = parserHasOwnFields(def.parser);
|
|
5323
5606
|
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
5324
5607
|
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
@@ -5337,9 +5620,13 @@ function emitNode(def, ctx, pos) {
|
|
|
5337
5620
|
const profHoist = `${i}const ${pmV} = _ctx._pmProfile, ${recV} = ${pmV}?.phase === 'recognizer', ${capV} = ${pmV}?.phase === 'capture'`;
|
|
5338
5621
|
const profileRecognizer = recV;
|
|
5339
5622
|
const profileCapture = capV;
|
|
5623
|
+
const directCstV = !structural && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
5624
|
+
const directCstGate = directCstV === null ? "false" : `${profileCapture} || _ctx.build?._parsemanCstOutput === true`;
|
|
5340
5625
|
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
5341
5626
|
const allocStmt = structural ? `${i}const ${capTLv} = !(${profileRecognizer}) && (${profileCapture} || ${structuralCapturesTrivia ? "true" : hostTriviaGate}), ${capSTv} = !(${profileRecognizer} || ${profileCapture}) && (_ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6)))${capFv ? `, ${capFv} = !(${profileRecognizer}) && (${profileCapture} || (_ctx.build !== undefined && _hostReads(_ctx.build, 2)))` : ""}
|
|
5342
|
-
${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${
|
|
5627
|
+
${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5628
|
+
` : ""}${i}const ${capTLv} = !(${profileRecognizer}), ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}, ${tlV} = ${profileRecognizer} ? undefined : []` : `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5629
|
+
` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
|
|
5343
5630
|
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
5344
5631
|
const fieldsOn = structural ? capFv ?? "false" : `${profileRecognizer} ? false : ${capturesFields ? "true" : "false"}`;
|
|
5345
5632
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
@@ -5456,14 +5743,23 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
5456
5743
|
const savedIndent = ctx.indent;
|
|
5457
5744
|
const savedFailLabel = ctx.failLabel;
|
|
5458
5745
|
const savedRecord = ctx.recordFail;
|
|
5746
|
+
const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
|
|
5747
|
+
const savedActiveRule = ctx.activeCoverageRuleId;
|
|
5748
|
+
const savedSuppressFailure = ctx.suppressCoverageFailure;
|
|
5459
5749
|
ctx.indent = 1;
|
|
5460
5750
|
ctx.failLabel = "_pfail";
|
|
5461
5751
|
ctx.recordFail = true;
|
|
5752
|
+
if (failureRuleId !== void 0) {
|
|
5753
|
+
ctx.activeCoverageRuleId = void 0;
|
|
5754
|
+
ctx.suppressCoverageFailure = true;
|
|
5755
|
+
}
|
|
5462
5756
|
const r = emit(resolved, ctx, "_pos");
|
|
5463
5757
|
ctx.indent = savedIndent;
|
|
5464
5758
|
ctx.failLabel = savedFailLabel;
|
|
5465
5759
|
ctx.recordFail = savedRecord;
|
|
5466
|
-
|
|
5760
|
+
ctx.activeCoverageRuleId = savedActiveRule;
|
|
5761
|
+
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
5762
|
+
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
5467
5763
|
}
|
|
5468
5764
|
const fnName = ctx.namedParsers.get(p);
|
|
5469
5765
|
return emitNamedFnCall(ctx, fnName, pos);
|
|
@@ -5514,6 +5810,30 @@ function emitExpect(def, ctx, pos) {
|
|
|
5514
5810
|
return { stmts, valueVar: valVar, endVar };
|
|
5515
5811
|
}
|
|
5516
5812
|
function emit(p, ctx, pos) {
|
|
5813
|
+
const dispatch = (emissionPos = pos) => {
|
|
5814
|
+
const savedRule = ctx.activeCoverageRuleId;
|
|
5815
|
+
const rule = ctx.coverage?.plan.rules.get(p);
|
|
5816
|
+
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
5817
|
+
const result = emitDispatch(p, ctx, emissionPos);
|
|
5818
|
+
ctx.activeCoverageRuleId = savedRule;
|
|
5819
|
+
return result;
|
|
5820
|
+
};
|
|
5821
|
+
const instrument = (r) => {
|
|
5822
|
+
const ruleId = ctx.coverage?.plan.rules.get(p);
|
|
5823
|
+
const labelIds = ctx.coverage?.plan.labels.get(p);
|
|
5824
|
+
if (!ruleId && !labelIds) return r;
|
|
5825
|
+
return {
|
|
5826
|
+
...r,
|
|
5827
|
+
stmts: [
|
|
5828
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`] : [],
|
|
5829
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: ${pos} })`] : [],
|
|
5830
|
+
...r.stmts,
|
|
5831
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`] : [],
|
|
5832
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`]) ?? [],
|
|
5833
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`]) ?? []
|
|
5834
|
+
]
|
|
5835
|
+
};
|
|
5836
|
+
};
|
|
5517
5837
|
const usage = ctx.lazyUsage;
|
|
5518
5838
|
if (usage && !ctx.noHoist && !ctx.capAsTrivia && !ctx.ruleNames?.has(p) && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && // Only hoist subtrees big enough that de-duplicating them beats the call
|
|
5519
5839
|
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
@@ -5530,14 +5850,14 @@ function emit(p, ctx, pos) {
|
|
|
5530
5850
|
ctx.indent = 1;
|
|
5531
5851
|
ctx.failLabel = "_pfail";
|
|
5532
5852
|
ctx.recordFail = true;
|
|
5533
|
-
const r =
|
|
5853
|
+
const r = dispatch("_pos");
|
|
5534
5854
|
ctx.indent = savedIndent;
|
|
5535
5855
|
ctx.failLabel = savedFailLabel;
|
|
5536
5856
|
ctx.recordFail = savedRecord;
|
|
5537
5857
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
5538
|
-
return emitNamedFnCall(ctx, fnName, pos);
|
|
5858
|
+
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
5539
5859
|
}
|
|
5540
|
-
return
|
|
5860
|
+
return instrument(dispatch());
|
|
5541
5861
|
}
|
|
5542
5862
|
function emitDispatch(p, ctx, pos) {
|
|
5543
5863
|
const def = p._def;
|
|
@@ -5551,7 +5871,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5551
5871
|
case "sequence":
|
|
5552
5872
|
return emitSeq(def, ctx, pos);
|
|
5553
5873
|
case "choice":
|
|
5554
|
-
return emitChoice(def, ctx, pos);
|
|
5874
|
+
return emitChoice(p, def, ctx, pos);
|
|
5875
|
+
case "attempt":
|
|
5876
|
+
return emitAttempt(p, def, ctx, pos);
|
|
5555
5877
|
case "many":
|
|
5556
5878
|
case "oneOrMore":
|
|
5557
5879
|
return emitMany(def, ctx, pos);
|
|
@@ -5620,6 +5942,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5620
5942
|
return emit(def.parser, ctx, pos);
|
|
5621
5943
|
case "token":
|
|
5622
5944
|
return emitToken(def, ctx, pos);
|
|
5945
|
+
case "leaf":
|
|
5946
|
+
return emitLeaf(def, ctx, pos);
|
|
5623
5947
|
case "label": {
|
|
5624
5948
|
const inner = emitFallible(def.parser, ctx, pos);
|
|
5625
5949
|
return {
|
|
@@ -5751,6 +6075,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5751
6075
|
case "grammar":
|
|
5752
6076
|
case "trivia":
|
|
5753
6077
|
case "token":
|
|
6078
|
+
case "leaf":
|
|
5754
6079
|
case "label":
|
|
5755
6080
|
case "field":
|
|
5756
6081
|
case "optional":
|
|
@@ -5778,16 +6103,32 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5778
6103
|
return false;
|
|
5779
6104
|
}
|
|
5780
6105
|
}
|
|
6106
|
+
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
6107
|
+
if (seen.has(p)) return false;
|
|
6108
|
+
seen.add(p);
|
|
6109
|
+
const d = p._def;
|
|
6110
|
+
if (d.tag === "node" && d.build !== void 0) return true;
|
|
6111
|
+
if (d.tag === "lazy") {
|
|
6112
|
+
try {
|
|
6113
|
+
return hasDirectBuildDef(d.thunk(), seen);
|
|
6114
|
+
} catch {
|
|
6115
|
+
return false;
|
|
6116
|
+
}
|
|
6117
|
+
}
|
|
6118
|
+
return childrenOf(d).some((child) => hasDirectBuildDef(child, seen));
|
|
6119
|
+
}
|
|
5781
6120
|
function childrenOf(def) {
|
|
5782
6121
|
switch (def.tag) {
|
|
5783
6122
|
case "sequence":
|
|
5784
6123
|
case "choice":
|
|
5785
6124
|
return def.parsers;
|
|
5786
6125
|
case "many":
|
|
6126
|
+
case "attempt":
|
|
5787
6127
|
case "optional":
|
|
5788
6128
|
case "transform":
|
|
5789
6129
|
case "trivia":
|
|
5790
6130
|
case "token":
|
|
6131
|
+
case "leaf":
|
|
5791
6132
|
case "label":
|
|
5792
6133
|
case "field":
|
|
5793
6134
|
case "grammar":
|
|
@@ -5962,10 +6303,25 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5962
6303
|
namedFnDecls: [],
|
|
5963
6304
|
capturing: hasNodeDef(combinator),
|
|
5964
6305
|
recovery: opts?.recovery ?? false,
|
|
6306
|
+
...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
|
|
5965
6307
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5966
6308
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5967
6309
|
};
|
|
5968
6310
|
const r = emit(combinator, ctx, "_pos");
|
|
6311
|
+
const coverageRootRuleId = ctx.coverage?.plan.rules.get(combinator);
|
|
6312
|
+
const resultBody = coverageRootRuleId === void 0 ? [
|
|
6313
|
+
` let pos = _pos`,
|
|
6314
|
+
...r.stmts,
|
|
6315
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6316
|
+
] : [
|
|
6317
|
+
` const _coverageResult = (() => {`,
|
|
6318
|
+
` let pos = _pos`,
|
|
6319
|
+
...r.stmts,
|
|
6320
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6321
|
+
` })()`,
|
|
6322
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6323
|
+
` return _coverageResult`
|
|
6324
|
+
];
|
|
5969
6325
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
5970
6326
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
5971
6327
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
@@ -5978,9 +6334,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5978
6334
|
...namedPrelude,
|
|
5979
6335
|
ctx.namedFnDecls.join("\n\n"),
|
|
5980
6336
|
`function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
|
|
5981
|
-
|
|
5982
|
-
...r.stmts,
|
|
5983
|
-
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6337
|
+
...resultBody,
|
|
5984
6338
|
`}`
|
|
5985
6339
|
].join("\n");
|
|
5986
6340
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
@@ -5990,9 +6344,15 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5990
6344
|
...ctx.expectedDecls,
|
|
5991
6345
|
...namedPrelude,
|
|
5992
6346
|
...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
|
|
5993
|
-
`let pos = _pos`,
|
|
5994
|
-
|
|
5995
|
-
|
|
6347
|
+
...coverageRootRuleId === void 0 ? [`let pos = _pos`, ...r.stmts, `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`] : [
|
|
6348
|
+
`const _coverageResult = (() => {`,
|
|
6349
|
+
` let pos = _pos`,
|
|
6350
|
+
...r.stmts,
|
|
6351
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6352
|
+
`})()`,
|
|
6353
|
+
`if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6354
|
+
`return _coverageResult`
|
|
6355
|
+
]
|
|
5996
6356
|
].join("\n"));
|
|
5997
6357
|
const defaultCtx = {
|
|
5998
6358
|
trackLines: false,
|
|
@@ -6004,10 +6364,11 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
6004
6364
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
6005
6365
|
const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
|
|
6006
6366
|
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
6007
|
-
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources) : null;
|
|
6367
|
+
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
|
|
6008
6368
|
return {
|
|
6009
6369
|
source,
|
|
6010
6370
|
inlineExpression,
|
|
6371
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
|
|
6011
6372
|
parse(input, pos = 0) {
|
|
6012
6373
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
|
|
6013
6374
|
},
|
|
@@ -6041,6 +6402,7 @@ function publicRuleWrapperSource(rule, fnSource) {
|
|
|
6041
6402
|
}
|
|
6042
6403
|
function compileRuleMap(ruleMap, opts) {
|
|
6043
6404
|
for (const [, rule] of ruleMap) markUnusedValues(rule);
|
|
6405
|
+
const coverageWinners = opts?.coverage ? Object.fromEntries(ruleMap.filter(([, rule]) => rule._def.tag !== "lazy")) : void 0;
|
|
6044
6406
|
const grammarTrivia = opts?.trivia;
|
|
6045
6407
|
const ctx = {
|
|
6046
6408
|
vars: 0,
|
|
@@ -6061,6 +6423,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
6061
6423
|
namedFnDecls: [],
|
|
6062
6424
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
6063
6425
|
recovery: opts?.recovery ?? false,
|
|
6426
|
+
...opts?.coverage ? { coverage: { plan: buildGrammarPlan(ruleMap.map(([, rule]) => rule), coverageWinners) } } : {},
|
|
6064
6427
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
6065
6428
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
6066
6429
|
};
|
|
@@ -6103,15 +6466,34 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
6103
6466
|
return i > 0 ? ["", ...lines] : lines;
|
|
6104
6467
|
})
|
|
6105
6468
|
].filter(Boolean);
|
|
6106
|
-
const
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6469
|
+
const entryRuleId = (rule) => {
|
|
6470
|
+
const direct = ctx.coverage?.plan.rules.get(rule);
|
|
6471
|
+
if (direct !== void 0 || rule._def.tag !== "lazy") return direct;
|
|
6472
|
+
try {
|
|
6473
|
+
return ctx.coverage?.plan.rules.get(rule._def.thunk());
|
|
6474
|
+
} catch {
|
|
6475
|
+
return void 0;
|
|
6476
|
+
}
|
|
6477
|
+
};
|
|
6478
|
+
const entryFnText = (r, rule) => {
|
|
6479
|
+
const ruleId = entryRuleId(rule);
|
|
6480
|
+
const body = ruleId === void 0 ? [
|
|
6481
|
+
` let pos = _pos`,
|
|
6482
|
+
...r.stmts,
|
|
6483
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6484
|
+
] : [
|
|
6485
|
+
` const _coverageResult = (() => {`,
|
|
6486
|
+
` let pos = _pos`,
|
|
6487
|
+
...r.stmts,
|
|
6488
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6489
|
+
` })()`,
|
|
6490
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6491
|
+
` return _coverageResult`
|
|
6492
|
+
];
|
|
6493
|
+
return [`function(input, _pos, _ctx) {`, ...body, `}`].join("\n");
|
|
6494
|
+
};
|
|
6113
6495
|
const objBody = perEntry.map(({ key, rule, r }) => {
|
|
6114
|
-
const src = publicRuleWrapperSource(rule, entryFnText(r));
|
|
6496
|
+
const src = publicRuleWrapperSource(rule, entryFnText(r, rule));
|
|
6115
6497
|
return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
|
|
6116
6498
|
}).join(",\n");
|
|
6117
6499
|
const replacement = [
|
|
@@ -6122,7 +6504,11 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
6122
6504
|
` }`,
|
|
6123
6505
|
`})()`
|
|
6124
6506
|
].join("\n");
|
|
6125
|
-
return {
|
|
6507
|
+
return {
|
|
6508
|
+
keys: perEntry.map((e) => e.key),
|
|
6509
|
+
replacement,
|
|
6510
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
6511
|
+
};
|
|
6126
6512
|
}
|
|
6127
6513
|
function compileLinkable(ruleMapArg, ns, opts) {
|
|
6128
6514
|
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
@@ -6155,8 +6541,13 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6155
6541
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
6156
6542
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
6157
6543
|
namedFnDecls: [],
|
|
6158
|
-
|
|
6544
|
+
// A recognition-only fragment normally has no node collector of its own.
|
|
6545
|
+
// Leaf composition can re-lower it beneath a local semantic node, though;
|
|
6546
|
+
// in that case its terminals must feed the caller's collector rather than
|
|
6547
|
+
// merely returning their scalar parse values.
|
|
6548
|
+
capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
6159
6549
|
recovery: opts?.recovery ?? false,
|
|
6550
|
+
...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
|
|
6160
6551
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
6161
6552
|
ns,
|
|
6162
6553
|
deferFirstSetRefs: true,
|
|
@@ -6230,7 +6621,14 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6230
6621
|
ctx.indent = savedIndent;
|
|
6231
6622
|
ctx.failLabel = savedFail;
|
|
6232
6623
|
ctx.recordFail = savedRec;
|
|
6233
|
-
|
|
6624
|
+
const ruleId = ctx.coverage?.plan.rules.get(rule);
|
|
6625
|
+
const stmts = ruleId === void 0 ? body.stmts : [
|
|
6626
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
|
|
6627
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: _pos })`,
|
|
6628
|
+
...body.stmts,
|
|
6629
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: _pos, end: ${body.endVar} })`
|
|
6630
|
+
];
|
|
6631
|
+
pushNamedFnDecl(ctx, fn, stmts, body.valueVar, body.endVar);
|
|
6234
6632
|
}
|
|
6235
6633
|
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
6236
6634
|
}
|
|
@@ -6287,15 +6685,46 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6287
6685
|
deps: ruleDependencies(ruleMap),
|
|
6288
6686
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
6289
6687
|
needsHostReads: !!ctx.needsHostReads,
|
|
6688
|
+
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
6689
|
+
isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule)),
|
|
6290
6690
|
mfFns: mfSrcs ? [] : ctx.mapFns,
|
|
6291
6691
|
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
6292
6692
|
};
|
|
6293
6693
|
}
|
|
6294
|
-
function
|
|
6295
|
-
const
|
|
6694
|
+
function hasSemanticReduction(roots) {
|
|
6695
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6696
|
+
const visit = (parser2) => {
|
|
6697
|
+
if (seen.has(parser2)) return false;
|
|
6698
|
+
seen.add(parser2);
|
|
6699
|
+
const def = parser2._def;
|
|
6700
|
+
if (def.tag === "transform" && !def.recognitionOnly) return true;
|
|
6701
|
+
if (def.tag === "choice" && def.gates.some(Boolean)) return true;
|
|
6702
|
+
if (def.tag === "guard" || def.tag === "withCtx") return true;
|
|
6703
|
+
if (def.tag === "node" && def.build !== void 0) return true;
|
|
6704
|
+
if (def.tag === "lazy") {
|
|
6705
|
+
try {
|
|
6706
|
+
return visit(def.thunk());
|
|
6707
|
+
} catch {
|
|
6708
|
+
return true;
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6711
|
+
return childrenOf(def).some(visit);
|
|
6712
|
+
};
|
|
6713
|
+
return roots.some(visit);
|
|
6714
|
+
}
|
|
6715
|
+
function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootRuleId) {
|
|
6716
|
+
const bodyLines = coverageRootRuleId === void 0 ? [
|
|
6296
6717
|
` let pos = _pos`,
|
|
6297
6718
|
...r.stmts,
|
|
6298
6719
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6720
|
+
] : [
|
|
6721
|
+
` const _coverageResult = (() => {`,
|
|
6722
|
+
` let pos = _pos`,
|
|
6723
|
+
...r.stmts,
|
|
6724
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6725
|
+
` })()`,
|
|
6726
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6727
|
+
` return _coverageResult`
|
|
6299
6728
|
];
|
|
6300
6729
|
const innerFn = [
|
|
6301
6730
|
`function(input, _pos, _ctx) {`,
|
|
@@ -6350,8 +6779,8 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
6350
6779
|
};
|
|
6351
6780
|
const emit2 = (end) => {
|
|
6352
6781
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
6353
|
-
const
|
|
6354
|
-
pushCstLeaf(ctx,
|
|
6782
|
+
const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
6783
|
+
pushCstLeaf(ctx, leaf2);
|
|
6355
6784
|
}
|
|
6356
6785
|
};
|
|
6357
6786
|
while (cur < input.length) {
|
|
@@ -6405,6 +6834,7 @@ function balanced(open, close, options = {}) {
|
|
|
6405
6834
|
);
|
|
6406
6835
|
if (combi._def.tag === "transform") {
|
|
6407
6836
|
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
6837
|
+
combi._def.recognitionOnly = true;
|
|
6408
6838
|
}
|
|
6409
6839
|
self.define(combi);
|
|
6410
6840
|
return combi;
|
|
@@ -6450,9 +6880,11 @@ function childrenOf2(def) {
|
|
|
6450
6880
|
case "many":
|
|
6451
6881
|
case "oneOrMore":
|
|
6452
6882
|
case "optional":
|
|
6883
|
+
case "attempt":
|
|
6453
6884
|
case "transform":
|
|
6454
6885
|
case "trivia":
|
|
6455
6886
|
case "token":
|
|
6887
|
+
case "leaf":
|
|
6456
6888
|
case "label":
|
|
6457
6889
|
case "field":
|
|
6458
6890
|
case "not":
|
|
@@ -6501,7 +6933,7 @@ function serializeRuleMap(ruleMap) {
|
|
|
6501
6933
|
}
|
|
6502
6934
|
}
|
|
6503
6935
|
function evalRuleMapIR(ir) {
|
|
6504
|
-
const _tf = (child, src) => {
|
|
6936
|
+
const _tf = (child, src, recognitionOnly = false) => {
|
|
6505
6937
|
let fn2;
|
|
6506
6938
|
try {
|
|
6507
6939
|
fn2 = (0, eval)(`(${src})`);
|
|
@@ -6512,8 +6944,22 @@ function evalRuleMapIR(ir) {
|
|
|
6512
6944
|
}
|
|
6513
6945
|
const t = transform(child, fn2);
|
|
6514
6946
|
t._def.fnSrc = src;
|
|
6947
|
+
if (recognitionOnly) t._def.recognitionOnly = true;
|
|
6515
6948
|
return t;
|
|
6516
6949
|
};
|
|
6950
|
+
const _lf = (child, src) => {
|
|
6951
|
+
let fn2;
|
|
6952
|
+
try {
|
|
6953
|
+
fn2 = (0, eval)(`(${src})`);
|
|
6954
|
+
} catch {
|
|
6955
|
+
fn2 = () => {
|
|
6956
|
+
throw new Error("IR leaf fn not materialized");
|
|
6957
|
+
};
|
|
6958
|
+
}
|
|
6959
|
+
const l = leaf(child, fn2);
|
|
6960
|
+
l._def.fnSrc = src;
|
|
6961
|
+
return l;
|
|
6962
|
+
};
|
|
6517
6963
|
const _nd = (type, child, src, opts, staticError) => {
|
|
6518
6964
|
if (staticError !== void 0 && staticError.length > 0) {
|
|
6519
6965
|
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
@@ -6572,6 +7018,7 @@ function evalRuleMapIR(ir) {
|
|
|
6572
7018
|
"keywords",
|
|
6573
7019
|
"sequence",
|
|
6574
7020
|
"choice",
|
|
7021
|
+
"attempt",
|
|
6575
7022
|
"many",
|
|
6576
7023
|
"oneOrMore",
|
|
6577
7024
|
"optional",
|
|
@@ -6581,6 +7028,7 @@ function evalRuleMapIR(ir) {
|
|
|
6581
7028
|
"parser",
|
|
6582
7029
|
"scanTo",
|
|
6583
7030
|
"token",
|
|
7031
|
+
"leaf",
|
|
6584
7032
|
"transform",
|
|
6585
7033
|
"skip",
|
|
6586
7034
|
"trivia",
|
|
@@ -6588,6 +7036,7 @@ function evalRuleMapIR(ir) {
|
|
|
6588
7036
|
"field",
|
|
6589
7037
|
"expect",
|
|
6590
7038
|
"_tf",
|
|
7039
|
+
"_lf",
|
|
6591
7040
|
"_nd",
|
|
6592
7041
|
"_gch",
|
|
6593
7042
|
"_wc",
|
|
@@ -6601,6 +7050,7 @@ function evalRuleMapIR(ir) {
|
|
|
6601
7050
|
keywords,
|
|
6602
7051
|
sequence,
|
|
6603
7052
|
choice,
|
|
7053
|
+
attempt,
|
|
6604
7054
|
many,
|
|
6605
7055
|
oneOrMore,
|
|
6606
7056
|
optional,
|
|
@@ -6610,6 +7060,7 @@ function evalRuleMapIR(ir) {
|
|
|
6610
7060
|
parser,
|
|
6611
7061
|
scanTo,
|
|
6612
7062
|
token,
|
|
7063
|
+
leaf,
|
|
6613
7064
|
transform,
|
|
6614
7065
|
skip,
|
|
6615
7066
|
trivia,
|
|
@@ -6617,6 +7068,7 @@ function evalRuleMapIR(ir) {
|
|
|
6617
7068
|
field,
|
|
6618
7069
|
expect,
|
|
6619
7070
|
_tf,
|
|
7071
|
+
_lf,
|
|
6620
7072
|
_nd,
|
|
6621
7073
|
_gch,
|
|
6622
7074
|
_wc
|
|
@@ -6748,6 +7200,8 @@ ${body}
|
|
|
6748
7200
|
return `oneOrMore(${kid(def.parser)})`;
|
|
6749
7201
|
case "optional":
|
|
6750
7202
|
return `optional(${kid(def.parser)})`;
|
|
7203
|
+
case "attempt":
|
|
7204
|
+
return `attempt(${kid(def.parser)})`;
|
|
6751
7205
|
case "sepBy":
|
|
6752
7206
|
return `sepBy(${kid(def.parser)}, ${kid(def.separator)})`;
|
|
6753
7207
|
case "not":
|
|
@@ -6756,6 +7210,10 @@ ${body}
|
|
|
6756
7210
|
return `trivia(${kid(def.parser)})`;
|
|
6757
7211
|
case "token":
|
|
6758
7212
|
return `token(${kid(def.parser)})`;
|
|
7213
|
+
case "leaf": {
|
|
7214
|
+
if (def.fnSrc === void 0) throw new Unserializable("leaf without fnSrc");
|
|
7215
|
+
return `_lf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7216
|
+
}
|
|
6759
7217
|
case "label":
|
|
6760
7218
|
return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
|
|
6761
7219
|
case "field":
|
|
@@ -6768,7 +7226,7 @@ ${body}
|
|
|
6768
7226
|
return `scanTo(${kid(def.sentinel)}, { skip: [${def.skip.map(kid).join(", ")}], orEOF: ${def.orEOF} })`;
|
|
6769
7227
|
case "transform": {
|
|
6770
7228
|
if (def.fnSrc === void 0) throw new Unserializable("transform without fnSrc");
|
|
6771
|
-
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7229
|
+
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)}${def.recognitionOnly ? ", true" : ""})`;
|
|
6772
7230
|
}
|
|
6773
7231
|
case "node": {
|
|
6774
7232
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
@@ -6814,15 +7272,15 @@ function normalizeCstCollapse(collapse) {
|
|
|
6814
7272
|
}
|
|
6815
7273
|
return typeof collapse === "function" ? collapse : void 0;
|
|
6816
7274
|
}
|
|
6817
|
-
function buildCstNode(type,
|
|
6818
|
-
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...
|
|
7275
|
+
function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
|
|
7276
|
+
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
|
|
6819
7277
|
}
|
|
6820
|
-
function cstBuildHost(typeOrOptions,
|
|
7278
|
+
function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
|
|
6821
7279
|
if (typeof typeOrOptions === "string") {
|
|
6822
|
-
return buildCstNode(typeOrOptions,
|
|
7280
|
+
return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
6823
7281
|
}
|
|
6824
7282
|
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
6825
|
-
const host = (type,
|
|
7283
|
+
const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3, fields, span2, rawChildren2, triviaLog2, state2);
|
|
6826
7284
|
host._parsemanCstOutput = true;
|
|
6827
7285
|
if (collapse) host._parsemanCstCollapse = collapse;
|
|
6828
7286
|
return host;
|
|
@@ -6905,9 +7363,12 @@ ${body}
|
|
|
6905
7363
|
function isIRPiece(p) {
|
|
6906
7364
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
6907
7365
|
}
|
|
6908
|
-
function materializePiece(p, trivia2) {
|
|
7366
|
+
function materializePiece(p, trivia2, captureTerminals = false) {
|
|
6909
7367
|
if (!isIRPiece(p)) return p;
|
|
6910
|
-
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns,
|
|
7368
|
+
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
|
|
7369
|
+
...trivia2 ? { trivia: trivia2 } : {},
|
|
7370
|
+
...captureTerminals ? { captureTerminals: true } : {}
|
|
7371
|
+
});
|
|
6911
7372
|
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
6912
7373
|
return pieces;
|
|
6913
7374
|
}
|
|
@@ -7136,6 +7597,7 @@ var SUPPORTED = {
|
|
|
7136
7597
|
word: (...a) => word(a[0], a[1]),
|
|
7137
7598
|
sequence: (...a) => sequence(...a),
|
|
7138
7599
|
choice: (...a) => choice(...a),
|
|
7600
|
+
attempt: (...a) => attempt(a[0]),
|
|
7139
7601
|
many: (...a) => many(a[0]),
|
|
7140
7602
|
oneOrMore: (...a) => oneOrMore(a[0]),
|
|
7141
7603
|
optional: (...a) => optional(a[0]),
|
|
@@ -7146,6 +7608,7 @@ var SUPPORTED = {
|
|
|
7146
7608
|
field: (...a) => field(a[0], a[1]),
|
|
7147
7609
|
noTrivia: (...a) => noTrivia(a[0]),
|
|
7148
7610
|
token: (...a) => token(a[0]),
|
|
7611
|
+
leaf: (...a) => leaf(a[0], a[1]),
|
|
7149
7612
|
expect: (...a) => expect(a[0], a[1])
|
|
7150
7613
|
};
|
|
7151
7614
|
function isScopeEntry(v2) {
|
|
@@ -7245,7 +7708,7 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
7245
7708
|
if (!parserArg || !fnArg || parserArg.type === "SpreadElement" || fnArg.type === "SpreadElement") return null;
|
|
7246
7709
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
7247
7710
|
if (!isCombinator(inner)) return null;
|
|
7248
|
-
const fnSrc =
|
|
7711
|
+
const fnSrc = stripTsFromSource(fnArg, code);
|
|
7249
7712
|
mfs.push(fnSrc);
|
|
7250
7713
|
try {
|
|
7251
7714
|
const combi = transform(inner, (v2) => v2);
|
|
@@ -7255,6 +7718,21 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
7255
7718
|
return null;
|
|
7256
7719
|
}
|
|
7257
7720
|
}
|
|
7721
|
+
if (callee.name === "leaf" && code !== void 0 && mfs !== void 0) {
|
|
7722
|
+
const [parserArg, fnArg] = node2.arguments;
|
|
7723
|
+
if (!parserArg || !fnArg || parserArg.type === "SpreadElement" || fnArg.type === "SpreadElement") return null;
|
|
7724
|
+
const inner = anyValue(parserArg, scope, code, mfs);
|
|
7725
|
+
if (!isCombinator(inner)) return null;
|
|
7726
|
+
const fnSrc = stripTsFromSource(fnArg, code);
|
|
7727
|
+
mfs.push(fnSrc);
|
|
7728
|
+
try {
|
|
7729
|
+
const combi = leaf(inner, (v2) => v2);
|
|
7730
|
+
if (combi._def.tag === "leaf") combi._def.fnSrc = fnSrc;
|
|
7731
|
+
return combi;
|
|
7732
|
+
} catch {
|
|
7733
|
+
return null;
|
|
7734
|
+
}
|
|
7735
|
+
}
|
|
7258
7736
|
if (callee.name === "node" && code !== void 0) {
|
|
7259
7737
|
const [firstArg, secondArg, thirdArg, fourthArg] = node2.arguments;
|
|
7260
7738
|
if (!firstArg || firstArg.type === "SpreadElement") return null;
|
|
@@ -7707,6 +8185,63 @@ function getCompiledResolver() {
|
|
|
7707
8185
|
mainFields: ["module", "main"]
|
|
7708
8186
|
});
|
|
7709
8187
|
}
|
|
8188
|
+
var PRIVATE_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts"]);
|
|
8189
|
+
function nearestPackageRoot(file) {
|
|
8190
|
+
let dir = path.dirname(file);
|
|
8191
|
+
for (; ; ) {
|
|
8192
|
+
try {
|
|
8193
|
+
if (fs.statSync(path.join(dir, "package.json")).isFile()) return fs.realpathSync(dir);
|
|
8194
|
+
} catch {
|
|
8195
|
+
}
|
|
8196
|
+
const parent = path.dirname(dir);
|
|
8197
|
+
if (parent === dir) return null;
|
|
8198
|
+
dir = parent;
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
function isWithinPackageRoot(file, root) {
|
|
8202
|
+
const relative2 = path.relative(root, file);
|
|
8203
|
+
return relative2 !== ".." && !relative2.startsWith(`..${path.sep}`) && !path.isAbsolute(relative2);
|
|
8204
|
+
}
|
|
8205
|
+
function resolvePrivateSourceModule(from, specifier) {
|
|
8206
|
+
if (!specifier.startsWith(".") && !path.isAbsolute(specifier)) return null;
|
|
8207
|
+
const packageRoot = nearestPackageRoot(from);
|
|
8208
|
+
if (!packageRoot) return null;
|
|
8209
|
+
const base = path.resolve(path.dirname(from), specifier);
|
|
8210
|
+
const ext = path.extname(base);
|
|
8211
|
+
const candidates = [
|
|
8212
|
+
base,
|
|
8213
|
+
...ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base.slice(0, -ext.length)}${next}`) : [],
|
|
8214
|
+
...!ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base}${next}`) : [],
|
|
8215
|
+
...!ext ? ["index.ts", "index.tsx", "index.mts", "index.cts"].map((next) => path.join(base, next)) : []
|
|
8216
|
+
];
|
|
8217
|
+
for (const candidate of candidates) {
|
|
8218
|
+
try {
|
|
8219
|
+
if (!fs.statSync(candidate).isFile()) continue;
|
|
8220
|
+
const real = fs.realpathSync(candidate);
|
|
8221
|
+
if (isWithinPackageRoot(real, packageRoot)) return real;
|
|
8222
|
+
} catch {
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
8225
|
+
return null;
|
|
8226
|
+
}
|
|
8227
|
+
function resolveGrammarModule(from, specifier) {
|
|
8228
|
+
if (PRIVATE_SOURCE_EXTENSIONS.has(path.extname(specifier))) {
|
|
8229
|
+
const file2 = resolvePrivateSourceModule(from, specifier);
|
|
8230
|
+
return file2 ? { file: file2, source: true } : null;
|
|
8231
|
+
}
|
|
8232
|
+
try {
|
|
8233
|
+
const file2 = getCompiledResolver().resolveFileSync(from, specifier).path;
|
|
8234
|
+
if (file2) return { file: file2, source: false };
|
|
8235
|
+
} catch {
|
|
8236
|
+
}
|
|
8237
|
+
const file = resolvePrivateSourceModule(from, specifier);
|
|
8238
|
+
return file ? { file, source: true } : null;
|
|
8239
|
+
}
|
|
8240
|
+
var _sourceLowering = /* @__PURE__ */ new Set();
|
|
8241
|
+
var _sourceLoweringCache = /* @__PURE__ */ new Map();
|
|
8242
|
+
function sourceLoweringCacheKey(file, moduleAliases, warnUnloweredRegex, recovery) {
|
|
8243
|
+
return `${file}\0${[...moduleAliases].sort().join("\0")}\0${warnUnloweredRegex ? "warn" : ""}\0${recovery ? "recovery" : ""}`;
|
|
8244
|
+
}
|
|
7710
8245
|
var _moduleParseCache = /* @__PURE__ */ new Map();
|
|
7711
8246
|
function parseModuleCached(filePath) {
|
|
7712
8247
|
let mtimeMs;
|
|
@@ -7740,7 +8275,7 @@ var plugin_default = (0, import_unplugin.createUnplugin)((opts = {}) => ({
|
|
|
7740
8275
|
if (!code.includes("parseman")) return null;
|
|
7741
8276
|
if (!code.includes("macro")) return null;
|
|
7742
8277
|
const moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE, ...opts.moduleAliases ?? []]);
|
|
7743
|
-
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true);
|
|
8278
|
+
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true, opts.grammarCoverage === true);
|
|
7744
8279
|
if (result?.warnings.length) {
|
|
7745
8280
|
for (const w of result.warnings) {
|
|
7746
8281
|
if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
|
|
@@ -7844,7 +8379,34 @@ function extractImportBindings(body) {
|
|
|
7844
8379
|
}
|
|
7845
8380
|
return out;
|
|
7846
8381
|
}
|
|
7847
|
-
function
|
|
8382
|
+
function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recovery) {
|
|
8383
|
+
if (_sourceLowering.has(file)) return null;
|
|
8384
|
+
let mtimeMs;
|
|
8385
|
+
try {
|
|
8386
|
+
mtimeMs = fs.statSync(file).mtimeMs;
|
|
8387
|
+
} catch {
|
|
8388
|
+
return null;
|
|
8389
|
+
}
|
|
8390
|
+
const cacheKey = sourceLoweringCacheKey(file, moduleAliases, warnUnloweredRegex, recovery);
|
|
8391
|
+
const hit = _sourceLoweringCache.get(cacheKey);
|
|
8392
|
+
if (hit && hit.mtimeMs === mtimeMs) return hit.parsed;
|
|
8393
|
+
_sourceLowering.add(file);
|
|
8394
|
+
let parsedModule = null;
|
|
8395
|
+
try {
|
|
8396
|
+
const source = fs.readFileSync(file, "utf8");
|
|
8397
|
+
const transformed = transformMacro(source, file, moduleAliases, warnUnloweredRegex, recovery);
|
|
8398
|
+
if (!transformed || transformed.warnings.length > 0) return null;
|
|
8399
|
+
const parsed = (0, import_oxc_parser2.parseSync)(file, transformed.code);
|
|
8400
|
+
parsedModule = parsed.errors.length === 0 ? { body: parsed.program.body, src: transformed.code } : null;
|
|
8401
|
+
return parsedModule;
|
|
8402
|
+
} catch {
|
|
8403
|
+
return null;
|
|
8404
|
+
} finally {
|
|
8405
|
+
_sourceLoweringCache.set(cacheKey, { mtimeMs, parsed: parsedModule });
|
|
8406
|
+
_sourceLowering.delete(file);
|
|
8407
|
+
}
|
|
8408
|
+
}
|
|
8409
|
+
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false, grammarCoverage = false) {
|
|
7848
8410
|
let result;
|
|
7849
8411
|
try {
|
|
7850
8412
|
result = (0, import_oxc_parser2.parseSync)(id, code);
|
|
@@ -7896,7 +8458,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7896
8458
|
anyUnresolved = true;
|
|
7897
8459
|
warnings.push(`${id}:${lineOf(pos)} \u2014 ${msg} (running via the interpreter; add the plugin or simplify the declaration to compile it)`);
|
|
7898
8460
|
};
|
|
7899
|
-
const
|
|
8461
|
+
const evaluateRulesFactory = (init, label2) => {
|
|
7900
8462
|
const args = init.arguments;
|
|
7901
8463
|
const arg0 = args[0];
|
|
7902
8464
|
const arg1 = args[1];
|
|
@@ -7916,15 +8478,21 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7916
8478
|
(p) => p.key?.name === "trivia"
|
|
7917
8479
|
)?.value : void 0;
|
|
7918
8480
|
const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
|
|
7919
|
-
|
|
8481
|
+
return { ruleMap, ...gTrivia ? { trivia: gTrivia } : {} };
|
|
8482
|
+
};
|
|
8483
|
+
const compileRulesFactory = (init, label2) => {
|
|
8484
|
+
const evaluated = evaluateRulesFactory(init, label2);
|
|
8485
|
+
if (!evaluated) return null;
|
|
8486
|
+
const compiled = compileRuleMap([...evaluated.ruleMap], { ...evaluated.trivia ? { trivia: evaluated.trivia } : {}, recovery, coverage: grammarCoverage });
|
|
7920
8487
|
if (!compiled) {
|
|
7921
8488
|
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
7922
8489
|
return null;
|
|
7923
8490
|
}
|
|
7924
|
-
return { replacement: compiled.replacement, ruleMap, ...
|
|
8491
|
+
return { replacement: compiled.replacement, ruleMap: evaluated.ruleMap, ...compiled.coverageDefinitions ? { coverageDefinitions: compiled.coverageDefinitions } : {}, ...evaluated.trivia ? { trivia: evaluated.trivia } : {} };
|
|
7925
8492
|
};
|
|
7926
8493
|
const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
|
|
7927
8494
|
const isComposeCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "compose";
|
|
8495
|
+
const isComposeLeafCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "composeLeaf";
|
|
7928
8496
|
const isPickCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "pick";
|
|
7929
8497
|
const localRuleMaps = /* @__PURE__ */ new Map();
|
|
7930
8498
|
const localGrammarTrivia = /* @__PURE__ */ new Map();
|
|
@@ -7934,18 +8502,29 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7934
8502
|
const mapLit = (m, stripVals = false) => `new Map([${[...m].map(
|
|
7935
8503
|
([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(stripVals && typeof v2 === "string" ? stripIndent(v2) : v2)}]`
|
|
7936
8504
|
).join(", ")}])`;
|
|
7937
|
-
return `{ ns: ${JSON.stringify(p.ns)}, keys: ${JSON.stringify(p.keys)}, prelude: ${JSON.stringify(p.prelude.map(stripIndent))}, ruleFns: ${mapLit(p.ruleFns, true)}, wrappers: ${mapLit(p.wrappers, true)}, firstSets: ${mapLit(p.firstSets)}, deps: ${mapLit(p.deps)}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, mfFns: [], buildFns: [] }`;
|
|
8505
|
+
return `{ ns: ${JSON.stringify(p.ns)}, keys: ${JSON.stringify(p.keys)}, prelude: ${JSON.stringify(p.prelude.map(stripIndent))}, ruleFns: ${mapLit(p.ruleFns, true)}, wrappers: ${mapLit(p.wrappers, true)}, firstSets: ${mapLit(p.firstSets)}, deps: ${mapLit(p.deps)}, needsEmptyTl: ${p.needsEmptyTl}, needsHostReads: ${p.needsHostReads}, hasDirectBuilders: ${p.hasDirectBuilders === true}, isRecognitionOnly: ${p.isRecognitionOnly === true}, mfFns: [], buildFns: [] }`;
|
|
7938
8506
|
};
|
|
7939
8507
|
const isSpread = (it) => "__spreadLocal" in it;
|
|
7940
8508
|
const isIR = (it) => "ir" in it && !("ruleFns" in it);
|
|
7941
8509
|
const serializeItem = (it) => isSpread(it) ? `...(${it.__spreadLocal}[Symbol.for('parseman.composedPieces')] ?? [])` : isIR(it) ? `{ ns: ${JSON.stringify(it.ns)}, ir: ${JSON.stringify(it.ir)} }` : serializePieces(it);
|
|
7942
8510
|
const serializeList = (list) => `[${list.map(serializeItem).join(", ")}]`;
|
|
7943
8511
|
const withCarriedPieces = (grammarExpr, list) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.composedPieces'), { value: ${serializeList(list)}, enumerable: false })`;
|
|
8512
|
+
const withLeafMarker = (grammarExpr) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.leafComposed'), { value: true, enumerable: false })`;
|
|
8513
|
+
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 })`;
|
|
8514
|
+
const emittedCoverageDefinitions = (source) => {
|
|
8515
|
+
const ids = /* @__PURE__ */ new Set();
|
|
8516
|
+
for (const match of source.matchAll(/id:\s*"([^"]+)"/g)) ids.add(match[1]);
|
|
8517
|
+
return [...ids].sort().map((id2) => ({
|
|
8518
|
+
id: id2,
|
|
8519
|
+
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : "choice-arm"
|
|
8520
|
+
}));
|
|
8521
|
+
};
|
|
7944
8522
|
const localComposedCarried = /* @__PURE__ */ new Map();
|
|
7945
8523
|
const localComposedTrivia = /* @__PURE__ */ new Map();
|
|
7946
8524
|
const importedPiecesCache = /* @__PURE__ */ new Map();
|
|
7947
|
-
const resolveModulePieces = (
|
|
7948
|
-
const
|
|
8525
|
+
const resolveModulePieces = (module2, exportName, seen) => {
|
|
8526
|
+
const { file } = module2;
|
|
8527
|
+
const mod = module2.source ? lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recovery) : parseModuleCached(file);
|
|
7949
8528
|
if (!mod) return null;
|
|
7950
8529
|
const localFor = exportLocalName(mod.body, exportName);
|
|
7951
8530
|
const initNode = localFor ? topLevelInit(mod.body, localFor) : null;
|
|
@@ -7964,12 +8543,10 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7964
8543
|
const b = imports.get(local);
|
|
7965
8544
|
let subPieces = [];
|
|
7966
8545
|
if (b) {
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
} catch {
|
|
8546
|
+
const subModule = resolveGrammarModule(file, b.source);
|
|
8547
|
+
if (subModule && !seen.has(subModule.file)) {
|
|
8548
|
+
subPieces = resolveModulePieces(subModule, b.imported, new Set(seen).add(subModule.file)) ?? [];
|
|
7971
8549
|
}
|
|
7972
|
-
if (subFile && !seen.has(subFile)) subPieces = resolveModulePieces(subFile, b.imported, new Set(seen).add(subFile)) ?? [];
|
|
7973
8550
|
}
|
|
7974
8551
|
stubNames.push(local);
|
|
7975
8552
|
stubVals.push({ [/* @__PURE__ */ Symbol.for("parseman.composedPieces")]: subPieces });
|
|
@@ -7986,29 +8563,56 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7986
8563
|
let result2 = null;
|
|
7987
8564
|
const binding = importBindings.get(localName);
|
|
7988
8565
|
if (binding) {
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
file = getCompiledResolver().resolveFileSync(id, binding.source).path ?? null;
|
|
7992
|
-
} catch {
|
|
7993
|
-
}
|
|
7994
|
-
result2 = file ? resolveModulePieces(file, binding.imported, /* @__PURE__ */ new Set([file])) : null;
|
|
8566
|
+
const module2 = resolveGrammarModule(id, binding.source);
|
|
8567
|
+
result2 = module2 ? resolveModulePieces(module2, binding.imported, /* @__PURE__ */ new Set([module2.file])) : null;
|
|
7995
8568
|
}
|
|
7996
8569
|
importedPiecesCache.set(localName, result2);
|
|
7997
8570
|
return result2;
|
|
7998
8571
|
};
|
|
7999
|
-
const materializeCarried = (items, composing) => {
|
|
8572
|
+
const materializeCarried = (items, composing, captureTerminals = false) => {
|
|
8000
8573
|
const out = [];
|
|
8001
8574
|
for (const it of items) {
|
|
8002
8575
|
if (isSpread(it)) {
|
|
8003
|
-
for (const p of importedPieces(it.__spreadLocal) ?? []) out.push(materializePiece(p, composing));
|
|
8576
|
+
for (const p of importedPieces(it.__spreadLocal) ?? []) out.push(materializePiece(p, composing, captureTerminals));
|
|
8004
8577
|
} else if (isIR(it)) {
|
|
8005
|
-
out.push(materializePiece(it, composing));
|
|
8578
|
+
out.push(materializePiece(it, composing, captureTerminals));
|
|
8006
8579
|
} else {
|
|
8007
8580
|
out.push(it);
|
|
8008
8581
|
}
|
|
8009
8582
|
}
|
|
8010
8583
|
return out;
|
|
8011
8584
|
};
|
|
8585
|
+
const materializeLeafCoverage = (items, localRules, localNs, composing, captureTerminals = false) => {
|
|
8586
|
+
const sources = [];
|
|
8587
|
+
const add = (item) => {
|
|
8588
|
+
if (!isIR(item)) return false;
|
|
8589
|
+
sources.push({ ns: item.ns, rules: evalRuleMapIR(item.ir) });
|
|
8590
|
+
return true;
|
|
8591
|
+
};
|
|
8592
|
+
for (const item of items) {
|
|
8593
|
+
if (isSpread(item)) {
|
|
8594
|
+
const imported = importedPieces(item.__spreadLocal);
|
|
8595
|
+
if (!imported || !imported.every(add)) return null;
|
|
8596
|
+
} else if (!add(item)) return null;
|
|
8597
|
+
}
|
|
8598
|
+
sources.push({ ns: localNs, rules: [...localRules] });
|
|
8599
|
+
const winners = {};
|
|
8600
|
+
for (const source of sources) for (const [name, rule] of source.rules) winners[name] = rule;
|
|
8601
|
+
const plan = buildGrammarPlan(Object.values(winners), winners);
|
|
8602
|
+
const pieces = [];
|
|
8603
|
+
for (let index = 0; index < sources.length; index++) {
|
|
8604
|
+
const source = sources[index];
|
|
8605
|
+
const piece = compileLinkable(source.rules, source.ns, {
|
|
8606
|
+
...composing ? { trivia: composing } : {},
|
|
8607
|
+
recovery,
|
|
8608
|
+
...index < sources.length - 1 && captureTerminals ? { captureTerminals: true } : {},
|
|
8609
|
+
coverage: plan
|
|
8610
|
+
});
|
|
8611
|
+
if (!piece) return null;
|
|
8612
|
+
pieces.push(piece);
|
|
8613
|
+
}
|
|
8614
|
+
return pieces;
|
|
8615
|
+
};
|
|
8012
8616
|
const localCarried = (rm, label2, composing) => {
|
|
8013
8617
|
const entries = [...rm];
|
|
8014
8618
|
const ns = nsFor(label2);
|
|
@@ -8124,6 +8728,64 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8124
8728
|
return null;
|
|
8125
8729
|
}
|
|
8126
8730
|
};
|
|
8731
|
+
const compileComposeLeafCall = (init) => {
|
|
8732
|
+
const args = init.arguments;
|
|
8733
|
+
const arr = args[0];
|
|
8734
|
+
if (!arr || arr.type !== "ArrayExpression") {
|
|
8735
|
+
warn(init.start, "composeLeaf(): expected a static array of grammars");
|
|
8736
|
+
return null;
|
|
8737
|
+
}
|
|
8738
|
+
const elements = arr.elements;
|
|
8739
|
+
if (elements.length < 2) {
|
|
8740
|
+
warn(init.start, "composeLeaf(): needs imported recognition grammar(s) and one local rules() map");
|
|
8741
|
+
return null;
|
|
8742
|
+
}
|
|
8743
|
+
const localArg = elements[elements.length - 1];
|
|
8744
|
+
let localRules = null;
|
|
8745
|
+
if (isRulesCall(localArg)) {
|
|
8746
|
+
const evaluated = evaluateRulesFactory(localArg, `composeLeaf${init.start}`);
|
|
8747
|
+
localRules = evaluated?.ruleMap ?? null;
|
|
8748
|
+
} else if (localArg.type === "Identifier") {
|
|
8749
|
+
localRules = localRuleMaps.get(localArg.name) ?? null;
|
|
8750
|
+
}
|
|
8751
|
+
if (!localRules) {
|
|
8752
|
+
warn(init.start, "composeLeaf(): final argument must be a local rules() map");
|
|
8753
|
+
return null;
|
|
8754
|
+
}
|
|
8755
|
+
const composing = composingTrivia(elements);
|
|
8756
|
+
const carried = [];
|
|
8757
|
+
for (let i = 0; i < elements.length - 1; i++) {
|
|
8758
|
+
const r = argPieces(elements[i], `composeLeaf${init.start}_${i}`, composing);
|
|
8759
|
+
if (!r) {
|
|
8760
|
+
warn(init.start, `composeLeaf(): argument ${i} isn't a build-resolvable recognition grammar`);
|
|
8761
|
+
return null;
|
|
8762
|
+
}
|
|
8763
|
+
carried.push(...r.carried);
|
|
8764
|
+
}
|
|
8765
|
+
try {
|
|
8766
|
+
const localNs = nsFor(`composeLeaf${init.start}`);
|
|
8767
|
+
const plainLocalPiece = compileLinkable([...localRules], localNs, { ...composing ? { trivia: composing } : {}, recovery });
|
|
8768
|
+
if (!plainLocalPiece) {
|
|
8769
|
+
warn(init.start, "composeLeaf(): local rules could not be statically compiled");
|
|
8770
|
+
return null;
|
|
8771
|
+
}
|
|
8772
|
+
const recognitionPieces = grammarCoverage ? materializeLeafCoverage(carried, localRules, localNs, composing, plainLocalPiece.hasDirectBuilders === true) : materializeCarried(carried, composing, plainLocalPiece.hasDirectBuilders === true);
|
|
8773
|
+
if (!recognitionPieces) {
|
|
8774
|
+
warn(init.start, "composeLeaf(): coverage needs re-lowerable recognition IR");
|
|
8775
|
+
return null;
|
|
8776
|
+
}
|
|
8777
|
+
const importedRecognitionPieces = grammarCoverage ? recognitionPieces.slice(0, -1) : recognitionPieces;
|
|
8778
|
+
if (importedRecognitionPieces.some((piece) => piece.hasDirectBuilders !== false || piece.isRecognitionOnly !== true)) {
|
|
8779
|
+
warn(init.start, "composeLeaf(): every pre-final grammar must explicitly prove recognition-only");
|
|
8780
|
+
return null;
|
|
8781
|
+
}
|
|
8782
|
+
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
|
|
8783
|
+
return { replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) };
|
|
8784
|
+
} catch (e) {
|
|
8785
|
+
warn(init.start, `composeLeaf(): ${e.message}`);
|
|
8786
|
+
return null;
|
|
8787
|
+
}
|
|
8788
|
+
};
|
|
8127
8789
|
const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
|
|
8128
8790
|
const refNames = /* @__PURE__ */ new Set();
|
|
8129
8791
|
for (const stmt of body) {
|
|
@@ -8190,7 +8852,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8190
8852
|
const refEntry = scope.get(varName);
|
|
8191
8853
|
const refCombi = refEntry?.combi ?? null;
|
|
8192
8854
|
if (refCombi) {
|
|
8193
|
-
const compiled2 = compile(refCombi, void 0, { recovery });
|
|
8855
|
+
const compiled2 = compile(refCombi, void 0, { recovery, coverage: grammarCoverage });
|
|
8194
8856
|
if (compiled2.inlineExpression === null) {
|
|
8195
8857
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
8196
8858
|
continue;
|
|
@@ -8204,7 +8866,10 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8204
8866
|
if (!compiledRules) continue;
|
|
8205
8867
|
localRuleMaps.set(varName, compiledRules.ruleMap);
|
|
8206
8868
|
if (compiledRules.trivia) localGrammarTrivia.set(varName, compiledRules.trivia);
|
|
8207
|
-
let replacement =
|
|
8869
|
+
let replacement = withCoverageDefinitions(
|
|
8870
|
+
compiledRules.replacement,
|
|
8871
|
+
compiledRules.coverageDefinitions?.length ? compiledRules.coverageDefinitions : emittedCoverageDefinitions(compiledRules.replacement)
|
|
8872
|
+
);
|
|
8208
8873
|
if (exportPrefix) {
|
|
8209
8874
|
const ns = nsFor(varName);
|
|
8210
8875
|
const pieces = compileLinkable([...compiledRules.ruleMap], ns, { recovery });
|
|
@@ -8225,7 +8890,15 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8225
8890
|
localComposedCarried.set(varName, fused.carried);
|
|
8226
8891
|
if (fused.trivia) localComposedTrivia.set(varName, fused.trivia);
|
|
8227
8892
|
const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.carried) : fused.replacement;
|
|
8228
|
-
replacements.push({ start: init.start, end: init.end, replacement });
|
|
8893
|
+
replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) });
|
|
8894
|
+
continue;
|
|
8895
|
+
}
|
|
8896
|
+
if (isComposeLeafCall(init)) {
|
|
8897
|
+
const fused = compileComposeLeafCall(init);
|
|
8898
|
+
if (!fused) {
|
|
8899
|
+
throw new Error(`${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden`);
|
|
8900
|
+
}
|
|
8901
|
+
replacements.push({ start: init.start, end: init.end, replacement: fused.replacement });
|
|
8229
8902
|
continue;
|
|
8230
8903
|
}
|
|
8231
8904
|
const mapFnSources = [];
|
|
@@ -8246,7 +8919,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8246
8919
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
8247
8920
|
continue;
|
|
8248
8921
|
}
|
|
8249
|
-
const compiled = compile(parser2, void 0, { recovery });
|
|
8922
|
+
const compiled = compile(parser2, void 0, { recovery, coverage: grammarCoverage });
|
|
8250
8923
|
if (compiled.inlineExpression === null) {
|
|
8251
8924
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
8252
8925
|
continue;
|