parseman 0.60.6 → 0.61.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/backtrack.d.ts +50 -0
- package/dist/analysis/backtrack.d.ts.map +1 -0
- package/dist/analysis/diagnostics.d.ts +3 -0
- package/dist/analysis/diagnostics.d.ts.map +1 -1
- package/dist/analysis/diagnostics.js +1162 -158
- package/dist/analysis/diagnostics.js.map +3 -3
- package/dist/analysis/rebuild.d.ts +17 -1
- package/dist/analysis/rebuild.d.ts.map +1 -1
- package/dist/cli/index.js +353 -69
- package/dist/cli/index.js.map +3 -3
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +2 -0
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/link-scope.d.ts +7 -0
- package/dist/combinators/link-scope.d.ts.map +1 -0
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/compiler/token-capability.js +1 -0
- package/dist/compiler/token-capability.js.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.js +121 -90
- package/dist/index.js.map +3 -3
- package/dist/language-service/index.js +1 -1
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/index.js +274 -243
- package/dist/plugin/index.js.map +3 -3
- package/dist/run/index.js +1 -1
- package/dist/run/index.js.map +1 -1
- package/dist/spec/index.js.map +1 -1
- package/dist/table/backtrack-probe.d.ts +41 -0
- package/dist/table/backtrack-probe.d.ts.map +1 -0
- package/dist/table/child-slots.d.ts +10 -0
- package/dist/table/child-slots.d.ts.map +1 -1
- package/dist/table/emit.d.ts.map +1 -1
- package/dist/table/index.js +31 -20
- package/dist/table/index.js.map +3 -3
- package/dist/table/program.d.ts +3 -1
- package/dist/table/program.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +5 -1
- package/src/analysis/backtrack.ts +249 -0
- package/src/analysis/diagnostics.ts +4 -0
- package/src/analysis/rebuild.ts +63 -11
- package/src/combinators/choice.ts +3 -1
- package/src/combinators/dispatch.ts +9 -0
- package/src/combinators/expect.ts +1 -0
- package/src/combinators/link-scope.ts +19 -0
- package/src/combinators/node.ts +11 -2
- package/src/combinators/parser.ts +37 -31
- package/src/compiler/value-usage.ts +16 -29
- package/src/coverage.ts +2 -14
- package/src/functional/run.ts +3 -1
- package/src/table/backtrack-probe.ts +326 -0
- package/src/table/child-slots.ts +30 -14
- package/src/table/emit.ts +5 -1
- package/src/table/program.ts +8 -2
- package/src/version.ts +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2552,6 +2552,206 @@ function asciiFoldKey(key) {
|
|
|
2552
2552
|
}
|
|
2553
2553
|
return out;
|
|
2554
2554
|
}
|
|
2555
|
+
function matchesDispatchMatcher(value, matcher) {
|
|
2556
|
+
const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
|
|
2557
|
+
const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
|
|
2558
|
+
switch (matcher.kind) {
|
|
2559
|
+
case "startsWith":
|
|
2560
|
+
return candidate.startsWith(expected);
|
|
2561
|
+
case "endsWith":
|
|
2562
|
+
return candidate.endsWith(expected);
|
|
2563
|
+
case "matches": {
|
|
2564
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
2565
|
+
return new RegExp(matcher.value, flags).test(value);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
function isStringMatcher(value) {
|
|
2570
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2571
|
+
const kind = value.kind;
|
|
2572
|
+
return kind === "startsWith" || kind === "endsWith" || kind === "matches";
|
|
2573
|
+
}
|
|
2574
|
+
function fixedMatcher(kind, value) {
|
|
2575
|
+
if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
|
|
2576
|
+
if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
|
|
2577
|
+
return { kind, value };
|
|
2578
|
+
}
|
|
2579
|
+
function startsWith(prefix) {
|
|
2580
|
+
return fixedMatcher("startsWith", prefix);
|
|
2581
|
+
}
|
|
2582
|
+
function endsWith(suffix) {
|
|
2583
|
+
return fixedMatcher("endsWith", suffix);
|
|
2584
|
+
}
|
|
2585
|
+
function matches(pattern) {
|
|
2586
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
|
|
2587
|
+
if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
|
|
2588
|
+
throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
|
|
2589
|
+
}
|
|
2590
|
+
return { kind: "matches", value: pattern.source, flags: pattern.flags };
|
|
2591
|
+
}
|
|
2592
|
+
function dispatchMatcher(entry) {
|
|
2593
|
+
switch (entry.kind) {
|
|
2594
|
+
case "startsWith":
|
|
2595
|
+
return startsWith(entry.value);
|
|
2596
|
+
case "endsWith":
|
|
2597
|
+
return endsWith(entry.value);
|
|
2598
|
+
case "matches":
|
|
2599
|
+
return matches(new RegExp(entry.value, entry.flags));
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
function when(key, parser2, opts = {}) {
|
|
2603
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
2604
|
+
if (isStringMatcher(key)) {
|
|
2605
|
+
return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2606
|
+
}
|
|
2607
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
2608
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
2609
|
+
for (const item of keys) {
|
|
2610
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
2611
|
+
}
|
|
2612
|
+
return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
2613
|
+
}
|
|
2614
|
+
function otherwise(parser2, opts = {}) {
|
|
2615
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
2616
|
+
return opts.commit === false ? { kind: "otherwise", parser: parser2, usesRouted, commit: false } : { kind: "otherwise", parser: parser2, usesRouted };
|
|
2617
|
+
}
|
|
2618
|
+
function routed(fallback) {
|
|
2619
|
+
return {
|
|
2620
|
+
_tag: "routed",
|
|
2621
|
+
_meta: {
|
|
2622
|
+
// The routed token is whatever the selector matched, so the first set stays
|
|
2623
|
+
// `any` even with a fallback — `any` already subsumes the fallback's.
|
|
2624
|
+
firstSet: { kind: "any" },
|
|
2625
|
+
canMatchNewline: fallback?._meta.canMatchNewline ?? false,
|
|
2626
|
+
isTrivia: false
|
|
2627
|
+
},
|
|
2628
|
+
_def: fallback === void 0 ? { tag: "routed" } : { tag: "routed", fallback },
|
|
2629
|
+
parse(_input, pos, ctx) {
|
|
2630
|
+
const item = ctx._routed;
|
|
2631
|
+
if (item === void 0 || pos !== item.span.start) {
|
|
2632
|
+
if (fallback !== void 0) return fallback.parse(_input, pos, ctx);
|
|
2633
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2634
|
+
}
|
|
2635
|
+
if (cstCaptureActive(ctx)) {
|
|
2636
|
+
pushCstLeaf(ctx, new PlainLeaf2(item.value, item.span));
|
|
2637
|
+
}
|
|
2638
|
+
return { ok: true, value: item.value, span: item.span };
|
|
2639
|
+
}
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
function dispatch(selector, ...arms) {
|
|
2643
|
+
if (parserUsesRouted(selector)) {
|
|
2644
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2645
|
+
}
|
|
2646
|
+
let fallback;
|
|
2647
|
+
let fallbackUsesRouted = false;
|
|
2648
|
+
let fallbackCommits = true;
|
|
2649
|
+
const matchers = [];
|
|
2650
|
+
const cases = [];
|
|
2651
|
+
const seen = [];
|
|
2652
|
+
for (let i = 0; i < arms.length; i++) {
|
|
2653
|
+
const arm = arms[i];
|
|
2654
|
+
if (arm.kind === "otherwise") {
|
|
2655
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
2656
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
2657
|
+
fallback = arm.parser;
|
|
2658
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
2659
|
+
fallbackCommits = arm.commit !== false;
|
|
2660
|
+
continue;
|
|
2661
|
+
}
|
|
2662
|
+
if (arm.kind === "whenMatcher") {
|
|
2663
|
+
const matcher = arm.matcher;
|
|
2664
|
+
matchers.push({
|
|
2665
|
+
kind: matcher.kind,
|
|
2666
|
+
value: matcher.value,
|
|
2667
|
+
...matcher.kind === "matches" ? { flags: matcher.flags } : {},
|
|
2668
|
+
parser: arm.parser,
|
|
2669
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2670
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2671
|
+
});
|
|
2672
|
+
continue;
|
|
2673
|
+
}
|
|
2674
|
+
for (const key of arm.keys) {
|
|
2675
|
+
const folded = asciiFoldKey(key);
|
|
2676
|
+
for (const prior of seen) {
|
|
2677
|
+
const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
|
|
2678
|
+
if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
2679
|
+
}
|
|
2680
|
+
seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
|
|
2681
|
+
}
|
|
2682
|
+
cases.push({
|
|
2683
|
+
keys: arm.keys,
|
|
2684
|
+
parser: arm.parser,
|
|
2685
|
+
caseInsensitive: arm.caseInsensitive,
|
|
2686
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
const meta = {
|
|
2690
|
+
firstSet: selector._meta.firstSet,
|
|
2691
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
2692
|
+
isTrivia: false
|
|
2693
|
+
};
|
|
2694
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2695
|
+
const byFoldedKey = /* @__PURE__ */ new Map();
|
|
2696
|
+
for (const entry of cases) {
|
|
2697
|
+
for (const key of entry.keys) {
|
|
2698
|
+
if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
|
|
2699
|
+
else byKey.set(key, entry);
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
return {
|
|
2703
|
+
_tag: "dispatch",
|
|
2704
|
+
_meta: meta,
|
|
2705
|
+
_def: {
|
|
2706
|
+
tag: "dispatch",
|
|
2707
|
+
selector,
|
|
2708
|
+
cases,
|
|
2709
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
2710
|
+
...fallback === void 0 ? {} : {
|
|
2711
|
+
otherwise: fallback,
|
|
2712
|
+
...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {},
|
|
2713
|
+
...fallbackCommits ? {} : { otherwiseCommit: false }
|
|
2714
|
+
}
|
|
2715
|
+
},
|
|
2716
|
+
parse(input, pos, ctx) {
|
|
2717
|
+
if (parserUsesRouted(selector)) {
|
|
2718
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
2719
|
+
}
|
|
2720
|
+
const selectorMark = saveTriviaMark(ctx);
|
|
2721
|
+
const selected = selector.parse(input, pos, ctx);
|
|
2722
|
+
if (!selected.ok) return selected;
|
|
2723
|
+
const chosen = byKey.get(selected.value) ?? (byFoldedKey.size === 0 ? void 0 : byFoldedKey.get(asciiFoldKey(selected.value))) ?? matchers.find((matcher) => matchesDispatchMatcher(selected.value, matcher));
|
|
2724
|
+
const branch = chosen ?? (fallback === void 0 ? void 0 : { keys: [], parser: fallback, caseInsensitive: false, usesRouted: fallbackUsesRouted });
|
|
2725
|
+
if (branch === void 0) {
|
|
2726
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
2727
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
2728
|
+
}
|
|
2729
|
+
const savedRouted = ctx._routed;
|
|
2730
|
+
const usesRouted = branchUsesRouted(branch);
|
|
2731
|
+
let mark = saveTriviaMark(ctx);
|
|
2732
|
+
if (usesRouted) {
|
|
2733
|
+
rollbackTrivia(ctx, selectorMark);
|
|
2734
|
+
mark = saveTriviaMark(ctx);
|
|
2735
|
+
ctx._routed = { value: selected.value, span: selected.span };
|
|
2736
|
+
}
|
|
2737
|
+
let result;
|
|
2738
|
+
try {
|
|
2739
|
+
result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
|
|
2740
|
+
} finally {
|
|
2741
|
+
if (usesRouted) ctx._routed = savedRouted;
|
|
2742
|
+
}
|
|
2743
|
+
if (!result.ok) {
|
|
2744
|
+
rollbackTrivia(ctx, mark);
|
|
2745
|
+
return chosen === void 0 && !fallbackCommits ? result : { ...result, committed: true };
|
|
2746
|
+
}
|
|
2747
|
+
return {
|
|
2748
|
+
ok: true,
|
|
2749
|
+
value: [selected.value, result.value],
|
|
2750
|
+
span: { start: pos, end: result.span.end }
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2555
2755
|
|
|
2556
2756
|
// src/recovery/scan.ts
|
|
2557
2757
|
import { PlainSpan as PlainSpan2 } from "../cst/plain.js";
|
|
@@ -2718,6 +2918,7 @@ function derive(c, seen) {
|
|
|
2718
2918
|
case "optional":
|
|
2719
2919
|
case "many":
|
|
2720
2920
|
case "oneOrMore":
|
|
2921
|
+
case "sepBy":
|
|
2721
2922
|
case "transform":
|
|
2722
2923
|
case "not":
|
|
2723
2924
|
case "peek":
|
|
@@ -2899,7 +3100,7 @@ function selectOptionalSuffixLexBody(ir) {
|
|
|
2899
3100
|
function reinstallsRuleTrivia(reference, target) {
|
|
2900
3101
|
return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
|
|
2901
3102
|
}
|
|
2902
|
-
function directTokenBodyParser(parser2, resolve2,
|
|
3103
|
+
function directTokenBodyParser(parser2, resolve2, scope2) {
|
|
2903
3104
|
const outer = parser2._def;
|
|
2904
3105
|
if (outer.tag !== "token") return void 0;
|
|
2905
3106
|
let body = outer.parser;
|
|
@@ -2909,7 +3110,7 @@ function directTokenBodyParser(parser2, resolve2, scope) {
|
|
|
2909
3110
|
const wrapper = body._def;
|
|
2910
3111
|
if (wrapper.tag === "grammar") {
|
|
2911
3112
|
if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
|
|
2912
|
-
if (
|
|
3113
|
+
if (scope2 !== void 0) scope2.cleared = true;
|
|
2913
3114
|
body = wrapper.parser;
|
|
2914
3115
|
continue;
|
|
2915
3116
|
}
|
|
@@ -3166,10 +3367,10 @@ function directFixedLexNode(parser2, resolve2, active, pureOnly = false, cleared
|
|
|
3166
3367
|
}
|
|
3167
3368
|
}
|
|
3168
3369
|
function directFixedTokenBody(parser2, resolve2) {
|
|
3169
|
-
const
|
|
3170
|
-
const body = directTokenBodyParser(parser2, resolve2,
|
|
3370
|
+
const scope2 = { cleared: false };
|
|
3371
|
+
const body = directTokenBodyParser(parser2, resolve2, scope2);
|
|
3171
3372
|
if (body === void 0) return void 0;
|
|
3172
|
-
const root = directFixedLexNode(body, resolve2, /* @__PURE__ */ new Set(), false,
|
|
3373
|
+
const root = directFixedLexNode(body, resolve2, /* @__PURE__ */ new Set(), false, scope2.cleared);
|
|
3173
3374
|
return root === void 0 ? void 0 : { kind: "fixed-tree", root };
|
|
3174
3375
|
}
|
|
3175
3376
|
function directBalancedTokenBody(parser2, resolve2) {
|
|
@@ -4257,15 +4458,20 @@ function markUnusedValues(root) {
|
|
|
4257
4458
|
case "many":
|
|
4258
4459
|
case "oneOrMore":
|
|
4259
4460
|
mark(def, consumed);
|
|
4260
|
-
visit(def.parser, consumed);
|
|
4261
|
-
return;
|
|
4262
4461
|
case "optional":
|
|
4462
|
+
// `optional` returns `inner | null` — no aggregate array/tuple to elide, so
|
|
4463
|
+
// it carries no valueUnused flag. Still descend so an inner many/sequence
|
|
4464
|
+
// under a node() is analyzed (it benefits even when its optional wrapper
|
|
4465
|
+
// doesn't).
|
|
4466
|
+
case "label":
|
|
4467
|
+
case "trivia":
|
|
4468
|
+
case "attempt":
|
|
4469
|
+
case "withCtx":
|
|
4470
|
+
case "expect":
|
|
4263
4471
|
visit(def.parser, consumed);
|
|
4264
4472
|
return;
|
|
4265
4473
|
case "sequence":
|
|
4266
4474
|
mark(def, consumed);
|
|
4267
|
-
for (const p of def.parsers) visit(p, consumed);
|
|
4268
|
-
return;
|
|
4269
4475
|
case "choice":
|
|
4270
4476
|
for (const p of def.parsers) visit(p, consumed);
|
|
4271
4477
|
return;
|
|
@@ -4276,22 +4482,24 @@ function markUnusedValues(root) {
|
|
|
4276
4482
|
if (def.otherwise) visit(def.otherwise, consumed);
|
|
4277
4483
|
return;
|
|
4278
4484
|
case "node":
|
|
4485
|
+
// builds from captured children, NOT the inner parser value.
|
|
4486
|
+
case "not":
|
|
4487
|
+
case "peek":
|
|
4488
|
+
// lookahead — value never observed
|
|
4489
|
+
case "token":
|
|
4279
4490
|
visit(def.parser, false);
|
|
4280
4491
|
return;
|
|
4281
4492
|
case "transform":
|
|
4282
|
-
|
|
4283
|
-
return;
|
|
4493
|
+
// the map fn reads the value → always consumed.
|
|
4284
4494
|
case "field":
|
|
4495
|
+
// the field capture records the parsed value → always consumed.
|
|
4496
|
+
case "leaf":
|
|
4285
4497
|
visit(def.parser, true);
|
|
4286
4498
|
return;
|
|
4287
4499
|
case "sepBy":
|
|
4288
4500
|
visit(def.parser, true);
|
|
4289
4501
|
visit(def.separator, false);
|
|
4290
4502
|
return;
|
|
4291
|
-
case "not":
|
|
4292
|
-
case "peek":
|
|
4293
|
-
visit(def.parser, false);
|
|
4294
|
-
return;
|
|
4295
4503
|
case "grammar":
|
|
4296
4504
|
visit(def.parser, consumed);
|
|
4297
4505
|
if (def.triviaParser) visit(def.triviaParser, false);
|
|
@@ -4300,19 +4508,6 @@ function markUnusedValues(root) {
|
|
|
4300
4508
|
visit(def.parser, consumed);
|
|
4301
4509
|
visit(def.sentinel, false);
|
|
4302
4510
|
return;
|
|
4303
|
-
case "token":
|
|
4304
|
-
visit(def.parser, false);
|
|
4305
|
-
return;
|
|
4306
|
-
case "label":
|
|
4307
|
-
case "trivia":
|
|
4308
|
-
case "attempt":
|
|
4309
|
-
case "withCtx":
|
|
4310
|
-
case "expect":
|
|
4311
|
-
visit(def.parser, consumed);
|
|
4312
|
-
return;
|
|
4313
|
-
case "leaf":
|
|
4314
|
-
visit(def.parser, true);
|
|
4315
|
-
return;
|
|
4316
4511
|
case "lazy":
|
|
4317
4512
|
return;
|
|
4318
4513
|
default:
|
|
@@ -4342,6 +4537,12 @@ function markUnusedValues(root) {
|
|
|
4342
4537
|
visit(resolveRoot(root), true);
|
|
4343
4538
|
}
|
|
4344
4539
|
|
|
4540
|
+
// src/combinators/link-scope.ts
|
|
4541
|
+
var scope;
|
|
4542
|
+
function afterLink(settle) {
|
|
4543
|
+
scope?.push(settle);
|
|
4544
|
+
}
|
|
4545
|
+
|
|
4345
4546
|
// src/cst/root-trivia-scope.ts
|
|
4346
4547
|
var ROOT_TRIVIA_SCOPE_REFUSAL = "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'.";
|
|
4347
4548
|
function refuseUnclassifiedRootScope(strict) {
|
|
@@ -4598,7 +4799,7 @@ function choice(...args) {
|
|
|
4598
4799
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
4599
4800
|
if (result.ok) return result;
|
|
4600
4801
|
expected.push(...result.expected);
|
|
4601
|
-
if (result.committed) return { ok: false, expected, span:
|
|
4802
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
4602
4803
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
4603
4804
|
}
|
|
4604
4805
|
if (ctx._probe !== void 0 || ctx._tolerant) for (const p of parsers) p.parse(input, pos, ctx);
|
|
@@ -5498,6 +5699,9 @@ function regex(pattern, flags = "") {
|
|
|
5498
5699
|
};
|
|
5499
5700
|
}
|
|
5500
5701
|
|
|
5702
|
+
// src/version.ts
|
|
5703
|
+
var PARSEMAN_VERSION = "0.61.1";
|
|
5704
|
+
|
|
5501
5705
|
// src/table/lex-body.ts
|
|
5502
5706
|
function buildLexBodyRecognizer(spec, constants) {
|
|
5503
5707
|
const raw = constants[spec[0]];
|
|
@@ -6113,11 +6317,12 @@ function assemblyExtraIps(prog) {
|
|
|
6113
6317
|
}
|
|
6114
6318
|
function expandCompact(p) {
|
|
6115
6319
|
if ("code" in p) return p;
|
|
6320
|
+
if (p.es === void 0) throw new Error(`parseman: this parser was printed by an earlier parseman; reprint it with parseman ${PARSEMAN_VERSION}`);
|
|
6116
6321
|
return ownTableProgram({
|
|
6117
6322
|
code: p.c,
|
|
6118
6323
|
k: p.k,
|
|
6119
6324
|
cc: p.x,
|
|
6120
|
-
fx: p.e,
|
|
6325
|
+
fx: p.e.map((set) => set.map((i) => p.es[i])),
|
|
6121
6326
|
disp: p.d,
|
|
6122
6327
|
rules: p.r,
|
|
6123
6328
|
fns: p.f,
|
|
@@ -7318,8 +7523,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
7318
7523
|
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
|
|
7319
7524
|
const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
7320
7525
|
const readsState = build ? buildReadsState(def) : project === void 0;
|
|
7321
|
-
|
|
7322
|
-
|
|
7526
|
+
let hasOwnFields = parserHasOwnFields(combinator);
|
|
7527
|
+
let capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
7528
|
+
if (!hasOwnFields) {
|
|
7529
|
+
afterLink(() => {
|
|
7530
|
+
hasOwnFields = parserHasOwnFields(combinator);
|
|
7531
|
+
capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
7532
|
+
});
|
|
7533
|
+
}
|
|
7323
7534
|
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
7324
7535
|
let failExpected;
|
|
7325
7536
|
return {
|
|
@@ -8845,7 +9056,7 @@ var Encoder = class {
|
|
|
8845
9056
|
const dispCovIds = this.plan?.dispatches.get(p);
|
|
8846
9057
|
let dispCov = 0;
|
|
8847
9058
|
const arms = [];
|
|
8848
|
-
const
|
|
9059
|
+
const routed2 = [];
|
|
8849
9060
|
const key = [], keyArm = [];
|
|
8850
9061
|
const fold = [], foldArm = [];
|
|
8851
9062
|
const match = [];
|
|
@@ -8853,7 +9064,7 @@ var Encoder = class {
|
|
|
8853
9064
|
for (const c of d.cases) {
|
|
8854
9065
|
const arm = arms.length;
|
|
8855
9066
|
arms.push(this.covWrap(this.node(c.parser).ip, dispCovIds?.[dispCov++], 1));
|
|
8856
|
-
|
|
9067
|
+
routed2.push(branchUsesRouted(c) ? 1 : 0);
|
|
8857
9068
|
for (const kk of c.keys) {
|
|
8858
9069
|
expected.push(JSON.stringify(kk));
|
|
8859
9070
|
if (c.caseInsensitive) {
|
|
@@ -8869,7 +9080,7 @@ var Encoder = class {
|
|
|
8869
9080
|
for (const m of d.matchers ?? []) {
|
|
8870
9081
|
const arm = arms.length;
|
|
8871
9082
|
arms.push(this.covWrap(this.node(m.parser).ip, dispCovIds?.[dispCov++], 1));
|
|
8872
|
-
|
|
9083
|
+
routed2.push(branchUsesRouted(m) ? 1 : 0);
|
|
8873
9084
|
if (!m.caseInsensitive) {
|
|
8874
9085
|
match.push([KIND[m.kind], m.value, m.flags ?? "", arm]);
|
|
8875
9086
|
continue;
|
|
@@ -8883,7 +9094,7 @@ var Encoder = class {
|
|
|
8883
9094
|
}
|
|
8884
9095
|
const other = d.otherwise === void 0 ? -1 : this.covWrap(this.node(d.otherwise).ip, dispCovIds?.[dispCov++], 1);
|
|
8885
9096
|
const dspIdx = this.dsp.length;
|
|
8886
|
-
this.dsp.push({ key, keyArm, fold, foldArm, match, routed, expected });
|
|
9097
|
+
this.dsp.push({ key, keyArm, fold, foldArm, match, routed: routed2, expected });
|
|
8887
9098
|
const head = this.emitHead(OP_DISPATCH, 5 + arms.length);
|
|
8888
9099
|
this.code[head + 1] = sel;
|
|
8889
9100
|
this.code[head + 2] = dspIdx;
|
|
@@ -10199,6 +10410,12 @@ function emitShapeMatch(shape, start, mint, ind, firstChar) {
|
|
|
10199
10410
|
|
|
10200
10411
|
// src/table/child-slots.ts
|
|
10201
10412
|
function childSlots(code, ip, out) {
|
|
10413
|
+
const from = out.length;
|
|
10414
|
+
if (!childSlotOffsets(code, ip, out)) return false;
|
|
10415
|
+
for (let i = from; i < out.length; i++) out[i] = code[out[i]];
|
|
10416
|
+
return true;
|
|
10417
|
+
}
|
|
10418
|
+
function childSlotOffsets(code, ip, out) {
|
|
10202
10419
|
switch (code[ip]) {
|
|
10203
10420
|
// ZERO-WIDTH / TERMINAL ROWS — no successor. `OP_GUARD` and `OP_ADJ` are both
|
|
10204
10421
|
// childless tests. `OP_LIVE` holds a hand-written combinator in `prog.fns`; its
|
|
@@ -10231,7 +10448,7 @@ function childSlots(code, ip, out) {
|
|
|
10231
10448
|
case OP_COV:
|
|
10232
10449
|
case OP_REJECT:
|
|
10233
10450
|
case OP_GAPGATE:
|
|
10234
|
-
out.push(
|
|
10451
|
+
out.push(ip + 1);
|
|
10235
10452
|
return true;
|
|
10236
10453
|
// Single child at `ip + 2`.
|
|
10237
10454
|
case OP_GATE:
|
|
@@ -10248,55 +10465,55 @@ function childSlots(code, ip, out) {
|
|
|
10248
10465
|
case OP_ARMGATE:
|
|
10249
10466
|
case OP_RGATE:
|
|
10250
10467
|
case OP_RGATE2:
|
|
10251
|
-
out.push(
|
|
10468
|
+
out.push(ip + 2);
|
|
10252
10469
|
return true;
|
|
10253
10470
|
// `STRICT strict tolerant` — both encodings are reachable; an assembly keeps one.
|
|
10254
10471
|
case OP_STRICT:
|
|
10255
|
-
out.push(
|
|
10472
|
+
out.push(ip + 1, ip + 2);
|
|
10256
10473
|
return true;
|
|
10257
10474
|
// `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
|
|
10258
10475
|
// data the enclosing `dispatch()` already consumed, so the only edge is the
|
|
10259
10476
|
// fallback.
|
|
10260
10477
|
case OP_ROUTED:
|
|
10261
|
-
if (code[ip + 1] >= 0) out.push(
|
|
10478
|
+
if (code[ip + 1] >= 0) out.push(ip + 1);
|
|
10262
10479
|
return true;
|
|
10263
10480
|
// `DISPATCH sel d other otherRouted n a1 … an` — the SELECTOR is a child on
|
|
10264
10481
|
// exactly the same footing as the arms: it runs inside whatever node and scope
|
|
10265
10482
|
// this site sits in.
|
|
10266
10483
|
case OP_DISPATCH: {
|
|
10267
|
-
out.push(
|
|
10268
|
-
if (code[ip + 3] >= 0) out.push(
|
|
10484
|
+
out.push(ip + 1);
|
|
10485
|
+
if (code[ip + 3] >= 0) out.push(ip + 3);
|
|
10269
10486
|
const n = code[ip + 5];
|
|
10270
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10487
|
+
for (let i = 0; i < n; i++) out.push(ip + 6 + i);
|
|
10271
10488
|
return true;
|
|
10272
10489
|
}
|
|
10273
10490
|
case OP_SEQ:
|
|
10274
10491
|
case OP_SEQV: {
|
|
10275
10492
|
const n = code[ip + 1];
|
|
10276
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10493
|
+
for (let i = 0; i < n; i++) out.push(ip + 2 + i);
|
|
10277
10494
|
return true;
|
|
10278
10495
|
}
|
|
10279
10496
|
case OP_SEQX: {
|
|
10280
10497
|
const n = code[ip + 2];
|
|
10281
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10498
|
+
for (let i = 0; i < n; i++) out.push(ip + 3 + i);
|
|
10282
10499
|
return true;
|
|
10283
10500
|
}
|
|
10284
10501
|
case OP_CHOICE: {
|
|
10285
10502
|
const n = code[ip + 2];
|
|
10286
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10503
|
+
for (let i = 0; i < n; i++) out.push(ip + 4 + i);
|
|
10287
10504
|
return true;
|
|
10288
10505
|
}
|
|
10289
10506
|
// Arms are stride-2 from `ip + 4` — the gate word sits beside each arm offset.
|
|
10290
10507
|
case OP_GREEDY: {
|
|
10291
|
-
out.push(
|
|
10508
|
+
out.push(ip + 1);
|
|
10292
10509
|
const n = code[ip + 2];
|
|
10293
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10510
|
+
for (let i = 0; i < n; i++) out.push(ip + 4 + 2 * i);
|
|
10294
10511
|
return true;
|
|
10295
10512
|
}
|
|
10296
10513
|
case OP_REP:
|
|
10297
10514
|
case OP_REPV:
|
|
10298
|
-
out.push(
|
|
10299
|
-
if (code[ip + 4] >= 0) out.push(
|
|
10515
|
+
out.push(ip + 1);
|
|
10516
|
+
if (code[ip + 4] >= 0) out.push(ip + 4);
|
|
10300
10517
|
return true;
|
|
10301
10518
|
default:
|
|
10302
10519
|
return false;
|
|
@@ -13430,9 +13647,6 @@ function clearOf(ranges, input, from, to) {
|
|
|
13430
13647
|
return true;
|
|
13431
13648
|
}
|
|
13432
13649
|
|
|
13433
|
-
// src/version.ts
|
|
13434
|
-
var PARSEMAN_VERSION = "0.60.6";
|
|
13435
|
-
|
|
13436
13650
|
// src/table/assemble.ts
|
|
13437
13651
|
import { PlainBuf as PlainBuf2, PlainField, PlainLeaf as PlainLeaf9, PlainNode as PlainNode2, PlainSpan as PlainSpan10 } from "../cst/plain.js";
|
|
13438
13652
|
|
|
@@ -16610,10 +16824,10 @@ function assemble(t2, prog, cfg) {
|
|
|
16610
16824
|
const hasFold = spec.byFold.size > 0;
|
|
16611
16825
|
const match = spec.match;
|
|
16612
16826
|
const matchN = match.length;
|
|
16613
|
-
const
|
|
16827
|
+
const routed2 = spec.routed;
|
|
16614
16828
|
const expected = spec.expected;
|
|
16615
16829
|
const validArm = (arm) => Number.isInteger(arm) && arm >= 0 && arm < n;
|
|
16616
|
-
if (
|
|
16830
|
+
if (routed2.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
|
|
16617
16831
|
for (const arm of byKey.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch exact arm");
|
|
16618
16832
|
for (const arm of byFold.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch folded arm");
|
|
16619
16833
|
for (const m of match) if (!validArm(m[3])) throw new TypeError("table assembler: malformed dispatch matcher arm");
|
|
@@ -16638,7 +16852,7 @@ function assemble(t2, prog, cfg) {
|
|
|
16638
16852
|
const classify = hasFold ? matchBlock === void 0 ? (key) => byKey.get(key) ?? byFold.get(asciiFoldKey(key)) : (key) => byKey.get(key) ?? byFold.get(asciiFoldKey(key)) ?? matchBlock(key) : matchBlock === void 0 ? (key) => byKey.get(key) : (key) => byKey.get(key) ?? matchBlock(key);
|
|
16639
16853
|
const neverBranch = () => FAIL;
|
|
16640
16854
|
const bindArms = (start) => {
|
|
16641
|
-
const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]),
|
|
16855
|
+
const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed2[i] === 1) : neverBranch;
|
|
16642
16856
|
const next = start + 4 < n ? bindArms(start + 4) : void 0;
|
|
16643
16857
|
return dispatchArmBlock(
|
|
16644
16858
|
start,
|
|
@@ -17412,12 +17626,15 @@ function assertPrintable(prog, who) {
|
|
|
17412
17626
|
}
|
|
17413
17627
|
}
|
|
17414
17628
|
function programFields(prog, fns, opts = {}) {
|
|
17629
|
+
const tokens = [...new Set(prog.fx.flat())];
|
|
17630
|
+
const tokenAt = new Map(tokens.map((token2, i) => [token2, i]));
|
|
17415
17631
|
return [
|
|
17416
17632
|
...emitAssemblies(prog, opts.assemblies ?? []),
|
|
17417
17633
|
`c:[${prog.code.join(",")}],`,
|
|
17418
17634
|
`k:[${prog.k.map(emitConst).join(",")}],`,
|
|
17419
17635
|
`x:${emitClassPool(prog.cc)},`,
|
|
17420
|
-
`e:[${prog.fx.map((f) => `[${f.map(
|
|
17636
|
+
`e:[${prog.fx.map((f) => `[${f.map((token2) => tokenAt.get(token2)).join(",")}]`).join(",")}],`,
|
|
17637
|
+
`es:[${tokens.map(jsString).join(",")}],`,
|
|
17421
17638
|
`d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
|
|
17422
17639
|
`r:${JSON.stringify(prog.rules)},`,
|
|
17423
17640
|
...prog.lines === 1 ? ["l:1,"] : [],
|
|
@@ -20250,6 +20467,38 @@ function not(combinator) {
|
|
|
20250
20467
|
};
|
|
20251
20468
|
}
|
|
20252
20469
|
|
|
20470
|
+
// src/combinators/withCtx.ts
|
|
20471
|
+
function withCtx(extra, combinator) {
|
|
20472
|
+
const meta = {
|
|
20473
|
+
firstSet: combinator._meta.firstSet,
|
|
20474
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
20475
|
+
isTrivia: false
|
|
20476
|
+
};
|
|
20477
|
+
const parse2 = typeof extra === "function" ? (input, pos, ctx) => {
|
|
20478
|
+
const saved = ctx.state;
|
|
20479
|
+
ctx.state = extra(saved);
|
|
20480
|
+
try {
|
|
20481
|
+
return combinator.parse(input, pos, ctx);
|
|
20482
|
+
} finally {
|
|
20483
|
+
ctx.state = saved;
|
|
20484
|
+
}
|
|
20485
|
+
} : (input, pos, ctx) => {
|
|
20486
|
+
const saved = ctx.state;
|
|
20487
|
+
ctx.state = extra;
|
|
20488
|
+
try {
|
|
20489
|
+
return combinator.parse(input, pos, ctx);
|
|
20490
|
+
} finally {
|
|
20491
|
+
ctx.state = saved;
|
|
20492
|
+
}
|
|
20493
|
+
};
|
|
20494
|
+
return {
|
|
20495
|
+
_tag: "withCtx",
|
|
20496
|
+
_meta: meta,
|
|
20497
|
+
_def: { tag: "withCtx", extra, parser: combinator },
|
|
20498
|
+
parse: parse2
|
|
20499
|
+
};
|
|
20500
|
+
}
|
|
20501
|
+
|
|
20253
20502
|
// src/analysis/rebuild.ts
|
|
20254
20503
|
var FROZEN_TAGS = /* @__PURE__ */ new Set([
|
|
20255
20504
|
"dispatch",
|
|
@@ -20263,6 +20512,7 @@ var FROZEN_TAGS = /* @__PURE__ */ new Set([
|
|
|
20263
20512
|
"lines",
|
|
20264
20513
|
"columns"
|
|
20265
20514
|
]);
|
|
20515
|
+
var THAWED_TAGS = /* @__PURE__ */ new Set(["dispatch", "withCtx", "routed", "guard"]);
|
|
20266
20516
|
var CARRIED_META = [
|
|
20267
20517
|
"grammarTrivia",
|
|
20268
20518
|
"grammarScanSkip",
|
|
@@ -20301,7 +20551,9 @@ function subtreeContains(p, targets) {
|
|
|
20301
20551
|
walk(p);
|
|
20302
20552
|
return hit;
|
|
20303
20553
|
}
|
|
20304
|
-
function rebuildCombinator(root, replacements) {
|
|
20554
|
+
function rebuildCombinator(root, replacements, options = {}) {
|
|
20555
|
+
const thaw = options.thaw === true;
|
|
20556
|
+
const after = options.after ?? ((_p, out) => out);
|
|
20305
20557
|
const memo = /* @__PURE__ */ new Map();
|
|
20306
20558
|
const frozenKeys = /* @__PURE__ */ new Set();
|
|
20307
20559
|
const frozen = [];
|
|
@@ -20321,15 +20573,16 @@ function rebuildCombinator(root, replacements) {
|
|
|
20321
20573
|
return p;
|
|
20322
20574
|
}
|
|
20323
20575
|
const here = p._ruleName ?? rule2;
|
|
20324
|
-
if (FROZEN_TAGS.has(d.tag)) {
|
|
20576
|
+
if (FROZEN_TAGS.has(d.tag) && !(thaw && THAWED_TAGS.has(d.tag))) {
|
|
20325
20577
|
const key = JSON.stringify([here, d.tag]);
|
|
20326
20578
|
if (!frozenKeys.has(key)) {
|
|
20327
20579
|
frozenKeys.add(key);
|
|
20328
20580
|
frozen.push({ tag: d.tag, rule: here });
|
|
20329
20581
|
}
|
|
20330
20582
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
20331
|
-
|
|
20332
|
-
|
|
20583
|
+
const kept = after(p, p);
|
|
20584
|
+
memo.set(p, kept);
|
|
20585
|
+
return kept;
|
|
20333
20586
|
}
|
|
20334
20587
|
if (d.tag === "lazy") {
|
|
20335
20588
|
let target;
|
|
@@ -20366,6 +20619,14 @@ function rebuildCombinator(root, replacements) {
|
|
|
20366
20619
|
break;
|
|
20367
20620
|
}
|
|
20368
20621
|
case "choice": {
|
|
20622
|
+
if (d.gates.some((g) => g !== null) && thaw) {
|
|
20623
|
+
const unsafeChoice = choice;
|
|
20624
|
+
out = unsafeChoice(...d.parsers.map((arm, i) => {
|
|
20625
|
+
const gate = d.gates[i];
|
|
20626
|
+
return gate ? { combinator: one(arm), gate } : one(arm);
|
|
20627
|
+
}));
|
|
20628
|
+
break;
|
|
20629
|
+
}
|
|
20369
20630
|
if (d.gates.some((g) => g !== null)) {
|
|
20370
20631
|
const key = JSON.stringify([here, "choice(gated)"]);
|
|
20371
20632
|
if (!frozenKeys.has(key)) {
|
|
@@ -20373,8 +20634,9 @@ function rebuildCombinator(root, replacements) {
|
|
|
20373
20634
|
frozen.push({ tag: "choice(gated)", rule: here });
|
|
20374
20635
|
}
|
|
20375
20636
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
20376
|
-
|
|
20377
|
-
|
|
20637
|
+
const kept = after(p, p);
|
|
20638
|
+
memo.set(p, kept);
|
|
20639
|
+
return kept;
|
|
20378
20640
|
}
|
|
20379
20641
|
const kids = d.parsers.map(one);
|
|
20380
20642
|
out = choice(...kids);
|
|
@@ -20452,13 +20714,33 @@ function rebuildCombinator(root, replacements) {
|
|
|
20452
20714
|
frozen.push({ tag: "node(untyped+build+opts)", rule: here });
|
|
20453
20715
|
}
|
|
20454
20716
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
20455
|
-
|
|
20456
|
-
|
|
20717
|
+
const kept = after(p, p);
|
|
20718
|
+
memo.set(p, kept);
|
|
20719
|
+
return kept;
|
|
20457
20720
|
}
|
|
20458
20721
|
out = d.type === void 0 ? d.build === void 0 ? node(one(d.parser), opts) : node(one(d.parser), d.build) : node(d.type, one(d.parser), d.build, opts);
|
|
20459
20722
|
if (d.buildRawUnused === true && out._def.tag === "node") out._def.buildRawUnused = true;
|
|
20460
20723
|
break;
|
|
20461
20724
|
}
|
|
20725
|
+
case "dispatch": {
|
|
20726
|
+
const arms = d.cases.map((e) => when(e.keys, one(e.parser), e.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
20727
|
+
for (const e of d.matchers ?? []) {
|
|
20728
|
+
arms.push(when(dispatchMatcher(e), one(e.parser), e.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
20729
|
+
}
|
|
20730
|
+
if (d.otherwise) arms.push(otherwise(one(d.otherwise), d.otherwiseCommit === false ? { commit: false } : void 0));
|
|
20731
|
+
const unsafeDispatch = dispatch;
|
|
20732
|
+
out = unsafeDispatch(one(d.selector), ...arms);
|
|
20733
|
+
break;
|
|
20734
|
+
}
|
|
20735
|
+
case "withCtx":
|
|
20736
|
+
out = withCtx(d.extra, one(d.parser));
|
|
20737
|
+
break;
|
|
20738
|
+
case "routed":
|
|
20739
|
+
out = d.fallback === void 0 ? routed() : routed(one(d.fallback));
|
|
20740
|
+
break;
|
|
20741
|
+
case "guard":
|
|
20742
|
+
out = p;
|
|
20743
|
+
break;
|
|
20462
20744
|
case "grammar": {
|
|
20463
20745
|
const inner = one(d.parser);
|
|
20464
20746
|
out = parser({
|
|
@@ -20476,13 +20758,15 @@ function rebuildCombinator(root, replacements) {
|
|
|
20476
20758
|
frozen.push({ tag: d.tag, rule: here });
|
|
20477
20759
|
}
|
|
20478
20760
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
20479
|
-
|
|
20480
|
-
|
|
20761
|
+
const kept = after(p, p);
|
|
20762
|
+
memo.set(p, kept);
|
|
20763
|
+
return kept;
|
|
20481
20764
|
}
|
|
20482
20765
|
}
|
|
20483
20766
|
carryStamps(p, out);
|
|
20484
|
-
|
|
20485
|
-
|
|
20767
|
+
const done = after(p, out);
|
|
20768
|
+
memo.set(p, done);
|
|
20769
|
+
return done;
|
|
20486
20770
|
};
|
|
20487
20771
|
const rebuilt = go(root, root._ruleName ?? "<entry>");
|
|
20488
20772
|
frozen.sort((a, b) => a.rule < b.rule ? -1 : a.rule > b.rule ? 1 : a.tag < b.tag ? -1 : a.tag > b.tag ? 1 : 0);
|