parseman 0.27.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/combinators/attempt.d.ts +8 -0
- package/dist/combinators/attempt.d.ts.map +1 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/combinators/token.d.ts +12 -0
- package/dist/combinators/token.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts +8 -4
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +12 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts +19 -0
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -0
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +12 -1
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts +68 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/functional/run.d.ts +13 -0
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +816 -77
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +816 -77
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +4 -1
- package/dist/language-service/index.cjs.map +2 -2
- package/dist/language-service/index.js +4 -1
- package/dist/language-service/index.js.map +2 -2
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +786 -113
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts +4 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +786 -113
- package/dist/plugin/index.js.map +4 -4
- package/dist/spec/index.cjs +3 -0
- package/dist/spec/index.cjs.map +2 -2
- package/dist/spec/index.js +3 -0
- package/dist/spec/index.js.map +2 -2
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
GRAMMAR_COVERAGE_DEFINITIONS: () => GRAMMAR_COVERAGE_DEFINITIONS,
|
|
23
24
|
OffsetIndex: () => OffsetIndex,
|
|
24
25
|
absoluteSpanAt: () => absoluteSpanAt,
|
|
25
26
|
absoluteSpanCST: () => absoluteSpanCST,
|
|
@@ -27,6 +28,7 @@ __export(index_exports, {
|
|
|
27
28
|
absolutizeCST: () => absolutizeCST,
|
|
28
29
|
annotateSpan: () => annotateSpan,
|
|
29
30
|
applyEdit: () => applyEdit,
|
|
31
|
+
attempt: () => attempt,
|
|
30
32
|
balanced: () => balanced,
|
|
31
33
|
blankLinesIn: () => blankLinesIn,
|
|
32
34
|
buildLineIndex: () => buildLineIndex,
|
|
@@ -36,20 +38,28 @@ __export(index_exports, {
|
|
|
36
38
|
collectLeafSlots: () => collectLeafSlots,
|
|
37
39
|
commentsIn: () => commentsIn,
|
|
38
40
|
compile: () => compile,
|
|
41
|
+
compiledGrammarCoverageDefinitions: () => compiledGrammarCoverageDefinitions,
|
|
39
42
|
completionsAt: () => completionsAt,
|
|
40
43
|
compose: () => compose,
|
|
44
|
+
composeLeaf: () => composeLeaf,
|
|
45
|
+
composedGrammarCoverageDefinitions: () => composedGrammarCoverageDefinitions,
|
|
46
|
+
createGrammarCoverageCollector: () => createGrammarCoverageCollector,
|
|
47
|
+
createGrammarInstrumentationContext: () => createGrammarInstrumentationContext,
|
|
48
|
+
createGrammarTraceSink: () => createGrammarTraceSink,
|
|
41
49
|
createVisitor: () => createVisitor,
|
|
42
50
|
cstBuildHost: () => cstBuildHost,
|
|
43
51
|
expect: () => expect,
|
|
44
52
|
field: () => field,
|
|
45
53
|
gapIsSignificant: () => gapIsSignificant,
|
|
46
54
|
gapText: () => gapText,
|
|
55
|
+
grammarCoverageDefinitions: () => grammarCoverageDefinitions,
|
|
47
56
|
guard: () => guard,
|
|
48
57
|
indentMixed: () => indentMixed,
|
|
49
58
|
indentWidth: () => indentWidth,
|
|
50
59
|
isParseError: () => isParseError,
|
|
51
60
|
keywords: () => keywords,
|
|
52
61
|
label: () => label,
|
|
62
|
+
leaf: () => leaf,
|
|
53
63
|
lineBreaksIn: () => lineBreaksIn,
|
|
54
64
|
lineStartWithin: () => lineStartWithin,
|
|
55
65
|
literal: () => literal,
|
|
@@ -70,6 +80,7 @@ __export(index_exports, {
|
|
|
70
80
|
relativizeCST: () => relativizeCST,
|
|
71
81
|
rules: () => rules,
|
|
72
82
|
run: () => run,
|
|
83
|
+
runWithGrammarCoverage: () => runWithGrammarCoverage,
|
|
73
84
|
scanTo: () => scanTo,
|
|
74
85
|
sepBy: () => sepBy,
|
|
75
86
|
sequence: () => sequence,
|
|
@@ -147,6 +158,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
147
158
|
case "label":
|
|
148
159
|
case "trivia":
|
|
149
160
|
case "token":
|
|
161
|
+
case "leaf":
|
|
150
162
|
case "expect":
|
|
151
163
|
case "withCtx":
|
|
152
164
|
case "node":
|
|
@@ -210,6 +222,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
210
222
|
case "label":
|
|
211
223
|
case "trivia":
|
|
212
224
|
case "token":
|
|
225
|
+
case "leaf":
|
|
213
226
|
case "node":
|
|
214
227
|
case "grammar":
|
|
215
228
|
case "expect":
|
|
@@ -278,10 +291,10 @@ function beginCstNodeCapture(ctx) {
|
|
|
278
291
|
}
|
|
279
292
|
function finishCstBuf(buf) {
|
|
280
293
|
if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
|
|
281
|
-
const
|
|
294
|
+
const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
|
|
282
295
|
const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
|
|
283
296
|
const triviaLog = buf.tl ?? EMPTY_TL;
|
|
284
|
-
return { children, rawChildren, triviaLog };
|
|
297
|
+
return { children: children2, rawChildren, triviaLog };
|
|
285
298
|
}
|
|
286
299
|
function endCstNodeCapture(ctx, saved) {
|
|
287
300
|
const materialized = finishCstBuf(ctx._cstBuf);
|
|
@@ -293,8 +306,8 @@ function endCstNodeCapture(ctx, saved) {
|
|
|
293
306
|
ctx.captureTrivia = saved.cap;
|
|
294
307
|
return materialized;
|
|
295
308
|
}
|
|
296
|
-
function pushCstLeaf(ctx,
|
|
297
|
-
pushCstChild(ctx,
|
|
309
|
+
function pushCstLeaf(ctx, leaf2) {
|
|
310
|
+
pushCstChild(ctx, leaf2, leaf2);
|
|
298
311
|
}
|
|
299
312
|
function pushCstChild(ctx, built, rawEntry) {
|
|
300
313
|
const b = ctx._cstBuf;
|
|
@@ -1028,10 +1041,13 @@ function deriveExpected(c) {
|
|
|
1028
1041
|
return def.parsers.flatMap(deriveExpected);
|
|
1029
1042
|
case "sequence":
|
|
1030
1043
|
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1044
|
+
case "attempt":
|
|
1045
|
+
return deriveExpected(def.parser);
|
|
1031
1046
|
case "node":
|
|
1032
1047
|
case "grammar":
|
|
1033
1048
|
case "trivia":
|
|
1034
1049
|
case "token":
|
|
1050
|
+
case "leaf":
|
|
1035
1051
|
case "optional":
|
|
1036
1052
|
case "many":
|
|
1037
1053
|
case "oneOrMore":
|
|
@@ -1809,6 +1825,24 @@ function sequence(...parsers) {
|
|
|
1809
1825
|
};
|
|
1810
1826
|
}
|
|
1811
1827
|
|
|
1828
|
+
// src/combinators/attempt.ts
|
|
1829
|
+
function attempt(parser2) {
|
|
1830
|
+
return {
|
|
1831
|
+
_tag: "attempt",
|
|
1832
|
+
_meta: parser2._meta,
|
|
1833
|
+
_def: { tag: "attempt", parser: parser2 },
|
|
1834
|
+
parse(input, pos, ctx) {
|
|
1835
|
+
const mark = saveCstMark(ctx);
|
|
1836
|
+
const log = ctx._triviaLog?.length;
|
|
1837
|
+
const result = parser2.parse(input, pos, ctx);
|
|
1838
|
+
if (result.ok) return result;
|
|
1839
|
+
rollbackCstCapture(ctx, mark);
|
|
1840
|
+
if (log !== void 0 && ctx._triviaLog) ctx._triviaLog.length = log;
|
|
1841
|
+
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
1842
|
+
}
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1812
1846
|
// src/combinators/repeat.ts
|
|
1813
1847
|
function repItem(combinator, input, cur, ctx) {
|
|
1814
1848
|
const mark = saveTriviaMark(ctx);
|
|
@@ -2118,10 +2152,14 @@ function markUnusedValues(root) {
|
|
|
2118
2152
|
case "label":
|
|
2119
2153
|
case "trivia":
|
|
2120
2154
|
case "token":
|
|
2155
|
+
case "attempt":
|
|
2121
2156
|
case "withCtx":
|
|
2122
2157
|
case "expect":
|
|
2123
2158
|
visit(def.parser, consumed);
|
|
2124
2159
|
return;
|
|
2160
|
+
case "leaf":
|
|
2161
|
+
visit(def.parser, true);
|
|
2162
|
+
return;
|
|
2125
2163
|
case "lazy":
|
|
2126
2164
|
return;
|
|
2127
2165
|
default:
|
|
@@ -2244,6 +2282,20 @@ function confirmedBuildArity(src) {
|
|
|
2244
2282
|
if (/\barguments\b/.test(s)) return null;
|
|
2245
2283
|
return parts.length;
|
|
2246
2284
|
}
|
|
2285
|
+
function buildReadsChildren(def) {
|
|
2286
|
+
if (!def.build) return true;
|
|
2287
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2288
|
+
const arity = confirmedBuildArity(src);
|
|
2289
|
+
if (arity === null) return true;
|
|
2290
|
+
return arity >= 1;
|
|
2291
|
+
}
|
|
2292
|
+
function buildReadsRaw(def) {
|
|
2293
|
+
if (!def.build) return true;
|
|
2294
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2295
|
+
const arity = confirmedBuildArity(src);
|
|
2296
|
+
if (arity === null) return true;
|
|
2297
|
+
return arity >= 4;
|
|
2298
|
+
}
|
|
2247
2299
|
function buildReadsTrivia(def) {
|
|
2248
2300
|
if (!def.build) return true;
|
|
2249
2301
|
const src = def.buildSrc ?? def.build.toString();
|
|
@@ -2299,9 +2351,11 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2299
2351
|
case "many":
|
|
2300
2352
|
case "oneOrMore":
|
|
2301
2353
|
case "optional":
|
|
2354
|
+
case "attempt":
|
|
2302
2355
|
case "transform":
|
|
2303
2356
|
case "trivia":
|
|
2304
2357
|
case "token":
|
|
2358
|
+
case "leaf":
|
|
2305
2359
|
case "label":
|
|
2306
2360
|
case "expect":
|
|
2307
2361
|
case "withCtx":
|
|
@@ -2334,9 +2388,11 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2334
2388
|
case "keywords":
|
|
2335
2389
|
case "guard":
|
|
2336
2390
|
case "token":
|
|
2391
|
+
case "leaf":
|
|
2337
2392
|
return false;
|
|
2338
2393
|
// Transparent single-child wrappers: recurse.
|
|
2339
2394
|
case "optional":
|
|
2395
|
+
case "attempt":
|
|
2340
2396
|
case "transform":
|
|
2341
2397
|
case "trivia":
|
|
2342
2398
|
case "label":
|
|
@@ -2383,6 +2439,7 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2383
2439
|
case "many":
|
|
2384
2440
|
case "oneOrMore":
|
|
2385
2441
|
case "optional":
|
|
2442
|
+
case "attempt":
|
|
2386
2443
|
case "transform":
|
|
2387
2444
|
case "trivia":
|
|
2388
2445
|
case "token":
|
|
@@ -2392,6 +2449,10 @@ function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2392
2449
|
case "withCtx":
|
|
2393
2450
|
case "not":
|
|
2394
2451
|
return parserEnablesTriviaCapture(d.parser, seen);
|
|
2452
|
+
// leaf() clears the inner CST/trivia collector and publishes only its own
|
|
2453
|
+
// terminal result. An inner parser() capture cannot reach this node.
|
|
2454
|
+
case "leaf":
|
|
2455
|
+
return false;
|
|
2395
2456
|
case "lazy": {
|
|
2396
2457
|
try {
|
|
2397
2458
|
return parserEnablesTriviaCapture(d.thunk(), seen);
|
|
@@ -2470,12 +2531,12 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2470
2531
|
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
2471
2532
|
ctx._fields = savedFields;
|
|
2472
2533
|
ctx._triviaCaptureMask = savedMask;
|
|
2473
|
-
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2534
|
+
const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2474
2535
|
if (!r.ok) return r;
|
|
2475
2536
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2476
2537
|
const nodeType = def.type ?? missingInferredType();
|
|
2477
2538
|
const cstOutput = ctx.build?._parsemanCstOutput === true;
|
|
2478
|
-
const built = unwrap &&
|
|
2539
|
+
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 };
|
|
2479
2540
|
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 };
|
|
2480
2541
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2481
2542
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -2706,6 +2767,141 @@ function token(root) {
|
|
|
2706
2767
|
}
|
|
2707
2768
|
};
|
|
2708
2769
|
}
|
|
2770
|
+
function leaf(root, fn) {
|
|
2771
|
+
const meta = {
|
|
2772
|
+
firstSet: root._meta.firstSet,
|
|
2773
|
+
canMatchNewline: root._meta.canMatchNewline,
|
|
2774
|
+
isTrivia: false
|
|
2775
|
+
};
|
|
2776
|
+
return {
|
|
2777
|
+
_tag: "leaf",
|
|
2778
|
+
_meta: meta,
|
|
2779
|
+
_def: { tag: "leaf", parser: root, fn },
|
|
2780
|
+
parse(input, pos, ctx) {
|
|
2781
|
+
const savedBuf = ctx._cstBuf;
|
|
2782
|
+
const savedChildren = ctx._cstChildren;
|
|
2783
|
+
const savedLeaves = ctx._cstLeaves;
|
|
2784
|
+
const savedRaw = ctx._cstRawChildren;
|
|
2785
|
+
const savedTriviaLog = ctx._cstTriviaLog;
|
|
2786
|
+
const savedOuterTriviaLog = ctx._triviaLog;
|
|
2787
|
+
const wasCapturing = cstCaptureActive(ctx);
|
|
2788
|
+
ctx._cstBuf = void 0;
|
|
2789
|
+
ctx._cstChildren = void 0;
|
|
2790
|
+
ctx._cstLeaves = void 0;
|
|
2791
|
+
ctx._cstRawChildren = void 0;
|
|
2792
|
+
ctx._cstTriviaLog = void 0;
|
|
2793
|
+
delete ctx._triviaLog;
|
|
2794
|
+
let result;
|
|
2795
|
+
try {
|
|
2796
|
+
result = root.parse(input, pos, ctx);
|
|
2797
|
+
} finally {
|
|
2798
|
+
ctx._cstBuf = savedBuf;
|
|
2799
|
+
ctx._cstChildren = savedChildren;
|
|
2800
|
+
ctx._cstLeaves = savedLeaves;
|
|
2801
|
+
ctx._cstRawChildren = savedRaw;
|
|
2802
|
+
ctx._cstTriviaLog = savedTriviaLog;
|
|
2803
|
+
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
2804
|
+
else ctx._triviaLog = savedOuterTriviaLog;
|
|
2805
|
+
}
|
|
2806
|
+
if (!result.ok) return result;
|
|
2807
|
+
const value = fn(result.value, result.span);
|
|
2808
|
+
if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span: result.span });
|
|
2809
|
+
return { ok: true, value, span: result.span };
|
|
2810
|
+
}
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
// src/compiler/grammar-coverage-ids.ts
|
|
2815
|
+
function children(def, winners) {
|
|
2816
|
+
switch (def.tag) {
|
|
2817
|
+
case "sequence":
|
|
2818
|
+
case "choice":
|
|
2819
|
+
return def.parsers;
|
|
2820
|
+
case "many":
|
|
2821
|
+
case "oneOrMore":
|
|
2822
|
+
case "optional":
|
|
2823
|
+
case "attempt":
|
|
2824
|
+
case "transform":
|
|
2825
|
+
case "trivia":
|
|
2826
|
+
case "token":
|
|
2827
|
+
case "leaf":
|
|
2828
|
+
case "label":
|
|
2829
|
+
case "field":
|
|
2830
|
+
case "grammar":
|
|
2831
|
+
case "not":
|
|
2832
|
+
case "node":
|
|
2833
|
+
case "guard":
|
|
2834
|
+
case "withCtx":
|
|
2835
|
+
case "recover":
|
|
2836
|
+
case "expect":
|
|
2837
|
+
return "parser" in def ? [def.parser] : [];
|
|
2838
|
+
case "sepBy":
|
|
2839
|
+
return [def.parser, def.separator];
|
|
2840
|
+
case "skip":
|
|
2841
|
+
return [def.main, def.skipped];
|
|
2842
|
+
case "scanTo":
|
|
2843
|
+
return [def.sentinel, ...def.skip];
|
|
2844
|
+
case "lazy": {
|
|
2845
|
+
let resolved;
|
|
2846
|
+
try {
|
|
2847
|
+
resolved = def.thunk();
|
|
2848
|
+
} catch {
|
|
2849
|
+
return [];
|
|
2850
|
+
}
|
|
2851
|
+
const name = resolved._ruleName;
|
|
2852
|
+
return name && winners?.[name] ? [winners[name]] : [resolved];
|
|
2853
|
+
}
|
|
2854
|
+
default:
|
|
2855
|
+
return [];
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
function buildGrammarPlan(entry, winners) {
|
|
2859
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
2860
|
+
const choices = /* @__PURE__ */ new WeakMap();
|
|
2861
|
+
const attempts = /* @__PURE__ */ new WeakMap();
|
|
2862
|
+
const labels = /* @__PURE__ */ new WeakMap();
|
|
2863
|
+
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
2864
|
+
const winnerNames = /* @__PURE__ */ new Map();
|
|
2865
|
+
if (winners) {
|
|
2866
|
+
for (const [name, winner] of Object.entries(winners)) {
|
|
2867
|
+
winnerNames.set(winner, name);
|
|
2868
|
+
if (winner._def.tag === "lazy") {
|
|
2869
|
+
try {
|
|
2870
|
+
winnerNames.set(winner._def.thunk(), name);
|
|
2871
|
+
} catch {
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2877
|
+
const visit = (parser2, path) => {
|
|
2878
|
+
if (seen.has(parser2)) return;
|
|
2879
|
+
seen.add(parser2);
|
|
2880
|
+
const rule = winnerNames.get(parser2) ?? parser2._ruleName;
|
|
2881
|
+
if (rule && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
|
|
2882
|
+
const id = `rule:${rule}`;
|
|
2883
|
+
definitions.set(id, { id, kind: "rule" });
|
|
2884
|
+
rules2.set(parser2, id);
|
|
2885
|
+
}
|
|
2886
|
+
if (parser2._def.tag === "choice") {
|
|
2887
|
+
const ids = parser2._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
|
|
2888
|
+
choices.set(parser2, ids);
|
|
2889
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
2890
|
+
}
|
|
2891
|
+
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
|
|
2892
|
+
if (parser2._def.tag === "label") {
|
|
2893
|
+
const id = `label:${path}`;
|
|
2894
|
+
labels.set(parser2, [id]);
|
|
2895
|
+
definitions.set(id, { id, kind: "label" });
|
|
2896
|
+
}
|
|
2897
|
+
children(parser2._def, winners).forEach((child, index) => visit(child, `${path}/${parser2._def.tag}:${index}`));
|
|
2898
|
+
};
|
|
2899
|
+
const roots = Array.isArray(entry) ? entry : [entry];
|
|
2900
|
+
for (const root of roots) {
|
|
2901
|
+
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
2902
|
+
}
|
|
2903
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
2904
|
+
}
|
|
2709
2905
|
|
|
2710
2906
|
// src/compiler/scannable-run.ts
|
|
2711
2907
|
var BACKSLASH = 92;
|
|
@@ -4090,21 +4286,23 @@ function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
|
4090
4286
|
}
|
|
4091
4287
|
function failBody(ctx, expected, posExpr) {
|
|
4092
4288
|
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
4289
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
4093
4290
|
if (ctx.failLabel) {
|
|
4094
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4095
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
4291
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4292
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
|
|
4096
4293
|
}
|
|
4097
|
-
return probe + failReturn(expected, posExpr);
|
|
4294
|
+
return probe + trace + failReturn(expected, posExpr);
|
|
4098
4295
|
}
|
|
4099
4296
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
4100
4297
|
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
4298
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
4101
4299
|
if (ctx.failLabel) {
|
|
4102
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4300
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4103
4301
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
4104
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
4302
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
|
|
4105
4303
|
}
|
|
4106
|
-
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4107
|
-
return probe + failReturnArr(expectedArr, posExpr);
|
|
4304
|
+
if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4305
|
+
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
4108
4306
|
}
|
|
4109
4307
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
4110
4308
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4139,7 +4337,7 @@ var NAMED_FN_END = "_pfEnd";
|
|
|
4139
4337
|
function namedFnPrelude() {
|
|
4140
4338
|
return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
|
|
4141
4339
|
}
|
|
4142
|
-
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
4340
|
+
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar, failureRuleId) {
|
|
4143
4341
|
ctx.namedFnDecls.push([
|
|
4144
4342
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
4145
4343
|
` _pfail: {`,
|
|
@@ -4147,6 +4345,7 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
|
4147
4345
|
` ${NAMED_FN_END} = ${endVar}`,
|
|
4148
4346
|
` return ${valueVar}`,
|
|
4149
4347
|
` }`,
|
|
4348
|
+
...failureRuleId === void 0 ? [] : [` _ctx._grammarTrace?.write({ id: ${JSON.stringify(failureRuleId)}, phase: 'failure', offset: _ctx._fe ?? _pos })`],
|
|
4150
4349
|
` return ${NAMED_FN_FAIL}`,
|
|
4151
4350
|
`}`
|
|
4152
4351
|
].join("\n"));
|
|
@@ -4308,6 +4507,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4308
4507
|
case "not":
|
|
4309
4508
|
case "trivia":
|
|
4310
4509
|
case "token":
|
|
4510
|
+
case "leaf":
|
|
4311
4511
|
case "scanTo":
|
|
4312
4512
|
case "unknown":
|
|
4313
4513
|
return false;
|
|
@@ -4319,6 +4519,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4319
4519
|
// nothing committed remains.
|
|
4320
4520
|
case "choice":
|
|
4321
4521
|
return false;
|
|
4522
|
+
case "attempt":
|
|
4523
|
+
return false;
|
|
4322
4524
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
4323
4525
|
case "optional":
|
|
4324
4526
|
case "many":
|
|
@@ -4371,6 +4573,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4371
4573
|
case "keywords":
|
|
4372
4574
|
case "node":
|
|
4373
4575
|
case "token":
|
|
4576
|
+
case "leaf":
|
|
4374
4577
|
return true;
|
|
4375
4578
|
case "not":
|
|
4376
4579
|
case "guard":
|
|
@@ -4385,6 +4588,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4385
4588
|
case "many":
|
|
4386
4589
|
case "oneOrMore":
|
|
4387
4590
|
case "optional":
|
|
4591
|
+
case "attempt":
|
|
4388
4592
|
case "transform":
|
|
4389
4593
|
case "label":
|
|
4390
4594
|
case "field":
|
|
@@ -4726,35 +4930,55 @@ function needsFirstSetGuard(p) {
|
|
|
4726
4930
|
const fs = p._meta.firstSet;
|
|
4727
4931
|
return fs.kind !== "any" && !canMatchEmptyAtStart(p);
|
|
4728
4932
|
}
|
|
4729
|
-
function
|
|
4730
|
-
|
|
4933
|
+
function coverageHit(ctx, id, offset = "_pos", end) {
|
|
4934
|
+
return id === void 0 ? [] : [
|
|
4935
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`,
|
|
4936
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'selected', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`,
|
|
4937
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`
|
|
4938
|
+
];
|
|
4939
|
+
}
|
|
4940
|
+
function coverageAttempt(ctx, id, offset) {
|
|
4941
|
+
return id === void 0 ? [] : [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'attempt', offset: ${offset} })`];
|
|
4942
|
+
}
|
|
4943
|
+
function coverageFailureBacktrack(ctx, id, failureOffset, startOffset) {
|
|
4944
|
+
return id === void 0 ? [] : [
|
|
4945
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'failure', offset: ${failureOffset} })`,
|
|
4946
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'backtrack', offset: ${startOffset} })`
|
|
4947
|
+
];
|
|
4948
|
+
}
|
|
4949
|
+
function emitDisjointArm(p, ctx, pos, valV, endV, coverageId) {
|
|
4950
|
+
if (failsAtStart(p) && coverageId === void 0) {
|
|
4731
4951
|
const r = emit(p, ctx, pos);
|
|
4732
|
-
return [...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}
|
|
4952
|
+
return [...coverageAttempt(ctx, coverageId, pos), ...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`, ...coverageHit(ctx, coverageId, pos, r.endVar)];
|
|
4733
4953
|
}
|
|
4734
4954
|
const { stmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
|
|
4735
4955
|
return [
|
|
4956
|
+
...coverageAttempt(ctx, coverageId, pos),
|
|
4736
4957
|
...stmts,
|
|
4737
|
-
...emitIfFail(ctx, `!${okVar}`, failArrBody(ctx, "_ctx._fx", pos, false)),
|
|
4958
|
+
...emitIfFail(ctx, `!${okVar}`, `${coverageFailureBacktrack(ctx, coverageId, "_ctx._fe", pos).join("; ")}; ${failArrBody(ctx, "_ctx._fx", pos, false)}`),
|
|
4738
4959
|
`${ind(ctx)}${valV} = ${valVar}`,
|
|
4739
|
-
`${ind(ctx)}${endV} = ${endVar}
|
|
4960
|
+
`${ind(ctx)}${endV} = ${endVar}`,
|
|
4961
|
+
...coverageHit(ctx, coverageId, pos, endVar)
|
|
4740
4962
|
];
|
|
4741
4963
|
}
|
|
4742
|
-
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4964
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageId) {
|
|
4743
4965
|
const p = def.parsers[i];
|
|
4744
4966
|
const gate = def.gates[i];
|
|
4745
|
-
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4967
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV, coverageId);
|
|
4746
4968
|
const gateIdx = ctx.mapFns.length;
|
|
4747
4969
|
ctx.mapFns.push(gate);
|
|
4748
4970
|
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4749
4971
|
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4750
4972
|
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4751
4973
|
ctx.indent++;
|
|
4752
|
-
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4974
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV, coverageId));
|
|
4753
4975
|
ctx.indent--;
|
|
4754
4976
|
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4755
4977
|
return stmts;
|
|
4756
4978
|
}
|
|
4757
|
-
function emitChoice(def, ctx, pos) {
|
|
4979
|
+
function emitChoice(parser2, def, ctx, pos) {
|
|
4980
|
+
const coverageIds = ctx.coverage?.plan.choices.get(parser2);
|
|
4981
|
+
const coverageBase = coverageIds?.[0]?.slice(0, -1);
|
|
4758
4982
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4759
4983
|
if (def.disjoint) {
|
|
4760
4984
|
const codeV = v(ctx, "_code");
|
|
@@ -4773,7 +4997,7 @@ function emitChoice(def, ctx, pos) {
|
|
|
4773
4997
|
stmts.push(`${ind(ctx)}{`);
|
|
4774
4998
|
ctx.indent++;
|
|
4775
4999
|
stmts.push(
|
|
4776
|
-
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
5000
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]),
|
|
4777
5001
|
`${ind(ctx)}break`
|
|
4778
5002
|
);
|
|
4779
5003
|
ctx.indent--;
|
|
@@ -4792,16 +5016,16 @@ function emitChoice(def, ctx, pos) {
|
|
|
4792
5016
|
first = false;
|
|
4793
5017
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4794
5018
|
ctx.indent++;
|
|
4795
|
-
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
5019
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]));
|
|
4796
5020
|
ctx.indent--;
|
|
4797
5021
|
stmts.push(`${ind(ctx)}}`);
|
|
4798
5022
|
}
|
|
4799
5023
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4800
5024
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4801
5025
|
}
|
|
4802
|
-
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
|
|
5026
|
+
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
4803
5027
|
}
|
|
4804
|
-
function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
5028
|
+
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
4805
5029
|
const superParser = def.parsers[superIndex];
|
|
4806
5030
|
const regexDef = getCoreRegexDef(superParser);
|
|
4807
5031
|
const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
@@ -4817,10 +5041,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4817
5041
|
const endV = v(ctx, "_ge");
|
|
4818
5042
|
const valV = v(ctx, "_gcv");
|
|
4819
5043
|
const regexExpected = JSON.stringify(deriveExpected(superParser));
|
|
5044
|
+
const superCoverageId = coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`;
|
|
4820
5045
|
const stmts = [
|
|
5046
|
+
...coverageAttempt(ctx, superCoverageId, pos),
|
|
4821
5047
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
4822
5048
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
4823
|
-
...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, regexExpected, pos)),
|
|
5049
|
+
...emitIfFail(ctx, `${matchV} === null`, `${coverageFailureBacktrack(ctx, superCoverageId, pos, pos).join("; ")}; ${failArrBody(ctx, regexExpected, pos)}`),
|
|
4824
5050
|
`${ind(ctx)}const ${wordV} = ${matchV}[0]`,
|
|
4825
5051
|
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
|
|
4826
5052
|
`${ind(ctx)}let ${valV}`
|
|
@@ -4836,8 +5062,9 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4836
5062
|
stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
|
|
4837
5063
|
ctx.indent++;
|
|
4838
5064
|
const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
|
|
5065
|
+
stmts.push(...coverageFailureBacktrack(ctx, superCoverageId, pos, pos));
|
|
4839
5066
|
stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
|
|
4840
|
-
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}
|
|
5067
|
+
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endV));
|
|
4841
5068
|
ctx.indent--;
|
|
4842
5069
|
stmts.push(`${ind(ctx)}}`);
|
|
4843
5070
|
}
|
|
@@ -4845,12 +5072,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4845
5072
|
const regexKw = first ? "if" : "else";
|
|
4846
5073
|
stmts.push(`${ind(ctx)}${regexKw} {`);
|
|
4847
5074
|
ctx.indent++;
|
|
4848
|
-
stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}
|
|
5075
|
+
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));
|
|
4849
5076
|
ctx.indent--;
|
|
4850
5077
|
stmts.push(`${ind(ctx)}}`);
|
|
4851
5078
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4852
5079
|
}
|
|
4853
|
-
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
5080
|
+
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, coverageBase) {
|
|
4854
5081
|
const valV = v(ctx, "_llv");
|
|
4855
5082
|
const endV = v(ctx, "_lle");
|
|
4856
5083
|
const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
|
|
@@ -4867,10 +5094,12 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4867
5094
|
ctx.indent++;
|
|
4868
5095
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
4869
5096
|
stmts.push(
|
|
5097
|
+
...coverageAttempt(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos),
|
|
4870
5098
|
...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
|
|
4871
5099
|
...tR.stmts,
|
|
4872
5100
|
`${ind(ctx)}${valV} = ${tR.valueVar}`,
|
|
4873
|
-
`${ind(ctx)}${endV} = ${litEnd}
|
|
5101
|
+
`${ind(ctx)}${endV} = ${litEnd}`,
|
|
5102
|
+
...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos, litEnd)
|
|
4874
5103
|
);
|
|
4875
5104
|
ctx.indent--;
|
|
4876
5105
|
stmts.push(`${ind(ctx)}}`);
|
|
@@ -4878,16 +5107,18 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4878
5107
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4879
5108
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4880
5109
|
}
|
|
4881
|
-
function emitFirstMatch(def, ctx, pos) {
|
|
5110
|
+
function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
4882
5111
|
const resValV = v(ctx, "_crv");
|
|
4883
5112
|
const resEndV = v(ctx, "_cre");
|
|
4884
5113
|
const resOkV = v(ctx, "_crok");
|
|
4885
5114
|
const codeV = v(ctx, "_chcode");
|
|
4886
5115
|
const slots = def.parsers.map(() => v(ctx, "_cfx"));
|
|
5116
|
+
const autoRejectedV = coverageBase === void 0 ? void 0 : v(ctx, "_carej");
|
|
4887
5117
|
const ind0 = ind(ctx);
|
|
4888
5118
|
const stmts = [
|
|
4889
5119
|
`${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`,
|
|
4890
5120
|
`${ind0}let ${slots.join(", ")}`,
|
|
5121
|
+
...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
|
|
4891
5122
|
`${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
|
|
4892
5123
|
];
|
|
4893
5124
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
@@ -4923,6 +5154,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4923
5154
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4924
5155
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
4925
5156
|
ctx.indent += fsGuard ? 2 : 1;
|
|
5157
|
+
if (coverageBase !== void 0) stmts.push(`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'attempt', offset: ${pos} })`);
|
|
4926
5158
|
if (markLeaves) {
|
|
4927
5159
|
stmts.push(
|
|
4928
5160
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
@@ -4945,13 +5177,21 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4945
5177
|
stmts.push(`${ind(ctx)} ${resValV} = ${valVar}`);
|
|
4946
5178
|
stmts.push(`${ind(ctx)} ${resEndV} = ${endVar}`);
|
|
4947
5179
|
stmts.push(`${ind(ctx)} ${resOkV} = true`);
|
|
5180
|
+
if (autoRejectedV !== void 0) {
|
|
5181
|
+
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} }) }`);
|
|
5182
|
+
}
|
|
5183
|
+
stmts.push(...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endVar));
|
|
4948
5184
|
stmts.push(`${ind(ctx)} }`);
|
|
5185
|
+
if (autoRejectedV !== void 0) {
|
|
5186
|
+
stmts.push(`${ind(ctx)} else { ${autoRejectedV}.push(${JSON.stringify(`${coverageBase}${i}`)}) }`);
|
|
5187
|
+
}
|
|
4949
5188
|
stmts.push(`${ind(ctx)}}`);
|
|
4950
|
-
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot} }`);
|
|
5189
|
+
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} });`} }`);
|
|
4951
5190
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
4952
5191
|
} else {
|
|
4953
|
-
|
|
4954
|
-
stmts.push(`${ind(ctx)}
|
|
5192
|
+
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} }) }`;
|
|
5193
|
+
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} })`} }`);
|
|
5194
|
+
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} })`} }`);
|
|
4955
5195
|
}
|
|
4956
5196
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
4957
5197
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -4961,12 +5201,12 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4961
5201
|
stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
|
|
4962
5202
|
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
4963
5203
|
}
|
|
4964
|
-
function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
5204
|
+
function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
|
|
4965
5205
|
if (strategy.tag === "greedyClassify")
|
|
4966
|
-
return emitGreedyClassify(def, strategy.superIndex, ctx, pos);
|
|
5206
|
+
return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
|
|
4967
5207
|
if (strategy.tag === "literalsLongestFirst")
|
|
4968
|
-
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
4969
|
-
return emitFirstMatch(def, ctx, pos);
|
|
5208
|
+
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
|
|
5209
|
+
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
4970
5210
|
}
|
|
4971
5211
|
function pushMapFn(ctx, fn, src) {
|
|
4972
5212
|
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
@@ -5084,6 +5324,27 @@ function emitOptional(def, ctx, pos) {
|
|
|
5084
5324
|
];
|
|
5085
5325
|
return { stmts, valueVar: valV, endVar: endV };
|
|
5086
5326
|
}
|
|
5327
|
+
function emitAttempt(p, def, ctx, pos) {
|
|
5328
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5329
|
+
const leaves = v(ctx, "_atl");
|
|
5330
|
+
const raw = v(ctx, "_atr");
|
|
5331
|
+
const trivia2 = v(ctx, "_att");
|
|
5332
|
+
const log = v(ctx, "_atg");
|
|
5333
|
+
const fields = v(ctx, "_atf");
|
|
5334
|
+
const errors = v(ctx, "_ate");
|
|
5335
|
+
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}`;
|
|
5336
|
+
const traceId = ctx.coverage?.plan.attempts.get(p);
|
|
5337
|
+
const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
|
|
5338
|
+
return {
|
|
5339
|
+
stmts: [
|
|
5340
|
+
`${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`,
|
|
5341
|
+
...inner.stmts,
|
|
5342
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
5343
|
+
],
|
|
5344
|
+
valueVar: inner.valVar,
|
|
5345
|
+
endVar: inner.endVar
|
|
5346
|
+
};
|
|
5347
|
+
}
|
|
5087
5348
|
function emitSepBy(_p, def, ctx, pos) {
|
|
5088
5349
|
const arrV = v(ctx, "_arr");
|
|
5089
5350
|
const curV = v(ctx, "_cur");
|
|
@@ -5374,6 +5635,36 @@ function emitToken(def, ctx, pos) {
|
|
|
5374
5635
|
endVar: inner.endVar
|
|
5375
5636
|
};
|
|
5376
5637
|
}
|
|
5638
|
+
function emitLeaf(def, ctx, pos) {
|
|
5639
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5640
|
+
const i = ind(ctx);
|
|
5641
|
+
const sc = v(ctx, "_leafCh");
|
|
5642
|
+
const sl = v(ctx, "_leafLv");
|
|
5643
|
+
const sr = v(ctx, "_leafRaw");
|
|
5644
|
+
const stl = v(ctx, "_leafTl");
|
|
5645
|
+
const sol = v(ctx, "_leafLog");
|
|
5646
|
+
const sb = v(ctx, "_leafBuf");
|
|
5647
|
+
const rawV = v(ctx, "_leafRawValue");
|
|
5648
|
+
const valV = v(ctx, "_leaf");
|
|
5649
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
5650
|
+
return {
|
|
5651
|
+
stmts: [
|
|
5652
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
|
|
5653
|
+
`${i}_ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
|
|
5654
|
+
`${i}try {`,
|
|
5655
|
+
...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
|
|
5656
|
+
`${i}} finally {`,
|
|
5657
|
+
`${i} _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
|
|
5658
|
+
`${i}}`,
|
|
5659
|
+
...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
|
|
5660
|
+
`${i}const ${rawV} = ${inner.valVar}`,
|
|
5661
|
+
`${i}const ${valV} = ${mfRef(ctx)}[${fnIdx}](${rawV}, { start: ${pos}, end: ${inner.endVar} })`,
|
|
5662
|
+
...emitLeafCapture(ctx, valV, pos, inner.endVar)
|
|
5663
|
+
],
|
|
5664
|
+
valueVar: valV,
|
|
5665
|
+
endVar: inner.endVar
|
|
5666
|
+
};
|
|
5667
|
+
}
|
|
5377
5668
|
function emitNode(def, ctx, pos) {
|
|
5378
5669
|
if (def.type === void 0) {
|
|
5379
5670
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -5389,6 +5680,8 @@ function emitNode(def, ctx, pos) {
|
|
|
5389
5680
|
const i = ind(ctx);
|
|
5390
5681
|
const capturesTrivia = mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
|
|
5391
5682
|
const clonesState = !structural && buildReadsState(def);
|
|
5683
|
+
const capturesChildren = !structural && (mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
|
|
5684
|
+
const capturesRaw = !structural && (mkType !== null || buildReadsRaw(def));
|
|
5392
5685
|
const hasFields = parserHasOwnFields(def.parser);
|
|
5393
5686
|
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
5394
5687
|
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
@@ -5407,9 +5700,13 @@ function emitNode(def, ctx, pos) {
|
|
|
5407
5700
|
const profHoist = `${i}const ${pmV} = _ctx._pmProfile, ${recV} = ${pmV}?.phase === 'recognizer', ${capV} = ${pmV}?.phase === 'capture'`;
|
|
5408
5701
|
const profileRecognizer = recV;
|
|
5409
5702
|
const profileCapture = capV;
|
|
5703
|
+
const directCstV = !structural && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
5704
|
+
const directCstGate = directCstV === null ? "false" : `${profileCapture} || _ctx.build?._parsemanCstOutput === true`;
|
|
5410
5705
|
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
5411
5706
|
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)))` : ""}
|
|
5412
|
-
${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${
|
|
5707
|
+
${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5708
|
+
` : ""}${i}const ${capTLv} = !(${profileRecognizer}), ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}, ${tlV} = ${profileRecognizer} ? undefined : []` : `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5709
|
+
` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
|
|
5413
5710
|
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
5414
5711
|
const fieldsOn = structural ? capFv ?? "false" : `${profileRecognizer} ? false : ${capturesFields ? "true" : "false"}`;
|
|
5415
5712
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
@@ -5526,14 +5823,23 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
5526
5823
|
const savedIndent = ctx.indent;
|
|
5527
5824
|
const savedFailLabel = ctx.failLabel;
|
|
5528
5825
|
const savedRecord = ctx.recordFail;
|
|
5826
|
+
const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
|
|
5827
|
+
const savedActiveRule = ctx.activeCoverageRuleId;
|
|
5828
|
+
const savedSuppressFailure = ctx.suppressCoverageFailure;
|
|
5529
5829
|
ctx.indent = 1;
|
|
5530
5830
|
ctx.failLabel = "_pfail";
|
|
5531
5831
|
ctx.recordFail = true;
|
|
5832
|
+
if (failureRuleId !== void 0) {
|
|
5833
|
+
ctx.activeCoverageRuleId = void 0;
|
|
5834
|
+
ctx.suppressCoverageFailure = true;
|
|
5835
|
+
}
|
|
5532
5836
|
const r = emit(resolved, ctx, "_pos");
|
|
5533
5837
|
ctx.indent = savedIndent;
|
|
5534
5838
|
ctx.failLabel = savedFailLabel;
|
|
5535
5839
|
ctx.recordFail = savedRecord;
|
|
5536
|
-
|
|
5840
|
+
ctx.activeCoverageRuleId = savedActiveRule;
|
|
5841
|
+
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
5842
|
+
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
5537
5843
|
}
|
|
5538
5844
|
const fnName = ctx.namedParsers.get(p);
|
|
5539
5845
|
return emitNamedFnCall(ctx, fnName, pos);
|
|
@@ -5584,6 +5890,30 @@ function emitExpect(def, ctx, pos) {
|
|
|
5584
5890
|
return { stmts, valueVar: valVar, endVar };
|
|
5585
5891
|
}
|
|
5586
5892
|
function emit(p, ctx, pos) {
|
|
5893
|
+
const dispatch = (emissionPos = pos) => {
|
|
5894
|
+
const savedRule = ctx.activeCoverageRuleId;
|
|
5895
|
+
const rule = ctx.coverage?.plan.rules.get(p);
|
|
5896
|
+
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
5897
|
+
const result = emitDispatch(p, ctx, emissionPos);
|
|
5898
|
+
ctx.activeCoverageRuleId = savedRule;
|
|
5899
|
+
return result;
|
|
5900
|
+
};
|
|
5901
|
+
const instrument = (r) => {
|
|
5902
|
+
const ruleId = ctx.coverage?.plan.rules.get(p);
|
|
5903
|
+
const labelIds = ctx.coverage?.plan.labels.get(p);
|
|
5904
|
+
if (!ruleId && !labelIds) return r;
|
|
5905
|
+
return {
|
|
5906
|
+
...r,
|
|
5907
|
+
stmts: [
|
|
5908
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`] : [],
|
|
5909
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: ${pos} })`] : [],
|
|
5910
|
+
...r.stmts,
|
|
5911
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`] : [],
|
|
5912
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`]) ?? [],
|
|
5913
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`]) ?? []
|
|
5914
|
+
]
|
|
5915
|
+
};
|
|
5916
|
+
};
|
|
5587
5917
|
const usage = ctx.lazyUsage;
|
|
5588
5918
|
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
|
|
5589
5919
|
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
@@ -5600,14 +5930,14 @@ function emit(p, ctx, pos) {
|
|
|
5600
5930
|
ctx.indent = 1;
|
|
5601
5931
|
ctx.failLabel = "_pfail";
|
|
5602
5932
|
ctx.recordFail = true;
|
|
5603
|
-
const r =
|
|
5933
|
+
const r = dispatch("_pos");
|
|
5604
5934
|
ctx.indent = savedIndent;
|
|
5605
5935
|
ctx.failLabel = savedFailLabel;
|
|
5606
5936
|
ctx.recordFail = savedRecord;
|
|
5607
5937
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
5608
|
-
return emitNamedFnCall(ctx, fnName, pos);
|
|
5938
|
+
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
5609
5939
|
}
|
|
5610
|
-
return
|
|
5940
|
+
return instrument(dispatch());
|
|
5611
5941
|
}
|
|
5612
5942
|
function emitDispatch(p, ctx, pos) {
|
|
5613
5943
|
const def = p._def;
|
|
@@ -5621,7 +5951,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5621
5951
|
case "sequence":
|
|
5622
5952
|
return emitSeq(def, ctx, pos);
|
|
5623
5953
|
case "choice":
|
|
5624
|
-
return emitChoice(def, ctx, pos);
|
|
5954
|
+
return emitChoice(p, def, ctx, pos);
|
|
5955
|
+
case "attempt":
|
|
5956
|
+
return emitAttempt(p, def, ctx, pos);
|
|
5625
5957
|
case "many":
|
|
5626
5958
|
case "oneOrMore":
|
|
5627
5959
|
return emitMany(def, ctx, pos);
|
|
@@ -5690,6 +6022,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5690
6022
|
return emit(def.parser, ctx, pos);
|
|
5691
6023
|
case "token":
|
|
5692
6024
|
return emitToken(def, ctx, pos);
|
|
6025
|
+
case "leaf":
|
|
6026
|
+
return emitLeaf(def, ctx, pos);
|
|
5693
6027
|
case "label": {
|
|
5694
6028
|
const inner = emitFallible(def.parser, ctx, pos);
|
|
5695
6029
|
return {
|
|
@@ -5821,6 +6155,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5821
6155
|
case "grammar":
|
|
5822
6156
|
case "trivia":
|
|
5823
6157
|
case "token":
|
|
6158
|
+
case "leaf":
|
|
5824
6159
|
case "label":
|
|
5825
6160
|
case "field":
|
|
5826
6161
|
case "optional":
|
|
@@ -5848,16 +6183,32 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5848
6183
|
return false;
|
|
5849
6184
|
}
|
|
5850
6185
|
}
|
|
6186
|
+
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
6187
|
+
if (seen.has(p)) return false;
|
|
6188
|
+
seen.add(p);
|
|
6189
|
+
const d = p._def;
|
|
6190
|
+
if (d.tag === "node" && d.build !== void 0) return true;
|
|
6191
|
+
if (d.tag === "lazy") {
|
|
6192
|
+
try {
|
|
6193
|
+
return hasDirectBuildDef(d.thunk(), seen);
|
|
6194
|
+
} catch {
|
|
6195
|
+
return false;
|
|
6196
|
+
}
|
|
6197
|
+
}
|
|
6198
|
+
return childrenOf(d).some((child) => hasDirectBuildDef(child, seen));
|
|
6199
|
+
}
|
|
5851
6200
|
function childrenOf(def) {
|
|
5852
6201
|
switch (def.tag) {
|
|
5853
6202
|
case "sequence":
|
|
5854
6203
|
case "choice":
|
|
5855
6204
|
return def.parsers;
|
|
5856
6205
|
case "many":
|
|
6206
|
+
case "attempt":
|
|
5857
6207
|
case "optional":
|
|
5858
6208
|
case "transform":
|
|
5859
6209
|
case "trivia":
|
|
5860
6210
|
case "token":
|
|
6211
|
+
case "leaf":
|
|
5861
6212
|
case "label":
|
|
5862
6213
|
case "field":
|
|
5863
6214
|
case "grammar":
|
|
@@ -6032,10 +6383,25 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
6032
6383
|
namedFnDecls: [],
|
|
6033
6384
|
capturing: hasNodeDef(combinator),
|
|
6034
6385
|
recovery: opts?.recovery ?? false,
|
|
6386
|
+
...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
|
|
6035
6387
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
6036
6388
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
6037
6389
|
};
|
|
6038
6390
|
const r = emit(combinator, ctx, "_pos");
|
|
6391
|
+
const coverageRootRuleId = ctx.coverage?.plan.rules.get(combinator);
|
|
6392
|
+
const resultBody = coverageRootRuleId === void 0 ? [
|
|
6393
|
+
` let pos = _pos`,
|
|
6394
|
+
...r.stmts,
|
|
6395
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6396
|
+
] : [
|
|
6397
|
+
` const _coverageResult = (() => {`,
|
|
6398
|
+
` let pos = _pos`,
|
|
6399
|
+
...r.stmts,
|
|
6400
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6401
|
+
` })()`,
|
|
6402
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6403
|
+
` return _coverageResult`
|
|
6404
|
+
];
|
|
6039
6405
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
6040
6406
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
6041
6407
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
@@ -6048,9 +6414,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
6048
6414
|
...namedPrelude,
|
|
6049
6415
|
ctx.namedFnDecls.join("\n\n"),
|
|
6050
6416
|
`function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
|
|
6051
|
-
|
|
6052
|
-
...r.stmts,
|
|
6053
|
-
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6417
|
+
...resultBody,
|
|
6054
6418
|
`}`
|
|
6055
6419
|
].join("\n");
|
|
6056
6420
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
@@ -6060,9 +6424,15 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
6060
6424
|
...ctx.expectedDecls,
|
|
6061
6425
|
...namedPrelude,
|
|
6062
6426
|
...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
|
|
6063
|
-
`let pos = _pos`,
|
|
6064
|
-
|
|
6065
|
-
|
|
6427
|
+
...coverageRootRuleId === void 0 ? [`let pos = _pos`, ...r.stmts, `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`] : [
|
|
6428
|
+
`const _coverageResult = (() => {`,
|
|
6429
|
+
` let pos = _pos`,
|
|
6430
|
+
...r.stmts,
|
|
6431
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6432
|
+
`})()`,
|
|
6433
|
+
`if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6434
|
+
`return _coverageResult`
|
|
6435
|
+
]
|
|
6066
6436
|
].join("\n"));
|
|
6067
6437
|
const defaultCtx = {
|
|
6068
6438
|
trackLines: false,
|
|
@@ -6074,10 +6444,11 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
6074
6444
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
6075
6445
|
const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
|
|
6076
6446
|
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
6077
|
-
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources) : null;
|
|
6447
|
+
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
|
|
6078
6448
|
return {
|
|
6079
6449
|
source,
|
|
6080
6450
|
inlineExpression,
|
|
6451
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
|
|
6081
6452
|
parse(input, pos = 0) {
|
|
6082
6453
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
|
|
6083
6454
|
},
|
|
@@ -6140,8 +6511,13 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6140
6511
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
6141
6512
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
6142
6513
|
namedFnDecls: [],
|
|
6143
|
-
|
|
6514
|
+
// A recognition-only fragment normally has no node collector of its own.
|
|
6515
|
+
// Leaf composition can re-lower it beneath a local semantic node, though;
|
|
6516
|
+
// in that case its terminals must feed the caller's collector rather than
|
|
6517
|
+
// merely returning their scalar parse values.
|
|
6518
|
+
capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
6144
6519
|
recovery: opts?.recovery ?? false,
|
|
6520
|
+
...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
|
|
6145
6521
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
6146
6522
|
ns,
|
|
6147
6523
|
deferFirstSetRefs: true,
|
|
@@ -6215,7 +6591,14 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6215
6591
|
ctx.indent = savedIndent;
|
|
6216
6592
|
ctx.failLabel = savedFail;
|
|
6217
6593
|
ctx.recordFail = savedRec;
|
|
6218
|
-
|
|
6594
|
+
const ruleId = ctx.coverage?.plan.rules.get(rule);
|
|
6595
|
+
const stmts = ruleId === void 0 ? body.stmts : [
|
|
6596
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
|
|
6597
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: _pos })`,
|
|
6598
|
+
...body.stmts,
|
|
6599
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: _pos, end: ${body.endVar} })`
|
|
6600
|
+
];
|
|
6601
|
+
pushNamedFnDecl(ctx, fn, stmts, body.valueVar, body.endVar);
|
|
6219
6602
|
}
|
|
6220
6603
|
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
6221
6604
|
}
|
|
@@ -6272,15 +6655,46 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6272
6655
|
deps: ruleDependencies(ruleMap),
|
|
6273
6656
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
6274
6657
|
needsHostReads: !!ctx.needsHostReads,
|
|
6658
|
+
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
6659
|
+
isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule)),
|
|
6275
6660
|
mfFns: mfSrcs ? [] : ctx.mapFns,
|
|
6276
6661
|
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
6277
6662
|
};
|
|
6278
6663
|
}
|
|
6279
|
-
function
|
|
6280
|
-
const
|
|
6664
|
+
function hasSemanticReduction(roots) {
|
|
6665
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6666
|
+
const visit = (parser2) => {
|
|
6667
|
+
if (seen.has(parser2)) return false;
|
|
6668
|
+
seen.add(parser2);
|
|
6669
|
+
const def = parser2._def;
|
|
6670
|
+
if (def.tag === "transform" && !def.recognitionOnly) return true;
|
|
6671
|
+
if (def.tag === "choice" && def.gates.some(Boolean)) return true;
|
|
6672
|
+
if (def.tag === "guard" || def.tag === "withCtx") return true;
|
|
6673
|
+
if (def.tag === "node" && def.build !== void 0) return true;
|
|
6674
|
+
if (def.tag === "lazy") {
|
|
6675
|
+
try {
|
|
6676
|
+
return visit(def.thunk());
|
|
6677
|
+
} catch {
|
|
6678
|
+
return true;
|
|
6679
|
+
}
|
|
6680
|
+
}
|
|
6681
|
+
return childrenOf(def).some(visit);
|
|
6682
|
+
};
|
|
6683
|
+
return roots.some(visit);
|
|
6684
|
+
}
|
|
6685
|
+
function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootRuleId) {
|
|
6686
|
+
const bodyLines = coverageRootRuleId === void 0 ? [
|
|
6281
6687
|
` let pos = _pos`,
|
|
6282
6688
|
...r.stmts,
|
|
6283
6689
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6690
|
+
] : [
|
|
6691
|
+
` const _coverageResult = (() => {`,
|
|
6692
|
+
` let pos = _pos`,
|
|
6693
|
+
...r.stmts,
|
|
6694
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6695
|
+
` })()`,
|
|
6696
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6697
|
+
` return _coverageResult`
|
|
6284
6698
|
];
|
|
6285
6699
|
const innerFn = [
|
|
6286
6700
|
`function(input, _pos, _ctx) {`,
|
|
@@ -6335,8 +6749,8 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
6335
6749
|
};
|
|
6336
6750
|
const emit2 = (end) => {
|
|
6337
6751
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
6338
|
-
const
|
|
6339
|
-
pushCstLeaf(ctx,
|
|
6752
|
+
const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
6753
|
+
pushCstLeaf(ctx, leaf2);
|
|
6340
6754
|
}
|
|
6341
6755
|
};
|
|
6342
6756
|
while (cur < input.length) {
|
|
@@ -6390,6 +6804,7 @@ function balanced(open, close, options = {}) {
|
|
|
6390
6804
|
);
|
|
6391
6805
|
if (combi._def.tag === "transform") {
|
|
6392
6806
|
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
6807
|
+
combi._def.recognitionOnly = true;
|
|
6393
6808
|
}
|
|
6394
6809
|
self.define(combi);
|
|
6395
6810
|
return combi;
|
|
@@ -6435,9 +6850,11 @@ function childrenOf2(def) {
|
|
|
6435
6850
|
case "many":
|
|
6436
6851
|
case "oneOrMore":
|
|
6437
6852
|
case "optional":
|
|
6853
|
+
case "attempt":
|
|
6438
6854
|
case "transform":
|
|
6439
6855
|
case "trivia":
|
|
6440
6856
|
case "token":
|
|
6857
|
+
case "leaf":
|
|
6441
6858
|
case "label":
|
|
6442
6859
|
case "field":
|
|
6443
6860
|
case "not":
|
|
@@ -6486,7 +6903,7 @@ function serializeRuleMap(ruleMap) {
|
|
|
6486
6903
|
}
|
|
6487
6904
|
}
|
|
6488
6905
|
function evalRuleMapIR(ir) {
|
|
6489
|
-
const _tf = (child, src) => {
|
|
6906
|
+
const _tf = (child, src, recognitionOnly = false) => {
|
|
6490
6907
|
let fn2;
|
|
6491
6908
|
try {
|
|
6492
6909
|
fn2 = (0, eval)(`(${src})`);
|
|
@@ -6497,8 +6914,22 @@ function evalRuleMapIR(ir) {
|
|
|
6497
6914
|
}
|
|
6498
6915
|
const t = transform(child, fn2);
|
|
6499
6916
|
t._def.fnSrc = src;
|
|
6917
|
+
if (recognitionOnly) t._def.recognitionOnly = true;
|
|
6500
6918
|
return t;
|
|
6501
6919
|
};
|
|
6920
|
+
const _lf = (child, src) => {
|
|
6921
|
+
let fn2;
|
|
6922
|
+
try {
|
|
6923
|
+
fn2 = (0, eval)(`(${src})`);
|
|
6924
|
+
} catch {
|
|
6925
|
+
fn2 = () => {
|
|
6926
|
+
throw new Error("IR leaf fn not materialized");
|
|
6927
|
+
};
|
|
6928
|
+
}
|
|
6929
|
+
const l = leaf(child, fn2);
|
|
6930
|
+
l._def.fnSrc = src;
|
|
6931
|
+
return l;
|
|
6932
|
+
};
|
|
6502
6933
|
const _nd = (type, child, src, opts, staticError) => {
|
|
6503
6934
|
if (staticError !== void 0 && staticError.length > 0) {
|
|
6504
6935
|
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
@@ -6557,6 +6988,7 @@ function evalRuleMapIR(ir) {
|
|
|
6557
6988
|
"keywords",
|
|
6558
6989
|
"sequence",
|
|
6559
6990
|
"choice",
|
|
6991
|
+
"attempt",
|
|
6560
6992
|
"many",
|
|
6561
6993
|
"oneOrMore",
|
|
6562
6994
|
"optional",
|
|
@@ -6566,6 +6998,7 @@ function evalRuleMapIR(ir) {
|
|
|
6566
6998
|
"parser",
|
|
6567
6999
|
"scanTo",
|
|
6568
7000
|
"token",
|
|
7001
|
+
"leaf",
|
|
6569
7002
|
"transform",
|
|
6570
7003
|
"skip",
|
|
6571
7004
|
"trivia",
|
|
@@ -6573,6 +7006,7 @@ function evalRuleMapIR(ir) {
|
|
|
6573
7006
|
"field",
|
|
6574
7007
|
"expect",
|
|
6575
7008
|
"_tf",
|
|
7009
|
+
"_lf",
|
|
6576
7010
|
"_nd",
|
|
6577
7011
|
"_gch",
|
|
6578
7012
|
"_wc",
|
|
@@ -6586,6 +7020,7 @@ function evalRuleMapIR(ir) {
|
|
|
6586
7020
|
keywords,
|
|
6587
7021
|
sequence,
|
|
6588
7022
|
choice,
|
|
7023
|
+
attempt,
|
|
6589
7024
|
many,
|
|
6590
7025
|
oneOrMore,
|
|
6591
7026
|
optional,
|
|
@@ -6595,6 +7030,7 @@ function evalRuleMapIR(ir) {
|
|
|
6595
7030
|
parser,
|
|
6596
7031
|
scanTo,
|
|
6597
7032
|
token,
|
|
7033
|
+
leaf,
|
|
6598
7034
|
transform,
|
|
6599
7035
|
skip,
|
|
6600
7036
|
trivia,
|
|
@@ -6602,6 +7038,7 @@ function evalRuleMapIR(ir) {
|
|
|
6602
7038
|
field,
|
|
6603
7039
|
expect,
|
|
6604
7040
|
_tf,
|
|
7041
|
+
_lf,
|
|
6605
7042
|
_nd,
|
|
6606
7043
|
_gch,
|
|
6607
7044
|
_wc
|
|
@@ -6733,6 +7170,8 @@ ${body}
|
|
|
6733
7170
|
return `oneOrMore(${kid(def.parser)})`;
|
|
6734
7171
|
case "optional":
|
|
6735
7172
|
return `optional(${kid(def.parser)})`;
|
|
7173
|
+
case "attempt":
|
|
7174
|
+
return `attempt(${kid(def.parser)})`;
|
|
6736
7175
|
case "sepBy":
|
|
6737
7176
|
return `sepBy(${kid(def.parser)}, ${kid(def.separator)})`;
|
|
6738
7177
|
case "not":
|
|
@@ -6741,6 +7180,10 @@ ${body}
|
|
|
6741
7180
|
return `trivia(${kid(def.parser)})`;
|
|
6742
7181
|
case "token":
|
|
6743
7182
|
return `token(${kid(def.parser)})`;
|
|
7183
|
+
case "leaf": {
|
|
7184
|
+
if (def.fnSrc === void 0) throw new Unserializable("leaf without fnSrc");
|
|
7185
|
+
return `_lf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7186
|
+
}
|
|
6744
7187
|
case "label":
|
|
6745
7188
|
return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
|
|
6746
7189
|
case "field":
|
|
@@ -6753,7 +7196,7 @@ ${body}
|
|
|
6753
7196
|
return `scanTo(${kid(def.sentinel)}, { skip: [${def.skip.map(kid).join(", ")}], orEOF: ${def.orEOF} })`;
|
|
6754
7197
|
case "transform": {
|
|
6755
7198
|
if (def.fnSrc === void 0) throw new Unserializable("transform without fnSrc");
|
|
6756
|
-
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7199
|
+
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)}${def.recognitionOnly ? ", true" : ""})`;
|
|
6757
7200
|
}
|
|
6758
7201
|
case "node": {
|
|
6759
7202
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
@@ -6805,15 +7248,15 @@ function normalizeCstCollapse(collapse) {
|
|
|
6805
7248
|
}
|
|
6806
7249
|
return typeof collapse === "function" ? collapse : void 0;
|
|
6807
7250
|
}
|
|
6808
|
-
function buildCstNode(type,
|
|
6809
|
-
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...
|
|
7251
|
+
function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
|
|
7252
|
+
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
|
|
6810
7253
|
}
|
|
6811
|
-
function cstBuildHost(typeOrOptions,
|
|
7254
|
+
function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
|
|
6812
7255
|
if (typeof typeOrOptions === "string") {
|
|
6813
|
-
return buildCstNode(typeOrOptions,
|
|
7256
|
+
return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
6814
7257
|
}
|
|
6815
7258
|
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
6816
|
-
const host = (type,
|
|
7259
|
+
const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3, fields, span2, rawChildren2, triviaLog2, state2);
|
|
6817
7260
|
host._parsemanCstOutput = true;
|
|
6818
7261
|
if (collapse) host._parsemanCstCollapse = collapse;
|
|
6819
7262
|
return host;
|
|
@@ -6872,13 +7315,39 @@ function fuseRules(pieces) {
|
|
|
6872
7315
|
return new Function("_env", body)(env);
|
|
6873
7316
|
}
|
|
6874
7317
|
var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
|
|
7318
|
+
var LEAF_COMPOSED = /* @__PURE__ */ Symbol.for("parseman.leafComposed");
|
|
6875
7319
|
var COMPOSED_TRIVIA = /* @__PURE__ */ Symbol.for("parseman.composedTrivia");
|
|
7320
|
+
var COMPOSED_COVERAGE_RULES = /* @__PURE__ */ Symbol.for("parseman.composedCoverageRules");
|
|
6876
7321
|
function isIRPiece(p) {
|
|
6877
7322
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
6878
7323
|
}
|
|
6879
|
-
function
|
|
7324
|
+
function coverageRulesOf(carried) {
|
|
7325
|
+
const winners = {};
|
|
7326
|
+
for (const piece of carried) {
|
|
7327
|
+
if (!isIRPiece(piece)) return void 0;
|
|
7328
|
+
const map = evalRuleMapIR(piece.ir);
|
|
7329
|
+
for (const [name, rule] of map) {
|
|
7330
|
+
if (rule._def.tag === "lazy") {
|
|
7331
|
+
try {
|
|
7332
|
+
rule._def.thunk();
|
|
7333
|
+
} catch {
|
|
7334
|
+
continue;
|
|
7335
|
+
}
|
|
7336
|
+
}
|
|
7337
|
+
winners[name] = rule;
|
|
7338
|
+
}
|
|
7339
|
+
}
|
|
7340
|
+
return winners;
|
|
7341
|
+
}
|
|
7342
|
+
function composedCoverageRules(grammar) {
|
|
7343
|
+
return grammar[COMPOSED_COVERAGE_RULES];
|
|
7344
|
+
}
|
|
7345
|
+
function materializePiece(p, trivia2, captureTerminals = false) {
|
|
6880
7346
|
if (!isIRPiece(p)) return p;
|
|
6881
|
-
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns,
|
|
7347
|
+
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
|
|
7348
|
+
...trivia2 ? { trivia: trivia2 } : {},
|
|
7349
|
+
...captureTerminals ? { captureTerminals: true } : {}
|
|
7350
|
+
});
|
|
6882
7351
|
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
6883
7352
|
return pieces;
|
|
6884
7353
|
}
|
|
@@ -6929,6 +7398,9 @@ function composingTriviaOf(items) {
|
|
|
6929
7398
|
return void 0;
|
|
6930
7399
|
}
|
|
6931
7400
|
function compose(items) {
|
|
7401
|
+
if (items.some((item) => item[LEAF_COMPOSED] === true)) {
|
|
7402
|
+
throw new Error("compose: a composeLeaf() result is terminal and cannot be composed again");
|
|
7403
|
+
}
|
|
6932
7404
|
const used = /* @__PURE__ */ new Set();
|
|
6933
7405
|
const trivia2 = composingTriviaOf(items);
|
|
6934
7406
|
const carried = items.flatMap((item) => itemCarried(item, used, trivia2));
|
|
@@ -6936,8 +7408,13 @@ function compose(items) {
|
|
|
6936
7408
|
const map = fuseRules(pieces);
|
|
6937
7409
|
Object.defineProperty(map, COMPOSED_PIECES, { value: carried, enumerable: false });
|
|
6938
7410
|
if (trivia2) Object.defineProperty(map, COMPOSED_TRIVIA, { value: trivia2, enumerable: false });
|
|
7411
|
+
const coverageRules = coverageRulesOf(carried);
|
|
7412
|
+
if (coverageRules) Object.defineProperty(map, COMPOSED_COVERAGE_RULES, { value: coverageRules, enumerable: false });
|
|
6939
7413
|
return map;
|
|
6940
7414
|
}
|
|
7415
|
+
function composeLeaf(_items) {
|
|
7416
|
+
throw new Error("composeLeaf(): requires Parseman macro lowering; runtime composition is forbidden");
|
|
7417
|
+
}
|
|
6941
7418
|
|
|
6942
7419
|
// src/combinators/guard.ts
|
|
6943
7420
|
function guard(predicate) {
|
|
@@ -7101,7 +7578,9 @@ function producesRepetition(def, depth = 0) {
|
|
|
7101
7578
|
// Transparent wrappers — look through to the inner parser.
|
|
7102
7579
|
case "node":
|
|
7103
7580
|
case "transform":
|
|
7581
|
+
case "attempt":
|
|
7104
7582
|
case "token":
|
|
7583
|
+
case "leaf":
|
|
7105
7584
|
case "label":
|
|
7106
7585
|
case "field":
|
|
7107
7586
|
case "expect":
|
|
@@ -7153,8 +7632,8 @@ function replaceAtPath(rebuild, root, path, newNode) {
|
|
|
7153
7632
|
newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(rebuild, root.children[idx], rest, newNode);
|
|
7154
7633
|
return rebuild(root, newChildren);
|
|
7155
7634
|
}
|
|
7156
|
-
function defaultRebuild(node2,
|
|
7157
|
-
return { ...node2, children };
|
|
7635
|
+
function defaultRebuild(node2, children2) {
|
|
7636
|
+
return { ...node2, children: children2 };
|
|
7158
7637
|
}
|
|
7159
7638
|
function shiftRelStart(child, delta) {
|
|
7160
7639
|
const c = child;
|
|
@@ -7494,7 +7973,8 @@ function runOnce(entry, input, options, phase, profileState) {
|
|
|
7494
7973
|
state: options.state,
|
|
7495
7974
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
7496
7975
|
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7497
|
-
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
7976
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {},
|
|
7977
|
+
...options.instrumentation === void 0 ? {} : options.instrumentation
|
|
7498
7978
|
};
|
|
7499
7979
|
const r = invoke(entry, input, 0, ctx);
|
|
7500
7980
|
let unconsumedFrom = null;
|
|
@@ -7549,6 +8029,265 @@ function run(entry, input, options = {}) {
|
|
|
7549
8029
|
};
|
|
7550
8030
|
}
|
|
7551
8031
|
|
|
8032
|
+
// src/coverage.ts
|
|
8033
|
+
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
8034
|
+
function compiledGrammarCoverageDefinitions(grammar) {
|
|
8035
|
+
const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
|
|
8036
|
+
if (!Array.isArray(definitions) || !definitions.every((definition) => typeof definition === "object" && definition !== null && typeof definition.id === "string" && (definition.kind === "rule" || definition.kind === "choice-arm" || definition.kind === "label"))) {
|
|
8037
|
+
throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
|
|
8038
|
+
}
|
|
8039
|
+
return definitions;
|
|
8040
|
+
}
|
|
8041
|
+
function createGrammarInstrumentationContext(options = {}) {
|
|
8042
|
+
return {
|
|
8043
|
+
trackLines: options.trackLines ?? false,
|
|
8044
|
+
...options.state === void 0 ? {} : { state: options.state },
|
|
8045
|
+
...options.collector === void 0 ? {} : { _grammarCoverage: (id) => options.collector.hit(id) },
|
|
8046
|
+
...options.trace === void 0 ? {} : { _grammarTrace: options.trace }
|
|
8047
|
+
};
|
|
8048
|
+
}
|
|
8049
|
+
function createGrammarTraceSink(options) {
|
|
8050
|
+
if (!Number.isInteger(options.capacity) || options.capacity < 0) throw new TypeError("trace capacity must be a finite non-negative integer");
|
|
8051
|
+
const events = [];
|
|
8052
|
+
let detached = false;
|
|
8053
|
+
let truncated = false;
|
|
8054
|
+
let dropped = 0;
|
|
8055
|
+
return {
|
|
8056
|
+
write(event) {
|
|
8057
|
+
if (detached || events.length >= options.capacity) {
|
|
8058
|
+
detached = true;
|
|
8059
|
+
truncated = true;
|
|
8060
|
+
dropped++;
|
|
8061
|
+
return;
|
|
8062
|
+
}
|
|
8063
|
+
events.push(Object.freeze({ ...event }));
|
|
8064
|
+
try {
|
|
8065
|
+
if (options.write?.(event) === false) {
|
|
8066
|
+
detached = true;
|
|
8067
|
+
truncated = true;
|
|
8068
|
+
}
|
|
8069
|
+
} catch {
|
|
8070
|
+
detached = true;
|
|
8071
|
+
truncated = true;
|
|
8072
|
+
}
|
|
8073
|
+
},
|
|
8074
|
+
snapshot() {
|
|
8075
|
+
return Object.freeze({ events: Object.freeze([...events]), truncated, dropped });
|
|
8076
|
+
}
|
|
8077
|
+
};
|
|
8078
|
+
}
|
|
8079
|
+
function createGrammarCoverageCollector(definitions) {
|
|
8080
|
+
const ordered = [...definitions].sort((a, b) => a.id.localeCompare(b.id));
|
|
8081
|
+
const known = new Set(ordered.map((definition) => definition.id));
|
|
8082
|
+
const hits = /* @__PURE__ */ new Set();
|
|
8083
|
+
return {
|
|
8084
|
+
hit(id) {
|
|
8085
|
+
if (known.has(id)) hits.add(id);
|
|
8086
|
+
},
|
|
8087
|
+
snapshot() {
|
|
8088
|
+
const hitList = [...hits].sort();
|
|
8089
|
+
const unhit = ordered.map((definition) => definition.id).filter((id) => !hits.has(id));
|
|
8090
|
+
return { definitions: ordered, hits: hitList, unhit, ratio: ordered.length === 0 ? 1 : hitList.length / ordered.length };
|
|
8091
|
+
},
|
|
8092
|
+
reset() {
|
|
8093
|
+
hits.clear();
|
|
8094
|
+
}
|
|
8095
|
+
};
|
|
8096
|
+
}
|
|
8097
|
+
function grammarCoverageDefinitions(entry, winners) {
|
|
8098
|
+
return buildGrammarPlan(entry, winners).definitions;
|
|
8099
|
+
}
|
|
8100
|
+
function composedGrammarCoverageDefinitions(grammar, startRule) {
|
|
8101
|
+
const winners = composedCoverageRules(grammar);
|
|
8102
|
+
if (!winners) throw new TypeError("semantic coverage needs re-lowerable composed IR; this composition contains an opaque artifact");
|
|
8103
|
+
const entry = winners[startRule];
|
|
8104
|
+
if (!entry) throw new TypeError(`semantic coverage start rule ${JSON.stringify(startRule)} is not a final winner`);
|
|
8105
|
+
return grammarCoverageDefinitions(entry, winners);
|
|
8106
|
+
}
|
|
8107
|
+
function coverageEntry(entry, collector, maps, trace) {
|
|
8108
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
8109
|
+
const build = (parser2) => {
|
|
8110
|
+
const existing = cache.get(parser2);
|
|
8111
|
+
if (existing) return existing;
|
|
8112
|
+
const rule = maps.rules.get(parser2);
|
|
8113
|
+
const wrap = (parse2) => {
|
|
8114
|
+
const wrapped = {
|
|
8115
|
+
_tag: parser2._tag,
|
|
8116
|
+
_meta: parser2._meta,
|
|
8117
|
+
_def: parser2._def,
|
|
8118
|
+
parse(input, pos, ctx) {
|
|
8119
|
+
if (rule) {
|
|
8120
|
+
collector.hit(rule);
|
|
8121
|
+
trace?.write({ id: rule, phase: "enter", offset: pos });
|
|
8122
|
+
}
|
|
8123
|
+
const result = parse2(input, pos, ctx);
|
|
8124
|
+
if (rule) trace?.write(result.ok ? { id: rule, phase: "success", offset: pos, end: result.span.end } : { id: rule, phase: "failure", offset: result.span.end });
|
|
8125
|
+
return result;
|
|
8126
|
+
}
|
|
8127
|
+
};
|
|
8128
|
+
cache.set(parser2, wrapped);
|
|
8129
|
+
return wrapped;
|
|
8130
|
+
};
|
|
8131
|
+
const def = parser2._def;
|
|
8132
|
+
if (def.tag === "lazy") {
|
|
8133
|
+
return wrap((input, pos, ctx) => build(def.thunk()).parse(input, pos, ctx));
|
|
8134
|
+
}
|
|
8135
|
+
if (def.tag === "label") {
|
|
8136
|
+
const base2 = label(def.label, build(def.parser));
|
|
8137
|
+
return wrap((input, pos, ctx) => {
|
|
8138
|
+
const result = base2.parse(input, pos, ctx);
|
|
8139
|
+
if (result.ok) for (const id of maps.labels.get(parser2) ?? []) {
|
|
8140
|
+
collector.hit(id);
|
|
8141
|
+
trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
|
|
8142
|
+
}
|
|
8143
|
+
return result;
|
|
8144
|
+
});
|
|
8145
|
+
}
|
|
8146
|
+
if (def.tag === "choice") {
|
|
8147
|
+
const ids = maps.choices.get(parser2) ?? [];
|
|
8148
|
+
const invocations = [];
|
|
8149
|
+
const arms = def.parsers.map((arm, index) => {
|
|
8150
|
+
const child = build(arm);
|
|
8151
|
+
return {
|
|
8152
|
+
_tag: child._tag,
|
|
8153
|
+
_meta: child._meta,
|
|
8154
|
+
_def: child._def,
|
|
8155
|
+
parse(input, pos, ctx) {
|
|
8156
|
+
const id = ids[index];
|
|
8157
|
+
if (id) trace?.write({ id, phase: "attempt", offset: pos });
|
|
8158
|
+
const result = child.parse(input, pos, ctx);
|
|
8159
|
+
if (result.ok) {
|
|
8160
|
+
if (def.strategy.tag !== "greedyClassify") collector.hit(ids[index]);
|
|
8161
|
+
const invocation = invocations[invocations.length - 1];
|
|
8162
|
+
if (invocation) {
|
|
8163
|
+
invocation.lastSuccessfulArm = index;
|
|
8164
|
+
invocation.successfulArms.push(index);
|
|
8165
|
+
}
|
|
8166
|
+
} else if (id) {
|
|
8167
|
+
trace?.write({ id, phase: "failure", offset: result.span.end });
|
|
8168
|
+
trace?.write({ id, phase: "backtrack", offset: pos });
|
|
8169
|
+
}
|
|
8170
|
+
return result;
|
|
8171
|
+
}
|
|
8172
|
+
};
|
|
8173
|
+
});
|
|
8174
|
+
const args = arms.map((arm, index) => def.gates[index] ? { combinator: arm, gate: def.gates[index] } : arm);
|
|
8175
|
+
const unsafeChoice = choice;
|
|
8176
|
+
const baseChoice = unsafeChoice(...args);
|
|
8177
|
+
return wrap((input, pos, ctx) => {
|
|
8178
|
+
const invocation = { lastSuccessfulArm: void 0, successfulArms: [] };
|
|
8179
|
+
invocations.push(invocation);
|
|
8180
|
+
const result = baseChoice.parse(input, pos, ctx);
|
|
8181
|
+
const strategy = def.strategy;
|
|
8182
|
+
if (result.ok && strategy.tag === "greedyClassify") {
|
|
8183
|
+
const text = input.slice(pos, result.span.end);
|
|
8184
|
+
const classified = def.parsers.findIndex((arm, index) => index !== strategy.superIndex && getCoreLiteralValue(arm) === text);
|
|
8185
|
+
if (classified !== -1) invocation.lastSuccessfulArm = classified;
|
|
8186
|
+
else invocation.lastSuccessfulArm = strategy.superIndex;
|
|
8187
|
+
}
|
|
8188
|
+
if (result.ok && invocation.lastSuccessfulArm !== void 0) {
|
|
8189
|
+
const id = ids[invocation.lastSuccessfulArm];
|
|
8190
|
+
for (const rejected of invocation.successfulArms) {
|
|
8191
|
+
if (rejected !== invocation.lastSuccessfulArm) {
|
|
8192
|
+
const rejectedId = ids[rejected];
|
|
8193
|
+
if (rejectedId) {
|
|
8194
|
+
trace?.write({ id: rejectedId, phase: "failure", offset: pos });
|
|
8195
|
+
trace?.write({ id: rejectedId, phase: "backtrack", offset: pos });
|
|
8196
|
+
}
|
|
8197
|
+
}
|
|
8198
|
+
}
|
|
8199
|
+
if (id) {
|
|
8200
|
+
collector.hit(id);
|
|
8201
|
+
trace?.write({ id, phase: "selected", offset: pos, end: result.span.end });
|
|
8202
|
+
trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
|
|
8203
|
+
}
|
|
8204
|
+
}
|
|
8205
|
+
invocations.pop();
|
|
8206
|
+
return result;
|
|
8207
|
+
});
|
|
8208
|
+
}
|
|
8209
|
+
const base = (() => {
|
|
8210
|
+
switch (def.tag) {
|
|
8211
|
+
case "sequence": {
|
|
8212
|
+
const unsafeSequence = sequence;
|
|
8213
|
+
return unsafeSequence(...def.parsers.map(build));
|
|
8214
|
+
}
|
|
8215
|
+
case "many":
|
|
8216
|
+
return many(build(def.parser));
|
|
8217
|
+
case "oneOrMore":
|
|
8218
|
+
return oneOrMore(build(def.parser));
|
|
8219
|
+
case "optional":
|
|
8220
|
+
return optional(build(def.parser));
|
|
8221
|
+
case "attempt": {
|
|
8222
|
+
const base2 = attempt(build(def.parser));
|
|
8223
|
+
const id = maps.attempts.get(parser2);
|
|
8224
|
+
return id === void 0 ? base2 : {
|
|
8225
|
+
...base2,
|
|
8226
|
+
parse(input, pos, ctx) {
|
|
8227
|
+
const result = base2.parse(input, pos, ctx);
|
|
8228
|
+
if (!result.ok) trace?.write({ id, phase: "rollback", offset: pos });
|
|
8229
|
+
return result;
|
|
8230
|
+
}
|
|
8231
|
+
};
|
|
8232
|
+
}
|
|
8233
|
+
case "sepBy":
|
|
8234
|
+
return sepBy(build(def.parser), build(def.separator));
|
|
8235
|
+
case "transform":
|
|
8236
|
+
return transform(build(def.parser), def.fn);
|
|
8237
|
+
case "skip":
|
|
8238
|
+
return skip(build(def.main), build(def.skipped));
|
|
8239
|
+
case "trivia":
|
|
8240
|
+
return trivia(build(def.parser));
|
|
8241
|
+
case "token":
|
|
8242
|
+
return token(build(def.parser));
|
|
8243
|
+
case "leaf":
|
|
8244
|
+
return leaf(build(def.parser), def.fn);
|
|
8245
|
+
case "field":
|
|
8246
|
+
return field(def.name, build(def.parser));
|
|
8247
|
+
case "grammar":
|
|
8248
|
+
return parser({
|
|
8249
|
+
...def.triviaParser === void 0 ? def.clearTrivia ? { trivia: null } : {} : { trivia: build(def.triviaParser) },
|
|
8250
|
+
...def.captureTrivia ? { captureTrivia: true } : {},
|
|
8251
|
+
...def.trackLines ? { trackLines: true } : {}
|
|
8252
|
+
}, build(def.parser));
|
|
8253
|
+
case "not":
|
|
8254
|
+
return not(build(def.parser));
|
|
8255
|
+
case "node": {
|
|
8256
|
+
const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
|
|
8257
|
+
return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
|
|
8258
|
+
}
|
|
8259
|
+
case "guard":
|
|
8260
|
+
return guard(def.predicate);
|
|
8261
|
+
case "withCtx":
|
|
8262
|
+
return withCtx(def.extra, build(def.parser));
|
|
8263
|
+
case "expect":
|
|
8264
|
+
return expect(build(def.parser), def.label);
|
|
8265
|
+
case "scanTo":
|
|
8266
|
+
return scanTo(build(def.sentinel), { skip: def.skip.map(build), orEOF: def.orEOF });
|
|
8267
|
+
case "literal":
|
|
8268
|
+
case "regex":
|
|
8269
|
+
case "keywords":
|
|
8270
|
+
return parser2;
|
|
8271
|
+
case "recover":
|
|
8272
|
+
case "unknown":
|
|
8273
|
+
throw new TypeError(`runWithGrammarCoverage does not yet support ${def.tag}`);
|
|
8274
|
+
default:
|
|
8275
|
+
return parser2;
|
|
8276
|
+
}
|
|
8277
|
+
})();
|
|
8278
|
+
return wrap((input, pos, ctx) => base.parse(input, pos, ctx));
|
|
8279
|
+
};
|
|
8280
|
+
return build(entry);
|
|
8281
|
+
}
|
|
8282
|
+
function runWithGrammarCoverage(entry, input, options = {}) {
|
|
8283
|
+
if (typeof entry === "function") throw new TypeError("runWithGrammarCoverage currently requires an interpreter combinator entry");
|
|
8284
|
+
const plan = buildGrammarPlan(entry);
|
|
8285
|
+
const definitions = plan.definitions;
|
|
8286
|
+
const collector = options.collector ?? createGrammarCoverageCollector(definitions);
|
|
8287
|
+
const { collector: _collector, trace, ...runOptions } = options;
|
|
8288
|
+
return { result: run(coverageEntry(entry, collector, plan, trace), input, runOptions), coverage: collector.snapshot() };
|
|
8289
|
+
}
|
|
8290
|
+
|
|
7552
8291
|
// src/cst/trivia-index.ts
|
|
7553
8292
|
function merge(map, key, run2) {
|
|
7554
8293
|
if (run2.length === 0) return;
|
|
@@ -7619,9 +8358,9 @@ function buildTriviaIndex(root, input = "", opts) {
|
|
|
7619
8358
|
function walk(root, visitor, ctx = void 0) {
|
|
7620
8359
|
const go = (node2, parent) => {
|
|
7621
8360
|
const descend = visitor.enter ? visitor.enter(node2, parent, ctx) : void 0;
|
|
7622
|
-
const
|
|
7623
|
-
if (descend !== false && Array.isArray(
|
|
7624
|
-
for (const child of
|
|
8361
|
+
const children2 = node2.children;
|
|
8362
|
+
if (descend !== false && Array.isArray(children2)) {
|
|
8363
|
+
for (const child of children2) go(child, node2);
|
|
7625
8364
|
}
|
|
7626
8365
|
visitor.leave?.(node2, parent, ctx);
|
|
7627
8366
|
};
|
|
@@ -7637,9 +8376,9 @@ function createVisitor(handlers) {
|
|
|
7637
8376
|
},
|
|
7638
8377
|
visitChildren(node2) {
|
|
7639
8378
|
const out = [];
|
|
7640
|
-
const
|
|
7641
|
-
if (Array.isArray(
|
|
7642
|
-
for (const child of
|
|
8379
|
+
const children2 = node2.children;
|
|
8380
|
+
if (Array.isArray(children2)) {
|
|
8381
|
+
for (const child of children2) {
|
|
7643
8382
|
const r = api.visit(child);
|
|
7644
8383
|
if (r !== void 0) out.push(r);
|
|
7645
8384
|
}
|