parseman 0.27.0 → 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/grammar.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +8 -0
- package/dist/combinators/node.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 +7 -0
- 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/inline-callback.d.ts.map +1 -1
- 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/cst/trivia-entries.d.ts +2 -0
- package/dist/cst/trivia-entries.d.ts.map +1 -1
- 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 +936 -103
- 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 +936 -103
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +7 -2
- package/dist/language-service/index.cjs.map +2 -2
- package/dist/language-service/index.js +7 -2
- package/dist/language-service/index.js.map +2 -2
- package/dist/plugin/direct-builder-static.d.ts +8 -0
- package/dist/plugin/direct-builder-static.d.ts.map +1 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +1084 -145
- 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 +1084 -145
- 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 +16 -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":
|
|
@@ -1525,6 +1541,12 @@ function scanTrivia(input, cur, ctx) {
|
|
|
1525
1541
|
const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1526
1542
|
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
1527
1543
|
}
|
|
1544
|
+
function consumeTrivia(input, cur, ctx) {
|
|
1545
|
+
if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
|
|
1546
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1547
|
+
scan.commit();
|
|
1548
|
+
return scan.end;
|
|
1549
|
+
}
|
|
1528
1550
|
function fastTriviaScanner(trivia2) {
|
|
1529
1551
|
const cached = fastTriviaCache.get(trivia2);
|
|
1530
1552
|
if (cached !== void 0) return cached;
|
|
@@ -1803,6 +1825,24 @@ function sequence(...parsers) {
|
|
|
1803
1825
|
};
|
|
1804
1826
|
}
|
|
1805
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
|
+
|
|
1806
1846
|
// src/combinators/repeat.ts
|
|
1807
1847
|
function repItem(combinator, input, cur, ctx) {
|
|
1808
1848
|
const mark = saveTriviaMark(ctx);
|
|
@@ -2112,10 +2152,14 @@ function markUnusedValues(root) {
|
|
|
2112
2152
|
case "label":
|
|
2113
2153
|
case "trivia":
|
|
2114
2154
|
case "token":
|
|
2155
|
+
case "attempt":
|
|
2115
2156
|
case "withCtx":
|
|
2116
2157
|
case "expect":
|
|
2117
2158
|
visit(def.parser, consumed);
|
|
2118
2159
|
return;
|
|
2160
|
+
case "leaf":
|
|
2161
|
+
visit(def.parser, true);
|
|
2162
|
+
return;
|
|
2119
2163
|
case "lazy":
|
|
2120
2164
|
return;
|
|
2121
2165
|
default:
|
|
@@ -2238,6 +2282,20 @@ function confirmedBuildArity(src) {
|
|
|
2238
2282
|
if (/\barguments\b/.test(s)) return null;
|
|
2239
2283
|
return parts.length;
|
|
2240
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
|
+
}
|
|
2241
2299
|
function buildReadsTrivia(def) {
|
|
2242
2300
|
if (!def.build) return true;
|
|
2243
2301
|
const src = def.buildSrc ?? def.build.toString();
|
|
@@ -2293,9 +2351,11 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2293
2351
|
case "many":
|
|
2294
2352
|
case "oneOrMore":
|
|
2295
2353
|
case "optional":
|
|
2354
|
+
case "attempt":
|
|
2296
2355
|
case "transform":
|
|
2297
2356
|
case "trivia":
|
|
2298
2357
|
case "token":
|
|
2358
|
+
case "leaf":
|
|
2299
2359
|
case "label":
|
|
2300
2360
|
case "expect":
|
|
2301
2361
|
case "withCtx":
|
|
@@ -2328,9 +2388,11 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2328
2388
|
case "keywords":
|
|
2329
2389
|
case "guard":
|
|
2330
2390
|
case "token":
|
|
2391
|
+
case "leaf":
|
|
2331
2392
|
return false;
|
|
2332
2393
|
// Transparent single-child wrappers: recurse.
|
|
2333
2394
|
case "optional":
|
|
2395
|
+
case "attempt":
|
|
2334
2396
|
case "transform":
|
|
2335
2397
|
case "trivia":
|
|
2336
2398
|
case "label":
|
|
@@ -2354,6 +2416,54 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2354
2416
|
return true;
|
|
2355
2417
|
}
|
|
2356
2418
|
}
|
|
2419
|
+
function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
2420
|
+
if (seen.has(p)) return false;
|
|
2421
|
+
seen.add(p);
|
|
2422
|
+
const d = p._def;
|
|
2423
|
+
switch (d.tag) {
|
|
2424
|
+
case "grammar":
|
|
2425
|
+
return d.captureTrivia === true || parserEnablesTriviaCapture(d.parser, seen);
|
|
2426
|
+
case "node":
|
|
2427
|
+
return false;
|
|
2428
|
+
case "sequence":
|
|
2429
|
+
case "choice":
|
|
2430
|
+
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2431
|
+
case "sepBy":
|
|
2432
|
+
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2433
|
+
case "skip":
|
|
2434
|
+
return parserEnablesTriviaCapture(d.main, seen) || parserEnablesTriviaCapture(d.skipped, seen);
|
|
2435
|
+
case "scanTo":
|
|
2436
|
+
return parserEnablesTriviaCapture(d.sentinel, seen) || d.skip.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2437
|
+
case "recover":
|
|
2438
|
+
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.sentinel, seen);
|
|
2439
|
+
case "many":
|
|
2440
|
+
case "oneOrMore":
|
|
2441
|
+
case "optional":
|
|
2442
|
+
case "attempt":
|
|
2443
|
+
case "transform":
|
|
2444
|
+
case "trivia":
|
|
2445
|
+
case "token":
|
|
2446
|
+
case "label":
|
|
2447
|
+
case "field":
|
|
2448
|
+
case "expect":
|
|
2449
|
+
case "withCtx":
|
|
2450
|
+
case "not":
|
|
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;
|
|
2456
|
+
case "lazy": {
|
|
2457
|
+
try {
|
|
2458
|
+
return parserEnablesTriviaCapture(d.thunk(), seen);
|
|
2459
|
+
} catch {
|
|
2460
|
+
return false;
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
default:
|
|
2464
|
+
return false;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2357
2467
|
function buildFieldMap(captures) {
|
|
2358
2468
|
if (!captures?.length) return void 0;
|
|
2359
2469
|
const out = {};
|
|
@@ -2391,11 +2501,13 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2391
2501
|
};
|
|
2392
2502
|
const unwrap = opts?.unwrap === true;
|
|
2393
2503
|
const collapse = opts?.collapse === true;
|
|
2504
|
+
const captureTrivia = opts?.captureTrivia === true;
|
|
2505
|
+
const trailingTrivia = opts?.trailingTrivia === true;
|
|
2394
2506
|
if (unwrap && collapse) {
|
|
2395
2507
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
2396
2508
|
}
|
|
2397
|
-
const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
|
|
2398
|
-
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
2509
|
+
const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
|
|
2510
|
+
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
|
|
2399
2511
|
const clonesState = build ? buildReadsState(def) : true;
|
|
2400
2512
|
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
2401
2513
|
return {
|
|
@@ -2411,16 +2523,21 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2411
2523
|
ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
|
|
2412
2524
|
}
|
|
2413
2525
|
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
2414
|
-
|
|
2526
|
+
let r = combinator.parse(input, pos, ctx);
|
|
2527
|
+
if (r.ok && trailingTrivia && ctx.trivia) {
|
|
2528
|
+
const end = consumeTrivia(input, r.span.end, ctx);
|
|
2529
|
+
r = { ...r, span: { start: r.span.start, end } };
|
|
2530
|
+
}
|
|
2415
2531
|
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
2416
2532
|
ctx._fields = savedFields;
|
|
2417
2533
|
ctx._triviaCaptureMask = savedMask;
|
|
2418
|
-
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2534
|
+
const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2419
2535
|
if (!r.ok) return r;
|
|
2420
2536
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2421
2537
|
const nodeType = def.type ?? missingInferredType();
|
|
2422
|
-
const
|
|
2423
|
-
const
|
|
2538
|
+
const cstOutput = ctx.build?._parsemanCstOutput === true;
|
|
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 };
|
|
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 };
|
|
2424
2541
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2425
2542
|
pushCstChild(ctx, built, rawEntry);
|
|
2426
2543
|
}
|
|
@@ -2537,6 +2654,7 @@ function parser(opts, root) {
|
|
|
2537
2654
|
parser: root,
|
|
2538
2655
|
triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
|
|
2539
2656
|
clearTrivia,
|
|
2657
|
+
...opts.captureTrivia ? { captureTrivia: true } : {},
|
|
2540
2658
|
trackLines: opts.trackLines ?? false
|
|
2541
2659
|
},
|
|
2542
2660
|
parse(input, pos, _ctx) {
|
|
@@ -2649,6 +2767,141 @@ function token(root) {
|
|
|
2649
2767
|
}
|
|
2650
2768
|
};
|
|
2651
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
|
+
}
|
|
2652
2905
|
|
|
2653
2906
|
// src/compiler/scannable-run.ts
|
|
2654
2907
|
var BACKSLASH = 92;
|
|
@@ -3698,7 +3951,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
|
|
|
3698
3951
|
` if (${m.end} > _e) {`,
|
|
3699
3952
|
` if (_cap) {`,
|
|
3700
3953
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
|
|
3701
|
-
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
3954
|
+
` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
3702
3955
|
` }`,
|
|
3703
3956
|
` _e = ${m.end}`,
|
|
3704
3957
|
` continue`,
|
|
@@ -3754,7 +4007,7 @@ function analyzeTriviaFastPath(trivia2) {
|
|
|
3754
4007
|
var CAP_RECORD = [
|
|
3755
4008
|
` if (_cap && _e > _pos) {`,
|
|
3756
4009
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
|
|
3757
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
4010
|
+
` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
3758
4011
|
` }`
|
|
3759
4012
|
].join("\n");
|
|
3760
4013
|
function composeFastLoop(shapes) {
|
|
@@ -3814,7 +4067,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
|
3814
4067
|
` const _ce = _e + _m${i}[0].length`,
|
|
3815
4068
|
` if (_cap) {`,
|
|
3816
4069
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
3817
|
-
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
4070
|
+
` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
3818
4071
|
` }`,
|
|
3819
4072
|
` _e = _ce`,
|
|
3820
4073
|
` _matched = true`,
|
|
@@ -3852,7 +4105,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
|
|
|
3852
4105
|
` const _ce = _r${i}.span.end`,
|
|
3853
4106
|
` if (_cap) {`,
|
|
3854
4107
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
3855
|
-
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
4108
|
+
` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
3856
4109
|
` }`,
|
|
3857
4110
|
` _e = _ce`,
|
|
3858
4111
|
` _matched = true`,
|
|
@@ -4033,21 +4286,23 @@ function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
|
4033
4286
|
}
|
|
4034
4287
|
function failBody(ctx, expected, posExpr) {
|
|
4035
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} }); `;
|
|
4036
4290
|
if (ctx.failLabel) {
|
|
4037
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4038
|
-
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} }`;
|
|
4039
4293
|
}
|
|
4040
|
-
return probe + failReturn(expected, posExpr);
|
|
4294
|
+
return probe + trace + failReturn(expected, posExpr);
|
|
4041
4295
|
}
|
|
4042
4296
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
4043
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} }); `;
|
|
4044
4299
|
if (ctx.failLabel) {
|
|
4045
|
-
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}`;
|
|
4046
4301
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
4047
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
4302
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
|
|
4048
4303
|
}
|
|
4049
|
-
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4050
|
-
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);
|
|
4051
4306
|
}
|
|
4052
4307
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
4053
4308
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -4082,7 +4337,7 @@ var NAMED_FN_END = "_pfEnd";
|
|
|
4082
4337
|
function namedFnPrelude() {
|
|
4083
4338
|
return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
|
|
4084
4339
|
}
|
|
4085
|
-
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
4340
|
+
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar, failureRuleId) {
|
|
4086
4341
|
ctx.namedFnDecls.push([
|
|
4087
4342
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
4088
4343
|
` _pfail: {`,
|
|
@@ -4090,6 +4345,7 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
|
4090
4345
|
` ${NAMED_FN_END} = ${endVar}`,
|
|
4091
4346
|
` return ${valueVar}`,
|
|
4092
4347
|
` }`,
|
|
4348
|
+
...failureRuleId === void 0 ? [] : [` _ctx._grammarTrace?.write({ id: ${JSON.stringify(failureRuleId)}, phase: 'failure', offset: _ctx._fe ?? _pos })`],
|
|
4093
4349
|
` return ${NAMED_FN_FAIL}`,
|
|
4094
4350
|
`}`
|
|
4095
4351
|
].join("\n"));
|
|
@@ -4195,7 +4451,7 @@ function ensureTriviaFn(ctx) {
|
|
|
4195
4451
|
` }`,
|
|
4196
4452
|
` if (_cap && _e > _pos) {`,
|
|
4197
4453
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
|
|
4198
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
4454
|
+
` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
4199
4455
|
` }`,
|
|
4200
4456
|
` return _e`,
|
|
4201
4457
|
`}`
|
|
@@ -4251,6 +4507,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4251
4507
|
case "not":
|
|
4252
4508
|
case "trivia":
|
|
4253
4509
|
case "token":
|
|
4510
|
+
case "leaf":
|
|
4254
4511
|
case "scanTo":
|
|
4255
4512
|
case "unknown":
|
|
4256
4513
|
return false;
|
|
@@ -4262,6 +4519,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4262
4519
|
// nothing committed remains.
|
|
4263
4520
|
case "choice":
|
|
4264
4521
|
return false;
|
|
4522
|
+
case "attempt":
|
|
4523
|
+
return false;
|
|
4265
4524
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
4266
4525
|
case "optional":
|
|
4267
4526
|
case "many":
|
|
@@ -4314,6 +4573,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4314
4573
|
case "keywords":
|
|
4315
4574
|
case "node":
|
|
4316
4575
|
case "token":
|
|
4576
|
+
case "leaf":
|
|
4317
4577
|
return true;
|
|
4318
4578
|
case "not":
|
|
4319
4579
|
case "guard":
|
|
@@ -4328,6 +4588,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4328
4588
|
case "many":
|
|
4329
4589
|
case "oneOrMore":
|
|
4330
4590
|
case "optional":
|
|
4591
|
+
case "attempt":
|
|
4331
4592
|
case "transform":
|
|
4332
4593
|
case "label":
|
|
4333
4594
|
case "field":
|
|
@@ -4669,35 +4930,55 @@ function needsFirstSetGuard(p) {
|
|
|
4669
4930
|
const fs = p._meta.firstSet;
|
|
4670
4931
|
return fs.kind !== "any" && !canMatchEmptyAtStart(p);
|
|
4671
4932
|
}
|
|
4672
|
-
function
|
|
4673
|
-
|
|
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) {
|
|
4674
4951
|
const r = emit(p, ctx, pos);
|
|
4675
|
-
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)];
|
|
4676
4953
|
}
|
|
4677
4954
|
const { stmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
|
|
4678
4955
|
return [
|
|
4956
|
+
...coverageAttempt(ctx, coverageId, pos),
|
|
4679
4957
|
...stmts,
|
|
4680
|
-
...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)}`),
|
|
4681
4959
|
`${ind(ctx)}${valV} = ${valVar}`,
|
|
4682
|
-
`${ind(ctx)}${endV} = ${endVar}
|
|
4960
|
+
`${ind(ctx)}${endV} = ${endVar}`,
|
|
4961
|
+
...coverageHit(ctx, coverageId, pos, endVar)
|
|
4683
4962
|
];
|
|
4684
4963
|
}
|
|
4685
|
-
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4964
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageId) {
|
|
4686
4965
|
const p = def.parsers[i];
|
|
4687
4966
|
const gate = def.gates[i];
|
|
4688
|
-
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4967
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV, coverageId);
|
|
4689
4968
|
const gateIdx = ctx.mapFns.length;
|
|
4690
4969
|
ctx.mapFns.push(gate);
|
|
4691
4970
|
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4692
4971
|
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4693
4972
|
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4694
4973
|
ctx.indent++;
|
|
4695
|
-
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4974
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV, coverageId));
|
|
4696
4975
|
ctx.indent--;
|
|
4697
4976
|
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4698
4977
|
return stmts;
|
|
4699
4978
|
}
|
|
4700
|
-
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);
|
|
4701
4982
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4702
4983
|
if (def.disjoint) {
|
|
4703
4984
|
const codeV = v(ctx, "_code");
|
|
@@ -4716,7 +4997,7 @@ function emitChoice(def, ctx, pos) {
|
|
|
4716
4997
|
stmts.push(`${ind(ctx)}{`);
|
|
4717
4998
|
ctx.indent++;
|
|
4718
4999
|
stmts.push(
|
|
4719
|
-
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
5000
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]),
|
|
4720
5001
|
`${ind(ctx)}break`
|
|
4721
5002
|
);
|
|
4722
5003
|
ctx.indent--;
|
|
@@ -4735,16 +5016,16 @@ function emitChoice(def, ctx, pos) {
|
|
|
4735
5016
|
first = false;
|
|
4736
5017
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4737
5018
|
ctx.indent++;
|
|
4738
|
-
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
5019
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]));
|
|
4739
5020
|
ctx.indent--;
|
|
4740
5021
|
stmts.push(`${ind(ctx)}}`);
|
|
4741
5022
|
}
|
|
4742
5023
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4743
5024
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4744
5025
|
}
|
|
4745
|
-
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
|
|
5026
|
+
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
4746
5027
|
}
|
|
4747
|
-
function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
5028
|
+
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
4748
5029
|
const superParser = def.parsers[superIndex];
|
|
4749
5030
|
const regexDef = getCoreRegexDef(superParser);
|
|
4750
5031
|
const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
@@ -4760,10 +5041,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4760
5041
|
const endV = v(ctx, "_ge");
|
|
4761
5042
|
const valV = v(ctx, "_gcv");
|
|
4762
5043
|
const regexExpected = JSON.stringify(deriveExpected(superParser));
|
|
5044
|
+
const superCoverageId = coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`;
|
|
4763
5045
|
const stmts = [
|
|
5046
|
+
...coverageAttempt(ctx, superCoverageId, pos),
|
|
4764
5047
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
4765
5048
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
4766
|
-
...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, regexExpected, pos)),
|
|
5049
|
+
...emitIfFail(ctx, `${matchV} === null`, `${coverageFailureBacktrack(ctx, superCoverageId, pos, pos).join("; ")}; ${failArrBody(ctx, regexExpected, pos)}`),
|
|
4767
5050
|
`${ind(ctx)}const ${wordV} = ${matchV}[0]`,
|
|
4768
5051
|
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
|
|
4769
5052
|
`${ind(ctx)}let ${valV}`
|
|
@@ -4779,8 +5062,9 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4779
5062
|
stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
|
|
4780
5063
|
ctx.indent++;
|
|
4781
5064
|
const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
|
|
5065
|
+
stmts.push(...coverageFailureBacktrack(ctx, superCoverageId, pos, pos));
|
|
4782
5066
|
stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
|
|
4783
|
-
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));
|
|
4784
5068
|
ctx.indent--;
|
|
4785
5069
|
stmts.push(`${ind(ctx)}}`);
|
|
4786
5070
|
}
|
|
@@ -4788,12 +5072,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4788
5072
|
const regexKw = first ? "if" : "else";
|
|
4789
5073
|
stmts.push(`${ind(ctx)}${regexKw} {`);
|
|
4790
5074
|
ctx.indent++;
|
|
4791
|
-
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));
|
|
4792
5076
|
ctx.indent--;
|
|
4793
5077
|
stmts.push(`${ind(ctx)}}`);
|
|
4794
5078
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4795
5079
|
}
|
|
4796
|
-
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
5080
|
+
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, coverageBase) {
|
|
4797
5081
|
const valV = v(ctx, "_llv");
|
|
4798
5082
|
const endV = v(ctx, "_lle");
|
|
4799
5083
|
const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
|
|
@@ -4810,10 +5094,12 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4810
5094
|
ctx.indent++;
|
|
4811
5095
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
4812
5096
|
stmts.push(
|
|
5097
|
+
...coverageAttempt(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos),
|
|
4813
5098
|
...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
|
|
4814
5099
|
...tR.stmts,
|
|
4815
5100
|
`${ind(ctx)}${valV} = ${tR.valueVar}`,
|
|
4816
|
-
`${ind(ctx)}${endV} = ${litEnd}
|
|
5101
|
+
`${ind(ctx)}${endV} = ${litEnd}`,
|
|
5102
|
+
...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos, litEnd)
|
|
4817
5103
|
);
|
|
4818
5104
|
ctx.indent--;
|
|
4819
5105
|
stmts.push(`${ind(ctx)}}`);
|
|
@@ -4821,16 +5107,18 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4821
5107
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4822
5108
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4823
5109
|
}
|
|
4824
|
-
function emitFirstMatch(def, ctx, pos) {
|
|
5110
|
+
function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
4825
5111
|
const resValV = v(ctx, "_crv");
|
|
4826
5112
|
const resEndV = v(ctx, "_cre");
|
|
4827
5113
|
const resOkV = v(ctx, "_crok");
|
|
4828
5114
|
const codeV = v(ctx, "_chcode");
|
|
4829
5115
|
const slots = def.parsers.map(() => v(ctx, "_cfx"));
|
|
5116
|
+
const autoRejectedV = coverageBase === void 0 ? void 0 : v(ctx, "_carej");
|
|
4830
5117
|
const ind0 = ind(ctx);
|
|
4831
5118
|
const stmts = [
|
|
4832
5119
|
`${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`,
|
|
4833
5120
|
`${ind0}let ${slots.join(", ")}`,
|
|
5121
|
+
...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
|
|
4834
5122
|
`${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
|
|
4835
5123
|
];
|
|
4836
5124
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
@@ -4866,6 +5154,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4866
5154
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4867
5155
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
4868
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} })`);
|
|
4869
5158
|
if (markLeaves) {
|
|
4870
5159
|
stmts.push(
|
|
4871
5160
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
@@ -4888,13 +5177,21 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4888
5177
|
stmts.push(`${ind(ctx)} ${resValV} = ${valVar}`);
|
|
4889
5178
|
stmts.push(`${ind(ctx)} ${resEndV} = ${endVar}`);
|
|
4890
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));
|
|
4891
5184
|
stmts.push(`${ind(ctx)} }`);
|
|
5185
|
+
if (autoRejectedV !== void 0) {
|
|
5186
|
+
stmts.push(`${ind(ctx)} else { ${autoRejectedV}.push(${JSON.stringify(`${coverageBase}${i}`)}) }`);
|
|
5187
|
+
}
|
|
4892
5188
|
stmts.push(`${ind(ctx)}}`);
|
|
4893
|
-
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} });`} }`);
|
|
4894
5190
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
4895
5191
|
} else {
|
|
4896
|
-
|
|
4897
|
-
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} })`} }`);
|
|
4898
5195
|
}
|
|
4899
5196
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
4900
5197
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -4904,12 +5201,12 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4904
5201
|
stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
|
|
4905
5202
|
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
4906
5203
|
}
|
|
4907
|
-
function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
5204
|
+
function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
|
|
4908
5205
|
if (strategy.tag === "greedyClassify")
|
|
4909
|
-
return emitGreedyClassify(def, strategy.superIndex, ctx, pos);
|
|
5206
|
+
return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
|
|
4910
5207
|
if (strategy.tag === "literalsLongestFirst")
|
|
4911
|
-
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
4912
|
-
return emitFirstMatch(def, ctx, pos);
|
|
5208
|
+
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
|
|
5209
|
+
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
4913
5210
|
}
|
|
4914
5211
|
function pushMapFn(ctx, fn, src) {
|
|
4915
5212
|
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
@@ -5027,6 +5324,27 @@ function emitOptional(def, ctx, pos) {
|
|
|
5027
5324
|
];
|
|
5028
5325
|
return { stmts, valueVar: valV, endVar: endV };
|
|
5029
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
|
+
}
|
|
5030
5348
|
function emitSepBy(_p, def, ctx, pos) {
|
|
5031
5349
|
const arrV = v(ctx, "_arr");
|
|
5032
5350
|
const curV = v(ctx, "_cur");
|
|
@@ -5317,6 +5635,36 @@ function emitToken(def, ctx, pos) {
|
|
|
5317
5635
|
endVar: inner.endVar
|
|
5318
5636
|
};
|
|
5319
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
|
+
}
|
|
5320
5668
|
function emitNode(def, ctx, pos) {
|
|
5321
5669
|
if (def.type === void 0) {
|
|
5322
5670
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -5330,17 +5678,20 @@ function emitNode(def, ctx, pos) {
|
|
|
5330
5678
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
5331
5679
|
}
|
|
5332
5680
|
const i = ind(ctx);
|
|
5333
|
-
const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
|
|
5681
|
+
const capturesTrivia = mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
|
|
5334
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));
|
|
5335
5685
|
const hasFields = parserHasOwnFields(def.parser);
|
|
5336
5686
|
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
5687
|
+
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
5337
5688
|
const chV = v(ctx, "_ch");
|
|
5338
5689
|
const rawV = v(ctx, "_raw");
|
|
5339
|
-
const capTLv = structural ? v(ctx, "_ctl") : null;
|
|
5690
|
+
const capTLv = structural || capturesTrivia ? v(ctx, "_ctl") : null;
|
|
5340
5691
|
const capSTv = structural ? v(ctx, "_cst") : null;
|
|
5341
5692
|
const capFv = structural && hasFields ? v(ctx, "_cf") : null;
|
|
5342
5693
|
const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
5343
|
-
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
5694
|
+
if (!capturesTrivia || structural) ctx.needsEmptyTl = true;
|
|
5344
5695
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
5345
5696
|
const smk = structural ? v(ctx, "_smk") : null;
|
|
5346
5697
|
if (structural) ctx.needsHostReads = true;
|
|
@@ -5349,16 +5700,21 @@ function emitNode(def, ctx, pos) {
|
|
|
5349
5700
|
const profHoist = `${i}const ${pmV} = _ctx._pmProfile, ${recV} = ${pmV}?.phase === 'recognizer', ${capV} = ${pmV}?.phase === 'capture'`;
|
|
5350
5701
|
const profileRecognizer = recV;
|
|
5351
5702
|
const profileCapture = capV;
|
|
5352
|
-
const
|
|
5353
|
-
|
|
5354
|
-
const
|
|
5703
|
+
const directCstV = !structural && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
5704
|
+
const directCstGate = directCstV === null ? "false" : `${profileCapture} || _ctx.build?._parsemanCstOutput === true`;
|
|
5705
|
+
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
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)))` : ""}
|
|
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`}`;
|
|
5710
|
+
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
5355
5711
|
const fieldsOn = structural ? capFv ?? "false" : `${profileRecognizer} ? false : ${capturesFields ? "true" : "false"}`;
|
|
5356
5712
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
5357
5713
|
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
5358
5714
|
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
5359
|
-
const needsTriviaFrame = parserHasTriviaSite(def.parser);
|
|
5715
|
+
const needsTriviaFrame = def.trailingTrivia === true || parserHasTriviaSite(def.parser);
|
|
5360
5716
|
const saveTrivia = needsTriviaFrame ? `, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}` : "";
|
|
5361
|
-
const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia =
|
|
5717
|
+
const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${capTLv ?? "false"}; _ctx._cstTriviaLog = ${innerTl}${smk ? `; _ctx._triviaCaptureMask = ${capTLv} && _ctx.build !== undefined && _ctx.build._parsemanTriviaKinds !== undefined ? _ctx.build._parsemanTriviaKinds(${JSON.stringify(def.type)}) : ${smk}` : ""}` : "";
|
|
5362
5718
|
const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
|
|
5363
5719
|
const stmts = [
|
|
5364
5720
|
profHoist,
|
|
@@ -5366,8 +5722,13 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5366
5722
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
5367
5723
|
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}${installTrivia}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
5368
5724
|
];
|
|
5369
|
-
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
5725
|
+
const { stmts: innerStmts, okVar, endVar: innerEndVar } = emitFallible(def.parser, ctx, pos);
|
|
5726
|
+
const endVar = def.trailingTrivia === true && ctx.activeTrivia ? v(ctx, "_trailend") : innerEndVar;
|
|
5370
5727
|
stmts.push(...innerStmts);
|
|
5728
|
+
if (def.trailingTrivia === true && ctx.activeTrivia) {
|
|
5729
|
+
const triviaFn = ensureTriviaFn(ctx);
|
|
5730
|
+
stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`);
|
|
5731
|
+
}
|
|
5371
5732
|
if (sf && fArr) {
|
|
5372
5733
|
stmts.push(`${i}const ${fArr} = _ctx._fields`);
|
|
5373
5734
|
}
|
|
@@ -5407,8 +5768,9 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5407
5768
|
}
|
|
5408
5769
|
const ndV = v(ctx, "_nd");
|
|
5409
5770
|
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
5410
|
-
const
|
|
5411
|
-
const
|
|
5771
|
+
const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
5772
|
+
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : `_ctx.build?._parsemanCstOutput === true ? (${hostBuildExpr}) : (${buildExpr})`;
|
|
5773
|
+
const hostCollapseExpr = structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
|
|
5412
5774
|
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
5413
5775
|
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
5414
5776
|
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
@@ -5416,7 +5778,7 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5416
5778
|
`${i}const ${ndV} = (${profileRecognizer} || ${profileCapture}) ? undefined : (${finalExpr})`,
|
|
5417
5779
|
`${i}if (!(${profileRecognizer})) {`,
|
|
5418
5780
|
`${i} if (${sc}) ${sc}.push(${ndV})`,
|
|
5419
|
-
`${i} if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'parseError')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`,
|
|
5781
|
+
`${i} if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'parseError')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : (typeof ${ndV} === 'object' && ${ndV} !== null ? input.slice(${pos}, ${endVar}) : ''), span: { start: ${pos}, end: ${endVar} } })`,
|
|
5420
5782
|
`${i}}`
|
|
5421
5783
|
);
|
|
5422
5784
|
return { stmts, valueVar: ndV, endVar };
|
|
@@ -5461,14 +5823,23 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
5461
5823
|
const savedIndent = ctx.indent;
|
|
5462
5824
|
const savedFailLabel = ctx.failLabel;
|
|
5463
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;
|
|
5464
5829
|
ctx.indent = 1;
|
|
5465
5830
|
ctx.failLabel = "_pfail";
|
|
5466
5831
|
ctx.recordFail = true;
|
|
5832
|
+
if (failureRuleId !== void 0) {
|
|
5833
|
+
ctx.activeCoverageRuleId = void 0;
|
|
5834
|
+
ctx.suppressCoverageFailure = true;
|
|
5835
|
+
}
|
|
5467
5836
|
const r = emit(resolved, ctx, "_pos");
|
|
5468
5837
|
ctx.indent = savedIndent;
|
|
5469
5838
|
ctx.failLabel = savedFailLabel;
|
|
5470
5839
|
ctx.recordFail = savedRecord;
|
|
5471
|
-
|
|
5840
|
+
ctx.activeCoverageRuleId = savedActiveRule;
|
|
5841
|
+
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
5842
|
+
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
5472
5843
|
}
|
|
5473
5844
|
const fnName = ctx.namedParsers.get(p);
|
|
5474
5845
|
return emitNamedFnCall(ctx, fnName, pos);
|
|
@@ -5519,6 +5890,30 @@ function emitExpect(def, ctx, pos) {
|
|
|
5519
5890
|
return { stmts, valueVar: valVar, endVar };
|
|
5520
5891
|
}
|
|
5521
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
|
+
};
|
|
5522
5917
|
const usage = ctx.lazyUsage;
|
|
5523
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
|
|
5524
5919
|
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
@@ -5535,14 +5930,14 @@ function emit(p, ctx, pos) {
|
|
|
5535
5930
|
ctx.indent = 1;
|
|
5536
5931
|
ctx.failLabel = "_pfail";
|
|
5537
5932
|
ctx.recordFail = true;
|
|
5538
|
-
const r =
|
|
5933
|
+
const r = dispatch("_pos");
|
|
5539
5934
|
ctx.indent = savedIndent;
|
|
5540
5935
|
ctx.failLabel = savedFailLabel;
|
|
5541
5936
|
ctx.recordFail = savedRecord;
|
|
5542
5937
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
5543
|
-
return emitNamedFnCall(ctx, fnName, pos);
|
|
5938
|
+
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
5544
5939
|
}
|
|
5545
|
-
return
|
|
5940
|
+
return instrument(dispatch());
|
|
5546
5941
|
}
|
|
5547
5942
|
function emitDispatch(p, ctx, pos) {
|
|
5548
5943
|
const def = p._def;
|
|
@@ -5556,7 +5951,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5556
5951
|
case "sequence":
|
|
5557
5952
|
return emitSeq(def, ctx, pos);
|
|
5558
5953
|
case "choice":
|
|
5559
|
-
return emitChoice(def, ctx, pos);
|
|
5954
|
+
return emitChoice(p, def, ctx, pos);
|
|
5955
|
+
case "attempt":
|
|
5956
|
+
return emitAttempt(p, def, ctx, pos);
|
|
5560
5957
|
case "many":
|
|
5561
5958
|
case "oneOrMore":
|
|
5562
5959
|
return emitMany(def, ctx, pos);
|
|
@@ -5625,6 +6022,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5625
6022
|
return emit(def.parser, ctx, pos);
|
|
5626
6023
|
case "token":
|
|
5627
6024
|
return emitToken(def, ctx, pos);
|
|
6025
|
+
case "leaf":
|
|
6026
|
+
return emitLeaf(def, ctx, pos);
|
|
5628
6027
|
case "label": {
|
|
5629
6028
|
const inner = emitFallible(def.parser, ctx, pos);
|
|
5630
6029
|
return {
|
|
@@ -5659,10 +6058,19 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5659
6058
|
ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
|
|
5660
6059
|
}
|
|
5661
6060
|
}
|
|
6061
|
+
const savedCapture = def.captureTrivia ? v(ctx, "_gcap") : null;
|
|
5662
6062
|
const r = emit(def.parser, ctx, pos);
|
|
5663
6063
|
ctx.activeTrivia = savedTrivia;
|
|
5664
6064
|
ctx.triviaKindLabels = savedKindLabels;
|
|
5665
|
-
return r;
|
|
6065
|
+
if (!savedCapture) return r;
|
|
6066
|
+
return {
|
|
6067
|
+
...r,
|
|
6068
|
+
stmts: [
|
|
6069
|
+
`${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
|
|
6070
|
+
...r.stmts,
|
|
6071
|
+
`${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
|
|
6072
|
+
]
|
|
6073
|
+
};
|
|
5666
6074
|
}
|
|
5667
6075
|
case "not":
|
|
5668
6076
|
return emitNot(def, ctx, pos);
|
|
@@ -5747,6 +6155,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5747
6155
|
case "grammar":
|
|
5748
6156
|
case "trivia":
|
|
5749
6157
|
case "token":
|
|
6158
|
+
case "leaf":
|
|
5750
6159
|
case "label":
|
|
5751
6160
|
case "field":
|
|
5752
6161
|
case "optional":
|
|
@@ -5774,16 +6183,32 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5774
6183
|
return false;
|
|
5775
6184
|
}
|
|
5776
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
|
+
}
|
|
5777
6200
|
function childrenOf(def) {
|
|
5778
6201
|
switch (def.tag) {
|
|
5779
6202
|
case "sequence":
|
|
5780
6203
|
case "choice":
|
|
5781
6204
|
return def.parsers;
|
|
5782
6205
|
case "many":
|
|
6206
|
+
case "attempt":
|
|
5783
6207
|
case "optional":
|
|
5784
6208
|
case "transform":
|
|
5785
6209
|
case "trivia":
|
|
5786
6210
|
case "token":
|
|
6211
|
+
case "leaf":
|
|
5787
6212
|
case "label":
|
|
5788
6213
|
case "field":
|
|
5789
6214
|
case "grammar":
|
|
@@ -5958,10 +6383,25 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5958
6383
|
namedFnDecls: [],
|
|
5959
6384
|
capturing: hasNodeDef(combinator),
|
|
5960
6385
|
recovery: opts?.recovery ?? false,
|
|
6386
|
+
...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
|
|
5961
6387
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5962
6388
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5963
6389
|
};
|
|
5964
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
|
+
];
|
|
5965
6405
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
5966
6406
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
5967
6407
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
@@ -5974,9 +6414,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5974
6414
|
...namedPrelude,
|
|
5975
6415
|
ctx.namedFnDecls.join("\n\n"),
|
|
5976
6416
|
`function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
|
|
5977
|
-
|
|
5978
|
-
...r.stmts,
|
|
5979
|
-
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6417
|
+
...resultBody,
|
|
5980
6418
|
`}`
|
|
5981
6419
|
].join("\n");
|
|
5982
6420
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
@@ -5986,9 +6424,15 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5986
6424
|
...ctx.expectedDecls,
|
|
5987
6425
|
...namedPrelude,
|
|
5988
6426
|
...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
|
|
5989
|
-
`let pos = _pos`,
|
|
5990
|
-
|
|
5991
|
-
|
|
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
|
+
]
|
|
5992
6436
|
].join("\n"));
|
|
5993
6437
|
const defaultCtx = {
|
|
5994
6438
|
trackLines: false,
|
|
@@ -6000,10 +6444,11 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
6000
6444
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
6001
6445
|
const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
|
|
6002
6446
|
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
6003
|
-
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources) : null;
|
|
6447
|
+
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
|
|
6004
6448
|
return {
|
|
6005
6449
|
source,
|
|
6006
6450
|
inlineExpression,
|
|
6451
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
|
|
6007
6452
|
parse(input, pos = 0) {
|
|
6008
6453
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
|
|
6009
6454
|
},
|
|
@@ -6066,8 +6511,13 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6066
6511
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
6067
6512
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
6068
6513
|
namedFnDecls: [],
|
|
6069
|
-
|
|
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)),
|
|
6070
6519
|
recovery: opts?.recovery ?? false,
|
|
6520
|
+
...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
|
|
6071
6521
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
6072
6522
|
ns,
|
|
6073
6523
|
deferFirstSetRefs: true,
|
|
@@ -6141,7 +6591,14 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6141
6591
|
ctx.indent = savedIndent;
|
|
6142
6592
|
ctx.failLabel = savedFail;
|
|
6143
6593
|
ctx.recordFail = savedRec;
|
|
6144
|
-
|
|
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);
|
|
6145
6602
|
}
|
|
6146
6603
|
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
6147
6604
|
}
|
|
@@ -6198,15 +6655,46 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6198
6655
|
deps: ruleDependencies(ruleMap),
|
|
6199
6656
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
6200
6657
|
needsHostReads: !!ctx.needsHostReads,
|
|
6658
|
+
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
6659
|
+
isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule)),
|
|
6201
6660
|
mfFns: mfSrcs ? [] : ctx.mapFns,
|
|
6202
6661
|
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
6203
6662
|
};
|
|
6204
6663
|
}
|
|
6205
|
-
function
|
|
6206
|
-
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 ? [
|
|
6207
6687
|
` let pos = _pos`,
|
|
6208
6688
|
...r.stmts,
|
|
6209
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`
|
|
6210
6698
|
];
|
|
6211
6699
|
const innerFn = [
|
|
6212
6700
|
`function(input, _pos, _ctx) {`,
|
|
@@ -6261,8 +6749,8 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
6261
6749
|
};
|
|
6262
6750
|
const emit2 = (end) => {
|
|
6263
6751
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
6264
|
-
const
|
|
6265
|
-
pushCstLeaf(ctx,
|
|
6752
|
+
const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
6753
|
+
pushCstLeaf(ctx, leaf2);
|
|
6266
6754
|
}
|
|
6267
6755
|
};
|
|
6268
6756
|
while (cur < input.length) {
|
|
@@ -6316,6 +6804,7 @@ function balanced(open, close, options = {}) {
|
|
|
6316
6804
|
);
|
|
6317
6805
|
if (combi._def.tag === "transform") {
|
|
6318
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;
|
|
6319
6808
|
}
|
|
6320
6809
|
self.define(combi);
|
|
6321
6810
|
return combi;
|
|
@@ -6361,9 +6850,11 @@ function childrenOf2(def) {
|
|
|
6361
6850
|
case "many":
|
|
6362
6851
|
case "oneOrMore":
|
|
6363
6852
|
case "optional":
|
|
6853
|
+
case "attempt":
|
|
6364
6854
|
case "transform":
|
|
6365
6855
|
case "trivia":
|
|
6366
6856
|
case "token":
|
|
6857
|
+
case "leaf":
|
|
6367
6858
|
case "label":
|
|
6368
6859
|
case "field":
|
|
6369
6860
|
case "not":
|
|
@@ -6412,7 +6903,7 @@ function serializeRuleMap(ruleMap) {
|
|
|
6412
6903
|
}
|
|
6413
6904
|
}
|
|
6414
6905
|
function evalRuleMapIR(ir) {
|
|
6415
|
-
const _tf = (child, src) => {
|
|
6906
|
+
const _tf = (child, src, recognitionOnly = false) => {
|
|
6416
6907
|
let fn2;
|
|
6417
6908
|
try {
|
|
6418
6909
|
fn2 = (0, eval)(`(${src})`);
|
|
@@ -6423,11 +6914,31 @@ function evalRuleMapIR(ir) {
|
|
|
6423
6914
|
}
|
|
6424
6915
|
const t = transform(child, fn2);
|
|
6425
6916
|
t._def.fnSrc = src;
|
|
6917
|
+
if (recognitionOnly) t._def.recognitionOnly = true;
|
|
6426
6918
|
return t;
|
|
6427
6919
|
};
|
|
6428
|
-
const
|
|
6429
|
-
|
|
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
|
+
};
|
|
6933
|
+
const _nd = (type, child, src, opts, staticError) => {
|
|
6934
|
+
if (staticError !== void 0 && staticError.length > 0) {
|
|
6935
|
+
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
6936
|
+
}
|
|
6937
|
+
const n = node(type, child, (() => {
|
|
6938
|
+
throw new Error("IR node build requires static re-lowering");
|
|
6939
|
+
}), opts);
|
|
6430
6940
|
n._def.buildSrc = src;
|
|
6941
|
+
if (staticError !== void 0) n._def.buildStaticError = staticError;
|
|
6431
6942
|
return n;
|
|
6432
6943
|
};
|
|
6433
6944
|
const _gch = (items) => {
|
|
@@ -6477,6 +6988,7 @@ function evalRuleMapIR(ir) {
|
|
|
6477
6988
|
"keywords",
|
|
6478
6989
|
"sequence",
|
|
6479
6990
|
"choice",
|
|
6991
|
+
"attempt",
|
|
6480
6992
|
"many",
|
|
6481
6993
|
"oneOrMore",
|
|
6482
6994
|
"optional",
|
|
@@ -6486,6 +6998,7 @@ function evalRuleMapIR(ir) {
|
|
|
6486
6998
|
"parser",
|
|
6487
6999
|
"scanTo",
|
|
6488
7000
|
"token",
|
|
7001
|
+
"leaf",
|
|
6489
7002
|
"transform",
|
|
6490
7003
|
"skip",
|
|
6491
7004
|
"trivia",
|
|
@@ -6493,6 +7006,7 @@ function evalRuleMapIR(ir) {
|
|
|
6493
7006
|
"field",
|
|
6494
7007
|
"expect",
|
|
6495
7008
|
"_tf",
|
|
7009
|
+
"_lf",
|
|
6496
7010
|
"_nd",
|
|
6497
7011
|
"_gch",
|
|
6498
7012
|
"_wc",
|
|
@@ -6506,6 +7020,7 @@ function evalRuleMapIR(ir) {
|
|
|
6506
7020
|
keywords,
|
|
6507
7021
|
sequence,
|
|
6508
7022
|
choice,
|
|
7023
|
+
attempt,
|
|
6509
7024
|
many,
|
|
6510
7025
|
oneOrMore,
|
|
6511
7026
|
optional,
|
|
@@ -6515,6 +7030,7 @@ function evalRuleMapIR(ir) {
|
|
|
6515
7030
|
parser,
|
|
6516
7031
|
scanTo,
|
|
6517
7032
|
token,
|
|
7033
|
+
leaf,
|
|
6518
7034
|
transform,
|
|
6519
7035
|
skip,
|
|
6520
7036
|
trivia,
|
|
@@ -6522,6 +7038,7 @@ function evalRuleMapIR(ir) {
|
|
|
6522
7038
|
field,
|
|
6523
7039
|
expect,
|
|
6524
7040
|
_tf,
|
|
7041
|
+
_lf,
|
|
6525
7042
|
_nd,
|
|
6526
7043
|
_gch,
|
|
6527
7044
|
_wc
|
|
@@ -6653,6 +7170,8 @@ ${body}
|
|
|
6653
7170
|
return `oneOrMore(${kid(def.parser)})`;
|
|
6654
7171
|
case "optional":
|
|
6655
7172
|
return `optional(${kid(def.parser)})`;
|
|
7173
|
+
case "attempt":
|
|
7174
|
+
return `attempt(${kid(def.parser)})`;
|
|
6656
7175
|
case "sepBy":
|
|
6657
7176
|
return `sepBy(${kid(def.parser)}, ${kid(def.separator)})`;
|
|
6658
7177
|
case "not":
|
|
@@ -6661,6 +7180,10 @@ ${body}
|
|
|
6661
7180
|
return `trivia(${kid(def.parser)})`;
|
|
6662
7181
|
case "token":
|
|
6663
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
|
+
}
|
|
6664
7187
|
case "label":
|
|
6665
7188
|
return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
|
|
6666
7189
|
case "field":
|
|
@@ -6673,21 +7196,30 @@ ${body}
|
|
|
6673
7196
|
return `scanTo(${kid(def.sentinel)}, { skip: [${def.skip.map(kid).join(", ")}], orEOF: ${def.orEOF} })`;
|
|
6674
7197
|
case "transform": {
|
|
6675
7198
|
if (def.fnSrc === void 0) throw new Unserializable("transform without fnSrc");
|
|
6676
|
-
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7199
|
+
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)}${def.recognitionOnly ? ", true" : ""})`;
|
|
6677
7200
|
}
|
|
6678
7201
|
case "node": {
|
|
6679
7202
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
6680
|
-
const
|
|
7203
|
+
const optEntries = [
|
|
7204
|
+
...def.unwrap ? ["unwrap: true"] : [],
|
|
7205
|
+
...def.collapse ? ["collapse: true"] : [],
|
|
7206
|
+
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
7207
|
+
...def.trailingTrivia ? ["trailingTrivia: true"] : []
|
|
7208
|
+
];
|
|
7209
|
+
const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
|
|
6681
7210
|
if (def.type === void 0) {
|
|
6682
7211
|
if (def.buildSrc !== void 0) throw new Unserializable("inferred node build without inferred type");
|
|
6683
7212
|
return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
|
|
6684
7213
|
}
|
|
6685
|
-
if (def.buildSrc !== void 0)
|
|
7214
|
+
if (def.buildSrc !== void 0) {
|
|
7215
|
+
const staticError = def.buildStaticError === void 0 ? "" : `${opts ? "" : ", undefined"}, ${JSON.stringify(def.buildStaticError)}`;
|
|
7216
|
+
return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${staticError})`;
|
|
7217
|
+
}
|
|
6686
7218
|
return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
|
|
6687
7219
|
}
|
|
6688
7220
|
case "grammar": {
|
|
6689
7221
|
const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
|
|
6690
|
-
return `parser({ trivia: ${trivia2}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
|
|
7222
|
+
return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
|
|
6691
7223
|
}
|
|
6692
7224
|
case "withCtx": {
|
|
6693
7225
|
if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
|
|
@@ -6716,18 +7248,20 @@ function normalizeCstCollapse(collapse) {
|
|
|
6716
7248
|
}
|
|
6717
7249
|
return typeof collapse === "function" ? collapse : void 0;
|
|
6718
7250
|
}
|
|
6719
|
-
function buildCstNode(type,
|
|
6720
|
-
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] };
|
|
6721
7253
|
}
|
|
6722
|
-
function cstBuildHost(typeOrOptions,
|
|
7254
|
+
function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
|
|
6723
7255
|
if (typeof typeOrOptions === "string") {
|
|
6724
|
-
return buildCstNode(typeOrOptions,
|
|
7256
|
+
return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
6725
7257
|
}
|
|
6726
7258
|
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
6727
|
-
const host = (type,
|
|
7259
|
+
const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3, fields, span2, rawChildren2, triviaLog2, state2);
|
|
7260
|
+
host._parsemanCstOutput = true;
|
|
6728
7261
|
if (collapse) host._parsemanCstCollapse = collapse;
|
|
6729
7262
|
return host;
|
|
6730
7263
|
}
|
|
7264
|
+
cstBuildHost._parsemanCstOutput = true;
|
|
6731
7265
|
function fusedBody(pieces) {
|
|
6732
7266
|
const winner = /* @__PURE__ */ new Map();
|
|
6733
7267
|
for (const p of pieces) for (const k of p.keys) winner.set(k, p);
|
|
@@ -6781,13 +7315,39 @@ function fuseRules(pieces) {
|
|
|
6781
7315
|
return new Function("_env", body)(env);
|
|
6782
7316
|
}
|
|
6783
7317
|
var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
|
|
7318
|
+
var LEAF_COMPOSED = /* @__PURE__ */ Symbol.for("parseman.leafComposed");
|
|
6784
7319
|
var COMPOSED_TRIVIA = /* @__PURE__ */ Symbol.for("parseman.composedTrivia");
|
|
7320
|
+
var COMPOSED_COVERAGE_RULES = /* @__PURE__ */ Symbol.for("parseman.composedCoverageRules");
|
|
6785
7321
|
function isIRPiece(p) {
|
|
6786
7322
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
6787
7323
|
}
|
|
6788
|
-
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) {
|
|
6789
7346
|
if (!isIRPiece(p)) return p;
|
|
6790
|
-
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
|
+
});
|
|
6791
7351
|
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
6792
7352
|
return pieces;
|
|
6793
7353
|
}
|
|
@@ -6838,6 +7398,9 @@ function composingTriviaOf(items) {
|
|
|
6838
7398
|
return void 0;
|
|
6839
7399
|
}
|
|
6840
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
|
+
}
|
|
6841
7404
|
const used = /* @__PURE__ */ new Set();
|
|
6842
7405
|
const trivia2 = composingTriviaOf(items);
|
|
6843
7406
|
const carried = items.flatMap((item) => itemCarried(item, used, trivia2));
|
|
@@ -6845,8 +7408,13 @@ function compose(items) {
|
|
|
6845
7408
|
const map = fuseRules(pieces);
|
|
6846
7409
|
Object.defineProperty(map, COMPOSED_PIECES, { value: carried, enumerable: false });
|
|
6847
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 });
|
|
6848
7413
|
return map;
|
|
6849
7414
|
}
|
|
7415
|
+
function composeLeaf(_items) {
|
|
7416
|
+
throw new Error("composeLeaf(): requires Parseman macro lowering; runtime composition is forbidden");
|
|
7417
|
+
}
|
|
6850
7418
|
|
|
6851
7419
|
// src/combinators/guard.ts
|
|
6852
7420
|
function guard(predicate) {
|
|
@@ -7010,7 +7578,9 @@ function producesRepetition(def, depth = 0) {
|
|
|
7010
7578
|
// Transparent wrappers — look through to the inner parser.
|
|
7011
7579
|
case "node":
|
|
7012
7580
|
case "transform":
|
|
7581
|
+
case "attempt":
|
|
7013
7582
|
case "token":
|
|
7583
|
+
case "leaf":
|
|
7014
7584
|
case "label":
|
|
7015
7585
|
case "field":
|
|
7016
7586
|
case "expect":
|
|
@@ -7062,8 +7632,8 @@ function replaceAtPath(rebuild, root, path, newNode) {
|
|
|
7062
7632
|
newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(rebuild, root.children[idx], rest, newNode);
|
|
7063
7633
|
return rebuild(root, newChildren);
|
|
7064
7634
|
}
|
|
7065
|
-
function defaultRebuild(node2,
|
|
7066
|
-
return { ...node2, children };
|
|
7635
|
+
function defaultRebuild(node2, children2) {
|
|
7636
|
+
return { ...node2, children: children2 };
|
|
7067
7637
|
}
|
|
7068
7638
|
function shiftRelStart(child, delta) {
|
|
7069
7639
|
const c = child;
|
|
@@ -7403,7 +7973,8 @@ function runOnce(entry, input, options, phase, profileState) {
|
|
|
7403
7973
|
state: options.state,
|
|
7404
7974
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
7405
7975
|
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7406
|
-
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
7976
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {},
|
|
7977
|
+
...options.instrumentation === void 0 ? {} : options.instrumentation
|
|
7407
7978
|
};
|
|
7408
7979
|
const r = invoke(entry, input, 0, ctx);
|
|
7409
7980
|
let unconsumedFrom = null;
|
|
@@ -7458,6 +8029,265 @@ function run(entry, input, options = {}) {
|
|
|
7458
8029
|
};
|
|
7459
8030
|
}
|
|
7460
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
|
+
|
|
7461
8291
|
// src/cst/trivia-index.ts
|
|
7462
8292
|
function merge(map, key, run2) {
|
|
7463
8293
|
if (run2.length === 0) return;
|
|
@@ -7528,9 +8358,9 @@ function buildTriviaIndex(root, input = "", opts) {
|
|
|
7528
8358
|
function walk(root, visitor, ctx = void 0) {
|
|
7529
8359
|
const go = (node2, parent) => {
|
|
7530
8360
|
const descend = visitor.enter ? visitor.enter(node2, parent, ctx) : void 0;
|
|
7531
|
-
const
|
|
7532
|
-
if (descend !== false && Array.isArray(
|
|
7533
|
-
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);
|
|
7534
8364
|
}
|
|
7535
8365
|
visitor.leave?.(node2, parent, ctx);
|
|
7536
8366
|
};
|
|
@@ -7546,9 +8376,9 @@ function createVisitor(handlers) {
|
|
|
7546
8376
|
},
|
|
7547
8377
|
visitChildren(node2) {
|
|
7548
8378
|
const out = [];
|
|
7549
|
-
const
|
|
7550
|
-
if (Array.isArray(
|
|
7551
|
-
for (const child of
|
|
8379
|
+
const children2 = node2.children;
|
|
8380
|
+
if (Array.isArray(children2)) {
|
|
8381
|
+
for (const child of children2) {
|
|
7552
8382
|
const r = api.visit(child);
|
|
7553
8383
|
if (r !== void 0) out.push(r);
|
|
7554
8384
|
}
|
|
@@ -7577,6 +8407,9 @@ function triviaEntries(log, labels, opts) {
|
|
|
7577
8407
|
end(i) {
|
|
7578
8408
|
return log[entryOffset(i, stride) + 1];
|
|
7579
8409
|
},
|
|
8410
|
+
insertIndex(i) {
|
|
8411
|
+
return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
|
|
8412
|
+
},
|
|
7580
8413
|
kindIndex(i) {
|
|
7581
8414
|
if (!labels) return void 0;
|
|
7582
8415
|
return log[entryOffset(i, stride) + baseStride];
|