parseman 0.27.1 → 0.28.1
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 +22 -9
- 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.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/plugin/index.ts
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
3
4
|
import { createUnplugin } from "unplugin";
|
|
4
5
|
import { parseSync as parseSync2 } from "oxc-parser";
|
|
5
6
|
import { ResolverFactory } from "oxc-resolver";
|
|
@@ -66,6 +67,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
66
67
|
case "label":
|
|
67
68
|
case "trivia":
|
|
68
69
|
case "token":
|
|
70
|
+
case "leaf":
|
|
69
71
|
case "expect":
|
|
70
72
|
case "withCtx":
|
|
71
73
|
case "node":
|
|
@@ -129,6 +131,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
129
131
|
case "label":
|
|
130
132
|
case "trivia":
|
|
131
133
|
case "token":
|
|
134
|
+
case "leaf":
|
|
132
135
|
case "node":
|
|
133
136
|
case "grammar":
|
|
134
137
|
case "expect":
|
|
@@ -234,10 +237,10 @@ function beginCstNodeCapture(ctx) {
|
|
|
234
237
|
}
|
|
235
238
|
function finishCstBuf(buf) {
|
|
236
239
|
if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
|
|
237
|
-
const
|
|
240
|
+
const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
|
|
238
241
|
const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
|
|
239
242
|
const triviaLog = buf.tl ?? EMPTY_TL;
|
|
240
|
-
return { children, rawChildren, triviaLog };
|
|
243
|
+
return { children: children2, rawChildren, triviaLog };
|
|
241
244
|
}
|
|
242
245
|
function endCstNodeCapture(ctx, saved) {
|
|
243
246
|
const materialized = finishCstBuf(ctx._cstBuf);
|
|
@@ -249,8 +252,8 @@ function endCstNodeCapture(ctx, saved) {
|
|
|
249
252
|
ctx.captureTrivia = saved.cap;
|
|
250
253
|
return materialized;
|
|
251
254
|
}
|
|
252
|
-
function pushCstLeaf(ctx,
|
|
253
|
-
pushCstChild(ctx,
|
|
255
|
+
function pushCstLeaf(ctx, leaf2) {
|
|
256
|
+
pushCstChild(ctx, leaf2, leaf2);
|
|
254
257
|
}
|
|
255
258
|
function pushCstChild(ctx, built, rawEntry) {
|
|
256
259
|
const b = ctx._cstBuf;
|
|
@@ -980,10 +983,13 @@ function deriveExpected(c) {
|
|
|
980
983
|
return def.parsers.flatMap(deriveExpected);
|
|
981
984
|
case "sequence":
|
|
982
985
|
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
986
|
+
case "attempt":
|
|
987
|
+
return deriveExpected(def.parser);
|
|
983
988
|
case "node":
|
|
984
989
|
case "grammar":
|
|
985
990
|
case "trivia":
|
|
986
991
|
case "token":
|
|
992
|
+
case "leaf":
|
|
987
993
|
case "optional":
|
|
988
994
|
case "many":
|
|
989
995
|
case "oneOrMore":
|
|
@@ -1758,6 +1764,24 @@ function sequence(...parsers) {
|
|
|
1758
1764
|
};
|
|
1759
1765
|
}
|
|
1760
1766
|
|
|
1767
|
+
// src/combinators/attempt.ts
|
|
1768
|
+
function attempt(parser2) {
|
|
1769
|
+
return {
|
|
1770
|
+
_tag: "attempt",
|
|
1771
|
+
_meta: parser2._meta,
|
|
1772
|
+
_def: { tag: "attempt", parser: parser2 },
|
|
1773
|
+
parse(input, pos, ctx) {
|
|
1774
|
+
const mark = saveCstMark(ctx);
|
|
1775
|
+
const log = ctx._triviaLog?.length;
|
|
1776
|
+
const result = parser2.parse(input, pos, ctx);
|
|
1777
|
+
if (result.ok) return result;
|
|
1778
|
+
rollbackCstCapture(ctx, mark);
|
|
1779
|
+
if (log !== void 0 && ctx._triviaLog) ctx._triviaLog.length = log;
|
|
1780
|
+
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1761
1785
|
// src/combinators/repeat.ts
|
|
1762
1786
|
function repItem(combinator, input, cur, ctx) {
|
|
1763
1787
|
const mark = saveTriviaMark(ctx);
|
|
@@ -1933,19 +1957,19 @@ function sepBy(combinator, separator) {
|
|
|
1933
1957
|
sepPos = advanceTrivia(input, cur, ctx);
|
|
1934
1958
|
}
|
|
1935
1959
|
}
|
|
1936
|
-
const
|
|
1937
|
-
if (!
|
|
1960
|
+
const sep2 = separator.parse(input, sepPos, ctx);
|
|
1961
|
+
if (!sep2.ok) {
|
|
1938
1962
|
rollbackTrivia(ctx, loopMark);
|
|
1939
1963
|
break;
|
|
1940
1964
|
}
|
|
1941
|
-
let nextPos =
|
|
1965
|
+
let nextPos = sep2.span.end;
|
|
1942
1966
|
if (ctx.trivia) {
|
|
1943
1967
|
if (needsDeferredTriviaCommit(ctx)) {
|
|
1944
|
-
const scan = scanTrivia(input,
|
|
1968
|
+
const scan = scanTrivia(input, sep2.span.end, ctx);
|
|
1945
1969
|
scan.commit();
|
|
1946
1970
|
nextPos = scan.end;
|
|
1947
1971
|
} else {
|
|
1948
|
-
nextPos = advanceTrivia(input,
|
|
1972
|
+
nextPos = advanceTrivia(input, sep2.span.end, ctx);
|
|
1949
1973
|
}
|
|
1950
1974
|
}
|
|
1951
1975
|
const next = combinator.parse(input, nextPos, ctx);
|
|
@@ -2030,10 +2054,14 @@ function markUnusedValues(root) {
|
|
|
2030
2054
|
case "label":
|
|
2031
2055
|
case "trivia":
|
|
2032
2056
|
case "token":
|
|
2057
|
+
case "attempt":
|
|
2033
2058
|
case "withCtx":
|
|
2034
2059
|
case "expect":
|
|
2035
2060
|
visit(def.parser, consumed);
|
|
2036
2061
|
return;
|
|
2062
|
+
case "leaf":
|
|
2063
|
+
visit(def.parser, true);
|
|
2064
|
+
return;
|
|
2037
2065
|
case "lazy":
|
|
2038
2066
|
return;
|
|
2039
2067
|
default:
|
|
@@ -2156,6 +2184,20 @@ function confirmedBuildArity(src) {
|
|
|
2156
2184
|
if (/\barguments\b/.test(s)) return null;
|
|
2157
2185
|
return parts.length;
|
|
2158
2186
|
}
|
|
2187
|
+
function buildReadsChildren(def) {
|
|
2188
|
+
if (!def.build) return true;
|
|
2189
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2190
|
+
const arity = confirmedBuildArity(src);
|
|
2191
|
+
if (arity === null) return true;
|
|
2192
|
+
return arity >= 1;
|
|
2193
|
+
}
|
|
2194
|
+
function buildReadsRaw(def) {
|
|
2195
|
+
if (!def.build) return true;
|
|
2196
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2197
|
+
const arity = confirmedBuildArity(src);
|
|
2198
|
+
if (arity === null) return true;
|
|
2199
|
+
return arity >= 4;
|
|
2200
|
+
}
|
|
2159
2201
|
function buildReadsTrivia(def) {
|
|
2160
2202
|
if (!def.build) return true;
|
|
2161
2203
|
const src = def.buildSrc ?? def.build.toString();
|
|
@@ -2211,9 +2253,11 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2211
2253
|
case "many":
|
|
2212
2254
|
case "oneOrMore":
|
|
2213
2255
|
case "optional":
|
|
2256
|
+
case "attempt":
|
|
2214
2257
|
case "transform":
|
|
2215
2258
|
case "trivia":
|
|
2216
2259
|
case "token":
|
|
2260
|
+
case "leaf":
|
|
2217
2261
|
case "label":
|
|
2218
2262
|
case "expect":
|
|
2219
2263
|
case "withCtx":
|
|
@@ -2246,9 +2290,11 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2246
2290
|
case "keywords":
|
|
2247
2291
|
case "guard":
|
|
2248
2292
|
case "token":
|
|
2293
|
+
case "leaf":
|
|
2249
2294
|
return false;
|
|
2250
2295
|
// Transparent single-child wrappers: recurse.
|
|
2251
2296
|
case "optional":
|
|
2297
|
+
case "attempt":
|
|
2252
2298
|
case "transform":
|
|
2253
2299
|
case "trivia":
|
|
2254
2300
|
case "label":
|
|
@@ -2295,6 +2341,7 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2295
2341
|
case "many":
|
|
2296
2342
|
case "oneOrMore":
|
|
2297
2343
|
case "optional":
|
|
2344
|
+
case "attempt":
|
|
2298
2345
|
case "transform":
|
|
2299
2346
|
case "trivia":
|
|
2300
2347
|
case "token":
|
|
@@ -2304,6 +2351,10 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2304
2351
|
case "withCtx":
|
|
2305
2352
|
case "not":
|
|
2306
2353
|
return parserEnablesTriviaCapture(d.parser, seen);
|
|
2354
|
+
// leaf() clears the inner CST/trivia collector and publishes only its own
|
|
2355
|
+
// terminal result. An inner parser() capture cannot reach this node.
|
|
2356
|
+
case "leaf":
|
|
2357
|
+
return false;
|
|
2307
2358
|
case "lazy": {
|
|
2308
2359
|
try {
|
|
2309
2360
|
return parserEnablesTriviaCapture(d.thunk(), seen);
|
|
@@ -2382,12 +2433,12 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2382
2433
|
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
2383
2434
|
ctx._fields = savedFields;
|
|
2384
2435
|
ctx._triviaCaptureMask = savedMask;
|
|
2385
|
-
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2436
|
+
const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2386
2437
|
if (!r.ok) return r;
|
|
2387
2438
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2388
2439
|
const nodeType = def.type ?? missingInferredType();
|
|
2389
2440
|
const cstOutput = ctx.build?._parsemanCstOutput === true;
|
|
2390
|
-
const built = unwrap &&
|
|
2441
|
+
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 };
|
|
2391
2442
|
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 };
|
|
2392
2443
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2393
2444
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -2593,6 +2644,141 @@ function token(root) {
|
|
|
2593
2644
|
}
|
|
2594
2645
|
};
|
|
2595
2646
|
}
|
|
2647
|
+
function leaf(root, fn) {
|
|
2648
|
+
const meta = {
|
|
2649
|
+
firstSet: root._meta.firstSet,
|
|
2650
|
+
canMatchNewline: root._meta.canMatchNewline,
|
|
2651
|
+
isTrivia: false
|
|
2652
|
+
};
|
|
2653
|
+
return {
|
|
2654
|
+
_tag: "leaf",
|
|
2655
|
+
_meta: meta,
|
|
2656
|
+
_def: { tag: "leaf", parser: root, fn },
|
|
2657
|
+
parse(input, pos, ctx) {
|
|
2658
|
+
const savedBuf = ctx._cstBuf;
|
|
2659
|
+
const savedChildren = ctx._cstChildren;
|
|
2660
|
+
const savedLeaves = ctx._cstLeaves;
|
|
2661
|
+
const savedRaw = ctx._cstRawChildren;
|
|
2662
|
+
const savedTriviaLog = ctx._cstTriviaLog;
|
|
2663
|
+
const savedOuterTriviaLog = ctx._triviaLog;
|
|
2664
|
+
const wasCapturing = cstCaptureActive(ctx);
|
|
2665
|
+
ctx._cstBuf = void 0;
|
|
2666
|
+
ctx._cstChildren = void 0;
|
|
2667
|
+
ctx._cstLeaves = void 0;
|
|
2668
|
+
ctx._cstRawChildren = void 0;
|
|
2669
|
+
ctx._cstTriviaLog = void 0;
|
|
2670
|
+
delete ctx._triviaLog;
|
|
2671
|
+
let result;
|
|
2672
|
+
try {
|
|
2673
|
+
result = root.parse(input, pos, ctx);
|
|
2674
|
+
} finally {
|
|
2675
|
+
ctx._cstBuf = savedBuf;
|
|
2676
|
+
ctx._cstChildren = savedChildren;
|
|
2677
|
+
ctx._cstLeaves = savedLeaves;
|
|
2678
|
+
ctx._cstRawChildren = savedRaw;
|
|
2679
|
+
ctx._cstTriviaLog = savedTriviaLog;
|
|
2680
|
+
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
2681
|
+
else ctx._triviaLog = savedOuterTriviaLog;
|
|
2682
|
+
}
|
|
2683
|
+
if (!result.ok) return result;
|
|
2684
|
+
const value = fn(result.value, result.span);
|
|
2685
|
+
if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span: result.span });
|
|
2686
|
+
return { ok: true, value, span: result.span };
|
|
2687
|
+
}
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
// src/compiler/grammar-coverage-ids.ts
|
|
2692
|
+
function children(def, winners) {
|
|
2693
|
+
switch (def.tag) {
|
|
2694
|
+
case "sequence":
|
|
2695
|
+
case "choice":
|
|
2696
|
+
return def.parsers;
|
|
2697
|
+
case "many":
|
|
2698
|
+
case "oneOrMore":
|
|
2699
|
+
case "optional":
|
|
2700
|
+
case "attempt":
|
|
2701
|
+
case "transform":
|
|
2702
|
+
case "trivia":
|
|
2703
|
+
case "token":
|
|
2704
|
+
case "leaf":
|
|
2705
|
+
case "label":
|
|
2706
|
+
case "field":
|
|
2707
|
+
case "grammar":
|
|
2708
|
+
case "not":
|
|
2709
|
+
case "node":
|
|
2710
|
+
case "guard":
|
|
2711
|
+
case "withCtx":
|
|
2712
|
+
case "recover":
|
|
2713
|
+
case "expect":
|
|
2714
|
+
return "parser" in def ? [def.parser] : [];
|
|
2715
|
+
case "sepBy":
|
|
2716
|
+
return [def.parser, def.separator];
|
|
2717
|
+
case "skip":
|
|
2718
|
+
return [def.main, def.skipped];
|
|
2719
|
+
case "scanTo":
|
|
2720
|
+
return [def.sentinel, ...def.skip];
|
|
2721
|
+
case "lazy": {
|
|
2722
|
+
let resolved;
|
|
2723
|
+
try {
|
|
2724
|
+
resolved = def.thunk();
|
|
2725
|
+
} catch {
|
|
2726
|
+
return [];
|
|
2727
|
+
}
|
|
2728
|
+
const name = resolved._ruleName;
|
|
2729
|
+
return name && winners?.[name] ? [winners[name]] : [resolved];
|
|
2730
|
+
}
|
|
2731
|
+
default:
|
|
2732
|
+
return [];
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
function buildGrammarPlan(entry, winners) {
|
|
2736
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
2737
|
+
const choices = /* @__PURE__ */ new WeakMap();
|
|
2738
|
+
const attempts = /* @__PURE__ */ new WeakMap();
|
|
2739
|
+
const labels = /* @__PURE__ */ new WeakMap();
|
|
2740
|
+
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
2741
|
+
const winnerNames = /* @__PURE__ */ new Map();
|
|
2742
|
+
if (winners) {
|
|
2743
|
+
for (const [name, winner] of Object.entries(winners)) {
|
|
2744
|
+
winnerNames.set(winner, name);
|
|
2745
|
+
if (winner._def.tag === "lazy") {
|
|
2746
|
+
try {
|
|
2747
|
+
winnerNames.set(winner._def.thunk(), name);
|
|
2748
|
+
} catch {
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2754
|
+
const visit = (parser2, path2) => {
|
|
2755
|
+
if (seen.has(parser2)) return;
|
|
2756
|
+
seen.add(parser2);
|
|
2757
|
+
const rule = winnerNames.get(parser2) ?? parser2._ruleName;
|
|
2758
|
+
if (rule && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
|
|
2759
|
+
const id = `rule:${rule}`;
|
|
2760
|
+
definitions.set(id, { id, kind: "rule" });
|
|
2761
|
+
rules2.set(parser2, id);
|
|
2762
|
+
}
|
|
2763
|
+
if (parser2._def.tag === "choice") {
|
|
2764
|
+
const ids = parser2._def.parsers.map((_, index) => `choice:${path2}/arm:${index}`);
|
|
2765
|
+
choices.set(parser2, ids);
|
|
2766
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
2767
|
+
}
|
|
2768
|
+
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path2}`);
|
|
2769
|
+
if (parser2._def.tag === "label") {
|
|
2770
|
+
const id = `label:${path2}`;
|
|
2771
|
+
labels.set(parser2, [id]);
|
|
2772
|
+
definitions.set(id, { id, kind: "label" });
|
|
2773
|
+
}
|
|
2774
|
+
children(parser2._def, winners).forEach((child, index) => visit(child, `${path2}/${parser2._def.tag}:${index}`));
|
|
2775
|
+
};
|
|
2776
|
+
const roots = Array.isArray(entry) ? entry : [entry];
|
|
2777
|
+
for (const root of roots) {
|
|
2778
|
+
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
2779
|
+
}
|
|
2780
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
2781
|
+
}
|
|
2596
2782
|
|
|
2597
2783
|
// src/compiler/scannable-run.ts
|
|
2598
2784
|
var BACKSLASH = 92;
|
|
@@ -3985,21 +4171,23 @@ function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
|
3985
4171
|
}
|
|
3986
4172
|
function failBody(ctx, expected, posExpr) {
|
|
3987
4173
|
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
4174
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
3988
4175
|
if (ctx.failLabel) {
|
|
3989
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3990
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
4176
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4177
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
|
|
3991
4178
|
}
|
|
3992
|
-
return probe + failReturn(expected, posExpr);
|
|
4179
|
+
return probe + trace + failReturn(expected, posExpr);
|
|
3993
4180
|
}
|
|
3994
4181
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3995
4182
|
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
4183
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
3996
4184
|
if (ctx.failLabel) {
|
|
3997
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4185
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3998
4186
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3999
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
4187
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
|
|
4000
4188
|
}
|
|
4001
|
-
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4002
|
-
return probe + failReturnArr(expectedArr, posExpr);
|
|
4189
|
+
if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4190
|
+
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
4003
4191
|
}
|
|
4004
4192
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
4005
4193
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4034,7 +4222,7 @@ var NAMED_FN_END = "_pfEnd";
|
|
|
4034
4222
|
function namedFnPrelude() {
|
|
4035
4223
|
return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
|
|
4036
4224
|
}
|
|
4037
|
-
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
4225
|
+
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar, failureRuleId) {
|
|
4038
4226
|
ctx.namedFnDecls.push([
|
|
4039
4227
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
4040
4228
|
` _pfail: {`,
|
|
@@ -4042,6 +4230,7 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
|
4042
4230
|
` ${NAMED_FN_END} = ${endVar}`,
|
|
4043
4231
|
` return ${valueVar}`,
|
|
4044
4232
|
` }`,
|
|
4233
|
+
...failureRuleId === void 0 ? [] : [` _ctx._grammarTrace?.write({ id: ${JSON.stringify(failureRuleId)}, phase: 'failure', offset: _ctx._fe ?? _pos })`],
|
|
4045
4234
|
` return ${NAMED_FN_FAIL}`,
|
|
4046
4235
|
`}`
|
|
4047
4236
|
].join("\n"));
|
|
@@ -4203,6 +4392,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4203
4392
|
case "not":
|
|
4204
4393
|
case "trivia":
|
|
4205
4394
|
case "token":
|
|
4395
|
+
case "leaf":
|
|
4206
4396
|
case "scanTo":
|
|
4207
4397
|
case "unknown":
|
|
4208
4398
|
return false;
|
|
@@ -4214,6 +4404,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4214
4404
|
// nothing committed remains.
|
|
4215
4405
|
case "choice":
|
|
4216
4406
|
return false;
|
|
4407
|
+
case "attempt":
|
|
4408
|
+
return false;
|
|
4217
4409
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
4218
4410
|
case "optional":
|
|
4219
4411
|
case "many":
|
|
@@ -4266,6 +4458,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4266
4458
|
case "keywords":
|
|
4267
4459
|
case "node":
|
|
4268
4460
|
case "token":
|
|
4461
|
+
case "leaf":
|
|
4269
4462
|
return true;
|
|
4270
4463
|
case "not":
|
|
4271
4464
|
case "guard":
|
|
@@ -4280,6 +4473,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4280
4473
|
case "many":
|
|
4281
4474
|
case "oneOrMore":
|
|
4282
4475
|
case "optional":
|
|
4476
|
+
case "attempt":
|
|
4283
4477
|
case "transform":
|
|
4284
4478
|
case "label":
|
|
4285
4479
|
case "field":
|
|
@@ -4621,35 +4815,55 @@ function needsFirstSetGuard(p) {
|
|
|
4621
4815
|
const fs2 = p._meta.firstSet;
|
|
4622
4816
|
return fs2.kind !== "any" && !canMatchEmptyAtStart(p);
|
|
4623
4817
|
}
|
|
4624
|
-
function
|
|
4625
|
-
|
|
4818
|
+
function coverageHit(ctx, id, offset = "_pos", end) {
|
|
4819
|
+
return id === void 0 ? [] : [
|
|
4820
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`,
|
|
4821
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'selected', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`,
|
|
4822
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`
|
|
4823
|
+
];
|
|
4824
|
+
}
|
|
4825
|
+
function coverageAttempt(ctx, id, offset) {
|
|
4826
|
+
return id === void 0 ? [] : [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'attempt', offset: ${offset} })`];
|
|
4827
|
+
}
|
|
4828
|
+
function coverageFailureBacktrack(ctx, id, failureOffset, startOffset) {
|
|
4829
|
+
return id === void 0 ? [] : [
|
|
4830
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'failure', offset: ${failureOffset} })`,
|
|
4831
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'backtrack', offset: ${startOffset} })`
|
|
4832
|
+
];
|
|
4833
|
+
}
|
|
4834
|
+
function emitDisjointArm(p, ctx, pos, valV, endV, coverageId) {
|
|
4835
|
+
if (failsAtStart(p) && coverageId === void 0) {
|
|
4626
4836
|
const r = emit(p, ctx, pos);
|
|
4627
|
-
return [...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}
|
|
4837
|
+
return [...coverageAttempt(ctx, coverageId, pos), ...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`, ...coverageHit(ctx, coverageId, pos, r.endVar)];
|
|
4628
4838
|
}
|
|
4629
4839
|
const { stmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
|
|
4630
4840
|
return [
|
|
4841
|
+
...coverageAttempt(ctx, coverageId, pos),
|
|
4631
4842
|
...stmts,
|
|
4632
|
-
...emitIfFail(ctx, `!${okVar}`, failArrBody(ctx, "_ctx._fx", pos, false)),
|
|
4843
|
+
...emitIfFail(ctx, `!${okVar}`, `${coverageFailureBacktrack(ctx, coverageId, "_ctx._fe", pos).join("; ")}; ${failArrBody(ctx, "_ctx._fx", pos, false)}`),
|
|
4633
4844
|
`${ind(ctx)}${valV} = ${valVar}`,
|
|
4634
|
-
`${ind(ctx)}${endV} = ${endVar}
|
|
4845
|
+
`${ind(ctx)}${endV} = ${endVar}`,
|
|
4846
|
+
...coverageHit(ctx, coverageId, pos, endVar)
|
|
4635
4847
|
];
|
|
4636
4848
|
}
|
|
4637
|
-
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4849
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageId) {
|
|
4638
4850
|
const p = def.parsers[i];
|
|
4639
4851
|
const gate = def.gates[i];
|
|
4640
|
-
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4852
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV, coverageId);
|
|
4641
4853
|
const gateIdx = ctx.mapFns.length;
|
|
4642
4854
|
ctx.mapFns.push(gate);
|
|
4643
4855
|
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4644
4856
|
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4645
4857
|
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4646
4858
|
ctx.indent++;
|
|
4647
|
-
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4859
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV, coverageId));
|
|
4648
4860
|
ctx.indent--;
|
|
4649
4861
|
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4650
4862
|
return stmts;
|
|
4651
4863
|
}
|
|
4652
|
-
function emitChoice(def, ctx, pos) {
|
|
4864
|
+
function emitChoice(parser2, def, ctx, pos) {
|
|
4865
|
+
const coverageIds = ctx.coverage?.plan.choices.get(parser2);
|
|
4866
|
+
const coverageBase = coverageIds?.[0]?.slice(0, -1);
|
|
4653
4867
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4654
4868
|
if (def.disjoint) {
|
|
4655
4869
|
const codeV = v(ctx, "_code");
|
|
@@ -4668,7 +4882,7 @@ function emitChoice(def, ctx, pos) {
|
|
|
4668
4882
|
stmts.push(`${ind(ctx)}{`);
|
|
4669
4883
|
ctx.indent++;
|
|
4670
4884
|
stmts.push(
|
|
4671
|
-
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
4885
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]),
|
|
4672
4886
|
`${ind(ctx)}break`
|
|
4673
4887
|
);
|
|
4674
4888
|
ctx.indent--;
|
|
@@ -4687,16 +4901,16 @@ function emitChoice(def, ctx, pos) {
|
|
|
4687
4901
|
first = false;
|
|
4688
4902
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4689
4903
|
ctx.indent++;
|
|
4690
|
-
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
4904
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]));
|
|
4691
4905
|
ctx.indent--;
|
|
4692
4906
|
stmts.push(`${ind(ctx)}}`);
|
|
4693
4907
|
}
|
|
4694
4908
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4695
4909
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4696
4910
|
}
|
|
4697
|
-
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
|
|
4911
|
+
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
4698
4912
|
}
|
|
4699
|
-
function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
4913
|
+
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
4700
4914
|
const superParser = def.parsers[superIndex];
|
|
4701
4915
|
const regexDef = getCoreRegexDef(superParser);
|
|
4702
4916
|
const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
@@ -4712,10 +4926,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4712
4926
|
const endV = v(ctx, "_ge");
|
|
4713
4927
|
const valV = v(ctx, "_gcv");
|
|
4714
4928
|
const regexExpected = JSON.stringify(deriveExpected(superParser));
|
|
4929
|
+
const superCoverageId = coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`;
|
|
4715
4930
|
const stmts = [
|
|
4931
|
+
...coverageAttempt(ctx, superCoverageId, pos),
|
|
4716
4932
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
4717
4933
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
4718
|
-
...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, regexExpected, pos)),
|
|
4934
|
+
...emitIfFail(ctx, `${matchV} === null`, `${coverageFailureBacktrack(ctx, superCoverageId, pos, pos).join("; ")}; ${failArrBody(ctx, regexExpected, pos)}`),
|
|
4719
4935
|
`${ind(ctx)}const ${wordV} = ${matchV}[0]`,
|
|
4720
4936
|
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
|
|
4721
4937
|
`${ind(ctx)}let ${valV}`
|
|
@@ -4731,8 +4947,9 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4731
4947
|
stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
|
|
4732
4948
|
ctx.indent++;
|
|
4733
4949
|
const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
|
|
4950
|
+
stmts.push(...coverageFailureBacktrack(ctx, superCoverageId, pos, pos));
|
|
4734
4951
|
stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
|
|
4735
|
-
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}
|
|
4952
|
+
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endV));
|
|
4736
4953
|
ctx.indent--;
|
|
4737
4954
|
stmts.push(`${ind(ctx)}}`);
|
|
4738
4955
|
}
|
|
@@ -4740,12 +4957,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4740
4957
|
const regexKw = first ? "if" : "else";
|
|
4741
4958
|
stmts.push(`${ind(ctx)}${regexKw} {`);
|
|
4742
4959
|
ctx.indent++;
|
|
4743
|
-
stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}
|
|
4960
|
+
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));
|
|
4744
4961
|
ctx.indent--;
|
|
4745
4962
|
stmts.push(`${ind(ctx)}}`);
|
|
4746
4963
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4747
4964
|
}
|
|
4748
|
-
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
4965
|
+
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, coverageBase) {
|
|
4749
4966
|
const valV = v(ctx, "_llv");
|
|
4750
4967
|
const endV = v(ctx, "_lle");
|
|
4751
4968
|
const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
|
|
@@ -4762,10 +4979,12 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4762
4979
|
ctx.indent++;
|
|
4763
4980
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
4764
4981
|
stmts.push(
|
|
4982
|
+
...coverageAttempt(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos),
|
|
4765
4983
|
...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
|
|
4766
4984
|
...tR.stmts,
|
|
4767
4985
|
`${ind(ctx)}${valV} = ${tR.valueVar}`,
|
|
4768
|
-
`${ind(ctx)}${endV} = ${litEnd}
|
|
4986
|
+
`${ind(ctx)}${endV} = ${litEnd}`,
|
|
4987
|
+
...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos, litEnd)
|
|
4769
4988
|
);
|
|
4770
4989
|
ctx.indent--;
|
|
4771
4990
|
stmts.push(`${ind(ctx)}}`);
|
|
@@ -4773,16 +4992,18 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4773
4992
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4774
4993
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4775
4994
|
}
|
|
4776
|
-
function emitFirstMatch(def, ctx, pos) {
|
|
4995
|
+
function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
4777
4996
|
const resValV = v(ctx, "_crv");
|
|
4778
4997
|
const resEndV = v(ctx, "_cre");
|
|
4779
4998
|
const resOkV = v(ctx, "_crok");
|
|
4780
4999
|
const codeV = v(ctx, "_chcode");
|
|
4781
5000
|
const slots = def.parsers.map(() => v(ctx, "_cfx"));
|
|
5001
|
+
const autoRejectedV = coverageBase === void 0 ? void 0 : v(ctx, "_carej");
|
|
4782
5002
|
const ind0 = ind(ctx);
|
|
4783
5003
|
const stmts = [
|
|
4784
5004
|
`${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`,
|
|
4785
5005
|
`${ind0}let ${slots.join(", ")}`,
|
|
5006
|
+
...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
|
|
4786
5007
|
`${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
|
|
4787
5008
|
];
|
|
4788
5009
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
@@ -4818,6 +5039,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4818
5039
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4819
5040
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
4820
5041
|
ctx.indent += fsGuard ? 2 : 1;
|
|
5042
|
+
if (coverageBase !== void 0) stmts.push(`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'attempt', offset: ${pos} })`);
|
|
4821
5043
|
if (markLeaves) {
|
|
4822
5044
|
stmts.push(
|
|
4823
5045
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
@@ -4840,13 +5062,21 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4840
5062
|
stmts.push(`${ind(ctx)} ${resValV} = ${valVar}`);
|
|
4841
5063
|
stmts.push(`${ind(ctx)} ${resEndV} = ${endVar}`);
|
|
4842
5064
|
stmts.push(`${ind(ctx)} ${resOkV} = true`);
|
|
5065
|
+
if (autoRejectedV !== void 0) {
|
|
5066
|
+
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} }) }`);
|
|
5067
|
+
}
|
|
5068
|
+
stmts.push(...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endVar));
|
|
4843
5069
|
stmts.push(`${ind(ctx)} }`);
|
|
5070
|
+
if (autoRejectedV !== void 0) {
|
|
5071
|
+
stmts.push(`${ind(ctx)} else { ${autoRejectedV}.push(${JSON.stringify(`${coverageBase}${i}`)}) }`);
|
|
5072
|
+
}
|
|
4844
5073
|
stmts.push(`${ind(ctx)}}`);
|
|
4845
|
-
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot} }`);
|
|
5074
|
+
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} });`} }`);
|
|
4846
5075
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
4847
5076
|
} else {
|
|
4848
|
-
|
|
4849
|
-
stmts.push(`${ind(ctx)}
|
|
5077
|
+
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} }) }`;
|
|
5078
|
+
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} })`} }`);
|
|
5079
|
+
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} })`} }`);
|
|
4850
5080
|
}
|
|
4851
5081
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
4852
5082
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -4856,12 +5086,12 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4856
5086
|
stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
|
|
4857
5087
|
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
4858
5088
|
}
|
|
4859
|
-
function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
5089
|
+
function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
|
|
4860
5090
|
if (strategy.tag === "greedyClassify")
|
|
4861
|
-
return emitGreedyClassify(def, strategy.superIndex, ctx, pos);
|
|
5091
|
+
return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
|
|
4862
5092
|
if (strategy.tag === "literalsLongestFirst")
|
|
4863
|
-
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
4864
|
-
return emitFirstMatch(def, ctx, pos);
|
|
5093
|
+
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
|
|
5094
|
+
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
4865
5095
|
}
|
|
4866
5096
|
function pushMapFn(ctx, fn, src) {
|
|
4867
5097
|
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
@@ -4979,6 +5209,27 @@ function emitOptional(def, ctx, pos) {
|
|
|
4979
5209
|
];
|
|
4980
5210
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4981
5211
|
}
|
|
5212
|
+
function emitAttempt(p, def, ctx, pos) {
|
|
5213
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5214
|
+
const leaves = v(ctx, "_atl");
|
|
5215
|
+
const raw = v(ctx, "_atr");
|
|
5216
|
+
const trivia2 = v(ctx, "_att");
|
|
5217
|
+
const log = v(ctx, "_atg");
|
|
5218
|
+
const fields = v(ctx, "_atf");
|
|
5219
|
+
const errors = v(ctx, "_ate");
|
|
5220
|
+
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}`;
|
|
5221
|
+
const traceId = ctx.coverage?.plan.attempts.get(p);
|
|
5222
|
+
const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
|
|
5223
|
+
return {
|
|
5224
|
+
stmts: [
|
|
5225
|
+
`${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`,
|
|
5226
|
+
...inner.stmts,
|
|
5227
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
5228
|
+
],
|
|
5229
|
+
valueVar: inner.valVar,
|
|
5230
|
+
endVar: inner.endVar
|
|
5231
|
+
};
|
|
5232
|
+
}
|
|
4982
5233
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4983
5234
|
const arrV = v(ctx, "_arr");
|
|
4984
5235
|
const curV = v(ctx, "_cur");
|
|
@@ -5224,11 +5475,11 @@ function tokenNullableRegex(def) {
|
|
|
5224
5475
|
}
|
|
5225
5476
|
if (inner.tag === "sepBy") {
|
|
5226
5477
|
const item = tokenSequenceSource(inner.parser);
|
|
5227
|
-
const
|
|
5228
|
-
if (!item || !
|
|
5229
|
-
const combined = combineTokenRegexSources([item,
|
|
5478
|
+
const sep2 = tokenSequenceSource(inner.separator);
|
|
5479
|
+
if (!item || !sep2) return null;
|
|
5480
|
+
const combined = combineTokenRegexSources([item, sep2]);
|
|
5230
5481
|
if (!combined) return null;
|
|
5231
|
-
return { tag: "regex", source: `(?:${item.source}(?:${
|
|
5482
|
+
return { tag: "regex", source: `(?:${item.source}(?:${sep2.source}${item.source})*)?`, flags: combined.flags };
|
|
5232
5483
|
}
|
|
5233
5484
|
return null;
|
|
5234
5485
|
}
|
|
@@ -5269,6 +5520,36 @@ function emitToken(def, ctx, pos) {
|
|
|
5269
5520
|
endVar: inner.endVar
|
|
5270
5521
|
};
|
|
5271
5522
|
}
|
|
5523
|
+
function emitLeaf(def, ctx, pos) {
|
|
5524
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5525
|
+
const i = ind(ctx);
|
|
5526
|
+
const sc = v(ctx, "_leafCh");
|
|
5527
|
+
const sl = v(ctx, "_leafLv");
|
|
5528
|
+
const sr = v(ctx, "_leafRaw");
|
|
5529
|
+
const stl = v(ctx, "_leafTl");
|
|
5530
|
+
const sol = v(ctx, "_leafLog");
|
|
5531
|
+
const sb = v(ctx, "_leafBuf");
|
|
5532
|
+
const rawV = v(ctx, "_leafRawValue");
|
|
5533
|
+
const valV = v(ctx, "_leaf");
|
|
5534
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
5535
|
+
return {
|
|
5536
|
+
stmts: [
|
|
5537
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
|
|
5538
|
+
`${i}_ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
|
|
5539
|
+
`${i}try {`,
|
|
5540
|
+
...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
|
|
5541
|
+
`${i}} finally {`,
|
|
5542
|
+
`${i} _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
|
|
5543
|
+
`${i}}`,
|
|
5544
|
+
...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
|
|
5545
|
+
`${i}const ${rawV} = ${inner.valVar}`,
|
|
5546
|
+
`${i}const ${valV} = ${mfRef(ctx)}[${fnIdx}](${rawV}, { start: ${pos}, end: ${inner.endVar} })`,
|
|
5547
|
+
...emitLeafCapture(ctx, valV, pos, inner.endVar)
|
|
5548
|
+
],
|
|
5549
|
+
valueVar: valV,
|
|
5550
|
+
endVar: inner.endVar
|
|
5551
|
+
};
|
|
5552
|
+
}
|
|
5272
5553
|
function emitNode(def, ctx, pos) {
|
|
5273
5554
|
if (def.type === void 0) {
|
|
5274
5555
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -5284,6 +5565,8 @@ function emitNode(def, ctx, pos) {
|
|
|
5284
5565
|
const i = ind(ctx);
|
|
5285
5566
|
const capturesTrivia = mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
|
|
5286
5567
|
const clonesState = !structural && buildReadsState(def);
|
|
5568
|
+
const capturesChildren = !structural && (mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
|
|
5569
|
+
const capturesRaw = !structural && (mkType !== null || buildReadsRaw(def));
|
|
5287
5570
|
const hasFields = parserHasOwnFields(def.parser);
|
|
5288
5571
|
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
5289
5572
|
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
@@ -5302,9 +5585,13 @@ function emitNode(def, ctx, pos) {
|
|
|
5302
5585
|
const profHoist = `${i}const ${pmV} = _ctx._pmProfile, ${recV} = ${pmV}?.phase === 'recognizer', ${capV} = ${pmV}?.phase === 'capture'`;
|
|
5303
5586
|
const profileRecognizer = recV;
|
|
5304
5587
|
const profileCapture = capV;
|
|
5588
|
+
const directCstV = !structural && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
5589
|
+
const directCstGate = directCstV === null ? "false" : `${profileCapture} || _ctx.build?._parsemanCstOutput === true`;
|
|
5305
5590
|
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
5306
5591
|
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)))` : ""}
|
|
5307
|
-
${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${
|
|
5592
|
+
${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5593
|
+
` : ""}${i}const ${capTLv} = !(${profileRecognizer}), ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}, ${tlV} = ${profileRecognizer} ? undefined : []` : `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5594
|
+
` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
|
|
5308
5595
|
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
5309
5596
|
const fieldsOn = structural ? capFv ?? "false" : `${profileRecognizer} ? false : ${capturesFields ? "true" : "false"}`;
|
|
5310
5597
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
@@ -5421,14 +5708,23 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
5421
5708
|
const savedIndent = ctx.indent;
|
|
5422
5709
|
const savedFailLabel = ctx.failLabel;
|
|
5423
5710
|
const savedRecord = ctx.recordFail;
|
|
5711
|
+
const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
|
|
5712
|
+
const savedActiveRule = ctx.activeCoverageRuleId;
|
|
5713
|
+
const savedSuppressFailure = ctx.suppressCoverageFailure;
|
|
5424
5714
|
ctx.indent = 1;
|
|
5425
5715
|
ctx.failLabel = "_pfail";
|
|
5426
5716
|
ctx.recordFail = true;
|
|
5717
|
+
if (failureRuleId !== void 0) {
|
|
5718
|
+
ctx.activeCoverageRuleId = void 0;
|
|
5719
|
+
ctx.suppressCoverageFailure = true;
|
|
5720
|
+
}
|
|
5427
5721
|
const r = emit(resolved, ctx, "_pos");
|
|
5428
5722
|
ctx.indent = savedIndent;
|
|
5429
5723
|
ctx.failLabel = savedFailLabel;
|
|
5430
5724
|
ctx.recordFail = savedRecord;
|
|
5431
|
-
|
|
5725
|
+
ctx.activeCoverageRuleId = savedActiveRule;
|
|
5726
|
+
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
5727
|
+
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
5432
5728
|
}
|
|
5433
5729
|
const fnName = ctx.namedParsers.get(p);
|
|
5434
5730
|
return emitNamedFnCall(ctx, fnName, pos);
|
|
@@ -5479,6 +5775,30 @@ function emitExpect(def, ctx, pos) {
|
|
|
5479
5775
|
return { stmts, valueVar: valVar, endVar };
|
|
5480
5776
|
}
|
|
5481
5777
|
function emit(p, ctx, pos) {
|
|
5778
|
+
const dispatch = (emissionPos = pos) => {
|
|
5779
|
+
const savedRule = ctx.activeCoverageRuleId;
|
|
5780
|
+
const rule = ctx.coverage?.plan.rules.get(p);
|
|
5781
|
+
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
5782
|
+
const result = emitDispatch(p, ctx, emissionPos);
|
|
5783
|
+
ctx.activeCoverageRuleId = savedRule;
|
|
5784
|
+
return result;
|
|
5785
|
+
};
|
|
5786
|
+
const instrument = (r) => {
|
|
5787
|
+
const ruleId = ctx.coverage?.plan.rules.get(p);
|
|
5788
|
+
const labelIds = ctx.coverage?.plan.labels.get(p);
|
|
5789
|
+
if (!ruleId && !labelIds) return r;
|
|
5790
|
+
return {
|
|
5791
|
+
...r,
|
|
5792
|
+
stmts: [
|
|
5793
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`] : [],
|
|
5794
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: ${pos} })`] : [],
|
|
5795
|
+
...r.stmts,
|
|
5796
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`] : [],
|
|
5797
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`]) ?? [],
|
|
5798
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`]) ?? []
|
|
5799
|
+
]
|
|
5800
|
+
};
|
|
5801
|
+
};
|
|
5482
5802
|
const usage = ctx.lazyUsage;
|
|
5483
5803
|
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
|
|
5484
5804
|
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
@@ -5495,14 +5815,14 @@ function emit(p, ctx, pos) {
|
|
|
5495
5815
|
ctx.indent = 1;
|
|
5496
5816
|
ctx.failLabel = "_pfail";
|
|
5497
5817
|
ctx.recordFail = true;
|
|
5498
|
-
const r =
|
|
5818
|
+
const r = dispatch("_pos");
|
|
5499
5819
|
ctx.indent = savedIndent;
|
|
5500
5820
|
ctx.failLabel = savedFailLabel;
|
|
5501
5821
|
ctx.recordFail = savedRecord;
|
|
5502
5822
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
5503
|
-
return emitNamedFnCall(ctx, fnName, pos);
|
|
5823
|
+
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
5504
5824
|
}
|
|
5505
|
-
return
|
|
5825
|
+
return instrument(dispatch());
|
|
5506
5826
|
}
|
|
5507
5827
|
function emitDispatch(p, ctx, pos) {
|
|
5508
5828
|
const def = p._def;
|
|
@@ -5516,7 +5836,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5516
5836
|
case "sequence":
|
|
5517
5837
|
return emitSeq(def, ctx, pos);
|
|
5518
5838
|
case "choice":
|
|
5519
|
-
return emitChoice(def, ctx, pos);
|
|
5839
|
+
return emitChoice(p, def, ctx, pos);
|
|
5840
|
+
case "attempt":
|
|
5841
|
+
return emitAttempt(p, def, ctx, pos);
|
|
5520
5842
|
case "many":
|
|
5521
5843
|
case "oneOrMore":
|
|
5522
5844
|
return emitMany(def, ctx, pos);
|
|
@@ -5585,6 +5907,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5585
5907
|
return emit(def.parser, ctx, pos);
|
|
5586
5908
|
case "token":
|
|
5587
5909
|
return emitToken(def, ctx, pos);
|
|
5910
|
+
case "leaf":
|
|
5911
|
+
return emitLeaf(def, ctx, pos);
|
|
5588
5912
|
case "label": {
|
|
5589
5913
|
const inner = emitFallible(def.parser, ctx, pos);
|
|
5590
5914
|
return {
|
|
@@ -5716,6 +6040,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5716
6040
|
case "grammar":
|
|
5717
6041
|
case "trivia":
|
|
5718
6042
|
case "token":
|
|
6043
|
+
case "leaf":
|
|
5719
6044
|
case "label":
|
|
5720
6045
|
case "field":
|
|
5721
6046
|
case "optional":
|
|
@@ -5743,16 +6068,32 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5743
6068
|
return false;
|
|
5744
6069
|
}
|
|
5745
6070
|
}
|
|
6071
|
+
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
6072
|
+
if (seen.has(p)) return false;
|
|
6073
|
+
seen.add(p);
|
|
6074
|
+
const d = p._def;
|
|
6075
|
+
if (d.tag === "node" && d.build !== void 0) return true;
|
|
6076
|
+
if (d.tag === "lazy") {
|
|
6077
|
+
try {
|
|
6078
|
+
return hasDirectBuildDef(d.thunk(), seen);
|
|
6079
|
+
} catch {
|
|
6080
|
+
return false;
|
|
6081
|
+
}
|
|
6082
|
+
}
|
|
6083
|
+
return childrenOf(d).some((child) => hasDirectBuildDef(child, seen));
|
|
6084
|
+
}
|
|
5746
6085
|
function childrenOf(def) {
|
|
5747
6086
|
switch (def.tag) {
|
|
5748
6087
|
case "sequence":
|
|
5749
6088
|
case "choice":
|
|
5750
6089
|
return def.parsers;
|
|
5751
6090
|
case "many":
|
|
6091
|
+
case "attempt":
|
|
5752
6092
|
case "optional":
|
|
5753
6093
|
case "transform":
|
|
5754
6094
|
case "trivia":
|
|
5755
6095
|
case "token":
|
|
6096
|
+
case "leaf":
|
|
5756
6097
|
case "label":
|
|
5757
6098
|
case "field":
|
|
5758
6099
|
case "grammar":
|
|
@@ -5927,10 +6268,25 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5927
6268
|
namedFnDecls: [],
|
|
5928
6269
|
capturing: hasNodeDef(combinator),
|
|
5929
6270
|
recovery: opts?.recovery ?? false,
|
|
6271
|
+
...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
|
|
5930
6272
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5931
6273
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5932
6274
|
};
|
|
5933
6275
|
const r = emit(combinator, ctx, "_pos");
|
|
6276
|
+
const coverageRootRuleId = ctx.coverage?.plan.rules.get(combinator);
|
|
6277
|
+
const resultBody = coverageRootRuleId === void 0 ? [
|
|
6278
|
+
` let pos = _pos`,
|
|
6279
|
+
...r.stmts,
|
|
6280
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6281
|
+
] : [
|
|
6282
|
+
` const _coverageResult = (() => {`,
|
|
6283
|
+
` let pos = _pos`,
|
|
6284
|
+
...r.stmts,
|
|
6285
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6286
|
+
` })()`,
|
|
6287
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6288
|
+
` return _coverageResult`
|
|
6289
|
+
];
|
|
5934
6290
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
5935
6291
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
5936
6292
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
@@ -5943,9 +6299,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5943
6299
|
...namedPrelude,
|
|
5944
6300
|
ctx.namedFnDecls.join("\n\n"),
|
|
5945
6301
|
`function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
|
|
5946
|
-
|
|
5947
|
-
...r.stmts,
|
|
5948
|
-
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6302
|
+
...resultBody,
|
|
5949
6303
|
`}`
|
|
5950
6304
|
].join("\n");
|
|
5951
6305
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
@@ -5955,9 +6309,15 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5955
6309
|
...ctx.expectedDecls,
|
|
5956
6310
|
...namedPrelude,
|
|
5957
6311
|
...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
|
|
5958
|
-
`let pos = _pos`,
|
|
5959
|
-
|
|
5960
|
-
|
|
6312
|
+
...coverageRootRuleId === void 0 ? [`let pos = _pos`, ...r.stmts, `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`] : [
|
|
6313
|
+
`const _coverageResult = (() => {`,
|
|
6314
|
+
` let pos = _pos`,
|
|
6315
|
+
...r.stmts,
|
|
6316
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6317
|
+
`})()`,
|
|
6318
|
+
`if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6319
|
+
`return _coverageResult`
|
|
6320
|
+
]
|
|
5961
6321
|
].join("\n"));
|
|
5962
6322
|
const defaultCtx = {
|
|
5963
6323
|
trackLines: false,
|
|
@@ -5969,10 +6329,11 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5969
6329
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
5970
6330
|
const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
|
|
5971
6331
|
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
5972
|
-
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources) : null;
|
|
6332
|
+
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
|
|
5973
6333
|
return {
|
|
5974
6334
|
source,
|
|
5975
6335
|
inlineExpression,
|
|
6336
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
|
|
5976
6337
|
parse(input, pos = 0) {
|
|
5977
6338
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
|
|
5978
6339
|
},
|
|
@@ -6006,6 +6367,7 @@ function publicRuleWrapperSource(rule, fnSource) {
|
|
|
6006
6367
|
}
|
|
6007
6368
|
function compileRuleMap(ruleMap, opts) {
|
|
6008
6369
|
for (const [, rule] of ruleMap) markUnusedValues(rule);
|
|
6370
|
+
const coverageWinners = opts?.coverage ? Object.fromEntries(ruleMap.filter(([, rule]) => rule._def.tag !== "lazy")) : void 0;
|
|
6009
6371
|
const grammarTrivia = opts?.trivia;
|
|
6010
6372
|
const ctx = {
|
|
6011
6373
|
vars: 0,
|
|
@@ -6026,6 +6388,7 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
6026
6388
|
namedFnDecls: [],
|
|
6027
6389
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
6028
6390
|
recovery: opts?.recovery ?? false,
|
|
6391
|
+
...opts?.coverage ? { coverage: { plan: buildGrammarPlan(ruleMap.map(([, rule]) => rule), coverageWinners) } } : {},
|
|
6029
6392
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
6030
6393
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
6031
6394
|
};
|
|
@@ -6068,15 +6431,34 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
6068
6431
|
return i > 0 ? ["", ...lines] : lines;
|
|
6069
6432
|
})
|
|
6070
6433
|
].filter(Boolean);
|
|
6071
|
-
const
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6434
|
+
const entryRuleId = (rule) => {
|
|
6435
|
+
const direct = ctx.coverage?.plan.rules.get(rule);
|
|
6436
|
+
if (direct !== void 0 || rule._def.tag !== "lazy") return direct;
|
|
6437
|
+
try {
|
|
6438
|
+
return ctx.coverage?.plan.rules.get(rule._def.thunk());
|
|
6439
|
+
} catch {
|
|
6440
|
+
return void 0;
|
|
6441
|
+
}
|
|
6442
|
+
};
|
|
6443
|
+
const entryFnText = (r, rule) => {
|
|
6444
|
+
const ruleId = entryRuleId(rule);
|
|
6445
|
+
const body = ruleId === void 0 ? [
|
|
6446
|
+
` let pos = _pos`,
|
|
6447
|
+
...r.stmts,
|
|
6448
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6449
|
+
] : [
|
|
6450
|
+
` const _coverageResult = (() => {`,
|
|
6451
|
+
` let pos = _pos`,
|
|
6452
|
+
...r.stmts,
|
|
6453
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6454
|
+
` })()`,
|
|
6455
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6456
|
+
` return _coverageResult`
|
|
6457
|
+
];
|
|
6458
|
+
return [`function(input, _pos, _ctx) {`, ...body, `}`].join("\n");
|
|
6459
|
+
};
|
|
6078
6460
|
const objBody = perEntry.map(({ key, rule, r }) => {
|
|
6079
|
-
const src = publicRuleWrapperSource(rule, entryFnText(r));
|
|
6461
|
+
const src = publicRuleWrapperSource(rule, entryFnText(r, rule));
|
|
6080
6462
|
return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
|
|
6081
6463
|
}).join(",\n");
|
|
6082
6464
|
const replacement = [
|
|
@@ -6087,7 +6469,11 @@ function compileRuleMap(ruleMap, opts) {
|
|
|
6087
6469
|
` }`,
|
|
6088
6470
|
`})()`
|
|
6089
6471
|
].join("\n");
|
|
6090
|
-
return {
|
|
6472
|
+
return {
|
|
6473
|
+
keys: perEntry.map((e) => e.key),
|
|
6474
|
+
replacement,
|
|
6475
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions }
|
|
6476
|
+
};
|
|
6091
6477
|
}
|
|
6092
6478
|
function compileLinkable(ruleMapArg, ns, opts) {
|
|
6093
6479
|
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
@@ -6120,8 +6506,13 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6120
6506
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
6121
6507
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
6122
6508
|
namedFnDecls: [],
|
|
6123
|
-
|
|
6509
|
+
// A recognition-only fragment normally has no node collector of its own.
|
|
6510
|
+
// Leaf composition can re-lower it beneath a local semantic node, though;
|
|
6511
|
+
// in that case its terminals must feed the caller's collector rather than
|
|
6512
|
+
// merely returning their scalar parse values.
|
|
6513
|
+
capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
6124
6514
|
recovery: opts?.recovery ?? false,
|
|
6515
|
+
...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
|
|
6125
6516
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
6126
6517
|
ns,
|
|
6127
6518
|
deferFirstSetRefs: true,
|
|
@@ -6195,7 +6586,14 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6195
6586
|
ctx.indent = savedIndent;
|
|
6196
6587
|
ctx.failLabel = savedFail;
|
|
6197
6588
|
ctx.recordFail = savedRec;
|
|
6198
|
-
|
|
6589
|
+
const ruleId = ctx.coverage?.plan.rules.get(rule);
|
|
6590
|
+
const stmts = ruleId === void 0 ? body.stmts : [
|
|
6591
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
|
|
6592
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: _pos })`,
|
|
6593
|
+
...body.stmts,
|
|
6594
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: _pos, end: ${body.endVar} })`
|
|
6595
|
+
];
|
|
6596
|
+
pushNamedFnDecl(ctx, fn, stmts, body.valueVar, body.endVar);
|
|
6199
6597
|
}
|
|
6200
6598
|
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
6201
6599
|
}
|
|
@@ -6252,15 +6650,46 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6252
6650
|
deps: ruleDependencies(ruleMap),
|
|
6253
6651
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
6254
6652
|
needsHostReads: !!ctx.needsHostReads,
|
|
6653
|
+
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
6654
|
+
isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule)),
|
|
6255
6655
|
mfFns: mfSrcs ? [] : ctx.mapFns,
|
|
6256
6656
|
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
6257
6657
|
};
|
|
6258
6658
|
}
|
|
6259
|
-
function
|
|
6260
|
-
const
|
|
6659
|
+
function hasSemanticReduction(roots) {
|
|
6660
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6661
|
+
const visit = (parser2) => {
|
|
6662
|
+
if (seen.has(parser2)) return false;
|
|
6663
|
+
seen.add(parser2);
|
|
6664
|
+
const def = parser2._def;
|
|
6665
|
+
if (def.tag === "transform" && !def.recognitionOnly) return true;
|
|
6666
|
+
if (def.tag === "choice" && def.gates.some(Boolean)) return true;
|
|
6667
|
+
if (def.tag === "guard" || def.tag === "withCtx") return true;
|
|
6668
|
+
if (def.tag === "node" && def.build !== void 0) return true;
|
|
6669
|
+
if (def.tag === "lazy") {
|
|
6670
|
+
try {
|
|
6671
|
+
return visit(def.thunk());
|
|
6672
|
+
} catch {
|
|
6673
|
+
return true;
|
|
6674
|
+
}
|
|
6675
|
+
}
|
|
6676
|
+
return childrenOf(def).some(visit);
|
|
6677
|
+
};
|
|
6678
|
+
return roots.some(visit);
|
|
6679
|
+
}
|
|
6680
|
+
function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootRuleId) {
|
|
6681
|
+
const bodyLines = coverageRootRuleId === void 0 ? [
|
|
6261
6682
|
` let pos = _pos`,
|
|
6262
6683
|
...r.stmts,
|
|
6263
6684
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6685
|
+
] : [
|
|
6686
|
+
` const _coverageResult = (() => {`,
|
|
6687
|
+
` let pos = _pos`,
|
|
6688
|
+
...r.stmts,
|
|
6689
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6690
|
+
` })()`,
|
|
6691
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6692
|
+
` return _coverageResult`
|
|
6264
6693
|
];
|
|
6265
6694
|
const innerFn = [
|
|
6266
6695
|
`function(input, _pos, _ctx) {`,
|
|
@@ -6315,8 +6744,8 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
6315
6744
|
};
|
|
6316
6745
|
const emit2 = (end) => {
|
|
6317
6746
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
6318
|
-
const
|
|
6319
|
-
pushCstLeaf(ctx,
|
|
6747
|
+
const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
6748
|
+
pushCstLeaf(ctx, leaf2);
|
|
6320
6749
|
}
|
|
6321
6750
|
};
|
|
6322
6751
|
while (cur < input.length) {
|
|
@@ -6370,6 +6799,7 @@ function balanced(open, close, options = {}) {
|
|
|
6370
6799
|
);
|
|
6371
6800
|
if (combi._def.tag === "transform") {
|
|
6372
6801
|
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
6802
|
+
combi._def.recognitionOnly = true;
|
|
6373
6803
|
}
|
|
6374
6804
|
self.define(combi);
|
|
6375
6805
|
return combi;
|
|
@@ -6415,9 +6845,11 @@ function childrenOf2(def) {
|
|
|
6415
6845
|
case "many":
|
|
6416
6846
|
case "oneOrMore":
|
|
6417
6847
|
case "optional":
|
|
6848
|
+
case "attempt":
|
|
6418
6849
|
case "transform":
|
|
6419
6850
|
case "trivia":
|
|
6420
6851
|
case "token":
|
|
6852
|
+
case "leaf":
|
|
6421
6853
|
case "label":
|
|
6422
6854
|
case "field":
|
|
6423
6855
|
case "not":
|
|
@@ -6466,7 +6898,7 @@ function serializeRuleMap(ruleMap) {
|
|
|
6466
6898
|
}
|
|
6467
6899
|
}
|
|
6468
6900
|
function evalRuleMapIR(ir) {
|
|
6469
|
-
const _tf = (child, src) => {
|
|
6901
|
+
const _tf = (child, src, recognitionOnly = false) => {
|
|
6470
6902
|
let fn2;
|
|
6471
6903
|
try {
|
|
6472
6904
|
fn2 = (0, eval)(`(${src})`);
|
|
@@ -6477,8 +6909,22 @@ function evalRuleMapIR(ir) {
|
|
|
6477
6909
|
}
|
|
6478
6910
|
const t = transform(child, fn2);
|
|
6479
6911
|
t._def.fnSrc = src;
|
|
6912
|
+
if (recognitionOnly) t._def.recognitionOnly = true;
|
|
6480
6913
|
return t;
|
|
6481
6914
|
};
|
|
6915
|
+
const _lf = (child, src) => {
|
|
6916
|
+
let fn2;
|
|
6917
|
+
try {
|
|
6918
|
+
fn2 = (0, eval)(`(${src})`);
|
|
6919
|
+
} catch {
|
|
6920
|
+
fn2 = () => {
|
|
6921
|
+
throw new Error("IR leaf fn not materialized");
|
|
6922
|
+
};
|
|
6923
|
+
}
|
|
6924
|
+
const l = leaf(child, fn2);
|
|
6925
|
+
l._def.fnSrc = src;
|
|
6926
|
+
return l;
|
|
6927
|
+
};
|
|
6482
6928
|
const _nd = (type, child, src, opts, staticError) => {
|
|
6483
6929
|
if (staticError !== void 0 && staticError.length > 0) {
|
|
6484
6930
|
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
@@ -6537,6 +6983,7 @@ function evalRuleMapIR(ir) {
|
|
|
6537
6983
|
"keywords",
|
|
6538
6984
|
"sequence",
|
|
6539
6985
|
"choice",
|
|
6986
|
+
"attempt",
|
|
6540
6987
|
"many",
|
|
6541
6988
|
"oneOrMore",
|
|
6542
6989
|
"optional",
|
|
@@ -6546,6 +6993,7 @@ function evalRuleMapIR(ir) {
|
|
|
6546
6993
|
"parser",
|
|
6547
6994
|
"scanTo",
|
|
6548
6995
|
"token",
|
|
6996
|
+
"leaf",
|
|
6549
6997
|
"transform",
|
|
6550
6998
|
"skip",
|
|
6551
6999
|
"trivia",
|
|
@@ -6553,6 +7001,7 @@ function evalRuleMapIR(ir) {
|
|
|
6553
7001
|
"field",
|
|
6554
7002
|
"expect",
|
|
6555
7003
|
"_tf",
|
|
7004
|
+
"_lf",
|
|
6556
7005
|
"_nd",
|
|
6557
7006
|
"_gch",
|
|
6558
7007
|
"_wc",
|
|
@@ -6566,6 +7015,7 @@ function evalRuleMapIR(ir) {
|
|
|
6566
7015
|
keywords,
|
|
6567
7016
|
sequence,
|
|
6568
7017
|
choice,
|
|
7018
|
+
attempt,
|
|
6569
7019
|
many,
|
|
6570
7020
|
oneOrMore,
|
|
6571
7021
|
optional,
|
|
@@ -6575,6 +7025,7 @@ function evalRuleMapIR(ir) {
|
|
|
6575
7025
|
parser,
|
|
6576
7026
|
scanTo,
|
|
6577
7027
|
token,
|
|
7028
|
+
leaf,
|
|
6578
7029
|
transform,
|
|
6579
7030
|
skip,
|
|
6580
7031
|
trivia,
|
|
@@ -6582,6 +7033,7 @@ function evalRuleMapIR(ir) {
|
|
|
6582
7033
|
field,
|
|
6583
7034
|
expect,
|
|
6584
7035
|
_tf,
|
|
7036
|
+
_lf,
|
|
6585
7037
|
_nd,
|
|
6586
7038
|
_gch,
|
|
6587
7039
|
_wc
|
|
@@ -6713,6 +7165,8 @@ ${body}
|
|
|
6713
7165
|
return `oneOrMore(${kid(def.parser)})`;
|
|
6714
7166
|
case "optional":
|
|
6715
7167
|
return `optional(${kid(def.parser)})`;
|
|
7168
|
+
case "attempt":
|
|
7169
|
+
return `attempt(${kid(def.parser)})`;
|
|
6716
7170
|
case "sepBy":
|
|
6717
7171
|
return `sepBy(${kid(def.parser)}, ${kid(def.separator)})`;
|
|
6718
7172
|
case "not":
|
|
@@ -6721,6 +7175,10 @@ ${body}
|
|
|
6721
7175
|
return `trivia(${kid(def.parser)})`;
|
|
6722
7176
|
case "token":
|
|
6723
7177
|
return `token(${kid(def.parser)})`;
|
|
7178
|
+
case "leaf": {
|
|
7179
|
+
if (def.fnSrc === void 0) throw new Unserializable("leaf without fnSrc");
|
|
7180
|
+
return `_lf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7181
|
+
}
|
|
6724
7182
|
case "label":
|
|
6725
7183
|
return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
|
|
6726
7184
|
case "field":
|
|
@@ -6733,7 +7191,7 @@ ${body}
|
|
|
6733
7191
|
return `scanTo(${kid(def.sentinel)}, { skip: [${def.skip.map(kid).join(", ")}], orEOF: ${def.orEOF} })`;
|
|
6734
7192
|
case "transform": {
|
|
6735
7193
|
if (def.fnSrc === void 0) throw new Unserializable("transform without fnSrc");
|
|
6736
|
-
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7194
|
+
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)}${def.recognitionOnly ? ", true" : ""})`;
|
|
6737
7195
|
}
|
|
6738
7196
|
case "node": {
|
|
6739
7197
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
@@ -6779,15 +7237,15 @@ function normalizeCstCollapse(collapse) {
|
|
|
6779
7237
|
}
|
|
6780
7238
|
return typeof collapse === "function" ? collapse : void 0;
|
|
6781
7239
|
}
|
|
6782
|
-
function buildCstNode(type,
|
|
6783
|
-
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...
|
|
7240
|
+
function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
|
|
7241
|
+
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
|
|
6784
7242
|
}
|
|
6785
|
-
function cstBuildHost(typeOrOptions,
|
|
7243
|
+
function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
|
|
6786
7244
|
if (typeof typeOrOptions === "string") {
|
|
6787
|
-
return buildCstNode(typeOrOptions,
|
|
7245
|
+
return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
6788
7246
|
}
|
|
6789
7247
|
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
6790
|
-
const host = (type,
|
|
7248
|
+
const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3, fields, span2, rawChildren2, triviaLog2, state2);
|
|
6791
7249
|
host._parsemanCstOutput = true;
|
|
6792
7250
|
if (collapse) host._parsemanCstCollapse = collapse;
|
|
6793
7251
|
return host;
|
|
@@ -6870,9 +7328,12 @@ ${body}
|
|
|
6870
7328
|
function isIRPiece(p) {
|
|
6871
7329
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
6872
7330
|
}
|
|
6873
|
-
function materializePiece(p, trivia2) {
|
|
7331
|
+
function materializePiece(p, trivia2, captureTerminals = false) {
|
|
6874
7332
|
if (!isIRPiece(p)) return p;
|
|
6875
|
-
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns,
|
|
7333
|
+
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
|
|
7334
|
+
...trivia2 ? { trivia: trivia2 } : {},
|
|
7335
|
+
...captureTerminals ? { captureTerminals: true } : {}
|
|
7336
|
+
});
|
|
6876
7337
|
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
6877
7338
|
return pieces;
|
|
6878
7339
|
}
|
|
@@ -7101,6 +7562,7 @@ var SUPPORTED = {
|
|
|
7101
7562
|
word: (...a) => word(a[0], a[1]),
|
|
7102
7563
|
sequence: (...a) => sequence(...a),
|
|
7103
7564
|
choice: (...a) => choice(...a),
|
|
7565
|
+
attempt: (...a) => attempt(a[0]),
|
|
7104
7566
|
many: (...a) => many(a[0]),
|
|
7105
7567
|
oneOrMore: (...a) => oneOrMore(a[0]),
|
|
7106
7568
|
optional: (...a) => optional(a[0]),
|
|
@@ -7111,6 +7573,7 @@ var SUPPORTED = {
|
|
|
7111
7573
|
field: (...a) => field(a[0], a[1]),
|
|
7112
7574
|
noTrivia: (...a) => noTrivia(a[0]),
|
|
7113
7575
|
token: (...a) => token(a[0]),
|
|
7576
|
+
leaf: (...a) => leaf(a[0], a[1]),
|
|
7114
7577
|
expect: (...a) => expect(a[0], a[1])
|
|
7115
7578
|
};
|
|
7116
7579
|
function isScopeEntry(v2) {
|
|
@@ -7210,7 +7673,7 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
7210
7673
|
if (!parserArg || !fnArg || parserArg.type === "SpreadElement" || fnArg.type === "SpreadElement") return null;
|
|
7211
7674
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
7212
7675
|
if (!isCombinator(inner)) return null;
|
|
7213
|
-
const fnSrc =
|
|
7676
|
+
const fnSrc = stripTsFromSource(fnArg, code);
|
|
7214
7677
|
mfs.push(fnSrc);
|
|
7215
7678
|
try {
|
|
7216
7679
|
const combi = transform(inner, (v2) => v2);
|
|
@@ -7220,6 +7683,21 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
7220
7683
|
return null;
|
|
7221
7684
|
}
|
|
7222
7685
|
}
|
|
7686
|
+
if (callee.name === "leaf" && code !== void 0 && mfs !== void 0) {
|
|
7687
|
+
const [parserArg, fnArg] = node2.arguments;
|
|
7688
|
+
if (!parserArg || !fnArg || parserArg.type === "SpreadElement" || fnArg.type === "SpreadElement") return null;
|
|
7689
|
+
const inner = anyValue(parserArg, scope, code, mfs);
|
|
7690
|
+
if (!isCombinator(inner)) return null;
|
|
7691
|
+
const fnSrc = stripTsFromSource(fnArg, code);
|
|
7692
|
+
mfs.push(fnSrc);
|
|
7693
|
+
try {
|
|
7694
|
+
const combi = leaf(inner, (v2) => v2);
|
|
7695
|
+
if (combi._def.tag === "leaf") combi._def.fnSrc = fnSrc;
|
|
7696
|
+
return combi;
|
|
7697
|
+
} catch {
|
|
7698
|
+
return null;
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7223
7701
|
if (callee.name === "node" && code !== void 0) {
|
|
7224
7702
|
const [firstArg, secondArg, thirdArg, fourthArg] = node2.arguments;
|
|
7225
7703
|
if (!firstArg || firstArg.type === "SpreadElement") return null;
|
|
@@ -7672,6 +8150,63 @@ function getCompiledResolver() {
|
|
|
7672
8150
|
mainFields: ["module", "main"]
|
|
7673
8151
|
});
|
|
7674
8152
|
}
|
|
8153
|
+
var PRIVATE_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts"]);
|
|
8154
|
+
function nearestPackageRoot(file) {
|
|
8155
|
+
let dir = path.dirname(file);
|
|
8156
|
+
for (; ; ) {
|
|
8157
|
+
try {
|
|
8158
|
+
if (fs.statSync(path.join(dir, "package.json")).isFile()) return fs.realpathSync(dir);
|
|
8159
|
+
} catch {
|
|
8160
|
+
}
|
|
8161
|
+
const parent = path.dirname(dir);
|
|
8162
|
+
if (parent === dir) return null;
|
|
8163
|
+
dir = parent;
|
|
8164
|
+
}
|
|
8165
|
+
}
|
|
8166
|
+
function isWithinPackageRoot(file, root) {
|
|
8167
|
+
const relative2 = path.relative(root, file);
|
|
8168
|
+
return relative2 !== ".." && !relative2.startsWith(`..${path.sep}`) && !path.isAbsolute(relative2);
|
|
8169
|
+
}
|
|
8170
|
+
function resolvePrivateSourceModule(from, specifier) {
|
|
8171
|
+
if (!specifier.startsWith(".") && !path.isAbsolute(specifier)) return null;
|
|
8172
|
+
const packageRoot = nearestPackageRoot(from);
|
|
8173
|
+
if (!packageRoot) return null;
|
|
8174
|
+
const base = path.resolve(path.dirname(from), specifier);
|
|
8175
|
+
const ext = path.extname(base);
|
|
8176
|
+
const candidates = [
|
|
8177
|
+
base,
|
|
8178
|
+
...ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base.slice(0, -ext.length)}${next}`) : [],
|
|
8179
|
+
...!ext ? [".ts", ".tsx", ".mts", ".cts"].map((next) => `${base}${next}`) : [],
|
|
8180
|
+
...!ext ? ["index.ts", "index.tsx", "index.mts", "index.cts"].map((next) => path.join(base, next)) : []
|
|
8181
|
+
];
|
|
8182
|
+
for (const candidate of candidates) {
|
|
8183
|
+
try {
|
|
8184
|
+
if (!fs.statSync(candidate).isFile()) continue;
|
|
8185
|
+
const real = fs.realpathSync(candidate);
|
|
8186
|
+
if (isWithinPackageRoot(real, packageRoot)) return real;
|
|
8187
|
+
} catch {
|
|
8188
|
+
}
|
|
8189
|
+
}
|
|
8190
|
+
return null;
|
|
8191
|
+
}
|
|
8192
|
+
function resolveGrammarModule(from, specifier) {
|
|
8193
|
+
if (PRIVATE_SOURCE_EXTENSIONS.has(path.extname(specifier))) {
|
|
8194
|
+
const file2 = resolvePrivateSourceModule(from, specifier);
|
|
8195
|
+
return file2 ? { file: file2, source: true } : null;
|
|
8196
|
+
}
|
|
8197
|
+
try {
|
|
8198
|
+
const file2 = getCompiledResolver().resolveFileSync(from, specifier).path;
|
|
8199
|
+
if (file2) return { file: file2, source: false };
|
|
8200
|
+
} catch {
|
|
8201
|
+
}
|
|
8202
|
+
const file = resolvePrivateSourceModule(from, specifier);
|
|
8203
|
+
return file ? { file, source: true } : null;
|
|
8204
|
+
}
|
|
8205
|
+
var _sourceLowering = /* @__PURE__ */ new Set();
|
|
8206
|
+
var _sourceLoweringCache = /* @__PURE__ */ new Map();
|
|
8207
|
+
function sourceLoweringCacheKey(file, moduleAliases, warnUnloweredRegex, recovery) {
|
|
8208
|
+
return `${file}\0${[...moduleAliases].sort().join("\0")}\0${warnUnloweredRegex ? "warn" : ""}\0${recovery ? "recovery" : ""}`;
|
|
8209
|
+
}
|
|
7675
8210
|
var _moduleParseCache = /* @__PURE__ */ new Map();
|
|
7676
8211
|
function parseModuleCached(filePath) {
|
|
7677
8212
|
let mtimeMs;
|
|
@@ -7705,7 +8240,7 @@ var plugin_default = createUnplugin((opts = {}) => ({
|
|
|
7705
8240
|
if (!code.includes("parseman")) return null;
|
|
7706
8241
|
if (!code.includes("macro")) return null;
|
|
7707
8242
|
const moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE, ...opts.moduleAliases ?? []]);
|
|
7708
|
-
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true);
|
|
8243
|
+
const result = transformMacro(code, id, moduleAliases, opts.warnUnloweredRegex === true, opts.recovery === true, opts.grammarCoverage === true);
|
|
7709
8244
|
if (result?.warnings.length) {
|
|
7710
8245
|
for (const w of result.warnings) {
|
|
7711
8246
|
if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
|
|
@@ -7809,7 +8344,34 @@ function extractImportBindings(body) {
|
|
|
7809
8344
|
}
|
|
7810
8345
|
return out;
|
|
7811
8346
|
}
|
|
7812
|
-
function
|
|
8347
|
+
function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recovery) {
|
|
8348
|
+
if (_sourceLowering.has(file)) return null;
|
|
8349
|
+
let mtimeMs;
|
|
8350
|
+
try {
|
|
8351
|
+
mtimeMs = fs.statSync(file).mtimeMs;
|
|
8352
|
+
} catch {
|
|
8353
|
+
return null;
|
|
8354
|
+
}
|
|
8355
|
+
const cacheKey = sourceLoweringCacheKey(file, moduleAliases, warnUnloweredRegex, recovery);
|
|
8356
|
+
const hit = _sourceLoweringCache.get(cacheKey);
|
|
8357
|
+
if (hit && hit.mtimeMs === mtimeMs) return hit.parsed;
|
|
8358
|
+
_sourceLowering.add(file);
|
|
8359
|
+
let parsedModule = null;
|
|
8360
|
+
try {
|
|
8361
|
+
const source = fs.readFileSync(file, "utf8");
|
|
8362
|
+
const transformed = transformMacro(source, file, moduleAliases, warnUnloweredRegex, recovery);
|
|
8363
|
+
if (!transformed || transformed.warnings.length > 0) return null;
|
|
8364
|
+
const parsed = parseSync2(file, transformed.code);
|
|
8365
|
+
parsedModule = parsed.errors.length === 0 ? { body: parsed.program.body, src: transformed.code } : null;
|
|
8366
|
+
return parsedModule;
|
|
8367
|
+
} catch {
|
|
8368
|
+
return null;
|
|
8369
|
+
} finally {
|
|
8370
|
+
_sourceLoweringCache.set(cacheKey, { mtimeMs, parsed: parsedModule });
|
|
8371
|
+
_sourceLowering.delete(file);
|
|
8372
|
+
}
|
|
8373
|
+
}
|
|
8374
|
+
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE]), warnUnloweredRegex = false, recovery = false, grammarCoverage = false) {
|
|
7813
8375
|
let result;
|
|
7814
8376
|
try {
|
|
7815
8377
|
result = parseSync2(id, code);
|
|
@@ -7861,7 +8423,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7861
8423
|
anyUnresolved = true;
|
|
7862
8424
|
warnings.push(`${id}:${lineOf(pos)} \u2014 ${msg} (running via the interpreter; add the plugin or simplify the declaration to compile it)`);
|
|
7863
8425
|
};
|
|
7864
|
-
const
|
|
8426
|
+
const evaluateRulesFactory = (init, label2) => {
|
|
7865
8427
|
const args = init.arguments;
|
|
7866
8428
|
const arg0 = args[0];
|
|
7867
8429
|
const arg1 = args[1];
|
|
@@ -7881,15 +8443,21 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7881
8443
|
(p) => p.key?.name === "trivia"
|
|
7882
8444
|
)?.value : void 0;
|
|
7883
8445
|
const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
|
|
7884
|
-
|
|
8446
|
+
return { ruleMap, ...gTrivia ? { trivia: gTrivia } : {} };
|
|
8447
|
+
};
|
|
8448
|
+
const compileRulesFactory = (init, label2) => {
|
|
8449
|
+
const evaluated = evaluateRulesFactory(init, label2);
|
|
8450
|
+
if (!evaluated) return null;
|
|
8451
|
+
const compiled = compileRuleMap([...evaluated.ruleMap], { ...evaluated.trivia ? { trivia: evaluated.trivia } : {}, recovery, coverage: grammarCoverage });
|
|
7885
8452
|
if (!compiled) {
|
|
7886
8453
|
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
7887
8454
|
return null;
|
|
7888
8455
|
}
|
|
7889
|
-
return { replacement: compiled.replacement, ruleMap, ...
|
|
8456
|
+
return { replacement: compiled.replacement, ruleMap: evaluated.ruleMap, ...compiled.coverageDefinitions ? { coverageDefinitions: compiled.coverageDefinitions } : {}, ...evaluated.trivia ? { trivia: evaluated.trivia } : {} };
|
|
7890
8457
|
};
|
|
7891
8458
|
const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
|
|
7892
8459
|
const isComposeCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "compose";
|
|
8460
|
+
const isComposeLeafCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "composeLeaf";
|
|
7893
8461
|
const isPickCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "pick";
|
|
7894
8462
|
const localRuleMaps = /* @__PURE__ */ new Map();
|
|
7895
8463
|
const localGrammarTrivia = /* @__PURE__ */ new Map();
|
|
@@ -7899,18 +8467,29 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7899
8467
|
const mapLit = (m, stripVals = false) => `new Map([${[...m].map(
|
|
7900
8468
|
([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(stripVals && typeof v2 === "string" ? stripIndent(v2) : v2)}]`
|
|
7901
8469
|
).join(", ")}])`;
|
|
7902
|
-
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: [] }`;
|
|
8470
|
+
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: [] }`;
|
|
7903
8471
|
};
|
|
7904
8472
|
const isSpread = (it) => "__spreadLocal" in it;
|
|
7905
8473
|
const isIR = (it) => "ir" in it && !("ruleFns" in it);
|
|
7906
8474
|
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);
|
|
7907
8475
|
const serializeList = (list) => `[${list.map(serializeItem).join(", ")}]`;
|
|
7908
8476
|
const withCarriedPieces = (grammarExpr, list) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.composedPieces'), { value: ${serializeList(list)}, enumerable: false })`;
|
|
8477
|
+
const withLeafMarker = (grammarExpr) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.leafComposed'), { value: true, enumerable: false })`;
|
|
8478
|
+
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 })`;
|
|
8479
|
+
const emittedCoverageDefinitions = (source) => {
|
|
8480
|
+
const ids = /* @__PURE__ */ new Set();
|
|
8481
|
+
for (const match of source.matchAll(/id:\s*"([^"]+)"/g)) ids.add(match[1]);
|
|
8482
|
+
return [...ids].sort().map((id2) => ({
|
|
8483
|
+
id: id2,
|
|
8484
|
+
kind: id2.startsWith("rule:") ? "rule" : id2.startsWith("label:") ? "label" : "choice-arm"
|
|
8485
|
+
}));
|
|
8486
|
+
};
|
|
7909
8487
|
const localComposedCarried = /* @__PURE__ */ new Map();
|
|
7910
8488
|
const localComposedTrivia = /* @__PURE__ */ new Map();
|
|
7911
8489
|
const importedPiecesCache = /* @__PURE__ */ new Map();
|
|
7912
|
-
const resolveModulePieces = (
|
|
7913
|
-
const
|
|
8490
|
+
const resolveModulePieces = (module, exportName, seen) => {
|
|
8491
|
+
const { file } = module;
|
|
8492
|
+
const mod = module.source ? lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recovery) : parseModuleCached(file);
|
|
7914
8493
|
if (!mod) return null;
|
|
7915
8494
|
const localFor = exportLocalName(mod.body, exportName);
|
|
7916
8495
|
const initNode = localFor ? topLevelInit(mod.body, localFor) : null;
|
|
@@ -7929,12 +8508,10 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7929
8508
|
const b = imports.get(local);
|
|
7930
8509
|
let subPieces = [];
|
|
7931
8510
|
if (b) {
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
} catch {
|
|
8511
|
+
const subModule = resolveGrammarModule(file, b.source);
|
|
8512
|
+
if (subModule && !seen.has(subModule.file)) {
|
|
8513
|
+
subPieces = resolveModulePieces(subModule, b.imported, new Set(seen).add(subModule.file)) ?? [];
|
|
7936
8514
|
}
|
|
7937
|
-
if (subFile && !seen.has(subFile)) subPieces = resolveModulePieces(subFile, b.imported, new Set(seen).add(subFile)) ?? [];
|
|
7938
8515
|
}
|
|
7939
8516
|
stubNames.push(local);
|
|
7940
8517
|
stubVals.push({ [/* @__PURE__ */ Symbol.for("parseman.composedPieces")]: subPieces });
|
|
@@ -7951,29 +8528,56 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
7951
8528
|
let result2 = null;
|
|
7952
8529
|
const binding = importBindings.get(localName);
|
|
7953
8530
|
if (binding) {
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
file = getCompiledResolver().resolveFileSync(id, binding.source).path ?? null;
|
|
7957
|
-
} catch {
|
|
7958
|
-
}
|
|
7959
|
-
result2 = file ? resolveModulePieces(file, binding.imported, /* @__PURE__ */ new Set([file])) : null;
|
|
8531
|
+
const module = resolveGrammarModule(id, binding.source);
|
|
8532
|
+
result2 = module ? resolveModulePieces(module, binding.imported, /* @__PURE__ */ new Set([module.file])) : null;
|
|
7960
8533
|
}
|
|
7961
8534
|
importedPiecesCache.set(localName, result2);
|
|
7962
8535
|
return result2;
|
|
7963
8536
|
};
|
|
7964
|
-
const materializeCarried = (items, composing) => {
|
|
8537
|
+
const materializeCarried = (items, composing, captureTerminals = false) => {
|
|
7965
8538
|
const out = [];
|
|
7966
8539
|
for (const it of items) {
|
|
7967
8540
|
if (isSpread(it)) {
|
|
7968
|
-
for (const p of importedPieces(it.__spreadLocal) ?? []) out.push(materializePiece(p, composing));
|
|
8541
|
+
for (const p of importedPieces(it.__spreadLocal) ?? []) out.push(materializePiece(p, composing, captureTerminals));
|
|
7969
8542
|
} else if (isIR(it)) {
|
|
7970
|
-
out.push(materializePiece(it, composing));
|
|
8543
|
+
out.push(materializePiece(it, composing, captureTerminals));
|
|
7971
8544
|
} else {
|
|
7972
8545
|
out.push(it);
|
|
7973
8546
|
}
|
|
7974
8547
|
}
|
|
7975
8548
|
return out;
|
|
7976
8549
|
};
|
|
8550
|
+
const materializeLeafCoverage = (items, localRules, localNs, composing, captureTerminals = false) => {
|
|
8551
|
+
const sources = [];
|
|
8552
|
+
const add = (item) => {
|
|
8553
|
+
if (!isIR(item)) return false;
|
|
8554
|
+
sources.push({ ns: item.ns, rules: evalRuleMapIR(item.ir) });
|
|
8555
|
+
return true;
|
|
8556
|
+
};
|
|
8557
|
+
for (const item of items) {
|
|
8558
|
+
if (isSpread(item)) {
|
|
8559
|
+
const imported = importedPieces(item.__spreadLocal);
|
|
8560
|
+
if (!imported || !imported.every(add)) return null;
|
|
8561
|
+
} else if (!add(item)) return null;
|
|
8562
|
+
}
|
|
8563
|
+
sources.push({ ns: localNs, rules: [...localRules] });
|
|
8564
|
+
const winners = {};
|
|
8565
|
+
for (const source of sources) for (const [name, rule] of source.rules) winners[name] = rule;
|
|
8566
|
+
const plan = buildGrammarPlan(Object.values(winners), winners);
|
|
8567
|
+
const pieces = [];
|
|
8568
|
+
for (let index = 0; index < sources.length; index++) {
|
|
8569
|
+
const source = sources[index];
|
|
8570
|
+
const piece = compileLinkable(source.rules, source.ns, {
|
|
8571
|
+
...composing ? { trivia: composing } : {},
|
|
8572
|
+
recovery,
|
|
8573
|
+
...index < sources.length - 1 && captureTerminals ? { captureTerminals: true } : {},
|
|
8574
|
+
coverage: plan
|
|
8575
|
+
});
|
|
8576
|
+
if (!piece) return null;
|
|
8577
|
+
pieces.push(piece);
|
|
8578
|
+
}
|
|
8579
|
+
return pieces;
|
|
8580
|
+
};
|
|
7977
8581
|
const localCarried = (rm, label2, composing) => {
|
|
7978
8582
|
const entries = [...rm];
|
|
7979
8583
|
const ns = nsFor(label2);
|
|
@@ -8089,6 +8693,64 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8089
8693
|
return null;
|
|
8090
8694
|
}
|
|
8091
8695
|
};
|
|
8696
|
+
const compileComposeLeafCall = (init) => {
|
|
8697
|
+
const args = init.arguments;
|
|
8698
|
+
const arr = args[0];
|
|
8699
|
+
if (!arr || arr.type !== "ArrayExpression") {
|
|
8700
|
+
warn(init.start, "composeLeaf(): expected a static array of grammars");
|
|
8701
|
+
return null;
|
|
8702
|
+
}
|
|
8703
|
+
const elements = arr.elements;
|
|
8704
|
+
if (elements.length < 2) {
|
|
8705
|
+
warn(init.start, "composeLeaf(): needs imported recognition grammar(s) and one local rules() map");
|
|
8706
|
+
return null;
|
|
8707
|
+
}
|
|
8708
|
+
const localArg = elements[elements.length - 1];
|
|
8709
|
+
let localRules = null;
|
|
8710
|
+
if (isRulesCall(localArg)) {
|
|
8711
|
+
const evaluated = evaluateRulesFactory(localArg, `composeLeaf${init.start}`);
|
|
8712
|
+
localRules = evaluated?.ruleMap ?? null;
|
|
8713
|
+
} else if (localArg.type === "Identifier") {
|
|
8714
|
+
localRules = localRuleMaps.get(localArg.name) ?? null;
|
|
8715
|
+
}
|
|
8716
|
+
if (!localRules) {
|
|
8717
|
+
warn(init.start, "composeLeaf(): final argument must be a local rules() map");
|
|
8718
|
+
return null;
|
|
8719
|
+
}
|
|
8720
|
+
const composing = composingTrivia(elements);
|
|
8721
|
+
const carried = [];
|
|
8722
|
+
for (let i = 0; i < elements.length - 1; i++) {
|
|
8723
|
+
const r = argPieces(elements[i], `composeLeaf${init.start}_${i}`, composing);
|
|
8724
|
+
if (!r) {
|
|
8725
|
+
warn(init.start, `composeLeaf(): argument ${i} isn't a build-resolvable recognition grammar`);
|
|
8726
|
+
return null;
|
|
8727
|
+
}
|
|
8728
|
+
carried.push(...r.carried);
|
|
8729
|
+
}
|
|
8730
|
+
try {
|
|
8731
|
+
const localNs = nsFor(`composeLeaf${init.start}`);
|
|
8732
|
+
const plainLocalPiece = compileLinkable([...localRules], localNs, { ...composing ? { trivia: composing } : {}, recovery });
|
|
8733
|
+
if (!plainLocalPiece) {
|
|
8734
|
+
warn(init.start, "composeLeaf(): local rules could not be statically compiled");
|
|
8735
|
+
return null;
|
|
8736
|
+
}
|
|
8737
|
+
const recognitionPieces = grammarCoverage ? materializeLeafCoverage(carried, localRules, localNs, composing, plainLocalPiece.hasDirectBuilders === true) : materializeCarried(carried, composing, plainLocalPiece.hasDirectBuilders === true);
|
|
8738
|
+
if (!recognitionPieces) {
|
|
8739
|
+
warn(init.start, "composeLeaf(): coverage needs re-lowerable recognition IR");
|
|
8740
|
+
return null;
|
|
8741
|
+
}
|
|
8742
|
+
const importedRecognitionPieces = grammarCoverage ? recognitionPieces.slice(0, -1) : recognitionPieces;
|
|
8743
|
+
if (importedRecognitionPieces.some((piece) => piece.hasDirectBuilders !== false || piece.isRecognitionOnly !== true)) {
|
|
8744
|
+
warn(init.start, "composeLeaf(): every pre-final grammar must explicitly prove recognition-only");
|
|
8745
|
+
return null;
|
|
8746
|
+
}
|
|
8747
|
+
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
|
|
8748
|
+
return { replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) };
|
|
8749
|
+
} catch (e) {
|
|
8750
|
+
warn(init.start, `composeLeaf(): ${e.message}`);
|
|
8751
|
+
return null;
|
|
8752
|
+
}
|
|
8753
|
+
};
|
|
8092
8754
|
const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
|
|
8093
8755
|
const refNames = /* @__PURE__ */ new Set();
|
|
8094
8756
|
for (const stmt of body) {
|
|
@@ -8155,7 +8817,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8155
8817
|
const refEntry = scope.get(varName);
|
|
8156
8818
|
const refCombi = refEntry?.combi ?? null;
|
|
8157
8819
|
if (refCombi) {
|
|
8158
|
-
const compiled2 = compile(refCombi, void 0, { recovery });
|
|
8820
|
+
const compiled2 = compile(refCombi, void 0, { recovery, coverage: grammarCoverage });
|
|
8159
8821
|
if (compiled2.inlineExpression === null) {
|
|
8160
8822
|
warn(init.start, `"${varName}" is a ref() that couldn't be inlined (was .define() called with a static combinator?)`);
|
|
8161
8823
|
continue;
|
|
@@ -8169,7 +8831,10 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8169
8831
|
if (!compiledRules) continue;
|
|
8170
8832
|
localRuleMaps.set(varName, compiledRules.ruleMap);
|
|
8171
8833
|
if (compiledRules.trivia) localGrammarTrivia.set(varName, compiledRules.trivia);
|
|
8172
|
-
let replacement =
|
|
8834
|
+
let replacement = withCoverageDefinitions(
|
|
8835
|
+
compiledRules.replacement,
|
|
8836
|
+
compiledRules.coverageDefinitions?.length ? compiledRules.coverageDefinitions : emittedCoverageDefinitions(compiledRules.replacement)
|
|
8837
|
+
);
|
|
8173
8838
|
if (exportPrefix) {
|
|
8174
8839
|
const ns = nsFor(varName);
|
|
8175
8840
|
const pieces = compileLinkable([...compiledRules.ruleMap], ns, { recovery });
|
|
@@ -8190,7 +8855,15 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8190
8855
|
localComposedCarried.set(varName, fused.carried);
|
|
8191
8856
|
if (fused.trivia) localComposedTrivia.set(varName, fused.trivia);
|
|
8192
8857
|
const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.carried) : fused.replacement;
|
|
8193
|
-
replacements.push({ start: init.start, end: init.end, replacement });
|
|
8858
|
+
replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) });
|
|
8859
|
+
continue;
|
|
8860
|
+
}
|
|
8861
|
+
if (isComposeLeafCall(init)) {
|
|
8862
|
+
const fused = compileComposeLeafCall(init);
|
|
8863
|
+
if (!fused) {
|
|
8864
|
+
throw new Error(`${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden`);
|
|
8865
|
+
}
|
|
8866
|
+
replacements.push({ start: init.start, end: init.end, replacement: fused.replacement });
|
|
8194
8867
|
continue;
|
|
8195
8868
|
}
|
|
8196
8869
|
const mapFnSources = [];
|
|
@@ -8211,7 +8884,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
8211
8884
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
8212
8885
|
continue;
|
|
8213
8886
|
}
|
|
8214
|
-
const compiled = compile(parser2, void 0, { recovery });
|
|
8887
|
+
const compiled = compile(parser2, void 0, { recovery, coverage: grammarCoverage });
|
|
8215
8888
|
if (compiled.inlineExpression === null) {
|
|
8216
8889
|
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
8217
8890
|
continue;
|