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.js
CHANGED
|
@@ -59,6 +59,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
59
59
|
case "label":
|
|
60
60
|
case "trivia":
|
|
61
61
|
case "token":
|
|
62
|
+
case "leaf":
|
|
62
63
|
case "expect":
|
|
63
64
|
case "withCtx":
|
|
64
65
|
case "node":
|
|
@@ -122,6 +123,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
122
123
|
case "label":
|
|
123
124
|
case "trivia":
|
|
124
125
|
case "token":
|
|
126
|
+
case "leaf":
|
|
125
127
|
case "node":
|
|
126
128
|
case "grammar":
|
|
127
129
|
case "expect":
|
|
@@ -190,10 +192,10 @@ function beginCstNodeCapture(ctx) {
|
|
|
190
192
|
}
|
|
191
193
|
function finishCstBuf(buf) {
|
|
192
194
|
if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
|
|
193
|
-
const
|
|
195
|
+
const children2 = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
|
|
194
196
|
const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
|
|
195
197
|
const triviaLog = buf.tl ?? EMPTY_TL;
|
|
196
|
-
return { children, rawChildren, triviaLog };
|
|
198
|
+
return { children: children2, rawChildren, triviaLog };
|
|
197
199
|
}
|
|
198
200
|
function endCstNodeCapture(ctx, saved) {
|
|
199
201
|
const materialized = finishCstBuf(ctx._cstBuf);
|
|
@@ -205,8 +207,8 @@ function endCstNodeCapture(ctx, saved) {
|
|
|
205
207
|
ctx.captureTrivia = saved.cap;
|
|
206
208
|
return materialized;
|
|
207
209
|
}
|
|
208
|
-
function pushCstLeaf(ctx,
|
|
209
|
-
pushCstChild(ctx,
|
|
210
|
+
function pushCstLeaf(ctx, leaf2) {
|
|
211
|
+
pushCstChild(ctx, leaf2, leaf2);
|
|
210
212
|
}
|
|
211
213
|
function pushCstChild(ctx, built, rawEntry) {
|
|
212
214
|
const b = ctx._cstBuf;
|
|
@@ -940,10 +942,13 @@ function deriveExpected(c) {
|
|
|
940
942
|
return def.parsers.flatMap(deriveExpected);
|
|
941
943
|
case "sequence":
|
|
942
944
|
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
945
|
+
case "attempt":
|
|
946
|
+
return deriveExpected(def.parser);
|
|
943
947
|
case "node":
|
|
944
948
|
case "grammar":
|
|
945
949
|
case "trivia":
|
|
946
950
|
case "token":
|
|
951
|
+
case "leaf":
|
|
947
952
|
case "optional":
|
|
948
953
|
case "many":
|
|
949
954
|
case "oneOrMore":
|
|
@@ -1437,6 +1442,12 @@ function scanTrivia(input, cur, ctx) {
|
|
|
1437
1442
|
const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1438
1443
|
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
1439
1444
|
}
|
|
1445
|
+
function consumeTrivia(input, cur, ctx) {
|
|
1446
|
+
if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
|
|
1447
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1448
|
+
scan.commit();
|
|
1449
|
+
return scan.end;
|
|
1450
|
+
}
|
|
1440
1451
|
function fastTriviaScanner(trivia2) {
|
|
1441
1452
|
const cached = fastTriviaCache.get(trivia2);
|
|
1442
1453
|
if (cached !== void 0) return cached;
|
|
@@ -1715,6 +1726,24 @@ function sequence(...parsers) {
|
|
|
1715
1726
|
};
|
|
1716
1727
|
}
|
|
1717
1728
|
|
|
1729
|
+
// src/combinators/attempt.ts
|
|
1730
|
+
function attempt(parser2) {
|
|
1731
|
+
return {
|
|
1732
|
+
_tag: "attempt",
|
|
1733
|
+
_meta: parser2._meta,
|
|
1734
|
+
_def: { tag: "attempt", parser: parser2 },
|
|
1735
|
+
parse(input, pos, ctx) {
|
|
1736
|
+
const mark = saveCstMark(ctx);
|
|
1737
|
+
const log = ctx._triviaLog?.length;
|
|
1738
|
+
const result = parser2.parse(input, pos, ctx);
|
|
1739
|
+
if (result.ok) return result;
|
|
1740
|
+
rollbackCstCapture(ctx, mark);
|
|
1741
|
+
if (log !== void 0 && ctx._triviaLog) ctx._triviaLog.length = log;
|
|
1742
|
+
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
1743
|
+
}
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1718
1747
|
// src/combinators/repeat.ts
|
|
1719
1748
|
function repItem(combinator, input, cur, ctx) {
|
|
1720
1749
|
const mark = saveTriviaMark(ctx);
|
|
@@ -2024,10 +2053,14 @@ function markUnusedValues(root) {
|
|
|
2024
2053
|
case "label":
|
|
2025
2054
|
case "trivia":
|
|
2026
2055
|
case "token":
|
|
2056
|
+
case "attempt":
|
|
2027
2057
|
case "withCtx":
|
|
2028
2058
|
case "expect":
|
|
2029
2059
|
visit(def.parser, consumed);
|
|
2030
2060
|
return;
|
|
2061
|
+
case "leaf":
|
|
2062
|
+
visit(def.parser, true);
|
|
2063
|
+
return;
|
|
2031
2064
|
case "lazy":
|
|
2032
2065
|
return;
|
|
2033
2066
|
default:
|
|
@@ -2150,6 +2183,20 @@ function confirmedBuildArity(src) {
|
|
|
2150
2183
|
if (/\barguments\b/.test(s)) return null;
|
|
2151
2184
|
return parts.length;
|
|
2152
2185
|
}
|
|
2186
|
+
function buildReadsChildren(def) {
|
|
2187
|
+
if (!def.build) return true;
|
|
2188
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2189
|
+
const arity = confirmedBuildArity(src);
|
|
2190
|
+
if (arity === null) return true;
|
|
2191
|
+
return arity >= 1;
|
|
2192
|
+
}
|
|
2193
|
+
function buildReadsRaw(def) {
|
|
2194
|
+
if (!def.build) return true;
|
|
2195
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
2196
|
+
const arity = confirmedBuildArity(src);
|
|
2197
|
+
if (arity === null) return true;
|
|
2198
|
+
return arity >= 4;
|
|
2199
|
+
}
|
|
2153
2200
|
function buildReadsTrivia(def) {
|
|
2154
2201
|
if (!def.build) return true;
|
|
2155
2202
|
const src = def.buildSrc ?? def.build.toString();
|
|
@@ -2205,9 +2252,11 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2205
2252
|
case "many":
|
|
2206
2253
|
case "oneOrMore":
|
|
2207
2254
|
case "optional":
|
|
2255
|
+
case "attempt":
|
|
2208
2256
|
case "transform":
|
|
2209
2257
|
case "trivia":
|
|
2210
2258
|
case "token":
|
|
2259
|
+
case "leaf":
|
|
2211
2260
|
case "label":
|
|
2212
2261
|
case "expect":
|
|
2213
2262
|
case "withCtx":
|
|
@@ -2240,9 +2289,11 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2240
2289
|
case "keywords":
|
|
2241
2290
|
case "guard":
|
|
2242
2291
|
case "token":
|
|
2292
|
+
case "leaf":
|
|
2243
2293
|
return false;
|
|
2244
2294
|
// Transparent single-child wrappers: recurse.
|
|
2245
2295
|
case "optional":
|
|
2296
|
+
case "attempt":
|
|
2246
2297
|
case "transform":
|
|
2247
2298
|
case "trivia":
|
|
2248
2299
|
case "label":
|
|
@@ -2266,6 +2317,54 @@ function parserHasTriviaSite(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
2266
2317
|
return true;
|
|
2267
2318
|
}
|
|
2268
2319
|
}
|
|
2320
|
+
function parserEnablesTriviaCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
2321
|
+
if (seen.has(p)) return false;
|
|
2322
|
+
seen.add(p);
|
|
2323
|
+
const d = p._def;
|
|
2324
|
+
switch (d.tag) {
|
|
2325
|
+
case "grammar":
|
|
2326
|
+
return d.captureTrivia === true || parserEnablesTriviaCapture(d.parser, seen);
|
|
2327
|
+
case "node":
|
|
2328
|
+
return false;
|
|
2329
|
+
case "sequence":
|
|
2330
|
+
case "choice":
|
|
2331
|
+
return d.parsers.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2332
|
+
case "sepBy":
|
|
2333
|
+
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.separator, seen);
|
|
2334
|
+
case "skip":
|
|
2335
|
+
return parserEnablesTriviaCapture(d.main, seen) || parserEnablesTriviaCapture(d.skipped, seen);
|
|
2336
|
+
case "scanTo":
|
|
2337
|
+
return parserEnablesTriviaCapture(d.sentinel, seen) || d.skip.some((x) => parserEnablesTriviaCapture(x, seen));
|
|
2338
|
+
case "recover":
|
|
2339
|
+
return parserEnablesTriviaCapture(d.parser, seen) || parserEnablesTriviaCapture(d.sentinel, seen);
|
|
2340
|
+
case "many":
|
|
2341
|
+
case "oneOrMore":
|
|
2342
|
+
case "optional":
|
|
2343
|
+
case "attempt":
|
|
2344
|
+
case "transform":
|
|
2345
|
+
case "trivia":
|
|
2346
|
+
case "token":
|
|
2347
|
+
case "label":
|
|
2348
|
+
case "field":
|
|
2349
|
+
case "expect":
|
|
2350
|
+
case "withCtx":
|
|
2351
|
+
case "not":
|
|
2352
|
+
return parserEnablesTriviaCapture(d.parser, seen);
|
|
2353
|
+
// leaf() clears the inner CST/trivia collector and publishes only its own
|
|
2354
|
+
// terminal result. An inner parser() capture cannot reach this node.
|
|
2355
|
+
case "leaf":
|
|
2356
|
+
return false;
|
|
2357
|
+
case "lazy": {
|
|
2358
|
+
try {
|
|
2359
|
+
return parserEnablesTriviaCapture(d.thunk(), seen);
|
|
2360
|
+
} catch {
|
|
2361
|
+
return false;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
default:
|
|
2365
|
+
return false;
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2269
2368
|
function buildFieldMap(captures) {
|
|
2270
2369
|
if (!captures?.length) return void 0;
|
|
2271
2370
|
const out = {};
|
|
@@ -2303,11 +2402,13 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2303
2402
|
};
|
|
2304
2403
|
const unwrap = opts?.unwrap === true;
|
|
2305
2404
|
const collapse = opts?.collapse === true;
|
|
2405
|
+
const captureTrivia = opts?.captureTrivia === true;
|
|
2406
|
+
const trailingTrivia = opts?.trailingTrivia === true;
|
|
2306
2407
|
if (unwrap && collapse) {
|
|
2307
2408
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
2308
2409
|
}
|
|
2309
|
-
const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
|
|
2310
|
-
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
2410
|
+
const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
|
|
2411
|
+
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
|
|
2311
2412
|
const clonesState = build ? buildReadsState(def) : true;
|
|
2312
2413
|
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
2313
2414
|
return {
|
|
@@ -2323,16 +2424,21 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2323
2424
|
ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
|
|
2324
2425
|
}
|
|
2325
2426
|
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
2326
|
-
|
|
2427
|
+
let r = combinator.parse(input, pos, ctx);
|
|
2428
|
+
if (r.ok && trailingTrivia && ctx.trivia) {
|
|
2429
|
+
const end = consumeTrivia(input, r.span.end, ctx);
|
|
2430
|
+
r = { ...r, span: { start: r.span.start, end } };
|
|
2431
|
+
}
|
|
2327
2432
|
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
2328
2433
|
ctx._fields = savedFields;
|
|
2329
2434
|
ctx._triviaCaptureMask = savedMask;
|
|
2330
|
-
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2435
|
+
const { children: children2, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
2331
2436
|
if (!r.ok) return r;
|
|
2332
2437
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2333
2438
|
const nodeType = def.type ?? missingInferredType();
|
|
2334
|
-
const
|
|
2335
|
-
const
|
|
2439
|
+
const cstOutput = ctx.build?._parsemanCstOutput === true;
|
|
2440
|
+
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 };
|
|
2441
|
+
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 };
|
|
2336
2442
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2337
2443
|
pushCstChild(ctx, built, rawEntry);
|
|
2338
2444
|
}
|
|
@@ -2449,6 +2555,7 @@ function parser(opts, root) {
|
|
|
2449
2555
|
parser: root,
|
|
2450
2556
|
triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
|
|
2451
2557
|
clearTrivia,
|
|
2558
|
+
...opts.captureTrivia ? { captureTrivia: true } : {},
|
|
2452
2559
|
trackLines: opts.trackLines ?? false
|
|
2453
2560
|
},
|
|
2454
2561
|
parse(input, pos, _ctx) {
|
|
@@ -2561,6 +2668,141 @@ function token(root) {
|
|
|
2561
2668
|
}
|
|
2562
2669
|
};
|
|
2563
2670
|
}
|
|
2671
|
+
function leaf(root, fn) {
|
|
2672
|
+
const meta = {
|
|
2673
|
+
firstSet: root._meta.firstSet,
|
|
2674
|
+
canMatchNewline: root._meta.canMatchNewline,
|
|
2675
|
+
isTrivia: false
|
|
2676
|
+
};
|
|
2677
|
+
return {
|
|
2678
|
+
_tag: "leaf",
|
|
2679
|
+
_meta: meta,
|
|
2680
|
+
_def: { tag: "leaf", parser: root, fn },
|
|
2681
|
+
parse(input, pos, ctx) {
|
|
2682
|
+
const savedBuf = ctx._cstBuf;
|
|
2683
|
+
const savedChildren = ctx._cstChildren;
|
|
2684
|
+
const savedLeaves = ctx._cstLeaves;
|
|
2685
|
+
const savedRaw = ctx._cstRawChildren;
|
|
2686
|
+
const savedTriviaLog = ctx._cstTriviaLog;
|
|
2687
|
+
const savedOuterTriviaLog = ctx._triviaLog;
|
|
2688
|
+
const wasCapturing = cstCaptureActive(ctx);
|
|
2689
|
+
ctx._cstBuf = void 0;
|
|
2690
|
+
ctx._cstChildren = void 0;
|
|
2691
|
+
ctx._cstLeaves = void 0;
|
|
2692
|
+
ctx._cstRawChildren = void 0;
|
|
2693
|
+
ctx._cstTriviaLog = void 0;
|
|
2694
|
+
delete ctx._triviaLog;
|
|
2695
|
+
let result;
|
|
2696
|
+
try {
|
|
2697
|
+
result = root.parse(input, pos, ctx);
|
|
2698
|
+
} finally {
|
|
2699
|
+
ctx._cstBuf = savedBuf;
|
|
2700
|
+
ctx._cstChildren = savedChildren;
|
|
2701
|
+
ctx._cstLeaves = savedLeaves;
|
|
2702
|
+
ctx._cstRawChildren = savedRaw;
|
|
2703
|
+
ctx._cstTriviaLog = savedTriviaLog;
|
|
2704
|
+
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
2705
|
+
else ctx._triviaLog = savedOuterTriviaLog;
|
|
2706
|
+
}
|
|
2707
|
+
if (!result.ok) return result;
|
|
2708
|
+
const value = fn(result.value, result.span);
|
|
2709
|
+
if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span: result.span });
|
|
2710
|
+
return { ok: true, value, span: result.span };
|
|
2711
|
+
}
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
// src/compiler/grammar-coverage-ids.ts
|
|
2716
|
+
function children(def, winners) {
|
|
2717
|
+
switch (def.tag) {
|
|
2718
|
+
case "sequence":
|
|
2719
|
+
case "choice":
|
|
2720
|
+
return def.parsers;
|
|
2721
|
+
case "many":
|
|
2722
|
+
case "oneOrMore":
|
|
2723
|
+
case "optional":
|
|
2724
|
+
case "attempt":
|
|
2725
|
+
case "transform":
|
|
2726
|
+
case "trivia":
|
|
2727
|
+
case "token":
|
|
2728
|
+
case "leaf":
|
|
2729
|
+
case "label":
|
|
2730
|
+
case "field":
|
|
2731
|
+
case "grammar":
|
|
2732
|
+
case "not":
|
|
2733
|
+
case "node":
|
|
2734
|
+
case "guard":
|
|
2735
|
+
case "withCtx":
|
|
2736
|
+
case "recover":
|
|
2737
|
+
case "expect":
|
|
2738
|
+
return "parser" in def ? [def.parser] : [];
|
|
2739
|
+
case "sepBy":
|
|
2740
|
+
return [def.parser, def.separator];
|
|
2741
|
+
case "skip":
|
|
2742
|
+
return [def.main, def.skipped];
|
|
2743
|
+
case "scanTo":
|
|
2744
|
+
return [def.sentinel, ...def.skip];
|
|
2745
|
+
case "lazy": {
|
|
2746
|
+
let resolved;
|
|
2747
|
+
try {
|
|
2748
|
+
resolved = def.thunk();
|
|
2749
|
+
} catch {
|
|
2750
|
+
return [];
|
|
2751
|
+
}
|
|
2752
|
+
const name = resolved._ruleName;
|
|
2753
|
+
return name && winners?.[name] ? [winners[name]] : [resolved];
|
|
2754
|
+
}
|
|
2755
|
+
default:
|
|
2756
|
+
return [];
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
function buildGrammarPlan(entry, winners) {
|
|
2760
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
2761
|
+
const choices = /* @__PURE__ */ new WeakMap();
|
|
2762
|
+
const attempts = /* @__PURE__ */ new WeakMap();
|
|
2763
|
+
const labels = /* @__PURE__ */ new WeakMap();
|
|
2764
|
+
const rules2 = /* @__PURE__ */ new WeakMap();
|
|
2765
|
+
const winnerNames = /* @__PURE__ */ new Map();
|
|
2766
|
+
if (winners) {
|
|
2767
|
+
for (const [name, winner] of Object.entries(winners)) {
|
|
2768
|
+
winnerNames.set(winner, name);
|
|
2769
|
+
if (winner._def.tag === "lazy") {
|
|
2770
|
+
try {
|
|
2771
|
+
winnerNames.set(winner._def.thunk(), name);
|
|
2772
|
+
} catch {
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2778
|
+
const visit = (parser2, path) => {
|
|
2779
|
+
if (seen.has(parser2)) return;
|
|
2780
|
+
seen.add(parser2);
|
|
2781
|
+
const rule = winnerNames.get(parser2) ?? parser2._ruleName;
|
|
2782
|
+
if (rule && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
|
|
2783
|
+
const id = `rule:${rule}`;
|
|
2784
|
+
definitions.set(id, { id, kind: "rule" });
|
|
2785
|
+
rules2.set(parser2, id);
|
|
2786
|
+
}
|
|
2787
|
+
if (parser2._def.tag === "choice") {
|
|
2788
|
+
const ids = parser2._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
|
|
2789
|
+
choices.set(parser2, ids);
|
|
2790
|
+
ids.forEach((id) => definitions.set(id, { id, kind: "choice-arm" }));
|
|
2791
|
+
}
|
|
2792
|
+
if (parser2._def.tag === "attempt") attempts.set(parser2, `attempt:${path}`);
|
|
2793
|
+
if (parser2._def.tag === "label") {
|
|
2794
|
+
const id = `label:${path}`;
|
|
2795
|
+
labels.set(parser2, [id]);
|
|
2796
|
+
definitions.set(id, { id, kind: "label" });
|
|
2797
|
+
}
|
|
2798
|
+
children(parser2._def, winners).forEach((child, index) => visit(child, `${path}/${parser2._def.tag}:${index}`));
|
|
2799
|
+
};
|
|
2800
|
+
const roots = Array.isArray(entry) ? entry : [entry];
|
|
2801
|
+
for (const root of roots) {
|
|
2802
|
+
visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
|
|
2803
|
+
}
|
|
2804
|
+
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, attempts, labels, rules: rules2 };
|
|
2805
|
+
}
|
|
2564
2806
|
|
|
2565
2807
|
// src/compiler/scannable-run.ts
|
|
2566
2808
|
var BACKSLASH = 92;
|
|
@@ -3610,7 +3852,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
|
|
|
3610
3852
|
` if (${m.end} > _e) {`,
|
|
3611
3853
|
` if (_cap) {`,
|
|
3612
3854
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
|
|
3613
|
-
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
3855
|
+
` 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})`,
|
|
3614
3856
|
` }`,
|
|
3615
3857
|
` _e = ${m.end}`,
|
|
3616
3858
|
` continue`,
|
|
@@ -3666,7 +3908,7 @@ function analyzeTriviaFastPath(trivia2) {
|
|
|
3666
3908
|
var CAP_RECORD = [
|
|
3667
3909
|
` if (_cap && _e > _pos) {`,
|
|
3668
3910
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
|
|
3669
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
3911
|
+
` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
3670
3912
|
` }`
|
|
3671
3913
|
].join("\n");
|
|
3672
3914
|
function composeFastLoop(shapes) {
|
|
@@ -3726,7 +3968,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
|
3726
3968
|
` const _ce = _e + _m${i}[0].length`,
|
|
3727
3969
|
` if (_cap) {`,
|
|
3728
3970
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
3729
|
-
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
3971
|
+
` 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})`,
|
|
3730
3972
|
` }`,
|
|
3731
3973
|
` _e = _ce`,
|
|
3732
3974
|
` _matched = true`,
|
|
@@ -3764,7 +4006,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
|
|
|
3764
4006
|
` const _ce = _r${i}.span.end`,
|
|
3765
4007
|
` if (_cap) {`,
|
|
3766
4008
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
3767
|
-
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
4009
|
+
` 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})`,
|
|
3768
4010
|
` }`,
|
|
3769
4011
|
` _e = _ce`,
|
|
3770
4012
|
` _matched = true`,
|
|
@@ -3945,21 +4187,23 @@ function probeUpdate(ctx, expectedArr, posExpr, constant = true) {
|
|
|
3945
4187
|
}
|
|
3946
4188
|
function failBody(ctx, expected, posExpr) {
|
|
3947
4189
|
const probe = probeUpdate(ctx, `[${expected}]`, posExpr);
|
|
4190
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
3948
4191
|
if (ctx.failLabel) {
|
|
3949
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3950
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; break ${ctx.failLabel} }`;
|
|
4192
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4193
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
|
|
3951
4194
|
}
|
|
3952
|
-
return probe + failReturn(expected, posExpr);
|
|
4195
|
+
return probe + trace + failReturn(expected, posExpr);
|
|
3953
4196
|
}
|
|
3954
4197
|
function failArrBody(ctx, expectedArr, posExpr, constant = true) {
|
|
3955
4198
|
const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
|
|
4199
|
+
const trace = ctx.activeCoverageRuleId === void 0 ? "" : `_ctx._grammarTrace?.write({ id: ${JSON.stringify(ctx.activeCoverageRuleId)}, phase: 'failure', offset: ${posExpr} }); `;
|
|
3956
4200
|
if (ctx.failLabel) {
|
|
3957
|
-
if (!ctx.recordFail) return probe ? `{ ${probe}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
4201
|
+
if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
|
|
3958
4202
|
const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
|
|
3959
|
-
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; break ${ctx.failLabel} }`;
|
|
4203
|
+
return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
|
|
3960
4204
|
}
|
|
3961
|
-
if (!constant) return `${probe}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
3962
|
-
return probe + failReturnArr(expectedArr, posExpr);
|
|
4205
|
+
if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
4206
|
+
return probe + trace + failReturnArr(expectedArr, posExpr);
|
|
3963
4207
|
}
|
|
3964
4208
|
function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
|
|
3965
4209
|
return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} } }`;
|
|
@@ -3994,7 +4238,7 @@ var NAMED_FN_END = "_pfEnd";
|
|
|
3994
4238
|
function namedFnPrelude() {
|
|
3995
4239
|
return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
|
|
3996
4240
|
}
|
|
3997
|
-
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
4241
|
+
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar, failureRuleId) {
|
|
3998
4242
|
ctx.namedFnDecls.push([
|
|
3999
4243
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
4000
4244
|
` _pfail: {`,
|
|
@@ -4002,6 +4246,7 @@ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
|
4002
4246
|
` ${NAMED_FN_END} = ${endVar}`,
|
|
4003
4247
|
` return ${valueVar}`,
|
|
4004
4248
|
` }`,
|
|
4249
|
+
...failureRuleId === void 0 ? [] : [` _ctx._grammarTrace?.write({ id: ${JSON.stringify(failureRuleId)}, phase: 'failure', offset: _ctx._fe ?? _pos })`],
|
|
4005
4250
|
` return ${NAMED_FN_FAIL}`,
|
|
4006
4251
|
`}`
|
|
4007
4252
|
].join("\n"));
|
|
@@ -4107,7 +4352,7 @@ function ensureTriviaFn(ctx) {
|
|
|
4107
4352
|
` }`,
|
|
4108
4353
|
` if (_cap && _e > _pos) {`,
|
|
4109
4354
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
|
|
4110
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
4355
|
+
` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
4111
4356
|
` }`,
|
|
4112
4357
|
` return _e`,
|
|
4113
4358
|
`}`
|
|
@@ -4163,6 +4408,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4163
4408
|
case "not":
|
|
4164
4409
|
case "trivia":
|
|
4165
4410
|
case "token":
|
|
4411
|
+
case "leaf":
|
|
4166
4412
|
case "scanTo":
|
|
4167
4413
|
case "unknown":
|
|
4168
4414
|
return false;
|
|
@@ -4174,6 +4420,8 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4174
4420
|
// nothing committed remains.
|
|
4175
4421
|
case "choice":
|
|
4176
4422
|
return false;
|
|
4423
|
+
case "attempt":
|
|
4424
|
+
return false;
|
|
4177
4425
|
// optional never fails; many/oneOrMore only "fail" with zero captured items.
|
|
4178
4426
|
case "optional":
|
|
4179
4427
|
case "many":
|
|
@@ -4226,6 +4474,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4226
4474
|
case "keywords":
|
|
4227
4475
|
case "node":
|
|
4228
4476
|
case "token":
|
|
4477
|
+
case "leaf":
|
|
4229
4478
|
return true;
|
|
4230
4479
|
case "not":
|
|
4231
4480
|
case "guard":
|
|
@@ -4240,6 +4489,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4240
4489
|
case "many":
|
|
4241
4490
|
case "oneOrMore":
|
|
4242
4491
|
case "optional":
|
|
4492
|
+
case "attempt":
|
|
4243
4493
|
case "transform":
|
|
4244
4494
|
case "label":
|
|
4245
4495
|
case "field":
|
|
@@ -4581,35 +4831,55 @@ function needsFirstSetGuard(p) {
|
|
|
4581
4831
|
const fs = p._meta.firstSet;
|
|
4582
4832
|
return fs.kind !== "any" && !canMatchEmptyAtStart(p);
|
|
4583
4833
|
}
|
|
4584
|
-
function
|
|
4585
|
-
|
|
4834
|
+
function coverageHit(ctx, id, offset = "_pos", end) {
|
|
4835
|
+
return id === void 0 ? [] : [
|
|
4836
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`,
|
|
4837
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'selected', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`,
|
|
4838
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${offset}${end === void 0 ? "" : `, end: ${end}`} })`
|
|
4839
|
+
];
|
|
4840
|
+
}
|
|
4841
|
+
function coverageAttempt(ctx, id, offset) {
|
|
4842
|
+
return id === void 0 ? [] : [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'attempt', offset: ${offset} })`];
|
|
4843
|
+
}
|
|
4844
|
+
function coverageFailureBacktrack(ctx, id, failureOffset, startOffset) {
|
|
4845
|
+
return id === void 0 ? [] : [
|
|
4846
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'failure', offset: ${failureOffset} })`,
|
|
4847
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'backtrack', offset: ${startOffset} })`
|
|
4848
|
+
];
|
|
4849
|
+
}
|
|
4850
|
+
function emitDisjointArm(p, ctx, pos, valV, endV, coverageId) {
|
|
4851
|
+
if (failsAtStart(p) && coverageId === void 0) {
|
|
4586
4852
|
const r = emit(p, ctx, pos);
|
|
4587
|
-
return [...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}
|
|
4853
|
+
return [...coverageAttempt(ctx, coverageId, pos), ...r.stmts, `${ind(ctx)}${valV} = ${r.valueVar}`, `${ind(ctx)}${endV} = ${r.endVar}`, ...coverageHit(ctx, coverageId, pos, r.endVar)];
|
|
4588
4854
|
}
|
|
4589
4855
|
const { stmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
|
|
4590
4856
|
return [
|
|
4857
|
+
...coverageAttempt(ctx, coverageId, pos),
|
|
4591
4858
|
...stmts,
|
|
4592
|
-
...emitIfFail(ctx, `!${okVar}`, failArrBody(ctx, "_ctx._fx", pos, false)),
|
|
4859
|
+
...emitIfFail(ctx, `!${okVar}`, `${coverageFailureBacktrack(ctx, coverageId, "_ctx._fe", pos).join("; ")}; ${failArrBody(ctx, "_ctx._fx", pos, false)}`),
|
|
4593
4860
|
`${ind(ctx)}${valV} = ${valVar}`,
|
|
4594
|
-
`${ind(ctx)}${endV} = ${endVar}
|
|
4861
|
+
`${ind(ctx)}${endV} = ${endVar}`,
|
|
4862
|
+
...coverageHit(ctx, coverageId, pos, endVar)
|
|
4595
4863
|
];
|
|
4596
4864
|
}
|
|
4597
|
-
function emitDisjointArmGated(def, i, ctx, pos, valV, endV) {
|
|
4865
|
+
function emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageId) {
|
|
4598
4866
|
const p = def.parsers[i];
|
|
4599
4867
|
const gate = def.gates[i];
|
|
4600
|
-
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV);
|
|
4868
|
+
if (!gate) return emitDisjointArm(p, ctx, pos, valV, endV, coverageId);
|
|
4601
4869
|
const gateIdx = ctx.mapFns.length;
|
|
4602
4870
|
ctx.mapFns.push(gate);
|
|
4603
4871
|
ctx.mapFnSrcs.push(def.gateSrcs?.[i] ?? null);
|
|
4604
4872
|
const gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
4605
4873
|
const stmts = [`${ind(ctx)}if (${gateCond}) {`];
|
|
4606
4874
|
ctx.indent++;
|
|
4607
|
-
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV));
|
|
4875
|
+
stmts.push(...emitDisjointArm(p, ctx, pos, valV, endV, coverageId));
|
|
4608
4876
|
ctx.indent--;
|
|
4609
4877
|
stmts.push(`${ind(ctx)}} else { ${failArrBody(ctx, deriveExpectedArr([p]), pos)} }`);
|
|
4610
4878
|
return stmts;
|
|
4611
4879
|
}
|
|
4612
|
-
function emitChoice(def, ctx, pos) {
|
|
4880
|
+
function emitChoice(parser2, def, ctx, pos) {
|
|
4881
|
+
const coverageIds = ctx.coverage?.plan.choices.get(parser2);
|
|
4882
|
+
const coverageBase = coverageIds?.[0]?.slice(0, -1);
|
|
4613
4883
|
const allExpected = deriveExpectedArr(def.parsers);
|
|
4614
4884
|
if (def.disjoint) {
|
|
4615
4885
|
const codeV = v(ctx, "_code");
|
|
@@ -4628,7 +4898,7 @@ function emitChoice(def, ctx, pos) {
|
|
|
4628
4898
|
stmts.push(`${ind(ctx)}{`);
|
|
4629
4899
|
ctx.indent++;
|
|
4630
4900
|
stmts.push(
|
|
4631
|
-
...emitDisjointArmGated(def, i, ctx, pos, valV, endV),
|
|
4901
|
+
...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]),
|
|
4632
4902
|
`${ind(ctx)}break`
|
|
4633
4903
|
);
|
|
4634
4904
|
ctx.indent--;
|
|
@@ -4647,16 +4917,16 @@ function emitChoice(def, ctx, pos) {
|
|
|
4647
4917
|
first = false;
|
|
4648
4918
|
stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
|
|
4649
4919
|
ctx.indent++;
|
|
4650
|
-
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV));
|
|
4920
|
+
stmts.push(...emitDisjointArmGated(def, i, ctx, pos, valV, endV, coverageIds?.[i]));
|
|
4651
4921
|
ctx.indent--;
|
|
4652
4922
|
stmts.push(`${ind(ctx)}}`);
|
|
4653
4923
|
}
|
|
4654
4924
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4655
4925
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4656
4926
|
}
|
|
4657
|
-
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
|
|
4927
|
+
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos, coverageBase);
|
|
4658
4928
|
}
|
|
4659
|
-
function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
4929
|
+
function emitGreedyClassify(def, superIndex, ctx, pos, coverageBase) {
|
|
4660
4930
|
const superParser = def.parsers[superIndex];
|
|
4661
4931
|
const regexDef = getCoreRegexDef(superParser);
|
|
4662
4932
|
const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
@@ -4672,10 +4942,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4672
4942
|
const endV = v(ctx, "_ge");
|
|
4673
4943
|
const valV = v(ctx, "_gcv");
|
|
4674
4944
|
const regexExpected = JSON.stringify(deriveExpected(superParser));
|
|
4945
|
+
const superCoverageId = coverageBase === void 0 ? void 0 : `${coverageBase}${superIndex}`;
|
|
4675
4946
|
const stmts = [
|
|
4947
|
+
...coverageAttempt(ctx, superCoverageId, pos),
|
|
4676
4948
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
4677
4949
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
4678
|
-
...emitIfFail(ctx, `${matchV} === null`, failArrBody(ctx, regexExpected, pos)),
|
|
4950
|
+
...emitIfFail(ctx, `${matchV} === null`, `${coverageFailureBacktrack(ctx, superCoverageId, pos, pos).join("; ")}; ${failArrBody(ctx, regexExpected, pos)}`),
|
|
4679
4951
|
`${ind(ctx)}const ${wordV} = ${matchV}[0]`,
|
|
4680
4952
|
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
|
|
4681
4953
|
`${ind(ctx)}let ${valV}`
|
|
@@ -4691,8 +4963,9 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4691
4963
|
stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
|
|
4692
4964
|
ctx.indent++;
|
|
4693
4965
|
const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
|
|
4966
|
+
stmts.push(...coverageFailureBacktrack(ctx, superCoverageId, pos, pos));
|
|
4694
4967
|
stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
|
|
4695
|
-
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}
|
|
4968
|
+
stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`, ...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endV));
|
|
4696
4969
|
ctx.indent--;
|
|
4697
4970
|
stmts.push(`${ind(ctx)}}`);
|
|
4698
4971
|
}
|
|
@@ -4700,12 +4973,12 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
4700
4973
|
const regexKw = first ? "if" : "else";
|
|
4701
4974
|
stmts.push(`${ind(ctx)}${regexKw} {`);
|
|
4702
4975
|
ctx.indent++;
|
|
4703
|
-
stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}
|
|
4976
|
+
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));
|
|
4704
4977
|
ctx.indent--;
|
|
4705
4978
|
stmts.push(`${ind(ctx)}}`);
|
|
4706
4979
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4707
4980
|
}
|
|
4708
|
-
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
4981
|
+
function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, coverageBase) {
|
|
4709
4982
|
const valV = v(ctx, "_llv");
|
|
4710
4983
|
const endV = v(ctx, "_lle");
|
|
4711
4984
|
const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
|
|
@@ -4722,10 +4995,12 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4722
4995
|
ctx.indent++;
|
|
4723
4996
|
const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
|
|
4724
4997
|
stmts.push(
|
|
4998
|
+
...coverageAttempt(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos),
|
|
4725
4999
|
...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
|
|
4726
5000
|
...tR.stmts,
|
|
4727
5001
|
`${ind(ctx)}${valV} = ${tR.valueVar}`,
|
|
4728
|
-
`${ind(ctx)}${endV} = ${litEnd}
|
|
5002
|
+
`${ind(ctx)}${endV} = ${litEnd}`,
|
|
5003
|
+
...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${idx}`, pos, litEnd)
|
|
4729
5004
|
);
|
|
4730
5005
|
ctx.indent--;
|
|
4731
5006
|
stmts.push(`${ind(ctx)}}`);
|
|
@@ -4733,16 +5008,18 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
4733
5008
|
stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
|
|
4734
5009
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4735
5010
|
}
|
|
4736
|
-
function emitFirstMatch(def, ctx, pos) {
|
|
5011
|
+
function emitFirstMatch(def, ctx, pos, coverageBase) {
|
|
4737
5012
|
const resValV = v(ctx, "_crv");
|
|
4738
5013
|
const resEndV = v(ctx, "_cre");
|
|
4739
5014
|
const resOkV = v(ctx, "_crok");
|
|
4740
5015
|
const codeV = v(ctx, "_chcode");
|
|
4741
5016
|
const slots = def.parsers.map(() => v(ctx, "_cfx"));
|
|
5017
|
+
const autoRejectedV = coverageBase === void 0 ? void 0 : v(ctx, "_carej");
|
|
4742
5018
|
const ind0 = ind(ctx);
|
|
4743
5019
|
const stmts = [
|
|
4744
5020
|
`${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`,
|
|
4745
5021
|
`${ind0}let ${slots.join(", ")}`,
|
|
5022
|
+
...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
|
|
4746
5023
|
`${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
|
|
4747
5024
|
];
|
|
4748
5025
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
@@ -4778,6 +5055,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4778
5055
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4779
5056
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
4780
5057
|
ctx.indent += fsGuard ? 2 : 1;
|
|
5058
|
+
if (coverageBase !== void 0) stmts.push(`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(`${coverageBase}${i}`)}, phase: 'attempt', offset: ${pos} })`);
|
|
4781
5059
|
if (markLeaves) {
|
|
4782
5060
|
stmts.push(
|
|
4783
5061
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
@@ -4800,13 +5078,21 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4800
5078
|
stmts.push(`${ind(ctx)} ${resValV} = ${valVar}`);
|
|
4801
5079
|
stmts.push(`${ind(ctx)} ${resEndV} = ${endVar}`);
|
|
4802
5080
|
stmts.push(`${ind(ctx)} ${resOkV} = true`);
|
|
5081
|
+
if (autoRejectedV !== void 0) {
|
|
5082
|
+
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} }) }`);
|
|
5083
|
+
}
|
|
5084
|
+
stmts.push(...coverageHit(ctx, coverageBase === void 0 ? void 0 : `${coverageBase}${i}`, pos, endVar));
|
|
4803
5085
|
stmts.push(`${ind(ctx)} }`);
|
|
5086
|
+
if (autoRejectedV !== void 0) {
|
|
5087
|
+
stmts.push(`${ind(ctx)} else { ${autoRejectedV}.push(${JSON.stringify(`${coverageBase}${i}`)}) }`);
|
|
5088
|
+
}
|
|
4804
5089
|
stmts.push(`${ind(ctx)}}`);
|
|
4805
|
-
stmts.push(`${ind(ctx)}else { ${slots[i]} = ${failSlot} }`);
|
|
5090
|
+
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} });`} }`);
|
|
4806
5091
|
if (rollback) stmts.push(`${ind(ctx)}if (!${resOkV}) { ${rollback} }`);
|
|
4807
5092
|
} else {
|
|
4808
|
-
|
|
4809
|
-
stmts.push(`${ind(ctx)}
|
|
5093
|
+
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} }) }`;
|
|
5094
|
+
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} })`} }`);
|
|
5095
|
+
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} })`} }`);
|
|
4810
5096
|
}
|
|
4811
5097
|
ctx.indent -= fsGuard ? 2 : 1;
|
|
4812
5098
|
if (fsGuard) stmts.push(`${ind(ctx)}} else { ${slots[i]} = ${staticFx} }`);
|
|
@@ -4816,12 +5102,12 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4816
5102
|
stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
|
|
4817
5103
|
return { stmts, valueVar: resValV, endVar: resEndV };
|
|
4818
5104
|
}
|
|
4819
|
-
function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
5105
|
+
function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
|
|
4820
5106
|
if (strategy.tag === "greedyClassify")
|
|
4821
|
-
return emitGreedyClassify(def, strategy.superIndex, ctx, pos);
|
|
5107
|
+
return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
|
|
4822
5108
|
if (strategy.tag === "literalsLongestFirst")
|
|
4823
|
-
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
4824
|
-
return emitFirstMatch(def, ctx, pos);
|
|
5109
|
+
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
|
|
5110
|
+
return emitFirstMatch(def, ctx, pos, coverageBase);
|
|
4825
5111
|
}
|
|
4826
5112
|
function pushMapFn(ctx, fn, src) {
|
|
4827
5113
|
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
@@ -4939,6 +5225,27 @@ function emitOptional(def, ctx, pos) {
|
|
|
4939
5225
|
];
|
|
4940
5226
|
return { stmts, valueVar: valV, endVar: endV };
|
|
4941
5227
|
}
|
|
5228
|
+
function emitAttempt(p, def, ctx, pos) {
|
|
5229
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5230
|
+
const leaves = v(ctx, "_atl");
|
|
5231
|
+
const raw = v(ctx, "_atr");
|
|
5232
|
+
const trivia2 = v(ctx, "_att");
|
|
5233
|
+
const log = v(ctx, "_atg");
|
|
5234
|
+
const fields = v(ctx, "_atf");
|
|
5235
|
+
const errors = v(ctx, "_ate");
|
|
5236
|
+
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}`;
|
|
5237
|
+
const traceId = ctx.coverage?.plan.attempts.get(p);
|
|
5238
|
+
const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
|
|
5239
|
+
return {
|
|
5240
|
+
stmts: [
|
|
5241
|
+
`${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`,
|
|
5242
|
+
...inner.stmts,
|
|
5243
|
+
...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
|
|
5244
|
+
],
|
|
5245
|
+
valueVar: inner.valVar,
|
|
5246
|
+
endVar: inner.endVar
|
|
5247
|
+
};
|
|
5248
|
+
}
|
|
4942
5249
|
function emitSepBy(_p, def, ctx, pos) {
|
|
4943
5250
|
const arrV = v(ctx, "_arr");
|
|
4944
5251
|
const curV = v(ctx, "_cur");
|
|
@@ -5229,6 +5536,36 @@ function emitToken(def, ctx, pos) {
|
|
|
5229
5536
|
endVar: inner.endVar
|
|
5230
5537
|
};
|
|
5231
5538
|
}
|
|
5539
|
+
function emitLeaf(def, ctx, pos) {
|
|
5540
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
5541
|
+
const i = ind(ctx);
|
|
5542
|
+
const sc = v(ctx, "_leafCh");
|
|
5543
|
+
const sl = v(ctx, "_leafLv");
|
|
5544
|
+
const sr = v(ctx, "_leafRaw");
|
|
5545
|
+
const stl = v(ctx, "_leafTl");
|
|
5546
|
+
const sol = v(ctx, "_leafLog");
|
|
5547
|
+
const sb = v(ctx, "_leafBuf");
|
|
5548
|
+
const rawV = v(ctx, "_leafRawValue");
|
|
5549
|
+
const valV = v(ctx, "_leaf");
|
|
5550
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
5551
|
+
return {
|
|
5552
|
+
stmts: [
|
|
5553
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
|
|
5554
|
+
`${i}_ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
|
|
5555
|
+
`${i}try {`,
|
|
5556
|
+
...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
|
|
5557
|
+
`${i}} finally {`,
|
|
5558
|
+
`${i} _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
|
|
5559
|
+
`${i}}`,
|
|
5560
|
+
...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
|
|
5561
|
+
`${i}const ${rawV} = ${inner.valVar}`,
|
|
5562
|
+
`${i}const ${valV} = ${mfRef(ctx)}[${fnIdx}](${rawV}, { start: ${pos}, end: ${inner.endVar} })`,
|
|
5563
|
+
...emitLeafCapture(ctx, valV, pos, inner.endVar)
|
|
5564
|
+
],
|
|
5565
|
+
valueVar: valV,
|
|
5566
|
+
endVar: inner.endVar
|
|
5567
|
+
};
|
|
5568
|
+
}
|
|
5232
5569
|
function emitNode(def, ctx, pos) {
|
|
5233
5570
|
if (def.type === void 0) {
|
|
5234
5571
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
@@ -5242,17 +5579,20 @@ function emitNode(def, ctx, pos) {
|
|
|
5242
5579
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
5243
5580
|
}
|
|
5244
5581
|
const i = ind(ctx);
|
|
5245
|
-
const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
|
|
5582
|
+
const capturesTrivia = mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
|
|
5246
5583
|
const clonesState = !structural && buildReadsState(def);
|
|
5584
|
+
const capturesChildren = !structural && (mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
|
|
5585
|
+
const capturesRaw = !structural && (mkType !== null || buildReadsRaw(def));
|
|
5247
5586
|
const hasFields = parserHasOwnFields(def.parser);
|
|
5248
5587
|
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
5588
|
+
const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
|
|
5249
5589
|
const chV = v(ctx, "_ch");
|
|
5250
5590
|
const rawV = v(ctx, "_raw");
|
|
5251
|
-
const capTLv = structural ? v(ctx, "_ctl") : null;
|
|
5591
|
+
const capTLv = structural || capturesTrivia ? v(ctx, "_ctl") : null;
|
|
5252
5592
|
const capSTv = structural ? v(ctx, "_cst") : null;
|
|
5253
5593
|
const capFv = structural && hasFields ? v(ctx, "_cf") : null;
|
|
5254
5594
|
const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
5255
|
-
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
5595
|
+
if (!capturesTrivia || structural) ctx.needsEmptyTl = true;
|
|
5256
5596
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
5257
5597
|
const smk = structural ? v(ctx, "_smk") : null;
|
|
5258
5598
|
if (structural) ctx.needsHostReads = true;
|
|
@@ -5261,16 +5601,21 @@ function emitNode(def, ctx, pos) {
|
|
|
5261
5601
|
const profHoist = `${i}const ${pmV} = _ctx._pmProfile, ${recV} = ${pmV}?.phase === 'recognizer', ${capV} = ${pmV}?.phase === 'capture'`;
|
|
5262
5602
|
const profileRecognizer = recV;
|
|
5263
5603
|
const profileCapture = capV;
|
|
5264
|
-
const
|
|
5265
|
-
|
|
5266
|
-
const
|
|
5604
|
+
const directCstV = !structural && (!capturesChildren || !capturesRaw) ? v(ctx, "_dcst") : null;
|
|
5605
|
+
const directCstGate = directCstV === null ? "false" : `${profileCapture} || _ctx.build?._parsemanCstOutput === true`;
|
|
5606
|
+
const structuralCapturesTrivia = structural && (def.captureTrivia === true || def.trailingTrivia === true);
|
|
5607
|
+
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)))` : ""}
|
|
5608
|
+
${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRecognizer} ? undefined : [], ${tlV} = ${profileRecognizer} ? undefined : ${innerEnablesTriviaCapture ? "[]" : `${capTLv} ? [] : _EMPTY_TL`}` : capturesTrivia ? `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5609
|
+
` : ""}${i}const ${capTLv} = !(${profileRecognizer}), ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}, ${tlV} = ${profileRecognizer} ? undefined : []` : `${directCstV ? `${i}const ${directCstV} = ${directCstGate}
|
|
5610
|
+
` : ""}${i}const ${chV} = ${profileRecognizer} ? undefined : ${capturesChildren ? "[]" : `${directCstV} ? [] : undefined`}, ${rawV} = ${profileRecognizer} ? undefined : ${capturesRaw ? "[]" : `${directCstV} ? [] : undefined`}`;
|
|
5611
|
+
const innerTl = structural || capturesTrivia ? structural && !innerEnablesTriviaCapture ? `${capTLv} ? ${tlV} : undefined` : tlV : "undefined";
|
|
5267
5612
|
const fieldsOn = structural ? capFv ?? "false" : `${profileRecognizer} ? false : ${capturesFields ? "true" : "false"}`;
|
|
5268
5613
|
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
5269
5614
|
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
5270
5615
|
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
5271
|
-
const needsTriviaFrame = parserHasTriviaSite(def.parser);
|
|
5616
|
+
const needsTriviaFrame = def.trailingTrivia === true || parserHasTriviaSite(def.parser);
|
|
5272
5617
|
const saveTrivia = needsTriviaFrame ? `, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}` : "";
|
|
5273
|
-
const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia =
|
|
5618
|
+
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}` : ""}` : "";
|
|
5274
5619
|
const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
|
|
5275
5620
|
const stmts = [
|
|
5276
5621
|
profHoist,
|
|
@@ -5278,8 +5623,13 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5278
5623
|
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
5279
5624
|
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}${installTrivia}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
5280
5625
|
];
|
|
5281
|
-
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
5626
|
+
const { stmts: innerStmts, okVar, endVar: innerEndVar } = emitFallible(def.parser, ctx, pos);
|
|
5627
|
+
const endVar = def.trailingTrivia === true && ctx.activeTrivia ? v(ctx, "_trailend") : innerEndVar;
|
|
5282
5628
|
stmts.push(...innerStmts);
|
|
5629
|
+
if (def.trailingTrivia === true && ctx.activeTrivia) {
|
|
5630
|
+
const triviaFn = ensureTriviaFn(ctx);
|
|
5631
|
+
stmts.push(`${i}const ${endVar} = ${okVar} ? ${triviaFn}(input, ${innerEndVar}, _ctx, 1) : ${innerEndVar}`);
|
|
5632
|
+
}
|
|
5283
5633
|
if (sf && fArr) {
|
|
5284
5634
|
stmts.push(`${i}const ${fArr} = _ctx._fields`);
|
|
5285
5635
|
}
|
|
@@ -5319,8 +5669,9 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5319
5669
|
}
|
|
5320
5670
|
const ndV = v(ctx, "_nd");
|
|
5321
5671
|
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})`;
|
|
5322
|
-
const
|
|
5323
|
-
const
|
|
5672
|
+
const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
5673
|
+
const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : `_ctx.build?._parsemanCstOutput === true ? (${hostBuildExpr}) : (${buildExpr})`;
|
|
5674
|
+
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;
|
|
5324
5675
|
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
5325
5676
|
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
5326
5677
|
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
@@ -5328,7 +5679,7 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
|
|
|
5328
5679
|
`${i}const ${ndV} = (${profileRecognizer} || ${profileCapture}) ? undefined : (${finalExpr})`,
|
|
5329
5680
|
`${i}if (!(${profileRecognizer})) {`,
|
|
5330
5681
|
`${i} if (${sc}) ${sc}.push(${ndV})`,
|
|
5331
|
-
`${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} } })`,
|
|
5682
|
+
`${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} } })`,
|
|
5332
5683
|
`${i}}`
|
|
5333
5684
|
);
|
|
5334
5685
|
return { stmts, valueVar: ndV, endVar };
|
|
@@ -5373,14 +5724,23 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
5373
5724
|
const savedIndent = ctx.indent;
|
|
5374
5725
|
const savedFailLabel = ctx.failLabel;
|
|
5375
5726
|
const savedRecord = ctx.recordFail;
|
|
5727
|
+
const failureRuleId = p === ctx.coverage?.entry ? void 0 : ctx.coverage?.plan.rules.get(p) ?? ctx.coverage?.plan.rules.get(resolved);
|
|
5728
|
+
const savedActiveRule = ctx.activeCoverageRuleId;
|
|
5729
|
+
const savedSuppressFailure = ctx.suppressCoverageFailure;
|
|
5376
5730
|
ctx.indent = 1;
|
|
5377
5731
|
ctx.failLabel = "_pfail";
|
|
5378
5732
|
ctx.recordFail = true;
|
|
5733
|
+
if (failureRuleId !== void 0) {
|
|
5734
|
+
ctx.activeCoverageRuleId = void 0;
|
|
5735
|
+
ctx.suppressCoverageFailure = true;
|
|
5736
|
+
}
|
|
5379
5737
|
const r = emit(resolved, ctx, "_pos");
|
|
5380
5738
|
ctx.indent = savedIndent;
|
|
5381
5739
|
ctx.failLabel = savedFailLabel;
|
|
5382
5740
|
ctx.recordFail = savedRecord;
|
|
5383
|
-
|
|
5741
|
+
ctx.activeCoverageRuleId = savedActiveRule;
|
|
5742
|
+
ctx.suppressCoverageFailure = savedSuppressFailure;
|
|
5743
|
+
pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar, failureRuleId);
|
|
5384
5744
|
}
|
|
5385
5745
|
const fnName = ctx.namedParsers.get(p);
|
|
5386
5746
|
return emitNamedFnCall(ctx, fnName, pos);
|
|
@@ -5431,6 +5791,30 @@ function emitExpect(def, ctx, pos) {
|
|
|
5431
5791
|
return { stmts, valueVar: valVar, endVar };
|
|
5432
5792
|
}
|
|
5433
5793
|
function emit(p, ctx, pos) {
|
|
5794
|
+
const dispatch = (emissionPos = pos) => {
|
|
5795
|
+
const savedRule = ctx.activeCoverageRuleId;
|
|
5796
|
+
const rule = ctx.coverage?.plan.rules.get(p);
|
|
5797
|
+
if (rule && p !== ctx.coverage?.entry && !ctx.suppressCoverageFailure) ctx.activeCoverageRuleId = rule;
|
|
5798
|
+
const result = emitDispatch(p, ctx, emissionPos);
|
|
5799
|
+
ctx.activeCoverageRuleId = savedRule;
|
|
5800
|
+
return result;
|
|
5801
|
+
};
|
|
5802
|
+
const instrument = (r) => {
|
|
5803
|
+
const ruleId = ctx.coverage?.plan.rules.get(p);
|
|
5804
|
+
const labelIds = ctx.coverage?.plan.labels.get(p);
|
|
5805
|
+
if (!ruleId && !labelIds) return r;
|
|
5806
|
+
return {
|
|
5807
|
+
...r,
|
|
5808
|
+
stmts: [
|
|
5809
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`] : [],
|
|
5810
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: ${pos} })`] : [],
|
|
5811
|
+
...r.stmts,
|
|
5812
|
+
...ruleId ? [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`] : [],
|
|
5813
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(id)})`]) ?? [],
|
|
5814
|
+
...labelIds?.flatMap((id) => [`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(id)}, phase: 'success', offset: ${pos}, end: ${r.endVar} })`]) ?? []
|
|
5815
|
+
]
|
|
5816
|
+
};
|
|
5817
|
+
};
|
|
5434
5818
|
const usage = ctx.lazyUsage;
|
|
5435
5819
|
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
|
|
5436
5820
|
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
@@ -5447,14 +5831,14 @@ function emit(p, ctx, pos) {
|
|
|
5447
5831
|
ctx.indent = 1;
|
|
5448
5832
|
ctx.failLabel = "_pfail";
|
|
5449
5833
|
ctx.recordFail = true;
|
|
5450
|
-
const r =
|
|
5834
|
+
const r = dispatch("_pos");
|
|
5451
5835
|
ctx.indent = savedIndent;
|
|
5452
5836
|
ctx.failLabel = savedFailLabel;
|
|
5453
5837
|
ctx.recordFail = savedRecord;
|
|
5454
5838
|
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
5455
|
-
return emitNamedFnCall(ctx, fnName, pos);
|
|
5839
|
+
return instrument(emitNamedFnCall(ctx, fnName, pos));
|
|
5456
5840
|
}
|
|
5457
|
-
return
|
|
5841
|
+
return instrument(dispatch());
|
|
5458
5842
|
}
|
|
5459
5843
|
function emitDispatch(p, ctx, pos) {
|
|
5460
5844
|
const def = p._def;
|
|
@@ -5468,7 +5852,9 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5468
5852
|
case "sequence":
|
|
5469
5853
|
return emitSeq(def, ctx, pos);
|
|
5470
5854
|
case "choice":
|
|
5471
|
-
return emitChoice(def, ctx, pos);
|
|
5855
|
+
return emitChoice(p, def, ctx, pos);
|
|
5856
|
+
case "attempt":
|
|
5857
|
+
return emitAttempt(p, def, ctx, pos);
|
|
5472
5858
|
case "many":
|
|
5473
5859
|
case "oneOrMore":
|
|
5474
5860
|
return emitMany(def, ctx, pos);
|
|
@@ -5537,6 +5923,8 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5537
5923
|
return emit(def.parser, ctx, pos);
|
|
5538
5924
|
case "token":
|
|
5539
5925
|
return emitToken(def, ctx, pos);
|
|
5926
|
+
case "leaf":
|
|
5927
|
+
return emitLeaf(def, ctx, pos);
|
|
5540
5928
|
case "label": {
|
|
5541
5929
|
const inner = emitFallible(def.parser, ctx, pos);
|
|
5542
5930
|
return {
|
|
@@ -5571,10 +5959,19 @@ function emitDispatch(p, ctx, pos) {
|
|
|
5571
5959
|
ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
|
|
5572
5960
|
}
|
|
5573
5961
|
}
|
|
5962
|
+
const savedCapture = def.captureTrivia ? v(ctx, "_gcap") : null;
|
|
5574
5963
|
const r = emit(def.parser, ctx, pos);
|
|
5575
5964
|
ctx.activeTrivia = savedTrivia;
|
|
5576
5965
|
ctx.triviaKindLabels = savedKindLabels;
|
|
5577
|
-
return r;
|
|
5966
|
+
if (!savedCapture) return r;
|
|
5967
|
+
return {
|
|
5968
|
+
...r,
|
|
5969
|
+
stmts: [
|
|
5970
|
+
`${ind(ctx)}const ${savedCapture} = _ctx.captureTrivia; _ctx.captureTrivia = true`,
|
|
5971
|
+
...r.stmts,
|
|
5972
|
+
`${ind(ctx)}_ctx.captureTrivia = ${savedCapture}`
|
|
5973
|
+
]
|
|
5974
|
+
};
|
|
5578
5975
|
}
|
|
5579
5976
|
case "not":
|
|
5580
5977
|
return emitNot(def, ctx, pos);
|
|
@@ -5659,6 +6056,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5659
6056
|
case "grammar":
|
|
5660
6057
|
case "trivia":
|
|
5661
6058
|
case "token":
|
|
6059
|
+
case "leaf":
|
|
5662
6060
|
case "label":
|
|
5663
6061
|
case "field":
|
|
5664
6062
|
case "optional":
|
|
@@ -5686,16 +6084,32 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
5686
6084
|
return false;
|
|
5687
6085
|
}
|
|
5688
6086
|
}
|
|
6087
|
+
function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
6088
|
+
if (seen.has(p)) return false;
|
|
6089
|
+
seen.add(p);
|
|
6090
|
+
const d = p._def;
|
|
6091
|
+
if (d.tag === "node" && d.build !== void 0) return true;
|
|
6092
|
+
if (d.tag === "lazy") {
|
|
6093
|
+
try {
|
|
6094
|
+
return hasDirectBuildDef(d.thunk(), seen);
|
|
6095
|
+
} catch {
|
|
6096
|
+
return false;
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
return childrenOf(d).some((child) => hasDirectBuildDef(child, seen));
|
|
6100
|
+
}
|
|
5689
6101
|
function childrenOf(def) {
|
|
5690
6102
|
switch (def.tag) {
|
|
5691
6103
|
case "sequence":
|
|
5692
6104
|
case "choice":
|
|
5693
6105
|
return def.parsers;
|
|
5694
6106
|
case "many":
|
|
6107
|
+
case "attempt":
|
|
5695
6108
|
case "optional":
|
|
5696
6109
|
case "transform":
|
|
5697
6110
|
case "trivia":
|
|
5698
6111
|
case "token":
|
|
6112
|
+
case "leaf":
|
|
5699
6113
|
case "label":
|
|
5700
6114
|
case "field":
|
|
5701
6115
|
case "grammar":
|
|
@@ -5870,10 +6284,25 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5870
6284
|
namedFnDecls: [],
|
|
5871
6285
|
capturing: hasNodeDef(combinator),
|
|
5872
6286
|
recovery: opts?.recovery ?? false,
|
|
6287
|
+
...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
|
|
5873
6288
|
lazyUsage: analyzeLazyUsage(combinator),
|
|
5874
6289
|
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5875
6290
|
};
|
|
5876
6291
|
const r = emit(combinator, ctx, "_pos");
|
|
6292
|
+
const coverageRootRuleId = ctx.coverage?.plan.rules.get(combinator);
|
|
6293
|
+
const resultBody = coverageRootRuleId === void 0 ? [
|
|
6294
|
+
` let pos = _pos`,
|
|
6295
|
+
...r.stmts,
|
|
6296
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6297
|
+
] : [
|
|
6298
|
+
` const _coverageResult = (() => {`,
|
|
6299
|
+
` let pos = _pos`,
|
|
6300
|
+
...r.stmts,
|
|
6301
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6302
|
+
` })()`,
|
|
6303
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6304
|
+
` return _coverageResult`
|
|
6305
|
+
];
|
|
5877
6306
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
5878
6307
|
const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
|
|
5879
6308
|
const hostReadsDecls = ctx.needsHostReads ? [HOST_READS_DECL] : [];
|
|
@@ -5886,9 +6315,7 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5886
6315
|
...namedPrelude,
|
|
5887
6316
|
ctx.namedFnDecls.join("\n\n"),
|
|
5888
6317
|
`function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
|
|
5889
|
-
|
|
5890
|
-
...r.stmts,
|
|
5891
|
-
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6318
|
+
...resultBody,
|
|
5892
6319
|
`}`
|
|
5893
6320
|
].join("\n");
|
|
5894
6321
|
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
@@ -5898,9 +6325,15 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5898
6325
|
...ctx.expectedDecls,
|
|
5899
6326
|
...namedPrelude,
|
|
5900
6327
|
...ctx.namedFnDecls.flatMap((decl, i) => i > 0 ? ["", decl] : [decl]),
|
|
5901
|
-
`let pos = _pos`,
|
|
5902
|
-
|
|
5903
|
-
|
|
6328
|
+
...coverageRootRuleId === void 0 ? [`let pos = _pos`, ...r.stmts, `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`] : [
|
|
6329
|
+
`const _coverageResult = (() => {`,
|
|
6330
|
+
` let pos = _pos`,
|
|
6331
|
+
...r.stmts,
|
|
6332
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6333
|
+
`})()`,
|
|
6334
|
+
`if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6335
|
+
`return _coverageResult`
|
|
6336
|
+
]
|
|
5904
6337
|
].join("\n"));
|
|
5905
6338
|
const defaultCtx = {
|
|
5906
6339
|
trackLines: false,
|
|
@@ -5912,10 +6345,11 @@ function compile(combinator, mapFnSources, opts) {
|
|
|
5912
6345
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
5913
6346
|
const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
|
|
5914
6347
|
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
5915
|
-
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources) : null;
|
|
6348
|
+
const inlineExpression = canInline ? buildInlineExpression(ctx, r, effectiveSources, buildSources, coverageRootRuleId) : null;
|
|
5916
6349
|
return {
|
|
5917
6350
|
source,
|
|
5918
6351
|
inlineExpression,
|
|
6352
|
+
...ctx.coverage === void 0 ? {} : { coverageDefinitions: ctx.coverage.plan.definitions },
|
|
5919
6353
|
parse(input, pos = 0) {
|
|
5920
6354
|
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
|
|
5921
6355
|
},
|
|
@@ -5978,8 +6412,13 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
5978
6412
|
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
5979
6413
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5980
6414
|
namedFnDecls: [],
|
|
5981
|
-
|
|
6415
|
+
// A recognition-only fragment normally has no node collector of its own.
|
|
6416
|
+
// Leaf composition can re-lower it beneath a local semantic node, though;
|
|
6417
|
+
// in that case its terminals must feed the caller's collector rather than
|
|
6418
|
+
// merely returning their scalar parse values.
|
|
6419
|
+
capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5982
6420
|
recovery: opts?.recovery ?? false,
|
|
6421
|
+
...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
|
|
5983
6422
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5984
6423
|
ns,
|
|
5985
6424
|
deferFirstSetRefs: true,
|
|
@@ -6053,7 +6492,14 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6053
6492
|
ctx.indent = savedIndent;
|
|
6054
6493
|
ctx.failLabel = savedFail;
|
|
6055
6494
|
ctx.recordFail = savedRec;
|
|
6056
|
-
|
|
6495
|
+
const ruleId = ctx.coverage?.plan.rules.get(rule);
|
|
6496
|
+
const stmts = ruleId === void 0 ? body.stmts : [
|
|
6497
|
+
`${ind(ctx)}_ctx._grammarCoverage?.(${JSON.stringify(ruleId)})`,
|
|
6498
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'enter', offset: _pos })`,
|
|
6499
|
+
...body.stmts,
|
|
6500
|
+
`${ind(ctx)}_ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'success', offset: _pos, end: ${body.endVar} })`
|
|
6501
|
+
];
|
|
6502
|
+
pushNamedFnDecl(ctx, fn, stmts, body.valueVar, body.endVar);
|
|
6057
6503
|
}
|
|
6058
6504
|
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
6059
6505
|
}
|
|
@@ -6110,15 +6556,46 @@ function compileLinkable(ruleMapArg, ns, opts) {
|
|
|
6110
6556
|
deps: ruleDependencies(ruleMap),
|
|
6111
6557
|
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
6112
6558
|
needsHostReads: !!ctx.needsHostReads,
|
|
6559
|
+
hasDirectBuilders: ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
6560
|
+
isRecognitionOnly: !hasSemanticReduction(ruleMap.map(([, rule]) => rule)),
|
|
6113
6561
|
mfFns: mfSrcs ? [] : ctx.mapFns,
|
|
6114
6562
|
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
6115
6563
|
};
|
|
6116
6564
|
}
|
|
6117
|
-
function
|
|
6118
|
-
const
|
|
6565
|
+
function hasSemanticReduction(roots) {
|
|
6566
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6567
|
+
const visit = (parser2) => {
|
|
6568
|
+
if (seen.has(parser2)) return false;
|
|
6569
|
+
seen.add(parser2);
|
|
6570
|
+
const def = parser2._def;
|
|
6571
|
+
if (def.tag === "transform" && !def.recognitionOnly) return true;
|
|
6572
|
+
if (def.tag === "choice" && def.gates.some(Boolean)) return true;
|
|
6573
|
+
if (def.tag === "guard" || def.tag === "withCtx") return true;
|
|
6574
|
+
if (def.tag === "node" && def.build !== void 0) return true;
|
|
6575
|
+
if (def.tag === "lazy") {
|
|
6576
|
+
try {
|
|
6577
|
+
return visit(def.thunk());
|
|
6578
|
+
} catch {
|
|
6579
|
+
return true;
|
|
6580
|
+
}
|
|
6581
|
+
}
|
|
6582
|
+
return childrenOf(def).some(visit);
|
|
6583
|
+
};
|
|
6584
|
+
return roots.some(visit);
|
|
6585
|
+
}
|
|
6586
|
+
function buildInlineExpression(ctx, r, mapFnSources, buildSources, coverageRootRuleId) {
|
|
6587
|
+
const bodyLines = coverageRootRuleId === void 0 ? [
|
|
6119
6588
|
` let pos = _pos`,
|
|
6120
6589
|
...r.stmts,
|
|
6121
6590
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
6591
|
+
] : [
|
|
6592
|
+
` const _coverageResult = (() => {`,
|
|
6593
|
+
` let pos = _pos`,
|
|
6594
|
+
...r.stmts,
|
|
6595
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
6596
|
+
` })()`,
|
|
6597
|
+
` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(coverageRootRuleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
|
|
6598
|
+
` return _coverageResult`
|
|
6122
6599
|
];
|
|
6123
6600
|
const innerFn = [
|
|
6124
6601
|
`function(input, _pos, _ctx) {`,
|
|
@@ -6173,8 +6650,8 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
|
6173
6650
|
};
|
|
6174
6651
|
const emit2 = (end) => {
|
|
6175
6652
|
if (end > pos && cstCaptureActive(ctx)) {
|
|
6176
|
-
const
|
|
6177
|
-
pushCstLeaf(ctx,
|
|
6653
|
+
const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
6654
|
+
pushCstLeaf(ctx, leaf2);
|
|
6178
6655
|
}
|
|
6179
6656
|
};
|
|
6180
6657
|
while (cur < input.length) {
|
|
@@ -6228,6 +6705,7 @@ function balanced(open, close, options = {}) {
|
|
|
6228
6705
|
);
|
|
6229
6706
|
if (combi._def.tag === "transform") {
|
|
6230
6707
|
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
6708
|
+
combi._def.recognitionOnly = true;
|
|
6231
6709
|
}
|
|
6232
6710
|
self.define(combi);
|
|
6233
6711
|
return combi;
|
|
@@ -6273,9 +6751,11 @@ function childrenOf2(def) {
|
|
|
6273
6751
|
case "many":
|
|
6274
6752
|
case "oneOrMore":
|
|
6275
6753
|
case "optional":
|
|
6754
|
+
case "attempt":
|
|
6276
6755
|
case "transform":
|
|
6277
6756
|
case "trivia":
|
|
6278
6757
|
case "token":
|
|
6758
|
+
case "leaf":
|
|
6279
6759
|
case "label":
|
|
6280
6760
|
case "field":
|
|
6281
6761
|
case "not":
|
|
@@ -6324,7 +6804,7 @@ function serializeRuleMap(ruleMap) {
|
|
|
6324
6804
|
}
|
|
6325
6805
|
}
|
|
6326
6806
|
function evalRuleMapIR(ir) {
|
|
6327
|
-
const _tf = (child, src) => {
|
|
6807
|
+
const _tf = (child, src, recognitionOnly = false) => {
|
|
6328
6808
|
let fn2;
|
|
6329
6809
|
try {
|
|
6330
6810
|
fn2 = (0, eval)(`(${src})`);
|
|
@@ -6335,11 +6815,31 @@ function evalRuleMapIR(ir) {
|
|
|
6335
6815
|
}
|
|
6336
6816
|
const t = transform(child, fn2);
|
|
6337
6817
|
t._def.fnSrc = src;
|
|
6818
|
+
if (recognitionOnly) t._def.recognitionOnly = true;
|
|
6338
6819
|
return t;
|
|
6339
6820
|
};
|
|
6340
|
-
const
|
|
6341
|
-
|
|
6821
|
+
const _lf = (child, src) => {
|
|
6822
|
+
let fn2;
|
|
6823
|
+
try {
|
|
6824
|
+
fn2 = (0, eval)(`(${src})`);
|
|
6825
|
+
} catch {
|
|
6826
|
+
fn2 = () => {
|
|
6827
|
+
throw new Error("IR leaf fn not materialized");
|
|
6828
|
+
};
|
|
6829
|
+
}
|
|
6830
|
+
const l = leaf(child, fn2);
|
|
6831
|
+
l._def.fnSrc = src;
|
|
6832
|
+
return l;
|
|
6833
|
+
};
|
|
6834
|
+
const _nd = (type, child, src, opts, staticError) => {
|
|
6835
|
+
if (staticError !== void 0 && staticError.length > 0) {
|
|
6836
|
+
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
6837
|
+
}
|
|
6838
|
+
const n = node(type, child, (() => {
|
|
6839
|
+
throw new Error("IR node build requires static re-lowering");
|
|
6840
|
+
}), opts);
|
|
6342
6841
|
n._def.buildSrc = src;
|
|
6842
|
+
if (staticError !== void 0) n._def.buildStaticError = staticError;
|
|
6343
6843
|
return n;
|
|
6344
6844
|
};
|
|
6345
6845
|
const _gch = (items) => {
|
|
@@ -6389,6 +6889,7 @@ function evalRuleMapIR(ir) {
|
|
|
6389
6889
|
"keywords",
|
|
6390
6890
|
"sequence",
|
|
6391
6891
|
"choice",
|
|
6892
|
+
"attempt",
|
|
6392
6893
|
"many",
|
|
6393
6894
|
"oneOrMore",
|
|
6394
6895
|
"optional",
|
|
@@ -6398,6 +6899,7 @@ function evalRuleMapIR(ir) {
|
|
|
6398
6899
|
"parser",
|
|
6399
6900
|
"scanTo",
|
|
6400
6901
|
"token",
|
|
6902
|
+
"leaf",
|
|
6401
6903
|
"transform",
|
|
6402
6904
|
"skip",
|
|
6403
6905
|
"trivia",
|
|
@@ -6405,6 +6907,7 @@ function evalRuleMapIR(ir) {
|
|
|
6405
6907
|
"field",
|
|
6406
6908
|
"expect",
|
|
6407
6909
|
"_tf",
|
|
6910
|
+
"_lf",
|
|
6408
6911
|
"_nd",
|
|
6409
6912
|
"_gch",
|
|
6410
6913
|
"_wc",
|
|
@@ -6418,6 +6921,7 @@ function evalRuleMapIR(ir) {
|
|
|
6418
6921
|
keywords,
|
|
6419
6922
|
sequence,
|
|
6420
6923
|
choice,
|
|
6924
|
+
attempt,
|
|
6421
6925
|
many,
|
|
6422
6926
|
oneOrMore,
|
|
6423
6927
|
optional,
|
|
@@ -6427,6 +6931,7 @@ function evalRuleMapIR(ir) {
|
|
|
6427
6931
|
parser,
|
|
6428
6932
|
scanTo,
|
|
6429
6933
|
token,
|
|
6934
|
+
leaf,
|
|
6430
6935
|
transform,
|
|
6431
6936
|
skip,
|
|
6432
6937
|
trivia,
|
|
@@ -6434,6 +6939,7 @@ function evalRuleMapIR(ir) {
|
|
|
6434
6939
|
field,
|
|
6435
6940
|
expect,
|
|
6436
6941
|
_tf,
|
|
6942
|
+
_lf,
|
|
6437
6943
|
_nd,
|
|
6438
6944
|
_gch,
|
|
6439
6945
|
_wc
|
|
@@ -6565,6 +7071,8 @@ ${body}
|
|
|
6565
7071
|
return `oneOrMore(${kid(def.parser)})`;
|
|
6566
7072
|
case "optional":
|
|
6567
7073
|
return `optional(${kid(def.parser)})`;
|
|
7074
|
+
case "attempt":
|
|
7075
|
+
return `attempt(${kid(def.parser)})`;
|
|
6568
7076
|
case "sepBy":
|
|
6569
7077
|
return `sepBy(${kid(def.parser)}, ${kid(def.separator)})`;
|
|
6570
7078
|
case "not":
|
|
@@ -6573,6 +7081,10 @@ ${body}
|
|
|
6573
7081
|
return `trivia(${kid(def.parser)})`;
|
|
6574
7082
|
case "token":
|
|
6575
7083
|
return `token(${kid(def.parser)})`;
|
|
7084
|
+
case "leaf": {
|
|
7085
|
+
if (def.fnSrc === void 0) throw new Unserializable("leaf without fnSrc");
|
|
7086
|
+
return `_lf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7087
|
+
}
|
|
6576
7088
|
case "label":
|
|
6577
7089
|
return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
|
|
6578
7090
|
case "field":
|
|
@@ -6585,21 +7097,30 @@ ${body}
|
|
|
6585
7097
|
return `scanTo(${kid(def.sentinel)}, { skip: [${def.skip.map(kid).join(", ")}], orEOF: ${def.orEOF} })`;
|
|
6586
7098
|
case "transform": {
|
|
6587
7099
|
if (def.fnSrc === void 0) throw new Unserializable("transform without fnSrc");
|
|
6588
|
-
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)})`;
|
|
7100
|
+
return `_tf(${kid(def.parser)}, ${JSON.stringify(def.fnSrc)}${def.recognitionOnly ? ", true" : ""})`;
|
|
6589
7101
|
}
|
|
6590
7102
|
case "node": {
|
|
6591
7103
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
6592
|
-
const
|
|
7104
|
+
const optEntries = [
|
|
7105
|
+
...def.unwrap ? ["unwrap: true"] : [],
|
|
7106
|
+
...def.collapse ? ["collapse: true"] : [],
|
|
7107
|
+
...def.captureTrivia ? ["captureTrivia: true"] : [],
|
|
7108
|
+
...def.trailingTrivia ? ["trailingTrivia: true"] : []
|
|
7109
|
+
];
|
|
7110
|
+
const opts = optEntries.length > 0 ? `, { ${optEntries.join(", ")} }` : "";
|
|
6593
7111
|
if (def.type === void 0) {
|
|
6594
7112
|
if (def.buildSrc !== void 0) throw new Unserializable("inferred node build without inferred type");
|
|
6595
7113
|
return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
|
|
6596
7114
|
}
|
|
6597
|
-
if (def.buildSrc !== void 0)
|
|
7115
|
+
if (def.buildSrc !== void 0) {
|
|
7116
|
+
const staticError = def.buildStaticError === void 0 ? "" : `${opts ? "" : ", undefined"}, ${JSON.stringify(def.buildStaticError)}`;
|
|
7117
|
+
return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts}${staticError})`;
|
|
7118
|
+
}
|
|
6598
7119
|
return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
|
|
6599
7120
|
}
|
|
6600
7121
|
case "grammar": {
|
|
6601
7122
|
const trivia2 = def.clearTrivia ? "null" : def.triviaParser ? kid(def.triviaParser) : "undefined";
|
|
6602
|
-
return `parser({ trivia: ${trivia2}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
|
|
7123
|
+
return `parser({ trivia: ${trivia2}${def.captureTrivia ? ", captureTrivia: true" : ""}${def.trackLines ? ", trackLines: true" : ""} }, ${kid(def.parser)})`;
|
|
6603
7124
|
}
|
|
6604
7125
|
case "withCtx": {
|
|
6605
7126
|
if (def.extraSrc === void 0) throw new Unserializable("withCtx without extraSrc");
|
|
@@ -6628,18 +7149,20 @@ function normalizeCstCollapse(collapse) {
|
|
|
6628
7149
|
}
|
|
6629
7150
|
return typeof collapse === "function" ? collapse : void 0;
|
|
6630
7151
|
}
|
|
6631
|
-
function buildCstNode(type,
|
|
6632
|
-
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...
|
|
7152
|
+
function buildCstNode(type, children2, _fields, span, _rawChildren, _triviaLog, state) {
|
|
7153
|
+
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children2] };
|
|
6633
7154
|
}
|
|
6634
|
-
function cstBuildHost(typeOrOptions,
|
|
7155
|
+
function cstBuildHost(typeOrOptions, children2, _fields, span, rawChildren, triviaLog, state) {
|
|
6635
7156
|
if (typeof typeOrOptions === "string") {
|
|
6636
|
-
return buildCstNode(typeOrOptions,
|
|
7157
|
+
return buildCstNode(typeOrOptions, children2 ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
6637
7158
|
}
|
|
6638
7159
|
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
6639
|
-
const host = (type,
|
|
7160
|
+
const host = (type, children3, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children3, fields, span2, rawChildren2, triviaLog2, state2);
|
|
7161
|
+
host._parsemanCstOutput = true;
|
|
6640
7162
|
if (collapse) host._parsemanCstCollapse = collapse;
|
|
6641
7163
|
return host;
|
|
6642
7164
|
}
|
|
7165
|
+
cstBuildHost._parsemanCstOutput = true;
|
|
6643
7166
|
function fusedBody(pieces) {
|
|
6644
7167
|
const winner = /* @__PURE__ */ new Map();
|
|
6645
7168
|
for (const p of pieces) for (const k of p.keys) winner.set(k, p);
|
|
@@ -6693,13 +7216,39 @@ function fuseRules(pieces) {
|
|
|
6693
7216
|
return new Function("_env", body)(env);
|
|
6694
7217
|
}
|
|
6695
7218
|
var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
|
|
7219
|
+
var LEAF_COMPOSED = /* @__PURE__ */ Symbol.for("parseman.leafComposed");
|
|
6696
7220
|
var COMPOSED_TRIVIA = /* @__PURE__ */ Symbol.for("parseman.composedTrivia");
|
|
7221
|
+
var COMPOSED_COVERAGE_RULES = /* @__PURE__ */ Symbol.for("parseman.composedCoverageRules");
|
|
6697
7222
|
function isIRPiece(p) {
|
|
6698
7223
|
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
6699
7224
|
}
|
|
6700
|
-
function
|
|
7225
|
+
function coverageRulesOf(carried) {
|
|
7226
|
+
const winners = {};
|
|
7227
|
+
for (const piece of carried) {
|
|
7228
|
+
if (!isIRPiece(piece)) return void 0;
|
|
7229
|
+
const map = evalRuleMapIR(piece.ir);
|
|
7230
|
+
for (const [name, rule] of map) {
|
|
7231
|
+
if (rule._def.tag === "lazy") {
|
|
7232
|
+
try {
|
|
7233
|
+
rule._def.thunk();
|
|
7234
|
+
} catch {
|
|
7235
|
+
continue;
|
|
7236
|
+
}
|
|
7237
|
+
}
|
|
7238
|
+
winners[name] = rule;
|
|
7239
|
+
}
|
|
7240
|
+
}
|
|
7241
|
+
return winners;
|
|
7242
|
+
}
|
|
7243
|
+
function composedCoverageRules(grammar) {
|
|
7244
|
+
return grammar[COMPOSED_COVERAGE_RULES];
|
|
7245
|
+
}
|
|
7246
|
+
function materializePiece(p, trivia2, captureTerminals = false) {
|
|
6701
7247
|
if (!isIRPiece(p)) return p;
|
|
6702
|
-
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns,
|
|
7248
|
+
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
|
|
7249
|
+
...trivia2 ? { trivia: trivia2 } : {},
|
|
7250
|
+
...captureTerminals ? { captureTerminals: true } : {}
|
|
7251
|
+
});
|
|
6703
7252
|
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
6704
7253
|
return pieces;
|
|
6705
7254
|
}
|
|
@@ -6750,6 +7299,9 @@ function composingTriviaOf(items) {
|
|
|
6750
7299
|
return void 0;
|
|
6751
7300
|
}
|
|
6752
7301
|
function compose(items) {
|
|
7302
|
+
if (items.some((item) => item[LEAF_COMPOSED] === true)) {
|
|
7303
|
+
throw new Error("compose: a composeLeaf() result is terminal and cannot be composed again");
|
|
7304
|
+
}
|
|
6753
7305
|
const used = /* @__PURE__ */ new Set();
|
|
6754
7306
|
const trivia2 = composingTriviaOf(items);
|
|
6755
7307
|
const carried = items.flatMap((item) => itemCarried(item, used, trivia2));
|
|
@@ -6757,8 +7309,13 @@ function compose(items) {
|
|
|
6757
7309
|
const map = fuseRules(pieces);
|
|
6758
7310
|
Object.defineProperty(map, COMPOSED_PIECES, { value: carried, enumerable: false });
|
|
6759
7311
|
if (trivia2) Object.defineProperty(map, COMPOSED_TRIVIA, { value: trivia2, enumerable: false });
|
|
7312
|
+
const coverageRules = coverageRulesOf(carried);
|
|
7313
|
+
if (coverageRules) Object.defineProperty(map, COMPOSED_COVERAGE_RULES, { value: coverageRules, enumerable: false });
|
|
6760
7314
|
return map;
|
|
6761
7315
|
}
|
|
7316
|
+
function composeLeaf(_items) {
|
|
7317
|
+
throw new Error("composeLeaf(): requires Parseman macro lowering; runtime composition is forbidden");
|
|
7318
|
+
}
|
|
6762
7319
|
|
|
6763
7320
|
// src/combinators/guard.ts
|
|
6764
7321
|
function guard(predicate) {
|
|
@@ -6922,7 +7479,9 @@ function producesRepetition(def, depth = 0) {
|
|
|
6922
7479
|
// Transparent wrappers — look through to the inner parser.
|
|
6923
7480
|
case "node":
|
|
6924
7481
|
case "transform":
|
|
7482
|
+
case "attempt":
|
|
6925
7483
|
case "token":
|
|
7484
|
+
case "leaf":
|
|
6926
7485
|
case "label":
|
|
6927
7486
|
case "field":
|
|
6928
7487
|
case "expect":
|
|
@@ -6974,8 +7533,8 @@ function replaceAtPath(rebuild, root, path, newNode) {
|
|
|
6974
7533
|
newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(rebuild, root.children[idx], rest, newNode);
|
|
6975
7534
|
return rebuild(root, newChildren);
|
|
6976
7535
|
}
|
|
6977
|
-
function defaultRebuild(node2,
|
|
6978
|
-
return { ...node2, children };
|
|
7536
|
+
function defaultRebuild(node2, children2) {
|
|
7537
|
+
return { ...node2, children: children2 };
|
|
6979
7538
|
}
|
|
6980
7539
|
function shiftRelStart(child, delta) {
|
|
6981
7540
|
const c = child;
|
|
@@ -7315,7 +7874,8 @@ function runOnce(entry, input, options, phase, profileState) {
|
|
|
7315
7874
|
state: options.state,
|
|
7316
7875
|
...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
|
|
7317
7876
|
...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
|
|
7318
|
-
...options.tolerant ? { _tolerant: true, _rec: REC } : {}
|
|
7877
|
+
...options.tolerant ? { _tolerant: true, _rec: REC } : {},
|
|
7878
|
+
...options.instrumentation === void 0 ? {} : options.instrumentation
|
|
7319
7879
|
};
|
|
7320
7880
|
const r = invoke(entry, input, 0, ctx);
|
|
7321
7881
|
let unconsumedFrom = null;
|
|
@@ -7370,6 +7930,265 @@ function run(entry, input, options = {}) {
|
|
|
7370
7930
|
};
|
|
7371
7931
|
}
|
|
7372
7932
|
|
|
7933
|
+
// src/coverage.ts
|
|
7934
|
+
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
7935
|
+
function compiledGrammarCoverageDefinitions(grammar) {
|
|
7936
|
+
const definitions = grammar[GRAMMAR_COVERAGE_DEFINITIONS];
|
|
7937
|
+
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"))) {
|
|
7938
|
+
throw new TypeError("grammar has no coverage definitions; enable grammarCoverage for this macro build");
|
|
7939
|
+
}
|
|
7940
|
+
return definitions;
|
|
7941
|
+
}
|
|
7942
|
+
function createGrammarInstrumentationContext(options = {}) {
|
|
7943
|
+
return {
|
|
7944
|
+
trackLines: options.trackLines ?? false,
|
|
7945
|
+
...options.state === void 0 ? {} : { state: options.state },
|
|
7946
|
+
...options.collector === void 0 ? {} : { _grammarCoverage: (id) => options.collector.hit(id) },
|
|
7947
|
+
...options.trace === void 0 ? {} : { _grammarTrace: options.trace }
|
|
7948
|
+
};
|
|
7949
|
+
}
|
|
7950
|
+
function createGrammarTraceSink(options) {
|
|
7951
|
+
if (!Number.isInteger(options.capacity) || options.capacity < 0) throw new TypeError("trace capacity must be a finite non-negative integer");
|
|
7952
|
+
const events = [];
|
|
7953
|
+
let detached = false;
|
|
7954
|
+
let truncated = false;
|
|
7955
|
+
let dropped = 0;
|
|
7956
|
+
return {
|
|
7957
|
+
write(event) {
|
|
7958
|
+
if (detached || events.length >= options.capacity) {
|
|
7959
|
+
detached = true;
|
|
7960
|
+
truncated = true;
|
|
7961
|
+
dropped++;
|
|
7962
|
+
return;
|
|
7963
|
+
}
|
|
7964
|
+
events.push(Object.freeze({ ...event }));
|
|
7965
|
+
try {
|
|
7966
|
+
if (options.write?.(event) === false) {
|
|
7967
|
+
detached = true;
|
|
7968
|
+
truncated = true;
|
|
7969
|
+
}
|
|
7970
|
+
} catch {
|
|
7971
|
+
detached = true;
|
|
7972
|
+
truncated = true;
|
|
7973
|
+
}
|
|
7974
|
+
},
|
|
7975
|
+
snapshot() {
|
|
7976
|
+
return Object.freeze({ events: Object.freeze([...events]), truncated, dropped });
|
|
7977
|
+
}
|
|
7978
|
+
};
|
|
7979
|
+
}
|
|
7980
|
+
function createGrammarCoverageCollector(definitions) {
|
|
7981
|
+
const ordered = [...definitions].sort((a, b) => a.id.localeCompare(b.id));
|
|
7982
|
+
const known = new Set(ordered.map((definition) => definition.id));
|
|
7983
|
+
const hits = /* @__PURE__ */ new Set();
|
|
7984
|
+
return {
|
|
7985
|
+
hit(id) {
|
|
7986
|
+
if (known.has(id)) hits.add(id);
|
|
7987
|
+
},
|
|
7988
|
+
snapshot() {
|
|
7989
|
+
const hitList = [...hits].sort();
|
|
7990
|
+
const unhit = ordered.map((definition) => definition.id).filter((id) => !hits.has(id));
|
|
7991
|
+
return { definitions: ordered, hits: hitList, unhit, ratio: ordered.length === 0 ? 1 : hitList.length / ordered.length };
|
|
7992
|
+
},
|
|
7993
|
+
reset() {
|
|
7994
|
+
hits.clear();
|
|
7995
|
+
}
|
|
7996
|
+
};
|
|
7997
|
+
}
|
|
7998
|
+
function grammarCoverageDefinitions(entry, winners) {
|
|
7999
|
+
return buildGrammarPlan(entry, winners).definitions;
|
|
8000
|
+
}
|
|
8001
|
+
function composedGrammarCoverageDefinitions(grammar, startRule) {
|
|
8002
|
+
const winners = composedCoverageRules(grammar);
|
|
8003
|
+
if (!winners) throw new TypeError("semantic coverage needs re-lowerable composed IR; this composition contains an opaque artifact");
|
|
8004
|
+
const entry = winners[startRule];
|
|
8005
|
+
if (!entry) throw new TypeError(`semantic coverage start rule ${JSON.stringify(startRule)} is not a final winner`);
|
|
8006
|
+
return grammarCoverageDefinitions(entry, winners);
|
|
8007
|
+
}
|
|
8008
|
+
function coverageEntry(entry, collector, maps, trace) {
|
|
8009
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
8010
|
+
const build = (parser2) => {
|
|
8011
|
+
const existing = cache.get(parser2);
|
|
8012
|
+
if (existing) return existing;
|
|
8013
|
+
const rule = maps.rules.get(parser2);
|
|
8014
|
+
const wrap = (parse2) => {
|
|
8015
|
+
const wrapped = {
|
|
8016
|
+
_tag: parser2._tag,
|
|
8017
|
+
_meta: parser2._meta,
|
|
8018
|
+
_def: parser2._def,
|
|
8019
|
+
parse(input, pos, ctx) {
|
|
8020
|
+
if (rule) {
|
|
8021
|
+
collector.hit(rule);
|
|
8022
|
+
trace?.write({ id: rule, phase: "enter", offset: pos });
|
|
8023
|
+
}
|
|
8024
|
+
const result = parse2(input, pos, ctx);
|
|
8025
|
+
if (rule) trace?.write(result.ok ? { id: rule, phase: "success", offset: pos, end: result.span.end } : { id: rule, phase: "failure", offset: result.span.end });
|
|
8026
|
+
return result;
|
|
8027
|
+
}
|
|
8028
|
+
};
|
|
8029
|
+
cache.set(parser2, wrapped);
|
|
8030
|
+
return wrapped;
|
|
8031
|
+
};
|
|
8032
|
+
const def = parser2._def;
|
|
8033
|
+
if (def.tag === "lazy") {
|
|
8034
|
+
return wrap((input, pos, ctx) => build(def.thunk()).parse(input, pos, ctx));
|
|
8035
|
+
}
|
|
8036
|
+
if (def.tag === "label") {
|
|
8037
|
+
const base2 = label(def.label, build(def.parser));
|
|
8038
|
+
return wrap((input, pos, ctx) => {
|
|
8039
|
+
const result = base2.parse(input, pos, ctx);
|
|
8040
|
+
if (result.ok) for (const id of maps.labels.get(parser2) ?? []) {
|
|
8041
|
+
collector.hit(id);
|
|
8042
|
+
trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
|
|
8043
|
+
}
|
|
8044
|
+
return result;
|
|
8045
|
+
});
|
|
8046
|
+
}
|
|
8047
|
+
if (def.tag === "choice") {
|
|
8048
|
+
const ids = maps.choices.get(parser2) ?? [];
|
|
8049
|
+
const invocations = [];
|
|
8050
|
+
const arms = def.parsers.map((arm, index) => {
|
|
8051
|
+
const child = build(arm);
|
|
8052
|
+
return {
|
|
8053
|
+
_tag: child._tag,
|
|
8054
|
+
_meta: child._meta,
|
|
8055
|
+
_def: child._def,
|
|
8056
|
+
parse(input, pos, ctx) {
|
|
8057
|
+
const id = ids[index];
|
|
8058
|
+
if (id) trace?.write({ id, phase: "attempt", offset: pos });
|
|
8059
|
+
const result = child.parse(input, pos, ctx);
|
|
8060
|
+
if (result.ok) {
|
|
8061
|
+
if (def.strategy.tag !== "greedyClassify") collector.hit(ids[index]);
|
|
8062
|
+
const invocation = invocations[invocations.length - 1];
|
|
8063
|
+
if (invocation) {
|
|
8064
|
+
invocation.lastSuccessfulArm = index;
|
|
8065
|
+
invocation.successfulArms.push(index);
|
|
8066
|
+
}
|
|
8067
|
+
} else if (id) {
|
|
8068
|
+
trace?.write({ id, phase: "failure", offset: result.span.end });
|
|
8069
|
+
trace?.write({ id, phase: "backtrack", offset: pos });
|
|
8070
|
+
}
|
|
8071
|
+
return result;
|
|
8072
|
+
}
|
|
8073
|
+
};
|
|
8074
|
+
});
|
|
8075
|
+
const args = arms.map((arm, index) => def.gates[index] ? { combinator: arm, gate: def.gates[index] } : arm);
|
|
8076
|
+
const unsafeChoice = choice;
|
|
8077
|
+
const baseChoice = unsafeChoice(...args);
|
|
8078
|
+
return wrap((input, pos, ctx) => {
|
|
8079
|
+
const invocation = { lastSuccessfulArm: void 0, successfulArms: [] };
|
|
8080
|
+
invocations.push(invocation);
|
|
8081
|
+
const result = baseChoice.parse(input, pos, ctx);
|
|
8082
|
+
const strategy = def.strategy;
|
|
8083
|
+
if (result.ok && strategy.tag === "greedyClassify") {
|
|
8084
|
+
const text = input.slice(pos, result.span.end);
|
|
8085
|
+
const classified = def.parsers.findIndex((arm, index) => index !== strategy.superIndex && getCoreLiteralValue(arm) === text);
|
|
8086
|
+
if (classified !== -1) invocation.lastSuccessfulArm = classified;
|
|
8087
|
+
else invocation.lastSuccessfulArm = strategy.superIndex;
|
|
8088
|
+
}
|
|
8089
|
+
if (result.ok && invocation.lastSuccessfulArm !== void 0) {
|
|
8090
|
+
const id = ids[invocation.lastSuccessfulArm];
|
|
8091
|
+
for (const rejected of invocation.successfulArms) {
|
|
8092
|
+
if (rejected !== invocation.lastSuccessfulArm) {
|
|
8093
|
+
const rejectedId = ids[rejected];
|
|
8094
|
+
if (rejectedId) {
|
|
8095
|
+
trace?.write({ id: rejectedId, phase: "failure", offset: pos });
|
|
8096
|
+
trace?.write({ id: rejectedId, phase: "backtrack", offset: pos });
|
|
8097
|
+
}
|
|
8098
|
+
}
|
|
8099
|
+
}
|
|
8100
|
+
if (id) {
|
|
8101
|
+
collector.hit(id);
|
|
8102
|
+
trace?.write({ id, phase: "selected", offset: pos, end: result.span.end });
|
|
8103
|
+
trace?.write({ id, phase: "success", offset: pos, end: result.span.end });
|
|
8104
|
+
}
|
|
8105
|
+
}
|
|
8106
|
+
invocations.pop();
|
|
8107
|
+
return result;
|
|
8108
|
+
});
|
|
8109
|
+
}
|
|
8110
|
+
const base = (() => {
|
|
8111
|
+
switch (def.tag) {
|
|
8112
|
+
case "sequence": {
|
|
8113
|
+
const unsafeSequence = sequence;
|
|
8114
|
+
return unsafeSequence(...def.parsers.map(build));
|
|
8115
|
+
}
|
|
8116
|
+
case "many":
|
|
8117
|
+
return many(build(def.parser));
|
|
8118
|
+
case "oneOrMore":
|
|
8119
|
+
return oneOrMore(build(def.parser));
|
|
8120
|
+
case "optional":
|
|
8121
|
+
return optional(build(def.parser));
|
|
8122
|
+
case "attempt": {
|
|
8123
|
+
const base2 = attempt(build(def.parser));
|
|
8124
|
+
const id = maps.attempts.get(parser2);
|
|
8125
|
+
return id === void 0 ? base2 : {
|
|
8126
|
+
...base2,
|
|
8127
|
+
parse(input, pos, ctx) {
|
|
8128
|
+
const result = base2.parse(input, pos, ctx);
|
|
8129
|
+
if (!result.ok) trace?.write({ id, phase: "rollback", offset: pos });
|
|
8130
|
+
return result;
|
|
8131
|
+
}
|
|
8132
|
+
};
|
|
8133
|
+
}
|
|
8134
|
+
case "sepBy":
|
|
8135
|
+
return sepBy(build(def.parser), build(def.separator));
|
|
8136
|
+
case "transform":
|
|
8137
|
+
return transform(build(def.parser), def.fn);
|
|
8138
|
+
case "skip":
|
|
8139
|
+
return skip(build(def.main), build(def.skipped));
|
|
8140
|
+
case "trivia":
|
|
8141
|
+
return trivia(build(def.parser));
|
|
8142
|
+
case "token":
|
|
8143
|
+
return token(build(def.parser));
|
|
8144
|
+
case "leaf":
|
|
8145
|
+
return leaf(build(def.parser), def.fn);
|
|
8146
|
+
case "field":
|
|
8147
|
+
return field(def.name, build(def.parser));
|
|
8148
|
+
case "grammar":
|
|
8149
|
+
return parser({
|
|
8150
|
+
...def.triviaParser === void 0 ? def.clearTrivia ? { trivia: null } : {} : { trivia: build(def.triviaParser) },
|
|
8151
|
+
...def.captureTrivia ? { captureTrivia: true } : {},
|
|
8152
|
+
...def.trackLines ? { trackLines: true } : {}
|
|
8153
|
+
}, build(def.parser));
|
|
8154
|
+
case "not":
|
|
8155
|
+
return not(build(def.parser));
|
|
8156
|
+
case "node": {
|
|
8157
|
+
const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
|
|
8158
|
+
return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
|
|
8159
|
+
}
|
|
8160
|
+
case "guard":
|
|
8161
|
+
return guard(def.predicate);
|
|
8162
|
+
case "withCtx":
|
|
8163
|
+
return withCtx(def.extra, build(def.parser));
|
|
8164
|
+
case "expect":
|
|
8165
|
+
return expect(build(def.parser), def.label);
|
|
8166
|
+
case "scanTo":
|
|
8167
|
+
return scanTo(build(def.sentinel), { skip: def.skip.map(build), orEOF: def.orEOF });
|
|
8168
|
+
case "literal":
|
|
8169
|
+
case "regex":
|
|
8170
|
+
case "keywords":
|
|
8171
|
+
return parser2;
|
|
8172
|
+
case "recover":
|
|
8173
|
+
case "unknown":
|
|
8174
|
+
throw new TypeError(`runWithGrammarCoverage does not yet support ${def.tag}`);
|
|
8175
|
+
default:
|
|
8176
|
+
return parser2;
|
|
8177
|
+
}
|
|
8178
|
+
})();
|
|
8179
|
+
return wrap((input, pos, ctx) => base.parse(input, pos, ctx));
|
|
8180
|
+
};
|
|
8181
|
+
return build(entry);
|
|
8182
|
+
}
|
|
8183
|
+
function runWithGrammarCoverage(entry, input, options = {}) {
|
|
8184
|
+
if (typeof entry === "function") throw new TypeError("runWithGrammarCoverage currently requires an interpreter combinator entry");
|
|
8185
|
+
const plan = buildGrammarPlan(entry);
|
|
8186
|
+
const definitions = plan.definitions;
|
|
8187
|
+
const collector = options.collector ?? createGrammarCoverageCollector(definitions);
|
|
8188
|
+
const { collector: _collector, trace, ...runOptions } = options;
|
|
8189
|
+
return { result: run(coverageEntry(entry, collector, plan, trace), input, runOptions), coverage: collector.snapshot() };
|
|
8190
|
+
}
|
|
8191
|
+
|
|
7373
8192
|
// src/cst/trivia-index.ts
|
|
7374
8193
|
function merge(map, key, run2) {
|
|
7375
8194
|
if (run2.length === 0) return;
|
|
@@ -7440,9 +8259,9 @@ function buildTriviaIndex(root, input = "", opts) {
|
|
|
7440
8259
|
function walk(root, visitor, ctx = void 0) {
|
|
7441
8260
|
const go = (node2, parent) => {
|
|
7442
8261
|
const descend = visitor.enter ? visitor.enter(node2, parent, ctx) : void 0;
|
|
7443
|
-
const
|
|
7444
|
-
if (descend !== false && Array.isArray(
|
|
7445
|
-
for (const child of
|
|
8262
|
+
const children2 = node2.children;
|
|
8263
|
+
if (descend !== false && Array.isArray(children2)) {
|
|
8264
|
+
for (const child of children2) go(child, node2);
|
|
7446
8265
|
}
|
|
7447
8266
|
visitor.leave?.(node2, parent, ctx);
|
|
7448
8267
|
};
|
|
@@ -7458,9 +8277,9 @@ function createVisitor(handlers) {
|
|
|
7458
8277
|
},
|
|
7459
8278
|
visitChildren(node2) {
|
|
7460
8279
|
const out = [];
|
|
7461
|
-
const
|
|
7462
|
-
if (Array.isArray(
|
|
7463
|
-
for (const child of
|
|
8280
|
+
const children2 = node2.children;
|
|
8281
|
+
if (Array.isArray(children2)) {
|
|
8282
|
+
for (const child of children2) {
|
|
7464
8283
|
const r = api.visit(child);
|
|
7465
8284
|
if (r !== void 0) out.push(r);
|
|
7466
8285
|
}
|
|
@@ -7489,6 +8308,9 @@ function triviaEntries(log, labels, opts) {
|
|
|
7489
8308
|
end(i) {
|
|
7490
8309
|
return log[entryOffset(i, stride) + 1];
|
|
7491
8310
|
},
|
|
8311
|
+
insertIndex(i) {
|
|
8312
|
+
return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
|
|
8313
|
+
},
|
|
7492
8314
|
kindIndex(i) {
|
|
7493
8315
|
if (!labels) return void 0;
|
|
7494
8316
|
return log[entryOffset(i, stride) + baseStride];
|
|
@@ -7698,6 +8520,7 @@ function buildOffsetIndex(root, input = "") {
|
|
|
7698
8520
|
// src/index.ts
|
|
7699
8521
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
7700
8522
|
export {
|
|
8523
|
+
GRAMMAR_COVERAGE_DEFINITIONS,
|
|
7701
8524
|
OffsetIndex,
|
|
7702
8525
|
absoluteSpanAt,
|
|
7703
8526
|
absoluteSpanCST,
|
|
@@ -7705,6 +8528,7 @@ export {
|
|
|
7705
8528
|
absolutizeCST,
|
|
7706
8529
|
annotateSpan,
|
|
7707
8530
|
applyEdit,
|
|
8531
|
+
attempt,
|
|
7708
8532
|
balanced,
|
|
7709
8533
|
blankLinesIn,
|
|
7710
8534
|
buildLineIndex,
|
|
@@ -7714,20 +8538,28 @@ export {
|
|
|
7714
8538
|
collectLeafSlots,
|
|
7715
8539
|
commentsIn,
|
|
7716
8540
|
compile,
|
|
8541
|
+
compiledGrammarCoverageDefinitions,
|
|
7717
8542
|
completionsAt,
|
|
7718
8543
|
compose,
|
|
8544
|
+
composeLeaf,
|
|
8545
|
+
composedGrammarCoverageDefinitions,
|
|
8546
|
+
createGrammarCoverageCollector,
|
|
8547
|
+
createGrammarInstrumentationContext,
|
|
8548
|
+
createGrammarTraceSink,
|
|
7719
8549
|
createVisitor,
|
|
7720
8550
|
cstBuildHost,
|
|
7721
8551
|
expect,
|
|
7722
8552
|
field,
|
|
7723
8553
|
gapIsSignificant,
|
|
7724
8554
|
gapText,
|
|
8555
|
+
grammarCoverageDefinitions,
|
|
7725
8556
|
guard,
|
|
7726
8557
|
indentMixed,
|
|
7727
8558
|
indentWidth,
|
|
7728
8559
|
isParseError,
|
|
7729
8560
|
keywords,
|
|
7730
8561
|
label,
|
|
8562
|
+
leaf,
|
|
7731
8563
|
lineBreaksIn,
|
|
7732
8564
|
lineStartWithin,
|
|
7733
8565
|
literal,
|
|
@@ -7748,6 +8580,7 @@ export {
|
|
|
7748
8580
|
relativizeCST,
|
|
7749
8581
|
rules,
|
|
7750
8582
|
run,
|
|
8583
|
+
runWithGrammarCoverage,
|
|
7751
8584
|
scanTo,
|
|
7752
8585
|
sepBy,
|
|
7753
8586
|
sequence,
|