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
|
@@ -424,13 +424,13 @@ function caseFoldVariants(cp) {
|
|
|
424
424
|
// src/combinators/probe.ts
|
|
425
425
|
function failAt(ctx, expected, pos) {
|
|
426
426
|
const r = { ok: false, expected, span: { start: pos, end: pos } };
|
|
427
|
-
const
|
|
428
|
-
if (
|
|
429
|
-
const best =
|
|
427
|
+
const probe2 = ctx._probe;
|
|
428
|
+
if (probe2 !== void 0 && pos <= probe2.offset) {
|
|
429
|
+
const best = probe2.best;
|
|
430
430
|
if (best === null || pos > best.span.start) {
|
|
431
|
-
|
|
431
|
+
probe2.best = r;
|
|
432
432
|
} else if (pos === best.span.start) {
|
|
433
|
-
|
|
433
|
+
probe2.best = { ...best, expected: [...best.expected, ...expected] };
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
436
|
return r;
|
|
@@ -2258,15 +2258,20 @@ function markUnusedValues(root) {
|
|
|
2258
2258
|
case "many":
|
|
2259
2259
|
case "oneOrMore":
|
|
2260
2260
|
mark(def, consumed);
|
|
2261
|
-
visit(def.parser, consumed);
|
|
2262
|
-
return;
|
|
2263
2261
|
case "optional":
|
|
2262
|
+
// `optional` returns `inner | null` — no aggregate array/tuple to elide, so
|
|
2263
|
+
// it carries no valueUnused flag. Still descend so an inner many/sequence
|
|
2264
|
+
// under a node() is analyzed (it benefits even when its optional wrapper
|
|
2265
|
+
// doesn't).
|
|
2266
|
+
case "label":
|
|
2267
|
+
case "trivia":
|
|
2268
|
+
case "attempt":
|
|
2269
|
+
case "withCtx":
|
|
2270
|
+
case "expect":
|
|
2264
2271
|
visit(def.parser, consumed);
|
|
2265
2272
|
return;
|
|
2266
2273
|
case "sequence":
|
|
2267
2274
|
mark(def, consumed);
|
|
2268
|
-
for (const p of def.parsers) visit(p, consumed);
|
|
2269
|
-
return;
|
|
2270
2275
|
case "choice":
|
|
2271
2276
|
for (const p of def.parsers) visit(p, consumed);
|
|
2272
2277
|
return;
|
|
@@ -2277,22 +2282,24 @@ function markUnusedValues(root) {
|
|
|
2277
2282
|
if (def.otherwise) visit(def.otherwise, consumed);
|
|
2278
2283
|
return;
|
|
2279
2284
|
case "node":
|
|
2285
|
+
// builds from captured children, NOT the inner parser value.
|
|
2286
|
+
case "not":
|
|
2287
|
+
case "peek":
|
|
2288
|
+
// lookahead — value never observed
|
|
2289
|
+
case "token":
|
|
2280
2290
|
visit(def.parser, false);
|
|
2281
2291
|
return;
|
|
2282
2292
|
case "transform":
|
|
2283
|
-
|
|
2284
|
-
return;
|
|
2293
|
+
// the map fn reads the value → always consumed.
|
|
2285
2294
|
case "field":
|
|
2295
|
+
// the field capture records the parsed value → always consumed.
|
|
2296
|
+
case "leaf":
|
|
2286
2297
|
visit(def.parser, true);
|
|
2287
2298
|
return;
|
|
2288
2299
|
case "sepBy":
|
|
2289
2300
|
visit(def.parser, true);
|
|
2290
2301
|
visit(def.separator, false);
|
|
2291
2302
|
return;
|
|
2292
|
-
case "not":
|
|
2293
|
-
case "peek":
|
|
2294
|
-
visit(def.parser, false);
|
|
2295
|
-
return;
|
|
2296
2303
|
case "grammar":
|
|
2297
2304
|
visit(def.parser, consumed);
|
|
2298
2305
|
if (def.triviaParser) visit(def.triviaParser, false);
|
|
@@ -2301,19 +2308,6 @@ function markUnusedValues(root) {
|
|
|
2301
2308
|
visit(def.parser, consumed);
|
|
2302
2309
|
visit(def.sentinel, false);
|
|
2303
2310
|
return;
|
|
2304
|
-
case "token":
|
|
2305
|
-
visit(def.parser, false);
|
|
2306
|
-
return;
|
|
2307
|
-
case "label":
|
|
2308
|
-
case "trivia":
|
|
2309
|
-
case "attempt":
|
|
2310
|
-
case "withCtx":
|
|
2311
|
-
case "expect":
|
|
2312
|
-
visit(def.parser, consumed);
|
|
2313
|
-
return;
|
|
2314
|
-
case "leaf":
|
|
2315
|
-
visit(def.parser, true);
|
|
2316
|
-
return;
|
|
2317
2311
|
case "lazy":
|
|
2318
2312
|
return;
|
|
2319
2313
|
default:
|
|
@@ -2616,6 +2610,7 @@ function matchesAt(sentinel, input, pos, ctx) {
|
|
|
2616
2610
|
function captureError(ctx, error) {
|
|
2617
2611
|
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
2618
2612
|
}
|
|
2613
|
+
var REC = { scan: recoverScan, at: matchesAt, or: orSentinel, sentinel: firstSetSentinel, capture: captureError };
|
|
2619
2614
|
|
|
2620
2615
|
// src/combinators/expect.ts
|
|
2621
2616
|
function deriveExpected(c) {
|
|
@@ -2676,6 +2671,7 @@ function derive(c, seen) {
|
|
|
2676
2671
|
case "optional":
|
|
2677
2672
|
case "many":
|
|
2678
2673
|
case "oneOrMore":
|
|
2674
|
+
case "sepBy":
|
|
2679
2675
|
case "transform":
|
|
2680
2676
|
case "not":
|
|
2681
2677
|
case "peek":
|
|
@@ -2823,7 +2819,7 @@ function choice(...args) {
|
|
|
2823
2819
|
const result = parsers[idx].parse(input, pos, ctx);
|
|
2824
2820
|
if (result.ok) return result;
|
|
2825
2821
|
expected.push(...result.expected);
|
|
2826
|
-
if (result.committed) return { ok: false, expected, span:
|
|
2822
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
2827
2823
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
2828
2824
|
}
|
|
2829
2825
|
if (ctx._probe !== void 0 || ctx._tolerant) for (const p of parsers) p.parse(input, pos, ctx);
|
|
@@ -4067,6 +4063,9 @@ function regex(pattern, flags = "") {
|
|
|
4067
4063
|
};
|
|
4068
4064
|
}
|
|
4069
4065
|
|
|
4066
|
+
// src/version.ts
|
|
4067
|
+
var PARSEMAN_VERSION = "0.61.1";
|
|
4068
|
+
|
|
4070
4069
|
// src/table/lex-body.ts
|
|
4071
4070
|
function buildLexBodyRecognizer(spec, constants) {
|
|
4072
4071
|
const raw = constants[spec[0]];
|
|
@@ -4535,7 +4534,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
|
|
|
4535
4534
|
if (!Number.isInteger(spec[2]) || spec[2] < 0) {
|
|
4536
4535
|
throw new TypeError("table balanced lexical program has an invalid scan reference");
|
|
4537
4536
|
}
|
|
4538
|
-
const
|
|
4537
|
+
const run2 = (_input, _pos, ctx, scan) => {
|
|
4539
4538
|
if (scan === void 0) throw new TypeError("table balanced lexical program lost its scan body");
|
|
4540
4539
|
const result = scan.parse(_input, _pos, ctx);
|
|
4541
4540
|
if (!result.ok) {
|
|
@@ -4545,7 +4544,7 @@ function buildLexProgramRunner(spec, matchers, classes, expected) {
|
|
|
4545
4544
|
}
|
|
4546
4545
|
return result.span.end;
|
|
4547
4546
|
};
|
|
4548
|
-
return Object.assign(
|
|
4547
|
+
return Object.assign(run2, { scan: spec[2] });
|
|
4549
4548
|
}
|
|
4550
4549
|
if (spec[0] === 2) return fixedTreeRunner(spec.slice(2), matchers, classes, expected);
|
|
4551
4550
|
if (spec[0] === 1) {
|
|
@@ -4682,11 +4681,12 @@ function assemblyExtraIps(prog) {
|
|
|
4682
4681
|
}
|
|
4683
4682
|
function expandCompact(p) {
|
|
4684
4683
|
if ("code" in p) return p;
|
|
4684
|
+
if (p.es === void 0) throw new Error(`parseman: this parser was printed by an earlier parseman; reprint it with parseman ${PARSEMAN_VERSION}`);
|
|
4685
4685
|
return ownTableProgram({
|
|
4686
4686
|
code: p.c,
|
|
4687
4687
|
k: p.k,
|
|
4688
4688
|
cc: p.x,
|
|
4689
|
-
fx: p.e,
|
|
4689
|
+
fx: p.e.map((set) => set.map((i) => p.es[i])),
|
|
4690
4690
|
disp: p.d,
|
|
4691
4691
|
rules: p.r,
|
|
4692
4692
|
fns: p.f,
|
|
@@ -6591,6 +6591,206 @@ function asciiFoldKey(key) {
|
|
|
6591
6591
|
}
|
|
6592
6592
|
return out;
|
|
6593
6593
|
}
|
|
6594
|
+
function matchesDispatchMatcher(value, matcher) {
|
|
6595
|
+
const candidate = matcher.caseInsensitive ? asciiFoldKey(value) : value;
|
|
6596
|
+
const expected = matcher.caseInsensitive ? asciiFoldKey(matcher.value) : matcher.value;
|
|
6597
|
+
switch (matcher.kind) {
|
|
6598
|
+
case "startsWith":
|
|
6599
|
+
return candidate.startsWith(expected);
|
|
6600
|
+
case "endsWith":
|
|
6601
|
+
return candidate.endsWith(expected);
|
|
6602
|
+
case "matches": {
|
|
6603
|
+
const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
|
|
6604
|
+
return new RegExp(matcher.value, flags).test(value);
|
|
6605
|
+
}
|
|
6606
|
+
}
|
|
6607
|
+
}
|
|
6608
|
+
function isStringMatcher(value) {
|
|
6609
|
+
if (typeof value !== "object" || value === null) return false;
|
|
6610
|
+
const kind = value.kind;
|
|
6611
|
+
return kind === "startsWith" || kind === "endsWith" || kind === "matches";
|
|
6612
|
+
}
|
|
6613
|
+
function fixedMatcher(kind, value) {
|
|
6614
|
+
if (typeof value !== "string") throw new TypeError(`parseman: ${kind}() value must be a string`);
|
|
6615
|
+
if (value.length === 0) throw new RangeError(`parseman: ${kind}() requires a non-empty value`);
|
|
6616
|
+
return { kind, value };
|
|
6617
|
+
}
|
|
6618
|
+
function startsWith(prefix) {
|
|
6619
|
+
return fixedMatcher("startsWith", prefix);
|
|
6620
|
+
}
|
|
6621
|
+
function endsWith(suffix) {
|
|
6622
|
+
return fixedMatcher("endsWith", suffix);
|
|
6623
|
+
}
|
|
6624
|
+
function matches(pattern) {
|
|
6625
|
+
if (!(pattern instanceof RegExp)) throw new TypeError("parseman: matches() requires a RegExp");
|
|
6626
|
+
if (pattern.flags.includes("g") || pattern.flags.includes("y")) {
|
|
6627
|
+
throw new TypeError("parseman: matches() does not accept global or sticky regex flags");
|
|
6628
|
+
}
|
|
6629
|
+
return { kind: "matches", value: pattern.source, flags: pattern.flags };
|
|
6630
|
+
}
|
|
6631
|
+
function dispatchMatcher(entry) {
|
|
6632
|
+
switch (entry.kind) {
|
|
6633
|
+
case "startsWith":
|
|
6634
|
+
return startsWith(entry.value);
|
|
6635
|
+
case "endsWith":
|
|
6636
|
+
return endsWith(entry.value);
|
|
6637
|
+
case "matches":
|
|
6638
|
+
return matches(new RegExp(entry.value, entry.flags));
|
|
6639
|
+
}
|
|
6640
|
+
}
|
|
6641
|
+
function when(key, parser2, opts = {}) {
|
|
6642
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
6643
|
+
if (isStringMatcher(key)) {
|
|
6644
|
+
return { kind: "whenMatcher", matcher: key, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
6645
|
+
}
|
|
6646
|
+
const keys = Array.isArray(key) ? [...key] : [key];
|
|
6647
|
+
if (keys.length === 0) throw new RangeError("parseman: when() requires at least one key");
|
|
6648
|
+
for (const item of keys) {
|
|
6649
|
+
if (typeof item !== "string") throw new TypeError("parseman: when() keys must be strings");
|
|
6650
|
+
}
|
|
6651
|
+
return { kind: "when", keys, parser: parser2, caseInsensitive: opts.caseInsensitive ?? false, usesRouted };
|
|
6652
|
+
}
|
|
6653
|
+
function otherwise(parser2, opts = {}) {
|
|
6654
|
+
const usesRouted = parserUsesRouted(parser2);
|
|
6655
|
+
return opts.commit === false ? { kind: "otherwise", parser: parser2, usesRouted, commit: false } : { kind: "otherwise", parser: parser2, usesRouted };
|
|
6656
|
+
}
|
|
6657
|
+
function routed(fallback) {
|
|
6658
|
+
return {
|
|
6659
|
+
_tag: "routed",
|
|
6660
|
+
_meta: {
|
|
6661
|
+
// The routed token is whatever the selector matched, so the first set stays
|
|
6662
|
+
// `any` even with a fallback — `any` already subsumes the fallback's.
|
|
6663
|
+
firstSet: { kind: "any" },
|
|
6664
|
+
canMatchNewline: fallback?._meta.canMatchNewline ?? false,
|
|
6665
|
+
isTrivia: false
|
|
6666
|
+
},
|
|
6667
|
+
_def: fallback === void 0 ? { tag: "routed" } : { tag: "routed", fallback },
|
|
6668
|
+
parse(_input, pos, ctx) {
|
|
6669
|
+
const item = ctx._routed;
|
|
6670
|
+
if (item === void 0 || pos !== item.span.start) {
|
|
6671
|
+
if (fallback !== void 0) return fallback.parse(_input, pos, ctx);
|
|
6672
|
+
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
6673
|
+
}
|
|
6674
|
+
if (cstCaptureActive(ctx)) {
|
|
6675
|
+
pushCstLeaf(ctx, new PlainLeaf6(item.value, item.span));
|
|
6676
|
+
}
|
|
6677
|
+
return { ok: true, value: item.value, span: item.span };
|
|
6678
|
+
}
|
|
6679
|
+
};
|
|
6680
|
+
}
|
|
6681
|
+
function dispatch(selector, ...arms) {
|
|
6682
|
+
if (parserUsesRouted(selector)) {
|
|
6683
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
6684
|
+
}
|
|
6685
|
+
let fallback;
|
|
6686
|
+
let fallbackUsesRouted = false;
|
|
6687
|
+
let fallbackCommits = true;
|
|
6688
|
+
const matchers = [];
|
|
6689
|
+
const cases = [];
|
|
6690
|
+
const seen = [];
|
|
6691
|
+
for (let i = 0; i < arms.length; i++) {
|
|
6692
|
+
const arm = arms[i];
|
|
6693
|
+
if (arm.kind === "otherwise") {
|
|
6694
|
+
if (fallback !== void 0) throw new Error("parseman: dispatch() accepts at most one otherwise() arm");
|
|
6695
|
+
if (i !== arms.length - 1) throw new Error("parseman: otherwise() must be the last dispatch() arm");
|
|
6696
|
+
fallback = arm.parser;
|
|
6697
|
+
fallbackUsesRouted = arm.usesRouted === true;
|
|
6698
|
+
fallbackCommits = arm.commit !== false;
|
|
6699
|
+
continue;
|
|
6700
|
+
}
|
|
6701
|
+
if (arm.kind === "whenMatcher") {
|
|
6702
|
+
const matcher = arm.matcher;
|
|
6703
|
+
matchers.push({
|
|
6704
|
+
kind: matcher.kind,
|
|
6705
|
+
value: matcher.value,
|
|
6706
|
+
...matcher.kind === "matches" ? { flags: matcher.flags } : {},
|
|
6707
|
+
parser: arm.parser,
|
|
6708
|
+
caseInsensitive: arm.caseInsensitive,
|
|
6709
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
6710
|
+
});
|
|
6711
|
+
continue;
|
|
6712
|
+
}
|
|
6713
|
+
for (const key of arm.keys) {
|
|
6714
|
+
const folded = asciiFoldKey(key);
|
|
6715
|
+
for (const prior of seen) {
|
|
6716
|
+
const overlaps = arm.caseInsensitive || prior.caseInsensitive ? folded === prior.folded : key === prior.raw;
|
|
6717
|
+
if (overlaps) throw new Error(`parseman: duplicate dispatch key ${JSON.stringify(key)}`);
|
|
6718
|
+
}
|
|
6719
|
+
seen.push({ raw: key, folded, caseInsensitive: arm.caseInsensitive });
|
|
6720
|
+
}
|
|
6721
|
+
cases.push({
|
|
6722
|
+
keys: arm.keys,
|
|
6723
|
+
parser: arm.parser,
|
|
6724
|
+
caseInsensitive: arm.caseInsensitive,
|
|
6725
|
+
...arm.usesRouted === true ? { usesRouted: true } : {}
|
|
6726
|
+
});
|
|
6727
|
+
}
|
|
6728
|
+
const meta = {
|
|
6729
|
+
firstSet: selector._meta.firstSet,
|
|
6730
|
+
canMatchNewline: selector._meta.canMatchNewline || cases.some((entry) => entry.parser._meta.canMatchNewline) || matchers.some((entry) => entry.parser._meta.canMatchNewline) || (fallback?._meta.canMatchNewline ?? false),
|
|
6731
|
+
isTrivia: false
|
|
6732
|
+
};
|
|
6733
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
6734
|
+
const byFoldedKey = /* @__PURE__ */ new Map();
|
|
6735
|
+
for (const entry of cases) {
|
|
6736
|
+
for (const key of entry.keys) {
|
|
6737
|
+
if (entry.caseInsensitive) byFoldedKey.set(asciiFoldKey(key), entry);
|
|
6738
|
+
else byKey.set(key, entry);
|
|
6739
|
+
}
|
|
6740
|
+
}
|
|
6741
|
+
return {
|
|
6742
|
+
_tag: "dispatch",
|
|
6743
|
+
_meta: meta,
|
|
6744
|
+
_def: {
|
|
6745
|
+
tag: "dispatch",
|
|
6746
|
+
selector,
|
|
6747
|
+
cases,
|
|
6748
|
+
...matchers.length === 0 ? {} : { matchers },
|
|
6749
|
+
...fallback === void 0 ? {} : {
|
|
6750
|
+
otherwise: fallback,
|
|
6751
|
+
...fallbackUsesRouted ? { otherwiseUsesRouted: true } : {},
|
|
6752
|
+
...fallbackCommits ? {} : { otherwiseCommit: false }
|
|
6753
|
+
}
|
|
6754
|
+
},
|
|
6755
|
+
parse(input, pos, ctx) {
|
|
6756
|
+
if (parserUsesRouted(selector)) {
|
|
6757
|
+
throw new Error("parseman: routed() can only appear inside a dispatch() branch");
|
|
6758
|
+
}
|
|
6759
|
+
const selectorMark = saveTriviaMark(ctx);
|
|
6760
|
+
const selected = selector.parse(input, pos, ctx);
|
|
6761
|
+
if (!selected.ok) return selected;
|
|
6762
|
+
const chosen = byKey.get(selected.value) ?? (byFoldedKey.size === 0 ? void 0 : byFoldedKey.get(asciiFoldKey(selected.value))) ?? matchers.find((matcher) => matchesDispatchMatcher(selected.value, matcher));
|
|
6763
|
+
const branch = chosen ?? (fallback === void 0 ? void 0 : { keys: [], parser: fallback, caseInsensitive: false, usesRouted: fallbackUsesRouted });
|
|
6764
|
+
if (branch === void 0) {
|
|
6765
|
+
const expected = cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key)));
|
|
6766
|
+
return { ok: false, expected, span: { start: selected.span.end, end: selected.span.end } };
|
|
6767
|
+
}
|
|
6768
|
+
const savedRouted = ctx._routed;
|
|
6769
|
+
const usesRouted = branchUsesRouted(branch);
|
|
6770
|
+
let mark = saveTriviaMark(ctx);
|
|
6771
|
+
if (usesRouted) {
|
|
6772
|
+
rollbackTrivia(ctx, selectorMark);
|
|
6773
|
+
mark = saveTriviaMark(ctx);
|
|
6774
|
+
ctx._routed = { value: selected.value, span: selected.span };
|
|
6775
|
+
}
|
|
6776
|
+
let result;
|
|
6777
|
+
try {
|
|
6778
|
+
result = branch.parser.parse(input, usesRouted ? pos : selected.span.end, ctx);
|
|
6779
|
+
} finally {
|
|
6780
|
+
if (usesRouted) ctx._routed = savedRouted;
|
|
6781
|
+
}
|
|
6782
|
+
if (!result.ok) {
|
|
6783
|
+
rollbackTrivia(ctx, mark);
|
|
6784
|
+
return chosen === void 0 && !fallbackCommits ? result : { ...result, committed: true };
|
|
6785
|
+
}
|
|
6786
|
+
return {
|
|
6787
|
+
ok: true,
|
|
6788
|
+
value: [selected.value, result.value],
|
|
6789
|
+
span: { start: pos, end: result.span.end }
|
|
6790
|
+
};
|
|
6791
|
+
}
|
|
6792
|
+
};
|
|
6793
|
+
}
|
|
6594
6794
|
|
|
6595
6795
|
// src/table/ops.ts
|
|
6596
6796
|
var OP_LIT = 1;
|
|
@@ -6693,6 +6893,12 @@ var OP_NAMES = {
|
|
|
6693
6893
|
[OP_STRICT]: "STRICT"
|
|
6694
6894
|
};
|
|
6695
6895
|
|
|
6896
|
+
// src/combinators/link-scope.ts
|
|
6897
|
+
var scope;
|
|
6898
|
+
function afterLink(settle) {
|
|
6899
|
+
scope?.push(settle);
|
|
6900
|
+
}
|
|
6901
|
+
|
|
6696
6902
|
// src/combinators/node.ts
|
|
6697
6903
|
import { PlainNode, PlainSpan as PlainSpan7 } from "../cst/plain.js";
|
|
6698
6904
|
function unwrapChild(child) {
|
|
@@ -6756,8 +6962,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
6756
6962
|
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;
|
|
6757
6963
|
const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
6758
6964
|
const readsState = build ? buildReadsState(def) : project === void 0;
|
|
6759
|
-
|
|
6760
|
-
|
|
6965
|
+
let hasOwnFields = parserHasOwnFields(combinator);
|
|
6966
|
+
let capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
6967
|
+
if (!hasOwnFields) {
|
|
6968
|
+
afterLink(() => {
|
|
6969
|
+
hasOwnFields = parserHasOwnFields(combinator);
|
|
6970
|
+
capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
|
|
6971
|
+
});
|
|
6972
|
+
}
|
|
6761
6973
|
const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
|
|
6762
6974
|
let failExpected;
|
|
6763
6975
|
return {
|
|
@@ -6863,7 +7075,7 @@ function selectOptionalSuffixLexBody(ir) {
|
|
|
6863
7075
|
function reinstallsRuleTrivia(reference, target) {
|
|
6864
7076
|
return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
|
|
6865
7077
|
}
|
|
6866
|
-
function directTokenBodyParser(parser2, resolve,
|
|
7078
|
+
function directTokenBodyParser(parser2, resolve, scope2) {
|
|
6867
7079
|
const outer = parser2._def;
|
|
6868
7080
|
if (outer.tag !== "token") return void 0;
|
|
6869
7081
|
let body = outer.parser;
|
|
@@ -6873,7 +7085,7 @@ function directTokenBodyParser(parser2, resolve, scope) {
|
|
|
6873
7085
|
const wrapper = body._def;
|
|
6874
7086
|
if (wrapper.tag === "grammar") {
|
|
6875
7087
|
if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
|
|
6876
|
-
if (
|
|
7088
|
+
if (scope2 !== void 0) scope2.cleared = true;
|
|
6877
7089
|
body = wrapper.parser;
|
|
6878
7090
|
continue;
|
|
6879
7091
|
}
|
|
@@ -7130,10 +7342,10 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false, cleared
|
|
|
7130
7342
|
}
|
|
7131
7343
|
}
|
|
7132
7344
|
function directFixedTokenBody(parser2, resolve) {
|
|
7133
|
-
const
|
|
7134
|
-
const body = directTokenBodyParser(parser2, resolve,
|
|
7345
|
+
const scope2 = { cleared: false };
|
|
7346
|
+
const body = directTokenBodyParser(parser2, resolve, scope2);
|
|
7135
7347
|
if (body === void 0) return void 0;
|
|
7136
|
-
const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false,
|
|
7348
|
+
const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope2.cleared);
|
|
7137
7349
|
return root === void 0 ? void 0 : { kind: "fixed-tree", root };
|
|
7138
7350
|
}
|
|
7139
7351
|
function directBalancedTokenBody(parser2, resolve) {
|
|
@@ -8633,7 +8845,7 @@ var Encoder = class {
|
|
|
8633
8845
|
const dispCovIds = this.plan?.dispatches.get(p);
|
|
8634
8846
|
let dispCov = 0;
|
|
8635
8847
|
const arms = [];
|
|
8636
|
-
const
|
|
8848
|
+
const routed2 = [];
|
|
8637
8849
|
const key = [], keyArm = [];
|
|
8638
8850
|
const fold = [], foldArm = [];
|
|
8639
8851
|
const match = [];
|
|
@@ -8641,7 +8853,7 @@ var Encoder = class {
|
|
|
8641
8853
|
for (const c of d.cases) {
|
|
8642
8854
|
const arm = arms.length;
|
|
8643
8855
|
arms.push(this.covWrap(this.node(c.parser).ip, dispCovIds?.[dispCov++], 1));
|
|
8644
|
-
|
|
8856
|
+
routed2.push(branchUsesRouted(c) ? 1 : 0);
|
|
8645
8857
|
for (const kk of c.keys) {
|
|
8646
8858
|
expected.push(JSON.stringify(kk));
|
|
8647
8859
|
if (c.caseInsensitive) {
|
|
@@ -8657,7 +8869,7 @@ var Encoder = class {
|
|
|
8657
8869
|
for (const m of d.matchers ?? []) {
|
|
8658
8870
|
const arm = arms.length;
|
|
8659
8871
|
arms.push(this.covWrap(this.node(m.parser).ip, dispCovIds?.[dispCov++], 1));
|
|
8660
|
-
|
|
8872
|
+
routed2.push(branchUsesRouted(m) ? 1 : 0);
|
|
8661
8873
|
if (!m.caseInsensitive) {
|
|
8662
8874
|
match.push([KIND[m.kind], m.value, m.flags ?? "", arm]);
|
|
8663
8875
|
continue;
|
|
@@ -8671,7 +8883,7 @@ var Encoder = class {
|
|
|
8671
8883
|
}
|
|
8672
8884
|
const other = d.otherwise === void 0 ? -1 : this.covWrap(this.node(d.otherwise).ip, dispCovIds?.[dispCov++], 1);
|
|
8673
8885
|
const dspIdx = this.dsp.length;
|
|
8674
|
-
this.dsp.push({ key, keyArm, fold, foldArm, match, routed, expected });
|
|
8886
|
+
this.dsp.push({ key, keyArm, fold, foldArm, match, routed: routed2, expected });
|
|
8675
8887
|
const head = this.emitHead(OP_DISPATCH, 5 + arms.length);
|
|
8676
8888
|
this.code[head + 1] = sel;
|
|
8677
8889
|
this.code[head + 2] = dspIdx;
|
|
@@ -9987,6 +10199,12 @@ function emitShapeMatch(shape, start, mint, ind, firstChar) {
|
|
|
9987
10199
|
|
|
9988
10200
|
// src/table/child-slots.ts
|
|
9989
10201
|
function childSlots(code, ip, out) {
|
|
10202
|
+
const from = out.length;
|
|
10203
|
+
if (!childSlotOffsets(code, ip, out)) return false;
|
|
10204
|
+
for (let i = from; i < out.length; i++) out[i] = code[out[i]];
|
|
10205
|
+
return true;
|
|
10206
|
+
}
|
|
10207
|
+
function childSlotOffsets(code, ip, out) {
|
|
9990
10208
|
switch (code[ip]) {
|
|
9991
10209
|
// ZERO-WIDTH / TERMINAL ROWS — no successor. `OP_GUARD` and `OP_ADJ` are both
|
|
9992
10210
|
// childless tests. `OP_LIVE` holds a hand-written combinator in `prog.fns`; its
|
|
@@ -10019,7 +10237,7 @@ function childSlots(code, ip, out) {
|
|
|
10019
10237
|
case OP_COV:
|
|
10020
10238
|
case OP_REJECT:
|
|
10021
10239
|
case OP_GAPGATE:
|
|
10022
|
-
out.push(
|
|
10240
|
+
out.push(ip + 1);
|
|
10023
10241
|
return true;
|
|
10024
10242
|
// Single child at `ip + 2`.
|
|
10025
10243
|
case OP_GATE:
|
|
@@ -10036,55 +10254,55 @@ function childSlots(code, ip, out) {
|
|
|
10036
10254
|
case OP_ARMGATE:
|
|
10037
10255
|
case OP_RGATE:
|
|
10038
10256
|
case OP_RGATE2:
|
|
10039
|
-
out.push(
|
|
10257
|
+
out.push(ip + 2);
|
|
10040
10258
|
return true;
|
|
10041
10259
|
// `STRICT strict tolerant` — both encodings are reachable; an assembly keeps one.
|
|
10042
10260
|
case OP_STRICT:
|
|
10043
|
-
out.push(
|
|
10261
|
+
out.push(ip + 1, ip + 2);
|
|
10044
10262
|
return true;
|
|
10045
10263
|
// `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
|
|
10046
10264
|
// data the enclosing `dispatch()` already consumed, so the only edge is the
|
|
10047
10265
|
// fallback.
|
|
10048
10266
|
case OP_ROUTED:
|
|
10049
|
-
if (code[ip + 1] >= 0) out.push(
|
|
10267
|
+
if (code[ip + 1] >= 0) out.push(ip + 1);
|
|
10050
10268
|
return true;
|
|
10051
10269
|
// `DISPATCH sel d other otherRouted n a1 … an` — the SELECTOR is a child on
|
|
10052
10270
|
// exactly the same footing as the arms: it runs inside whatever node and scope
|
|
10053
10271
|
// this site sits in.
|
|
10054
10272
|
case OP_DISPATCH: {
|
|
10055
|
-
out.push(
|
|
10056
|
-
if (code[ip + 3] >= 0) out.push(
|
|
10273
|
+
out.push(ip + 1);
|
|
10274
|
+
if (code[ip + 3] >= 0) out.push(ip + 3);
|
|
10057
10275
|
const n = code[ip + 5];
|
|
10058
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10276
|
+
for (let i = 0; i < n; i++) out.push(ip + 6 + i);
|
|
10059
10277
|
return true;
|
|
10060
10278
|
}
|
|
10061
10279
|
case OP_SEQ:
|
|
10062
10280
|
case OP_SEQV: {
|
|
10063
10281
|
const n = code[ip + 1];
|
|
10064
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10282
|
+
for (let i = 0; i < n; i++) out.push(ip + 2 + i);
|
|
10065
10283
|
return true;
|
|
10066
10284
|
}
|
|
10067
10285
|
case OP_SEQX: {
|
|
10068
10286
|
const n = code[ip + 2];
|
|
10069
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10287
|
+
for (let i = 0; i < n; i++) out.push(ip + 3 + i);
|
|
10070
10288
|
return true;
|
|
10071
10289
|
}
|
|
10072
10290
|
case OP_CHOICE: {
|
|
10073
10291
|
const n = code[ip + 2];
|
|
10074
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10292
|
+
for (let i = 0; i < n; i++) out.push(ip + 4 + i);
|
|
10075
10293
|
return true;
|
|
10076
10294
|
}
|
|
10077
10295
|
// Arms are stride-2 from `ip + 4` — the gate word sits beside each arm offset.
|
|
10078
10296
|
case OP_GREEDY: {
|
|
10079
|
-
out.push(
|
|
10297
|
+
out.push(ip + 1);
|
|
10080
10298
|
const n = code[ip + 2];
|
|
10081
|
-
for (let i = 0; i < n; i++) out.push(
|
|
10299
|
+
for (let i = 0; i < n; i++) out.push(ip + 4 + 2 * i);
|
|
10082
10300
|
return true;
|
|
10083
10301
|
}
|
|
10084
10302
|
case OP_REP:
|
|
10085
10303
|
case OP_REPV:
|
|
10086
|
-
out.push(
|
|
10087
|
-
if (code[ip + 4] >= 0) out.push(
|
|
10304
|
+
out.push(ip + 1);
|
|
10305
|
+
if (code[ip + 4] >= 0) out.push(ip + 4);
|
|
10088
10306
|
return true;
|
|
10089
10307
|
default:
|
|
10090
10308
|
return false;
|
|
@@ -10899,7 +11117,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
|
|
|
10899
11117
|
const swapLegal = !cfg.trackLines;
|
|
10900
11118
|
const hostCst = cfg.hostCst;
|
|
10901
11119
|
const LOGS = (prog.triviaSpecs?.length ?? 0) > 0 || cfg.inheritedTrivia === true;
|
|
10902
|
-
const
|
|
11120
|
+
const REC2 = prog.rec === 1 && cfg.tolerant;
|
|
10903
11121
|
if (cfg.coverage) throw new Unemittable("a coverage assembly");
|
|
10904
11122
|
const roots = [...Object.values(prog.rules), ...extraIps];
|
|
10905
11123
|
const reachable = [...reachableSites(code, roots)];
|
|
@@ -10972,7 +11190,7 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false, s
|
|
|
10972
11190
|
const op = code[ip];
|
|
10973
11191
|
sinkBits.set(
|
|
10974
11192
|
ip,
|
|
10975
|
-
op === OP_SCAN || !scanSinkNeutral && op === OP_LEX_PROGRAM && t2.lexPrograms[code[ip + 1]].scan !== void 0 ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT ||
|
|
11193
|
+
op === OP_SCAN || !scanSinkNeutral && op === OP_LEX_PROGRAM && t2.lexPrograms[code[ip + 1]].scan !== void 0 ? 3 : (op === OP_FIELD ? 1 : 0) | (op === OP_EXPECT || REC2 && (op === OP_REP || op === OP_REPV) ? 2 : 0)
|
|
10976
11194
|
);
|
|
10977
11195
|
}
|
|
10978
11196
|
const sinkKids = [];
|
|
@@ -11497,7 +11715,7 @@ if(v!==FAIL)return v
|
|
|
11497
11715
|
const err={_tag:'parseError',span:${prog.lines === 1 ? "spanLines(ctx,pos,pos)" : "new _SP(pos,pos)"},expected:${xf}}
|
|
11498
11716
|
const es=ctx._errors
|
|
11499
11717
|
if(es!==undefined)es.push(err)
|
|
11500
|
-
${
|
|
11718
|
+
${REC2 ? "if(ctx._tolerant===true)captureError(ctx,err)\n" : ""}ctx._fc=false
|
|
11501
11719
|
EC.e=pos
|
|
11502
11720
|
return err
|
|
11503
11721
|
}`;
|
|
@@ -11627,7 +11845,7 @@ return v
|
|
|
11627
11845
|
}
|
|
11628
11846
|
case OP_LEX_PROGRAM: {
|
|
11629
11847
|
const programId = code[ip + 1];
|
|
11630
|
-
const
|
|
11848
|
+
const run2 = hoist("lexProgram", `LEXPROG[${programId}]`);
|
|
11631
11849
|
const scanId = t2.lexPrograms[programId].scan;
|
|
11632
11850
|
if (scanId !== void 0) return `${head}
|
|
11633
11851
|
const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan
|
|
@@ -11645,7 +11863,7 @@ ctx._cstTriviaLog=undefined
|
|
|
11645
11863
|
ctx._triviaLog=undefined
|
|
11646
11864
|
ctx._rootTriviaLog=undefined
|
|
11647
11865
|
let e
|
|
11648
|
-
try{e=${
|
|
11866
|
+
try{e=${run2}(input,pos,ctx,SCANS[${scanId}])}finally{
|
|
11649
11867
|
_pfScan=sScan
|
|
11650
11868
|
ctx.trivia=sTri
|
|
11651
11869
|
ctx.triviaKindLabels=sKinds
|
|
@@ -11664,7 +11882,7 @@ EC.e=e
|
|
|
11664
11882
|
return v
|
|
11665
11883
|
}`;
|
|
11666
11884
|
return `${head}
|
|
11667
|
-
const e=${
|
|
11885
|
+
const e=${run2}(input,pos,ctx)
|
|
11668
11886
|
if(e<0)return FAIL
|
|
11669
11887
|
const v=input.slice(pos,e)
|
|
11670
11888
|
if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,new _LF(v,new _SP(pos,e)))
|
|
@@ -11675,7 +11893,7 @@ return v
|
|
|
11675
11893
|
/* ── transaction ─────────────────────────────────────────────────────── */
|
|
11676
11894
|
case OP_ATTEMPT: {
|
|
11677
11895
|
const child = link(code[ip + 1]);
|
|
11678
|
-
const clean = !
|
|
11896
|
+
const clean = !REC2 && failureRollbackClean(prog, ip);
|
|
11679
11897
|
const logs = clean && LOGS && failureLogRollback(prog, ip);
|
|
11680
11898
|
const p = tmp();
|
|
11681
11899
|
return `${head}
|
|
@@ -11741,7 +11959,7 @@ return null
|
|
|
11741
11959
|
}
|
|
11742
11960
|
case OP_OPT: {
|
|
11743
11961
|
const child = link(code[ip + 1]);
|
|
11744
|
-
const clean = !
|
|
11962
|
+
const clean = !REC2 && failureRollbackClean(prog, ip);
|
|
11745
11963
|
const logs = clean && LOGS && failureLogRollback(prog, ip);
|
|
11746
11964
|
const p = tmp();
|
|
11747
11965
|
return `${head}
|
|
@@ -11772,15 +11990,15 @@ return v
|
|
|
11772
11990
|
const childIp = code[base + i];
|
|
11773
11991
|
kids.push(code[childIp] === OP_ADJ ? "" : link(childIp));
|
|
11774
11992
|
}
|
|
11775
|
-
const sy =
|
|
11993
|
+
const sy = REC2 ? `${tmp()}sy` : "";
|
|
11776
11994
|
const pub = (i) => {
|
|
11777
11995
|
const s = sentRef(code[base + n + i]);
|
|
11778
11996
|
return s === "undefined" ? `ctx._sync=${sy}` : `ctx._sync=${s}??${sy}`;
|
|
11779
11997
|
};
|
|
11780
11998
|
const parts = [head];
|
|
11781
|
-
if (
|
|
11999
|
+
if (REC2) parts.push(`const ${sy}=ctx._sync`, "try{", pub(0));
|
|
11782
12000
|
parts.push(`const v0=${kids[0]}(input,pos,ctx)`, "if(v0===FAIL)return FAIL");
|
|
11783
|
-
const close = () =>
|
|
12001
|
+
const close = () => REC2 ? `${parts.join("\n")}
|
|
11784
12002
|
}finally{ctx._sync=${sy}}
|
|
11785
12003
|
}` : `${parts.join("\n")}
|
|
11786
12004
|
}`;
|
|
@@ -11793,7 +12011,7 @@ return v
|
|
|
11793
12011
|
for (let i = 1; i < n; i++) {
|
|
11794
12012
|
const vn = `v${i}`;
|
|
11795
12013
|
parts.push(`let ${vn}`);
|
|
11796
|
-
if (
|
|
12014
|
+
if (REC2) parts.push(pub(i));
|
|
11797
12015
|
const childIp = code[base + i];
|
|
11798
12016
|
if (code[childIp] === OP_ADJ) {
|
|
11799
12017
|
const negated = code[childIp + 1] === 1;
|
|
@@ -11898,7 +12116,7 @@ return FAIL
|
|
|
11898
12116
|
if (maskable) maskPlan.push(~di);
|
|
11899
12117
|
const p = tmp();
|
|
11900
12118
|
const encodedRollbackMask = choiceRollbackMask(prog, ip) ?? -1;
|
|
11901
|
-
const rollbackMask =
|
|
12119
|
+
const rollbackMask = REC2 ? -1 : encodedRollbackMask;
|
|
11902
12120
|
const hasRollback = rollbackMask !== 0;
|
|
11903
12121
|
const logMask = rollbackMask === -1 || !LOGS ? 0 : choiceLogRollbackMask(prog, ip);
|
|
11904
12122
|
const choiceMark = hasRollback ? emitMark(p, L.buf, L.raw, sinks) : "";
|
|
@@ -12151,7 +12369,7 @@ return [key,v]
|
|
|
12151
12369
|
const collect = op === OP_REP;
|
|
12152
12370
|
let itemCls;
|
|
12153
12371
|
let itemAscii = false;
|
|
12154
|
-
if (!
|
|
12372
|
+
if (!REC2) {
|
|
12155
12373
|
const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
|
|
12156
12374
|
if (itemClassIndex >= 0) {
|
|
12157
12375
|
const resolved = t2.cc[itemClassIndex];
|
|
@@ -12164,14 +12382,14 @@ return [key,v]
|
|
|
12164
12382
|
const itemMiss = (at) => itemAscii ? `${itemCls}.ascii[input.charCodeAt(${at})]!==1` : `!classHas(${itemCls},lead(input,${at}))`;
|
|
12165
12383
|
let sepCls;
|
|
12166
12384
|
let sepAscii = false;
|
|
12167
|
-
if (!
|
|
12385
|
+
if (!REC2 && sepIp >= 0 && (code[ip + 5] & 8) !== 0 && !leadingTriviaFieldAt(code, k, sepIp) && !rowNullable(code, k, sepIp, nullable2)) {
|
|
12168
12386
|
const resolved = t2.cc[code[ip + 8]];
|
|
12169
12387
|
const ci = classes.push([resolved]) - 1;
|
|
12170
12388
|
classPlan.push([code[ip + 8]]);
|
|
12171
12389
|
sepCls = hoist("rs", `CLS[${ci}][0]`);
|
|
12172
12390
|
sepAscii = isAsciiOnlyClass(resolved);
|
|
12173
12391
|
}
|
|
12174
|
-
const gapIp = !gapNeutral && sepIp < 0 && min === 0 && !
|
|
12392
|
+
const gapIp = !gapNeutral && sepIp < 0 && min === 0 && !REC2 && code[code[ip + 1]] === OP_GAPGATE ? code[ip + 1] : -1;
|
|
12175
12393
|
let gapCode = (_rb) => "";
|
|
12176
12394
|
if (gapIp >= 0) {
|
|
12177
12395
|
const row = code[gapIp + 2];
|
|
@@ -12256,11 +12474,11 @@ ${p}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
|
|
|
12256
12474
|
${p}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0${markSinks}
|
|
12257
12475
|
}`;
|
|
12258
12476
|
const my = `${p}my`;
|
|
12259
|
-
const recFx = !
|
|
12260
|
-
const sepSent =
|
|
12477
|
+
const recFx = !REC2 ? "" : (flags & 16) !== 0 ? "[]" : fxRef(code[ip + 6]);
|
|
12478
|
+
const sepSent = REC2 ? sentRef(code[ip + 7]) : "undefined";
|
|
12261
12479
|
const recSent = sep === void 0 ? my : sepSent === "undefined" ? `orSentinel(${my},undefined)` : `orSentinel(${sepSent}??${my},${sepSent}===undefined?undefined:${my})`;
|
|
12262
12480
|
const recGate = sep !== void 0 || min === 0 ? "" : `count>=${min}&&`;
|
|
12263
|
-
const recBranch = !
|
|
12481
|
+
const recBranch = !REC2 ? "" : `if(ctx._tolerant===true&&${my}!==undefined&&${recGate}!matchesAt(${my},input,itemStart,ctx)){
|
|
12264
12482
|
${sep === void 0 ? `${rb}
|
|
12265
12483
|
` : ""}const rr=recoverScan(input,itemStart,ctx,${recSent},${recFx})
|
|
12266
12484
|
${collect ? "out.push(rr.error)\n" : ""}captureError(ctx,rr.error)
|
|
@@ -12271,7 +12489,7 @@ continue
|
|
|
12271
12489
|
`;
|
|
12272
12490
|
return `${head}
|
|
12273
12491
|
const out=${collect ? "[]" : "undefined"}
|
|
12274
|
-
${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${
|
|
12492
|
+
${knownTrivia === void 0 ? "const hasTrivia=ctx.trivia!==undefined\n" : ""}${L.buf ? "" : "const needMark=_rollbackNeeded(ctx)\n"}${REC2 ? `const ${my}=ctx._sync
|
|
12275
12493
|
` : ""}${itemCls === void 0 && sepCls === void 0 ? "" : `const ${p}gate=ctx._probe===undefined
|
|
12276
12494
|
`}let cur=pos
|
|
12277
12495
|
let count=0
|
|
@@ -12314,7 +12532,7 @@ ${trailingAllowed ? "if(sepEnd>=0)cur=sepEnd\n" : ""}break
|
|
|
12314
12532
|
`}${gapCode(rb)}ctx._fc=false
|
|
12315
12533
|
const v=${child}(input,itemStart,ctx)
|
|
12316
12534
|
${gapIp >= 0 ? "if(gapped)GAP.at=-1\n" : ""}if(v===FAIL){
|
|
12317
|
-
${
|
|
12535
|
+
${REC2 ? `if(ctx._fc===true){
|
|
12318
12536
|
${rb}
|
|
12319
12537
|
return FAIL
|
|
12320
12538
|
}
|
|
@@ -12540,13 +12758,13 @@ return nd
|
|
|
12540
12758
|
}
|
|
12541
12759
|
}
|
|
12542
12760
|
const served = (ip) => select === void 0 || select.has(resolveAlias(ip));
|
|
12543
|
-
const
|
|
12761
|
+
const ruleEntries2 = [];
|
|
12544
12762
|
for (const [rname, entryIp] of Object.entries(prog.rules)) {
|
|
12545
12763
|
if (!served(entryIp)) continue;
|
|
12546
12764
|
const target = link(entryIp);
|
|
12547
12765
|
const rn = `_r_${rname.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
12548
12766
|
bodies.push(`const ${rn}=${target}`);
|
|
12549
|
-
|
|
12767
|
+
ruleEntries2.push(`${q(rname)}:${rn}`);
|
|
12550
12768
|
}
|
|
12551
12769
|
const extra = [];
|
|
12552
12770
|
const exported = /* @__PURE__ */ new Set();
|
|
@@ -12612,7 +12830,7 @@ _pfHost=prior[1]
|
|
|
12612
12830
|
EC.e=prior[2]
|
|
12613
12831
|
}
|
|
12614
12832
|
return{
|
|
12615
|
-
pieces:{${
|
|
12833
|
+
pieces:{${ruleEntries2.join(",")}},
|
|
12616
12834
|
byIp:{${extra.join(",")}},
|
|
12617
12835
|
end:function(){return EC.e},
|
|
12618
12836
|
begin:_begin,
|
|
@@ -12721,31 +12939,31 @@ function lines(prefix, body, options = {}) {
|
|
|
12721
12939
|
_def: { tag: "lines", prefix, body, ...first === void 0 ? {} : { first }, ...lazy === void 0 ? {} : { lazy } },
|
|
12722
12940
|
parse(input, pos, ctx) {
|
|
12723
12941
|
const c = ctx;
|
|
12724
|
-
const
|
|
12725
|
-
|
|
12726
|
-
const
|
|
12942
|
+
const probe2 = createDetachedParseContext(false, ctx.state);
|
|
12943
|
+
probe2.lineView = c.lineView;
|
|
12944
|
+
const run2 = [];
|
|
12727
12945
|
const parts = [];
|
|
12728
12946
|
let offset = 0;
|
|
12729
12947
|
for (let start = pos; start < input.length || start === pos; ) {
|
|
12730
12948
|
let end2 = input.indexOf("\n", start);
|
|
12731
12949
|
if (end2 < 0) end2 = input.length;
|
|
12732
|
-
|
|
12733
|
-
const head = (
|
|
12950
|
+
probe2._columnsSplit = void 0;
|
|
12951
|
+
const head = (run2.length === 0 ? opening : prefix).parse(input, start, probe2);
|
|
12734
12952
|
let content;
|
|
12735
12953
|
let joined;
|
|
12736
12954
|
if (head.ok && head.span.end <= end2) {
|
|
12737
12955
|
content = head.span.end;
|
|
12738
12956
|
joined = "prefix";
|
|
12739
|
-
} else if (
|
|
12957
|
+
} else if (run2.length === 0) {
|
|
12740
12958
|
return { ok: false, expected: head.ok ? ["line prefix"] : head.expected, span: { start, end: start } };
|
|
12741
|
-
} else if (lazy !== void 0 && lazy.parse(input, start,
|
|
12959
|
+
} else if (lazy !== void 0 && lazy.parse(input, start, probe2).ok) {
|
|
12742
12960
|
content = start;
|
|
12743
12961
|
joined = "lazy";
|
|
12744
12962
|
} else break;
|
|
12745
|
-
const mark =
|
|
12963
|
+
const mark = probe2._columnsSplit;
|
|
12746
12964
|
const here = columnAt(input, content, c);
|
|
12747
12965
|
const split = joined === "prefix" && mark !== void 0 && mark.at === content ? mark.split : here.split;
|
|
12748
|
-
|
|
12966
|
+
run2.push({ offset, source: content, end: end2, column: here.column + (split - here.split), split, lazy: joined === "lazy" });
|
|
12749
12967
|
const text = input.slice(content, end2);
|
|
12750
12968
|
const newline = end2 < input.length;
|
|
12751
12969
|
parts.push(newline ? `${text}
|
|
@@ -12754,11 +12972,11 @@ function lines(prefix, body, options = {}) {
|
|
|
12754
12972
|
start = end2 + 1;
|
|
12755
12973
|
if (!newline) break;
|
|
12756
12974
|
}
|
|
12757
|
-
const view = { lines:
|
|
12975
|
+
const view = { lines: run2, parent: c.lineView };
|
|
12758
12976
|
const saved = c.lineView, starts = c._lineStarts, lineIndex = c._lineIndex, scanned = c._lineScannedTo, probing = c._probe;
|
|
12759
12977
|
const errors = c._errors?.length ?? 0;
|
|
12760
12978
|
let cursor = -1;
|
|
12761
|
-
if (probing !== void 0) for (const line2 of
|
|
12979
|
+
if (probing !== void 0) for (const line2 of run2) {
|
|
12762
12980
|
if (probing.offset >= line2.source && probing.offset <= line2.end) {
|
|
12763
12981
|
cursor = line2.offset + probing.offset - line2.source;
|
|
12764
12982
|
break;
|
|
@@ -12791,8 +13009,8 @@ function lines(prefix, body, options = {}) {
|
|
|
12791
13009
|
}
|
|
12792
13010
|
const stop = result.span.end;
|
|
12793
13011
|
const index = lineIndexAt(view, stop);
|
|
12794
|
-
const line =
|
|
12795
|
-
const end = stop === line.offset && index > 0 ?
|
|
13012
|
+
const line = run2[index];
|
|
13013
|
+
const end = stop === line.offset && index > 0 ? run2[index - 1].end + 1 : stop - line.offset > line.end - line.source ? line.end + 1 : line.source + (stop - line.offset);
|
|
12796
13014
|
recordLineRangeFromContext(c, input, pos, end);
|
|
12797
13015
|
return { ok: true, value: result.value, span: { start: pos, end } };
|
|
12798
13016
|
}
|
|
@@ -12901,12 +13119,12 @@ function literal(value, opts = {}) {
|
|
|
12901
13119
|
}
|
|
12902
13120
|
|
|
12903
13121
|
// src/combinators/ref.ts
|
|
12904
|
-
function withRuleTrivia(trivia2, ctx,
|
|
13122
|
+
function withRuleTrivia(trivia2, ctx, run2) {
|
|
12905
13123
|
const savedLabels = ctx.triviaKindLabels;
|
|
12906
13124
|
ctx.trivia = trivia2;
|
|
12907
13125
|
ctx.triviaKindLabels = trivia2._meta.triviaKindLabels;
|
|
12908
13126
|
try {
|
|
12909
|
-
return
|
|
13127
|
+
return run2();
|
|
12910
13128
|
} finally {
|
|
12911
13129
|
ctx.trivia = void 0;
|
|
12912
13130
|
ctx.triviaKindLabels = savedLabels;
|
|
@@ -13285,9 +13503,6 @@ function clearOf(ranges, input, from, to) {
|
|
|
13285
13503
|
return true;
|
|
13286
13504
|
}
|
|
13287
13505
|
|
|
13288
|
-
// src/version.ts
|
|
13289
|
-
var PARSEMAN_VERSION = "0.60.6";
|
|
13290
|
-
|
|
13291
13506
|
// src/table/assemble.ts
|
|
13292
13507
|
import { PlainBuf as PlainBuf2, PlainField, PlainLeaf as PlainLeaf9, PlainNode as PlainNode2, PlainSpan as PlainSpan10 } from "../cst/plain.js";
|
|
13293
13508
|
|
|
@@ -13411,6 +13626,19 @@ function failCleanAnalysis(code) {
|
|
|
13411
13626
|
// src/cst/host-mode.ts
|
|
13412
13627
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
13413
13628
|
var FUSED_HOST_ELIDED = /* @__PURE__ */ Symbol.for("parseman.fusedHostElided");
|
|
13629
|
+
function assertHostModeCompatible(mode, build, hostBranchElided = true) {
|
|
13630
|
+
const isCstHost = build?._parsemanCstOutput === true;
|
|
13631
|
+
if (mode === "ast" && isCstHost && hostBranchElided) {
|
|
13632
|
+
throw new Error(
|
|
13633
|
+
"parseman: this parser was compiled for host mode \"ast\" (the default), so its nodes build through their own `build` callbacks and no positioned-CST branch was emitted. It cannot be driven with a positioned-CST host (cstBuildHost / a language-service host). Compile a second artifact from the SAME grammar with `compile(grammar, { hostMode: 'cst' })` \u2014 or, under the macro, a second `rules({ hostMode: 'cst' }, factory)` call site \u2014 and drive that one instead."
|
|
13634
|
+
);
|
|
13635
|
+
}
|
|
13636
|
+
if (mode === "cst" && !isCstHost) {
|
|
13637
|
+
throw new Error(
|
|
13638
|
+
'parseman: this parser was compiled for host mode "cst", so every node builds through a positioned-CST `ctx.build` host. Pass one (e.g. `{ build: cstBuildHost }`), or use an artifact compiled with the default `hostMode: "ast"` to get the grammar\'s own AST.'
|
|
13639
|
+
);
|
|
13640
|
+
}
|
|
13641
|
+
}
|
|
13414
13642
|
|
|
13415
13643
|
// src/grammar-metadata.ts
|
|
13416
13644
|
var GRAMMAR_COVERAGE_DEFINITIONS = /* @__PURE__ */ Symbol.for("parseman.grammarCoverageDefinitions");
|
|
@@ -13545,8 +13773,8 @@ function linkMatcher(m) {
|
|
|
13545
13773
|
}
|
|
13546
13774
|
var NO_COVERAGE = (_id) => {
|
|
13547
13775
|
};
|
|
13548
|
-
function cfgKeyOf(hostCst, trackLines, tolerant, coverage,
|
|
13549
|
-
return (hostCst ? 1 : 0) | (trackLines ? 2 : 0) | (tolerant ? 4 : 0) | (coverage ? 8 : 0) | (
|
|
13776
|
+
function cfgKeyOf(hostCst, trackLines, tolerant, coverage, probe2, hostReadsChildren = true, inheritedTrivia = false) {
|
|
13777
|
+
return (hostCst ? 1 : 0) | (trackLines ? 2 : 0) | (tolerant ? 4 : 0) | (coverage ? 8 : 0) | (probe2 ? 16 : 0) | (hostReadsChildren ? 0 : 32) | (inheritedTrivia ? 64 : 0);
|
|
13550
13778
|
}
|
|
13551
13779
|
function cfgKey(c) {
|
|
13552
13780
|
return cfgKeyOf(c.hostCst, c.trackLines, c.tolerant, c.coverage, c.probe, c.hostReadsChildren, c.inheritedTrivia);
|
|
@@ -13563,7 +13791,7 @@ function assemble(t2, prog, cfg) {
|
|
|
13563
13791
|
const triviaScan = t2.triviaScan;
|
|
13564
13792
|
const swapLegal = !cfg.trackLines;
|
|
13565
13793
|
const hostCst = cfg.hostCst;
|
|
13566
|
-
const
|
|
13794
|
+
const REC2 = prog.rec === 1 && cfg.tolerant;
|
|
13567
13795
|
const PROBE = cfg.probe;
|
|
13568
13796
|
const sentinels = /* @__PURE__ */ new Map();
|
|
13569
13797
|
function sentinelFor(cls) {
|
|
@@ -13613,7 +13841,7 @@ function assemble(t2, prog, cfg) {
|
|
|
13613
13841
|
const memo = /* @__PURE__ */ new Map();
|
|
13614
13842
|
const reached = /* @__PURE__ */ new Set();
|
|
13615
13843
|
const NULLABLE = /* @__PURE__ */ new Map();
|
|
13616
|
-
const CLEAN =
|
|
13844
|
+
const CLEAN = REC2 ? () => false : failCleanAnalysis(code);
|
|
13617
13845
|
function pushLeaf(ctx, value, s, e) {
|
|
13618
13846
|
const lf = new PlainLeaf9(value, new PlainSpan10(s, e));
|
|
13619
13847
|
pushCstLeaf(ctx, lf);
|
|
@@ -14324,7 +14552,7 @@ function assemble(t2, prog, cfg) {
|
|
|
14324
14552
|
};
|
|
14325
14553
|
function lookaheadLedNode(ip) {
|
|
14326
14554
|
const op = code[ip];
|
|
14327
|
-
if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst ||
|
|
14555
|
+
if (op !== OP_NODE && op !== OP_NODE_TRACK || hostCst || REC2 || cfg.probe || cfg.coverage || cfg.trackLines) return void 0;
|
|
14328
14556
|
if (passCollapse(code, ip, hostCst) || gatedPassCollapse(code, ip, hostCst) !== void 0) return void 0;
|
|
14329
14557
|
const body = code[ip + 2];
|
|
14330
14558
|
const bop = code[body];
|
|
@@ -14700,7 +14928,7 @@ function assemble(t2, prog, cfg) {
|
|
|
14700
14928
|
const child = link(code[ip + 1]);
|
|
14701
14929
|
const xf = fx[code[ip + 2]];
|
|
14702
14930
|
const expectSpan = (ctx, pos) => prog.lines === 1 ? spanLines(ctx, pos, pos) : new PlainSpan10(pos, pos);
|
|
14703
|
-
if (
|
|
14931
|
+
if (REC2) {
|
|
14704
14932
|
return (input, pos, ctx) => {
|
|
14705
14933
|
const v = child(input, pos, ctx);
|
|
14706
14934
|
if (v !== FAIL) return v;
|
|
@@ -15097,8 +15325,8 @@ function assemble(t2, prog, cfg) {
|
|
|
15097
15325
|
};
|
|
15098
15326
|
}
|
|
15099
15327
|
case OP_LEX_PROGRAM: {
|
|
15100
|
-
const
|
|
15101
|
-
const scanId =
|
|
15328
|
+
const run2 = t2.lexPrograms[code[ip + 1]];
|
|
15329
|
+
const scanId = run2.scan;
|
|
15102
15330
|
if (scanId !== void 0) {
|
|
15103
15331
|
return (input, pos, ctx) => {
|
|
15104
15332
|
const sTrivia = ctx.trivia, sKinds = ctx.triviaKindLabels;
|
|
@@ -15119,7 +15347,7 @@ function assemble(t2, prog, cfg) {
|
|
|
15119
15347
|
ctx._rootTriviaLog = void 0;
|
|
15120
15348
|
let end;
|
|
15121
15349
|
try {
|
|
15122
|
-
end =
|
|
15350
|
+
end = run2(input, pos, ctx, scans[scanId]);
|
|
15123
15351
|
} finally {
|
|
15124
15352
|
SCAN = sScan;
|
|
15125
15353
|
ctx.trivia = sTrivia;
|
|
@@ -15140,7 +15368,7 @@ function assemble(t2, prog, cfg) {
|
|
|
15140
15368
|
};
|
|
15141
15369
|
}
|
|
15142
15370
|
return (input, pos, ctx) => {
|
|
15143
|
-
const end =
|
|
15371
|
+
const end = run2(input, pos, ctx);
|
|
15144
15372
|
if (end < 0) return FAIL;
|
|
15145
15373
|
const value = input.slice(pos, end);
|
|
15146
15374
|
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, new PlainLeaf9(value, new PlainSpan10(pos, end)));
|
|
@@ -15241,7 +15469,7 @@ function assemble(t2, prog, cfg) {
|
|
|
15241
15469
|
return next === void 0 ? cur : next(input, cur, ctx, values, inherited);
|
|
15242
15470
|
};
|
|
15243
15471
|
};
|
|
15244
|
-
if (
|
|
15472
|
+
if (REC2) {
|
|
15245
15473
|
const first2 = linkFirst();
|
|
15246
15474
|
const firstSync = sentinelFor(code[base + n]);
|
|
15247
15475
|
const runnerAt = (i) => {
|
|
@@ -15730,7 +15958,7 @@ function assemble(t2, prog, cfg) {
|
|
|
15730
15958
|
if (n === 2 || n === 3) {
|
|
15731
15959
|
const a0 = link(code[base]), a1 = link(code[base + 1]);
|
|
15732
15960
|
const a2 = n === 3 ? link(code[base + 2]) : void 0;
|
|
15733
|
-
const predecide = !
|
|
15961
|
+
const predecide = !REC2 && !cfg.probe && !cfg.coverage && !cfg.trackLines;
|
|
15734
15962
|
const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
|
|
15735
15963
|
const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
|
|
15736
15964
|
const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
|
|
@@ -15960,7 +16188,7 @@ function assemble(t2, prog, cfg) {
|
|
|
15960
16188
|
const masked = bindMasked(0, EMPTY_EXPECTED_PREFIX);
|
|
15961
16189
|
const pBit = [];
|
|
15962
16190
|
const pRec = [];
|
|
15963
|
-
if (!
|
|
16191
|
+
if (!REC2 && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
|
|
15964
16192
|
for (let i = 0; i < n; i++) {
|
|
15965
16193
|
for (const terminal of largeChoiceLiteralPretest(code, k, code[base + i]) ?? []) {
|
|
15966
16194
|
pBit.push(1 << i);
|
|
@@ -16248,18 +16476,18 @@ function assemble(t2, prog, cfg) {
|
|
|
16248
16476
|
const itemFx = reportItem ? fx[code[ip + 6]] : EMPTY_FX2;
|
|
16249
16477
|
const collect = op === OP_REP;
|
|
16250
16478
|
const itemClassIndex = sepIp < 0 ? code[ip + 7] : -1;
|
|
16251
|
-
const itemClass = !
|
|
16479
|
+
const itemClass = !REC2 && itemClassIndex >= 0 ? cc[itemClassIndex] : void 0;
|
|
16252
16480
|
const itemMayStart = itemClass === void 0 ? void 0 : (input, pos) => classHas2(itemClass, lead(input, pos));
|
|
16253
16481
|
const sepClassIndex = sepIp >= 0 && !sepLeads && (flags & 8) !== 0 ? code[ip + 8] : -1;
|
|
16254
|
-
const sepClass = !
|
|
16255
|
-
const gapIp = sepIp < 0 && min === 0 && !
|
|
16482
|
+
const sepClass = !REC2 && sepClassIndex >= 0 && !rowNullable(code, k, sepIp, NULLABLE) ? cc[sepClassIndex] : void 0;
|
|
16483
|
+
const gapIp = sepIp < 0 && min === 0 && !REC2 && code[code[ip + 1]] === OP_GAPGATE ? code[ip + 1] : -1;
|
|
16256
16484
|
const gapRow = gapIp >= 0 ? code[gapIp + 2] : -1;
|
|
16257
16485
|
const gapRe = gapIp >= 0 ? k[code[gapRow + 1]] : void 0;
|
|
16258
16486
|
const gapFollow = gapIp >= 0 ? cc[code[gapIp + 3]] : void 0;
|
|
16259
16487
|
const gapOther = gapIp >= 0 && code[gapIp + 4] >= 0 ? cc[code[gapIp + 4]] : void 0;
|
|
16260
16488
|
const skipBeforeFirst = sepIp < 0 && min === 0;
|
|
16261
16489
|
const itemClean = sepIp < 0 && CLEAN(code[ip + 1]) && !rowNullable(code, k, code[ip + 1], NULLABLE);
|
|
16262
|
-
if (
|
|
16490
|
+
if (REC2) {
|
|
16263
16491
|
const itemFx2 = fx[code[ip + 6]];
|
|
16264
16492
|
const recFx = (flags & 16) !== 0 ? EMPTY_FX2 : itemFx2;
|
|
16265
16493
|
const sepSent = sentinelFor(code[ip + 7]);
|
|
@@ -16469,10 +16697,10 @@ function assemble(t2, prog, cfg) {
|
|
|
16469
16697
|
const hasFold = spec.byFold.size > 0;
|
|
16470
16698
|
const match = spec.match;
|
|
16471
16699
|
const matchN = match.length;
|
|
16472
|
-
const
|
|
16700
|
+
const routed2 = spec.routed;
|
|
16473
16701
|
const expected = spec.expected;
|
|
16474
16702
|
const validArm = (arm) => Number.isInteger(arm) && arm >= 0 && arm < n;
|
|
16475
|
-
if (
|
|
16703
|
+
if (routed2.length !== n) throw new TypeError("table assembler: malformed dispatch routed arity");
|
|
16476
16704
|
for (const arm of byKey.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch exact arm");
|
|
16477
16705
|
for (const arm of byFold.values()) if (!validArm(arm)) throw new TypeError("table assembler: malformed dispatch folded arm");
|
|
16478
16706
|
for (const m of match) if (!validArm(m[3])) throw new TypeError("table assembler: malformed dispatch matcher arm");
|
|
@@ -16497,7 +16725,7 @@ function assemble(t2, prog, cfg) {
|
|
|
16497
16725
|
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);
|
|
16498
16726
|
const neverBranch = () => FAIL;
|
|
16499
16727
|
const bindArms = (start) => {
|
|
16500
|
-
const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]),
|
|
16728
|
+
const branch = (i) => i < n ? dispatchBranch(link(code[armBase + i]), routed2[i] === 1) : neverBranch;
|
|
16501
16729
|
const next = start + 4 < n ? bindArms(start + 4) : void 0;
|
|
16502
16730
|
return dispatchArmBlock(
|
|
16503
16731
|
start,
|
|
@@ -16812,7 +17040,7 @@ function assemble(t2, prog, cfg) {
|
|
|
16812
17040
|
lead,
|
|
16813
17041
|
asciiFoldKey,
|
|
16814
17042
|
ROUTED_FX,
|
|
16815
|
-
|
|
17043
|
+
REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
|
|
16816
17044
|
matchesAt,
|
|
16817
17045
|
recoverScan,
|
|
16818
17046
|
orSentinel,
|
|
@@ -16901,7 +17129,7 @@ function assemble(t2, prog, cfg) {
|
|
|
16901
17129
|
// — a strict one emits no reader — and through the SAME `sentinelFor` memo
|
|
16902
17130
|
// the closure pieces use, so both engines resync to the same combinator
|
|
16903
17131
|
// object rather than to two separately constructed ones.
|
|
16904
|
-
|
|
17132
|
+
REC2 ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
|
|
16905
17133
|
matchesAt,
|
|
16906
17134
|
recoverScan,
|
|
16907
17135
|
orSentinel,
|
|
@@ -17116,9 +17344,9 @@ var AssemblyCache = class {
|
|
|
17116
17344
|
const trackLines = ctx.trackLines === true;
|
|
17117
17345
|
const tolerant = ctx._tolerant === true;
|
|
17118
17346
|
const coverage = ctx._grammarCoverage !== void 0;
|
|
17119
|
-
const
|
|
17347
|
+
const probe2 = ctx._probe !== void 0;
|
|
17120
17348
|
const inheritedTrivia = this.noOwnTrivia && ctx.trivia !== void 0;
|
|
17121
|
-
const key = cfgKeyOf(hostCst, trackLines, tolerant, coverage,
|
|
17349
|
+
const key = cfgKeyOf(hostCst, trackLines, tolerant, coverage, probe2, hostReadsChildren, inheritedTrivia);
|
|
17122
17350
|
let cache = this.byCfg;
|
|
17123
17351
|
if (hostCaptureTrivia !== void 0) {
|
|
17124
17352
|
if (this.hostPredicate === hostCaptureTrivia) {
|
|
@@ -17138,7 +17366,7 @@ var AssemblyCache = class {
|
|
|
17138
17366
|
trackLines,
|
|
17139
17367
|
tolerant,
|
|
17140
17368
|
coverage,
|
|
17141
|
-
probe,
|
|
17369
|
+
probe: probe2,
|
|
17142
17370
|
inheritedTrivia
|
|
17143
17371
|
});
|
|
17144
17372
|
cache[key] = made;
|
|
@@ -17271,12 +17499,15 @@ function assertPrintable(prog, who) {
|
|
|
17271
17499
|
}
|
|
17272
17500
|
}
|
|
17273
17501
|
function programFields(prog, fns, opts = {}) {
|
|
17502
|
+
const tokens = [...new Set(prog.fx.flat())];
|
|
17503
|
+
const tokenAt = new Map(tokens.map((token2, i) => [token2, i]));
|
|
17274
17504
|
return [
|
|
17275
17505
|
...emitAssemblies(prog, opts.assemblies ?? []),
|
|
17276
17506
|
`c:[${prog.code.join(",")}],`,
|
|
17277
17507
|
`k:[${prog.k.map(emitConst).join(",")}],`,
|
|
17278
17508
|
`x:${emitClassPool(prog.cc)},`,
|
|
17279
|
-
`e:[${prog.fx.map((f) => `[${f.map(
|
|
17509
|
+
`e:[${prog.fx.map((f) => `[${f.map((token2) => tokenAt.get(token2)).join(",")}]`).join(",")}],`,
|
|
17510
|
+
`es:[${tokens.map(jsString).join(",")}],`,
|
|
17280
17511
|
`d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
|
|
17281
17512
|
`r:${JSON.stringify(prog.rules)},`,
|
|
17282
17513
|
...prog.lines === 1 ? ["l:1,"] : [],
|
|
@@ -18047,36 +18278,36 @@ function findRegexFragments(visited) {
|
|
|
18047
18278
|
if (branches.length >= 2) runs.add(branches.join("|"));
|
|
18048
18279
|
for (let i = 0; i < branches.length; i++) {
|
|
18049
18280
|
for (let n = 2; n <= Math.min(MAX_RUN, branches.length - i); n++) {
|
|
18050
|
-
const
|
|
18051
|
-
if (
|
|
18052
|
-
runs.add(
|
|
18281
|
+
const run2 = branches.slice(i, i + n).join("|");
|
|
18282
|
+
if (run2.length < 4) continue;
|
|
18283
|
+
runs.add(run2);
|
|
18053
18284
|
}
|
|
18054
18285
|
}
|
|
18055
18286
|
}
|
|
18056
|
-
for (const
|
|
18057
|
-
let e = byRun.get(
|
|
18287
|
+
for (const run2 of runs) {
|
|
18288
|
+
let e = byRun.get(run2);
|
|
18058
18289
|
if (e === void 0) {
|
|
18059
|
-
e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches:
|
|
18060
|
-
byRun.set(
|
|
18290
|
+
e = { occ: [], nodes: /* @__PURE__ */ new Set(), branches: run2.split("|").length };
|
|
18291
|
+
byRun.set(run2, e);
|
|
18061
18292
|
}
|
|
18062
18293
|
if (e.nodes.has(v.p)) continue;
|
|
18063
18294
|
e.nodes.add(v.p);
|
|
18064
18295
|
e.occ.push({ site: v.site, source: d.source });
|
|
18065
18296
|
}
|
|
18066
18297
|
}
|
|
18067
|
-
const candidates = [...byRun.entries()].filter(([, e]) => e.occ.length >= 2).map(([
|
|
18298
|
+
const candidates = [...byRun.entries()].filter(([, e]) => e.occ.length >= 2).map(([run2, e]) => ({ run: run2, e, savings: (e.occ.length - 1) * run2.length })).sort((a, b) => b.e.occ.length - a.e.occ.length || b.savings - a.savings || b.run.length - a.run.length);
|
|
18068
18299
|
const kept = [];
|
|
18069
18300
|
for (const c of candidates) {
|
|
18070
18301
|
if (kept.some((k) => k.e.occ.length >= c.e.occ.length && `|${k.run}|`.includes(`|${c.run}|`))) continue;
|
|
18071
18302
|
kept.push(c);
|
|
18072
18303
|
}
|
|
18073
|
-
return kept.map(({ run, e }) => ({
|
|
18304
|
+
return kept.map(({ run: run2, e }) => ({
|
|
18074
18305
|
kind: "regex-fragment",
|
|
18075
|
-
id: `regex-fragment:${
|
|
18076
|
-
fragment:
|
|
18306
|
+
id: `regex-fragment:${run2}`,
|
|
18307
|
+
fragment: run2,
|
|
18077
18308
|
branches: e.branches,
|
|
18078
18309
|
count: e.occ.length,
|
|
18079
|
-
savings: (e.occ.length - 1) *
|
|
18310
|
+
savings: (e.occ.length - 1) * run2.length,
|
|
18080
18311
|
sources: e.occ.map((o) => `/${o.source}/`),
|
|
18081
18312
|
sites: e.occ.map((o) => o.site),
|
|
18082
18313
|
suggestion: `this ${e.branches}-branch alternation is re-spelled in ${e.occ.length} DISTINCT regex() terminals. Hoist it to one shared source string and interpolate it (\`new RegExp(\\\`\u2026\\\${OP}\u2026\\\`)\`) or lift the shared part into its own terminal \u2014 an edit to the operator set currently has to land in ${e.occ.length} places, and the analysis cannot tell you when one of them drifts.`
|
|
@@ -18930,9 +19161,9 @@ function withAmbient(ruleMap, opts) {
|
|
|
18930
19161
|
const addTrivia = opts.trivia !== void 0 && rule2._meta.grammarTrivia === void 0;
|
|
18931
19162
|
const addScanSkip = opts.scanSkip !== void 0 && rule2._meta.grammarScanSkip === void 0;
|
|
18932
19163
|
if (!addTrivia && !addScanSkip) return [name, rule2];
|
|
18933
|
-
let
|
|
18934
|
-
if (
|
|
18935
|
-
|
|
19164
|
+
let wrapped2 = wrappers.get(rule2);
|
|
19165
|
+
if (wrapped2 === void 0) {
|
|
19166
|
+
wrapped2 = {
|
|
18936
19167
|
...rule2,
|
|
18937
19168
|
_meta: {
|
|
18938
19169
|
...rule2._meta,
|
|
@@ -18940,9 +19171,9 @@ function withAmbient(ruleMap, opts) {
|
|
|
18940
19171
|
...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
|
|
18941
19172
|
}
|
|
18942
19173
|
};
|
|
18943
|
-
wrappers.set(rule2,
|
|
19174
|
+
wrappers.set(rule2, wrapped2);
|
|
18944
19175
|
}
|
|
18945
|
-
return [name,
|
|
19176
|
+
return [name, wrapped2];
|
|
18946
19177
|
});
|
|
18947
19178
|
}
|
|
18948
19179
|
function compileRuleMapRunnable(ruleMap, opts = {}) {
|
|
@@ -19124,7 +19355,7 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
|
|
|
19124
19355
|
const emitOpts = { fnSources: sources };
|
|
19125
19356
|
const source = printable ? emitTableModule(artifact, { name: "grammar", ...emitOpts }) : "";
|
|
19126
19357
|
const inlineExpression = printable ? emitTableExpression(artifact, { entry: ENTRY, runtimeRef: opts.runtimeRef ?? "tableRules", ...emitOpts }) : null;
|
|
19127
|
-
const
|
|
19358
|
+
const runOnce2 = (input, pos, ctx) => entry(input, pos, ctx);
|
|
19128
19359
|
return {
|
|
19129
19360
|
source,
|
|
19130
19361
|
inlineExpression,
|
|
@@ -19138,10 +19369,10 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
|
|
|
19138
19369
|
// parser runs where a combinator does. A caller probing many positions
|
|
19139
19370
|
// passes one context and pays for none per call.
|
|
19140
19371
|
parse(input, pos = 0, ctx) {
|
|
19141
|
-
return
|
|
19372
|
+
return runOnce2(input, pos, ctx ?? createParseContext());
|
|
19142
19373
|
},
|
|
19143
19374
|
parseWithContext(input, parseCtx, pos = 0) {
|
|
19144
|
-
return
|
|
19375
|
+
return runOnce2(input, pos, parseCtx);
|
|
19145
19376
|
},
|
|
19146
19377
|
/**
|
|
19147
19378
|
* NO LONGER REFUSES. It used to throw unless the caller passed
|
|
@@ -19157,7 +19388,7 @@ function compileImpl(combinator, mapFnSources, opts = {}) {
|
|
|
19157
19388
|
const errors = [];
|
|
19158
19389
|
ctx._errors = errors;
|
|
19159
19390
|
ctx._tolerant = true;
|
|
19160
|
-
const r =
|
|
19391
|
+
const r = runOnce2(input, pos, ctx);
|
|
19161
19392
|
return { ...r, errors };
|
|
19162
19393
|
}
|
|
19163
19394
|
};
|
|
@@ -19402,6 +19633,38 @@ function not(combinator) {
|
|
|
19402
19633
|
};
|
|
19403
19634
|
}
|
|
19404
19635
|
|
|
19636
|
+
// src/combinators/withCtx.ts
|
|
19637
|
+
function withCtx(extra, combinator) {
|
|
19638
|
+
const meta = {
|
|
19639
|
+
firstSet: combinator._meta.firstSet,
|
|
19640
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
19641
|
+
isTrivia: false
|
|
19642
|
+
};
|
|
19643
|
+
const parse2 = typeof extra === "function" ? (input, pos, ctx) => {
|
|
19644
|
+
const saved = ctx.state;
|
|
19645
|
+
ctx.state = extra(saved);
|
|
19646
|
+
try {
|
|
19647
|
+
return combinator.parse(input, pos, ctx);
|
|
19648
|
+
} finally {
|
|
19649
|
+
ctx.state = saved;
|
|
19650
|
+
}
|
|
19651
|
+
} : (input, pos, ctx) => {
|
|
19652
|
+
const saved = ctx.state;
|
|
19653
|
+
ctx.state = extra;
|
|
19654
|
+
try {
|
|
19655
|
+
return combinator.parse(input, pos, ctx);
|
|
19656
|
+
} finally {
|
|
19657
|
+
ctx.state = saved;
|
|
19658
|
+
}
|
|
19659
|
+
};
|
|
19660
|
+
return {
|
|
19661
|
+
_tag: "withCtx",
|
|
19662
|
+
_meta: meta,
|
|
19663
|
+
_def: { tag: "withCtx", extra, parser: combinator },
|
|
19664
|
+
parse: parse2
|
|
19665
|
+
};
|
|
19666
|
+
}
|
|
19667
|
+
|
|
19405
19668
|
// src/analysis/rebuild.ts
|
|
19406
19669
|
var FROZEN_TAGS = /* @__PURE__ */ new Set([
|
|
19407
19670
|
"dispatch",
|
|
@@ -19415,6 +19678,7 @@ var FROZEN_TAGS = /* @__PURE__ */ new Set([
|
|
|
19415
19678
|
"lines",
|
|
19416
19679
|
"columns"
|
|
19417
19680
|
]);
|
|
19681
|
+
var THAWED_TAGS = /* @__PURE__ */ new Set(["dispatch", "withCtx", "routed", "guard"]);
|
|
19418
19682
|
var CARRIED_META = [
|
|
19419
19683
|
"grammarTrivia",
|
|
19420
19684
|
"grammarScanSkip",
|
|
@@ -19453,7 +19717,9 @@ function subtreeContains(p, targets) {
|
|
|
19453
19717
|
walk(p);
|
|
19454
19718
|
return hit;
|
|
19455
19719
|
}
|
|
19456
|
-
function rebuildCombinator(root, replacements) {
|
|
19720
|
+
function rebuildCombinator(root, replacements, options = {}) {
|
|
19721
|
+
const thaw = options.thaw === true;
|
|
19722
|
+
const after = options.after ?? ((_p, out) => out);
|
|
19457
19723
|
const memo = /* @__PURE__ */ new Map();
|
|
19458
19724
|
const frozenKeys = /* @__PURE__ */ new Set();
|
|
19459
19725
|
const frozen = [];
|
|
@@ -19473,15 +19739,16 @@ function rebuildCombinator(root, replacements) {
|
|
|
19473
19739
|
return p;
|
|
19474
19740
|
}
|
|
19475
19741
|
const here = p._ruleName ?? rule2;
|
|
19476
|
-
if (FROZEN_TAGS.has(d.tag)) {
|
|
19742
|
+
if (FROZEN_TAGS.has(d.tag) && !(thaw && THAWED_TAGS.has(d.tag))) {
|
|
19477
19743
|
const key = JSON.stringify([here, d.tag]);
|
|
19478
19744
|
if (!frozenKeys.has(key)) {
|
|
19479
19745
|
frozenKeys.add(key);
|
|
19480
19746
|
frozen.push({ tag: d.tag, rule: here });
|
|
19481
19747
|
}
|
|
19482
19748
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
19483
|
-
|
|
19484
|
-
|
|
19749
|
+
const kept = after(p, p);
|
|
19750
|
+
memo.set(p, kept);
|
|
19751
|
+
return kept;
|
|
19485
19752
|
}
|
|
19486
19753
|
if (d.tag === "lazy") {
|
|
19487
19754
|
let target;
|
|
@@ -19518,6 +19785,14 @@ function rebuildCombinator(root, replacements) {
|
|
|
19518
19785
|
break;
|
|
19519
19786
|
}
|
|
19520
19787
|
case "choice": {
|
|
19788
|
+
if (d.gates.some((g) => g !== null) && thaw) {
|
|
19789
|
+
const unsafeChoice = choice;
|
|
19790
|
+
out = unsafeChoice(...d.parsers.map((arm, i) => {
|
|
19791
|
+
const gate = d.gates[i];
|
|
19792
|
+
return gate ? { combinator: one(arm), gate } : one(arm);
|
|
19793
|
+
}));
|
|
19794
|
+
break;
|
|
19795
|
+
}
|
|
19521
19796
|
if (d.gates.some((g) => g !== null)) {
|
|
19522
19797
|
const key = JSON.stringify([here, "choice(gated)"]);
|
|
19523
19798
|
if (!frozenKeys.has(key)) {
|
|
@@ -19525,8 +19800,9 @@ function rebuildCombinator(root, replacements) {
|
|
|
19525
19800
|
frozen.push({ tag: "choice(gated)", rule: here });
|
|
19526
19801
|
}
|
|
19527
19802
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
19528
|
-
|
|
19529
|
-
|
|
19803
|
+
const kept = after(p, p);
|
|
19804
|
+
memo.set(p, kept);
|
|
19805
|
+
return kept;
|
|
19530
19806
|
}
|
|
19531
19807
|
const kids = d.parsers.map(one);
|
|
19532
19808
|
out = choice(...kids);
|
|
@@ -19604,13 +19880,33 @@ function rebuildCombinator(root, replacements) {
|
|
|
19604
19880
|
frozen.push({ tag: "node(untyped+build+opts)", rule: here });
|
|
19605
19881
|
}
|
|
19606
19882
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
19607
|
-
|
|
19608
|
-
|
|
19883
|
+
const kept = after(p, p);
|
|
19884
|
+
memo.set(p, kept);
|
|
19885
|
+
return kept;
|
|
19609
19886
|
}
|
|
19610
19887
|
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);
|
|
19611
19888
|
if (d.buildRawUnused === true && out._def.tag === "node") out._def.buildRawUnused = true;
|
|
19612
19889
|
break;
|
|
19613
19890
|
}
|
|
19891
|
+
case "dispatch": {
|
|
19892
|
+
const arms = d.cases.map((e) => when(e.keys, one(e.parser), e.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
19893
|
+
for (const e of d.matchers ?? []) {
|
|
19894
|
+
arms.push(when(dispatchMatcher(e), one(e.parser), e.caseInsensitive ? { caseInsensitive: true } : void 0));
|
|
19895
|
+
}
|
|
19896
|
+
if (d.otherwise) arms.push(otherwise(one(d.otherwise), d.otherwiseCommit === false ? { commit: false } : void 0));
|
|
19897
|
+
const unsafeDispatch = dispatch;
|
|
19898
|
+
out = unsafeDispatch(one(d.selector), ...arms);
|
|
19899
|
+
break;
|
|
19900
|
+
}
|
|
19901
|
+
case "withCtx":
|
|
19902
|
+
out = withCtx(d.extra, one(d.parser));
|
|
19903
|
+
break;
|
|
19904
|
+
case "routed":
|
|
19905
|
+
out = d.fallback === void 0 ? routed() : routed(one(d.fallback));
|
|
19906
|
+
break;
|
|
19907
|
+
case "guard":
|
|
19908
|
+
out = p;
|
|
19909
|
+
break;
|
|
19614
19910
|
case "grammar": {
|
|
19615
19911
|
const inner = one(d.parser);
|
|
19616
19912
|
out = parser({
|
|
@@ -19628,13 +19924,15 @@ function rebuildCombinator(root, replacements) {
|
|
|
19628
19924
|
frozen.push({ tag: d.tag, rule: here });
|
|
19629
19925
|
}
|
|
19630
19926
|
for (const t2 of subtreeContains(p, targets)) if (!unapplied.includes(t2)) unapplied.push(t2);
|
|
19631
|
-
|
|
19632
|
-
|
|
19927
|
+
const kept = after(p, p);
|
|
19928
|
+
memo.set(p, kept);
|
|
19929
|
+
return kept;
|
|
19633
19930
|
}
|
|
19634
19931
|
}
|
|
19635
19932
|
carryStamps(p, out);
|
|
19636
|
-
|
|
19637
|
-
|
|
19933
|
+
const done = after(p, out);
|
|
19934
|
+
memo.set(p, done);
|
|
19935
|
+
return done;
|
|
19638
19936
|
};
|
|
19639
19937
|
const rebuilt = go(root, root._ruleName ?? "<entry>");
|
|
19640
19938
|
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);
|
|
@@ -20871,9 +21169,715 @@ function measureChoiceCost(c, samples, arms) {
|
|
|
20871
21169
|
function armFirstSets(choiceArms2) {
|
|
20872
21170
|
return choiceArms2.map((a) => ({ firstSet: firstSetOf(a) }));
|
|
20873
21171
|
}
|
|
21172
|
+
|
|
21173
|
+
// src/cst/trivia-entries.ts
|
|
21174
|
+
var EMPTY_INDICES = Object.freeze([]);
|
|
21175
|
+
var EMPTY_GAPS = Object.freeze([]);
|
|
21176
|
+
var SELECTED_ROOT_STRIDE = 5;
|
|
21177
|
+
function buildRootTriviaIndex(log, labels) {
|
|
21178
|
+
const length = Math.floor(log.length / SELECTED_ROOT_STRIDE);
|
|
21179
|
+
const markerOffset = (i) => i * SELECTED_ROOT_STRIDE;
|
|
21180
|
+
const ownedRangeStart = (i) => log[markerOffset(i)];
|
|
21181
|
+
const ownedRangeEnd = (i) => log[markerOffset(i) + 1];
|
|
21182
|
+
const markerStart = (i) => log[markerOffset(i) + 2];
|
|
21183
|
+
const markerEnd = (i) => log[markerOffset(i) + 3];
|
|
21184
|
+
const markerKind = (i) => log[markerOffset(i) + 4];
|
|
21185
|
+
const entries = {
|
|
21186
|
+
length,
|
|
21187
|
+
labels,
|
|
21188
|
+
stride: SELECTED_ROOT_STRIDE,
|
|
21189
|
+
start: markerStart,
|
|
21190
|
+
end: markerEnd,
|
|
21191
|
+
insertIndex: () => void 0,
|
|
21192
|
+
kindIndex: markerKind,
|
|
21193
|
+
kind(i) {
|
|
21194
|
+
return labels[markerKind(i)];
|
|
21195
|
+
},
|
|
21196
|
+
text(i, input) {
|
|
21197
|
+
return input.slice(markerStart(i), markerEnd(i));
|
|
21198
|
+
}
|
|
21199
|
+
};
|
|
21200
|
+
const lowerBound = (offset, by) => {
|
|
21201
|
+
let lo = 0;
|
|
21202
|
+
let hi = length;
|
|
21203
|
+
while (lo < hi) {
|
|
21204
|
+
const mid = lo + hi >>> 1;
|
|
21205
|
+
if (by(mid) < offset) lo = mid + 1;
|
|
21206
|
+
else hi = mid;
|
|
21207
|
+
}
|
|
21208
|
+
return lo;
|
|
21209
|
+
};
|
|
21210
|
+
const gapRowsAt = (offset, direction) => {
|
|
21211
|
+
const edge = direction === "before" ? ownedRangeEnd : ownedRangeStart;
|
|
21212
|
+
let first = lowerBound(offset, edge);
|
|
21213
|
+
if (first === length || edge(first) !== offset) return void 0;
|
|
21214
|
+
const start = ownedRangeStart(first);
|
|
21215
|
+
const end = ownedRangeEnd(first);
|
|
21216
|
+
while (first > 0 && ownedRangeStart(first - 1) === start && ownedRangeEnd(first - 1) === end) first--;
|
|
21217
|
+
let last = first + 1;
|
|
21218
|
+
while (last < length && ownedRangeStart(last) === start && ownedRangeEnd(last) === end) last++;
|
|
21219
|
+
return [first, last];
|
|
21220
|
+
};
|
|
21221
|
+
const indices = (first, last) => {
|
|
21222
|
+
const out = [];
|
|
21223
|
+
for (let i = first; i < last; i++) out.push(i);
|
|
21224
|
+
return out;
|
|
21225
|
+
};
|
|
21226
|
+
const makeGap = (first, last) => {
|
|
21227
|
+
const start = ownedRangeStart(first);
|
|
21228
|
+
const end = ownedRangeEnd(first);
|
|
21229
|
+
let entryIndices;
|
|
21230
|
+
return {
|
|
21231
|
+
start,
|
|
21232
|
+
end,
|
|
21233
|
+
get entryIndices() {
|
|
21234
|
+
return entryIndices ??= indices(first, last);
|
|
21235
|
+
},
|
|
21236
|
+
hasKind(kind) {
|
|
21237
|
+
for (let i = first; i < last; i++) {
|
|
21238
|
+
if (labels[markerKind(i)] === kind) return true;
|
|
21239
|
+
}
|
|
21240
|
+
return false;
|
|
21241
|
+
},
|
|
21242
|
+
text(input) {
|
|
21243
|
+
return input.slice(start, end);
|
|
21244
|
+
}
|
|
21245
|
+
};
|
|
21246
|
+
};
|
|
21247
|
+
let maps;
|
|
21248
|
+
const getMaps = () => {
|
|
21249
|
+
if (maps !== void 0) return maps;
|
|
21250
|
+
const before = /* @__PURE__ */ new Map();
|
|
21251
|
+
const after = /* @__PURE__ */ new Map();
|
|
21252
|
+
const beforeGaps = /* @__PURE__ */ new Map();
|
|
21253
|
+
const afterGaps = /* @__PURE__ */ new Map();
|
|
21254
|
+
const gaps = [];
|
|
21255
|
+
for (let first = 0; first < length; ) {
|
|
21256
|
+
let last = first + 1;
|
|
21257
|
+
while (last < length && ownedRangeStart(last) === ownedRangeStart(first) && ownedRangeEnd(last) === ownedRangeEnd(first)) last++;
|
|
21258
|
+
const gap = makeGap(first, last);
|
|
21259
|
+
gaps.push(gap);
|
|
21260
|
+
afterGaps.set(gap.start, gap);
|
|
21261
|
+
beforeGaps.set(gap.end, gap);
|
|
21262
|
+
after.set(gap.start, [...gap.entryIndices]);
|
|
21263
|
+
before.set(gap.end, [...gap.entryIndices]);
|
|
21264
|
+
first = last;
|
|
21265
|
+
}
|
|
21266
|
+
maps = { before, after, beforeGaps, afterGaps, gaps };
|
|
21267
|
+
return maps;
|
|
21268
|
+
};
|
|
21269
|
+
return {
|
|
21270
|
+
entries,
|
|
21271
|
+
labels,
|
|
21272
|
+
get before() {
|
|
21273
|
+
return getMaps().before;
|
|
21274
|
+
},
|
|
21275
|
+
get after() {
|
|
21276
|
+
return getMaps().after;
|
|
21277
|
+
},
|
|
21278
|
+
entryIndicesBefore(offset) {
|
|
21279
|
+
const rows = gapRowsAt(offset, "before");
|
|
21280
|
+
return rows ? indices(rows[0], rows[1]) : EMPTY_INDICES;
|
|
21281
|
+
},
|
|
21282
|
+
entryIndicesAfter(offset) {
|
|
21283
|
+
const rows = gapRowsAt(offset, "after");
|
|
21284
|
+
return rows ? indices(rows[0], rows[1]) : EMPTY_INDICES;
|
|
21285
|
+
},
|
|
21286
|
+
gapBefore(offset) {
|
|
21287
|
+
const rows = gapRowsAt(offset, "before");
|
|
21288
|
+
return rows ? makeGap(rows[0], rows[1]) : void 0;
|
|
21289
|
+
},
|
|
21290
|
+
gapAfter(offset) {
|
|
21291
|
+
const rows = gapRowsAt(offset, "after");
|
|
21292
|
+
return rows ? makeGap(rows[0], rows[1]) : void 0;
|
|
21293
|
+
},
|
|
21294
|
+
gaps() {
|
|
21295
|
+
return getMaps().gaps;
|
|
21296
|
+
},
|
|
21297
|
+
gapsWithKind(kind) {
|
|
21298
|
+
const kinds = typeof kind === "string" ? [kind] : kind;
|
|
21299
|
+
const matches2 = [];
|
|
21300
|
+
for (let first = 0; first < length; ) {
|
|
21301
|
+
let last = first + 1;
|
|
21302
|
+
while (last < length && ownedRangeStart(last) === ownedRangeStart(first) && ownedRangeEnd(last) === ownedRangeEnd(first)) last++;
|
|
21303
|
+
let matched = false;
|
|
21304
|
+
for (let i = first; i < last && !matched; i++) {
|
|
21305
|
+
const label2 = labels[markerKind(i)];
|
|
21306
|
+
for (const kind2 of kinds) {
|
|
21307
|
+
if (label2 === kind2) {
|
|
21308
|
+
matched = true;
|
|
21309
|
+
break;
|
|
21310
|
+
}
|
|
21311
|
+
}
|
|
21312
|
+
}
|
|
21313
|
+
if (matched) matches2.push(makeGap(first, last));
|
|
21314
|
+
first = last;
|
|
21315
|
+
}
|
|
21316
|
+
return matches2.length === 0 ? EMPTY_GAPS : matches2;
|
|
21317
|
+
}
|
|
21318
|
+
};
|
|
21319
|
+
}
|
|
21320
|
+
|
|
21321
|
+
// src/functional/run.ts
|
|
21322
|
+
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
21323
|
+
var REMOVED_RUN_RESULT_FIELDS = [
|
|
21324
|
+
[
|
|
21325
|
+
"triviaMap",
|
|
21326
|
+
`It was a dense root-trivia index built on every parse; root trivia is now an OPT-IN sparse capture, because most grammars paid for an index they never read. Migration: name the trivia labels your grammar defines \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia\`, whose \`.index\` carries the labels and gap lookups \`triviaMap\` exposed.`
|
|
21327
|
+
],
|
|
21328
|
+
[
|
|
21329
|
+
"triviaLog",
|
|
21330
|
+
`It was the flat \`start, end[, kindIndex]\` log every other trivia view was derived from, and it is no longer allocated at all \u2014 not empty, absent. Migration: request the labels you need \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia.rows\`. Do NOT reuse a stride-2/3 reader: rows are a different width and a different unit (one row per SELECTED marker, not one per trivia chunk), so an old loop reads confidently wrong offsets rather than failing.`
|
|
21331
|
+
],
|
|
21332
|
+
[
|
|
21333
|
+
"triviaKindLabels",
|
|
21334
|
+
`It was already optional, so nothing ever flagged its disappearance \u2014 and \`triviaKindMask(undefined, \u2026)\` means "capture everything", so reading it now silently WIDENS capture instead of erroring. Migration: request labels \u2014 ${SELECT_EXAMPLE} \u2014 then the set you asked for is \`RunResult.rootTrivia.select\` and the resolved table is \`RunResult.rootTrivia.index.labels\`.`
|
|
21335
|
+
]
|
|
21336
|
+
];
|
|
21337
|
+
var RunResultRecord = class {
|
|
21338
|
+
constructor(ok, value, span, expected, errors, unconsumedFrom) {
|
|
21339
|
+
this.ok = ok;
|
|
21340
|
+
this.value = value;
|
|
21341
|
+
this.span = span;
|
|
21342
|
+
this.expected = expected;
|
|
21343
|
+
this.errors = errors;
|
|
21344
|
+
this.unconsumedFrom = unconsumedFrom;
|
|
21345
|
+
}
|
|
21346
|
+
};
|
|
21347
|
+
var RunResultWithRootTrivia = class {
|
|
21348
|
+
constructor(ok, value, span, expected, errors, rootTrivia, unconsumedFrom) {
|
|
21349
|
+
this.ok = ok;
|
|
21350
|
+
this.value = value;
|
|
21351
|
+
this.span = span;
|
|
21352
|
+
this.expected = expected;
|
|
21353
|
+
this.errors = errors;
|
|
21354
|
+
this.rootTrivia = rootTrivia;
|
|
21355
|
+
this.unconsumedFrom = unconsumedFrom;
|
|
21356
|
+
}
|
|
21357
|
+
};
|
|
21358
|
+
for (const proto of [RunResultRecord.prototype, RunResultWithRootTrivia.prototype]) {
|
|
21359
|
+
for (const [name, detail] of REMOVED_RUN_RESULT_FIELDS) {
|
|
21360
|
+
Object.defineProperty(proto, name, {
|
|
21361
|
+
configurable: true,
|
|
21362
|
+
enumerable: false,
|
|
21363
|
+
get() {
|
|
21364
|
+
throw new TypeError(
|
|
21365
|
+
`RunResult.${name} was REMOVED in parseman 0.44.0 and has no default replacement. ${detail}`
|
|
21366
|
+
);
|
|
21367
|
+
}
|
|
21368
|
+
});
|
|
21369
|
+
}
|
|
21370
|
+
}
|
|
21371
|
+
var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
|
|
21372
|
+
function ambientTriviaFromRunnable(r) {
|
|
21373
|
+
if (!r) return void 0;
|
|
21374
|
+
if (typeof r === "function") return r._meta?.grammarTrivia;
|
|
21375
|
+
if (r._meta.isTrivia) return void 0;
|
|
21376
|
+
return r._meta.grammarTrivia ?? (r._def.tag === "grammar" ? r._def.triviaParser : void 0);
|
|
21377
|
+
}
|
|
21378
|
+
function triviaKindLabelsFromRunnable(r) {
|
|
21379
|
+
if (!r) return void 0;
|
|
21380
|
+
if (typeof r === "function") return r._meta?.triviaKindLabels;
|
|
21381
|
+
const grammarTrivia = r._meta.grammarTrivia;
|
|
21382
|
+
return grammarTrivia?._meta.triviaKindLabels ?? r._meta.triviaKindLabels ?? (r._def.tag === "grammar" ? r._def.triviaParser?._meta.triviaKindLabels : void 0);
|
|
21383
|
+
}
|
|
21384
|
+
function rootTriviaClassifiedFromRunnable(r) {
|
|
21385
|
+
if (!r) return false;
|
|
21386
|
+
if (typeof r === "function") return r._meta?.rootTriviaClassified === true;
|
|
21387
|
+
const grammarTrivia = r._meta.grammarTrivia;
|
|
21388
|
+
return grammarTrivia?._meta.rootTriviaClassified === true || r._meta.rootTriviaClassified === true;
|
|
21389
|
+
}
|
|
21390
|
+
function makeSelectedRootLabelIndex(labels) {
|
|
21391
|
+
const index = /* @__PURE__ */ Object.create(null);
|
|
21392
|
+
for (let i = 0; i < labels.length; i++) {
|
|
21393
|
+
if (index[labels[i]] === void 0) index[labels[i]] = i;
|
|
21394
|
+
}
|
|
21395
|
+
return index;
|
|
21396
|
+
}
|
|
21397
|
+
function growSpanEnd(span, input, end) {
|
|
21398
|
+
if (span.endLine === void 0 || span.endColumn === void 0) {
|
|
21399
|
+
return { start: span.start, end };
|
|
21400
|
+
}
|
|
21401
|
+
let line = span.endLine;
|
|
21402
|
+
let column = span.endColumn;
|
|
21403
|
+
for (let i = span.end; i < end; i++) {
|
|
21404
|
+
if (input.charCodeAt(i) === 10) {
|
|
21405
|
+
line++;
|
|
21406
|
+
column = 1;
|
|
21407
|
+
} else {
|
|
21408
|
+
column++;
|
|
21409
|
+
}
|
|
21410
|
+
}
|
|
21411
|
+
return { ...span, end, endLine: line, endColumn: column };
|
|
21412
|
+
}
|
|
21413
|
+
function runOnce(entry, input, options) {
|
|
21414
|
+
if (typeof entry !== "function" && typeof entry?.parse !== "function") {
|
|
21415
|
+
throw new TypeError(
|
|
21416
|
+
`run(): start production is ${entry === null ? "null" : typeof entry}, not a rule \u2014 the requested grammar rule does not exist (check the rule name).`
|
|
21417
|
+
);
|
|
21418
|
+
}
|
|
21419
|
+
const rootTriviaSelection = options.rootTrivia?.select;
|
|
21420
|
+
const captureRootTrivia = rootTriviaSelection !== void 0 && rootTriviaSelection.length > 0;
|
|
21421
|
+
const selectedRootLog = captureRootTrivia ? [] : void 0;
|
|
21422
|
+
const selectedRootLabelIndex = captureRootTrivia ? makeSelectedRootLabelIndex(rootTriviaSelection) : void 0;
|
|
21423
|
+
const errors = [];
|
|
21424
|
+
const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
|
|
21425
|
+
const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
|
|
21426
|
+
const triviaKindLabels = triviaKindLabelsFromRunnable(entry) ?? triviaKindLabelsFromRunnable(options.trivia);
|
|
21427
|
+
if (captureRootTrivia && triviaKindLabels === void 0) {
|
|
21428
|
+
throw new TypeError("run(): rootTrivia.select requires labeled grammar trivia.");
|
|
21429
|
+
}
|
|
21430
|
+
if (captureRootTrivia) {
|
|
21431
|
+
for (const label2 of rootTriviaSelection) {
|
|
21432
|
+
if (!triviaKindLabels.includes(label2)) {
|
|
21433
|
+
throw new TypeError(`run(): rootTrivia.select contains unknown trivia label ${JSON.stringify(label2)}.`);
|
|
21434
|
+
}
|
|
21435
|
+
}
|
|
21436
|
+
}
|
|
21437
|
+
if (captureRootTrivia && !rootTriviaClassifiedFromRunnable(entry) && !rootTriviaClassifiedFromRunnable(options.trivia)) {
|
|
21438
|
+
throw new TypeError(
|
|
21439
|
+
"run(): rootTrivia.select requires classifiedTrivia() at the root."
|
|
21440
|
+
);
|
|
21441
|
+
}
|
|
21442
|
+
const stamped = entry;
|
|
21443
|
+
assertHostModeCompatible(
|
|
21444
|
+
typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
|
|
21445
|
+
options.build,
|
|
21446
|
+
typeof entry === "function" && stamped[FUSED_HOST_ELIDED] === true
|
|
21447
|
+
);
|
|
21448
|
+
const ctx = createParseContext();
|
|
21449
|
+
if (captureRootTrivia) {
|
|
21450
|
+
ctx._rootTriviaLog = selectedRootLog;
|
|
21451
|
+
ctx._rootTriviaKindIndex = selectedRootLabelIndex;
|
|
21452
|
+
ctx._rootTriviaStrictScopes = true;
|
|
21453
|
+
}
|
|
21454
|
+
ctx._errors = errors;
|
|
21455
|
+
ctx.build = options.build;
|
|
21456
|
+
ctx.state = options.state;
|
|
21457
|
+
if (grammarTrivia !== void 0) ctx.trivia = grammarTrivia;
|
|
21458
|
+
if (triviaKindLabels) ctx.triviaKindLabels = triviaKindLabels;
|
|
21459
|
+
if (grammarScanSkip !== void 0) ctx.scanSkip = grammarScanSkip;
|
|
21460
|
+
if (options.triviaCaptureMask !== void 0) ctx._triviaCaptureMask = options.triviaCaptureMask;
|
|
21461
|
+
if (options.tolerant) {
|
|
21462
|
+
ctx._tolerant = true;
|
|
21463
|
+
ctx._rec = REC;
|
|
21464
|
+
}
|
|
21465
|
+
if (options.instrumentation !== void 0) {
|
|
21466
|
+
ctx._grammarCoverage = options.instrumentation._grammarCoverage;
|
|
21467
|
+
ctx._grammarTrace = options.instrumentation._grammarTrace;
|
|
21468
|
+
}
|
|
21469
|
+
const r = invoke(entry, input, 0, ctx);
|
|
21470
|
+
const value = r.ok ? r.value : void 0;
|
|
21471
|
+
let span = r.span ?? { start: 0, end: 0 };
|
|
21472
|
+
const expected = r.ok ? [] : [...new Set(r.expected ?? [])];
|
|
21473
|
+
let unconsumedFrom = null;
|
|
21474
|
+
if (r.ok) {
|
|
21475
|
+
let pos = span.end;
|
|
21476
|
+
const tail = options.trivia ?? ambientTriviaFromRunnable(entry);
|
|
21477
|
+
if (tail !== void 0 && pos < input.length) {
|
|
21478
|
+
const t2 = invoke(tail, input, pos, createParseContext());
|
|
21479
|
+
if (t2.ok && t2.span.end > pos) {
|
|
21480
|
+
span = growSpanEnd(span, input, t2.span.end);
|
|
21481
|
+
pos = t2.span.end;
|
|
21482
|
+
}
|
|
21483
|
+
}
|
|
21484
|
+
unconsumedFrom = pos < input.length ? pos : null;
|
|
21485
|
+
}
|
|
21486
|
+
return selectedRootLog !== void 0 && selectedRootLog.length > 0 ? new RunResultWithRootTrivia(
|
|
21487
|
+
r.ok,
|
|
21488
|
+
value,
|
|
21489
|
+
span,
|
|
21490
|
+
expected,
|
|
21491
|
+
errors,
|
|
21492
|
+
{
|
|
21493
|
+
rows: selectedRootLog,
|
|
21494
|
+
select: rootTriviaSelection,
|
|
21495
|
+
index: buildRootTriviaIndex(selectedRootLog, rootTriviaSelection)
|
|
21496
|
+
},
|
|
21497
|
+
unconsumedFrom
|
|
21498
|
+
) : new RunResultRecord(r.ok, value, span, expected, errors, unconsumedFrom);
|
|
21499
|
+
}
|
|
21500
|
+
function run(entry, input, options = {}) {
|
|
21501
|
+
return runOnce(entry, input, options);
|
|
21502
|
+
}
|
|
21503
|
+
|
|
21504
|
+
// src/table/backtrack-probe.ts
|
|
21505
|
+
var LOOKAROUND = /(?<!\\)\(\?<?[=!]/;
|
|
21506
|
+
function hasLookaround(re) {
|
|
21507
|
+
return LOOKAROUND.test(re.source);
|
|
21508
|
+
}
|
|
21509
|
+
function lookaroundExtent(re, input, start, end) {
|
|
21510
|
+
const probe2 = new RegExp(re.source, re.flags.includes("y") ? re.flags : `${re.flags}y`);
|
|
21511
|
+
const same = (n) => {
|
|
21512
|
+
probe2.lastIndex = start;
|
|
21513
|
+
return probe2.test(input.slice(0, end + n)) && probe2.lastIndex === end;
|
|
21514
|
+
};
|
|
21515
|
+
let lo = 0;
|
|
21516
|
+
let hi = input.length - end;
|
|
21517
|
+
while (lo < hi) {
|
|
21518
|
+
const mid = lo + hi >>> 1;
|
|
21519
|
+
if (same(mid)) hi = mid;
|
|
21520
|
+
else lo = mid + 1;
|
|
21521
|
+
}
|
|
21522
|
+
return lo;
|
|
21523
|
+
}
|
|
21524
|
+
var BacktrackRecorder = class {
|
|
21525
|
+
input = "";
|
|
21526
|
+
counts = zeroCounts();
|
|
21527
|
+
look = 0;
|
|
21528
|
+
opaque = 0;
|
|
21529
|
+
last = 0;
|
|
21530
|
+
furthest = 0;
|
|
21531
|
+
begin(input) {
|
|
21532
|
+
this.input = input;
|
|
21533
|
+
this.counts = zeroCounts();
|
|
21534
|
+
this.look = 0;
|
|
21535
|
+
this.opaque = 0;
|
|
21536
|
+
this.last = 0;
|
|
21537
|
+
this.furthest = 0;
|
|
21538
|
+
}
|
|
21539
|
+
/** The counts for the parse `begin` opened. Throws if a region was left open. */
|
|
21540
|
+
end() {
|
|
21541
|
+
if (this.look !== 0 || this.opaque !== 0) {
|
|
21542
|
+
throw new Error(`backtrack probe: unbalanced region (lookahead ${this.look}, opaque ${this.opaque})`);
|
|
21543
|
+
}
|
|
21544
|
+
return this.counts;
|
|
21545
|
+
}
|
|
21546
|
+
consume(start, end) {
|
|
21547
|
+
if (this.opaque > 0 || end <= start) return;
|
|
21548
|
+
const c = this.counts;
|
|
21549
|
+
if (this.look > 0) {
|
|
21550
|
+
c.lookaheadBytes += end - start;
|
|
21551
|
+
return;
|
|
21552
|
+
}
|
|
21553
|
+
if (start < this.last) c.rewinds++;
|
|
21554
|
+
if (start < this.furthest) c.bytesReread += Math.min(end, this.furthest) - start;
|
|
21555
|
+
this.last = end;
|
|
21556
|
+
if (end > this.furthest) this.furthest = end;
|
|
21557
|
+
}
|
|
21558
|
+
enterLookahead() {
|
|
21559
|
+
if (this.opaque === 0) this.counts.lookaheads++;
|
|
21560
|
+
this.look++;
|
|
21561
|
+
}
|
|
21562
|
+
exitLookahead() {
|
|
21563
|
+
this.look--;
|
|
21564
|
+
}
|
|
21565
|
+
regexAttempt() {
|
|
21566
|
+
if (this.opaque === 0) this.counts.regexLookarounds++;
|
|
21567
|
+
}
|
|
21568
|
+
regexMatch(re, start, end) {
|
|
21569
|
+
if (this.opaque === 0) this.counts.regexLookaroundBytes += lookaroundExtent(re, this.input, start, end);
|
|
21570
|
+
this.consume(start, end);
|
|
21571
|
+
}
|
|
21572
|
+
/** A read whose inner steps are not the grammar's (the interpreter's scans). */
|
|
21573
|
+
enterOpaque() {
|
|
21574
|
+
this.opaque++;
|
|
21575
|
+
}
|
|
21576
|
+
exitOpaque() {
|
|
21577
|
+
this.opaque--;
|
|
21578
|
+
}
|
|
21579
|
+
};
|
|
21580
|
+
function zeroCounts() {
|
|
21581
|
+
return { rewinds: 0, bytesReread: 0, lookaheads: 0, lookaheadBytes: 0, regexLookarounds: 0, regexLookaroundBytes: 0 };
|
|
21582
|
+
}
|
|
21583
|
+
function rowStarts(code, roots) {
|
|
21584
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21585
|
+
const stack = [...roots];
|
|
21586
|
+
const kids = [];
|
|
21587
|
+
while (stack.length > 0) {
|
|
21588
|
+
const ip = stack.pop();
|
|
21589
|
+
if (seen.has(ip)) continue;
|
|
21590
|
+
seen.add(ip);
|
|
21591
|
+
kids.length = 0;
|
|
21592
|
+
childSlots(code, ip, kids);
|
|
21593
|
+
for (const c of kids) stack.push(c);
|
|
21594
|
+
}
|
|
21595
|
+
return [...seen, code.length].sort((a, b) => a - b);
|
|
21596
|
+
}
|
|
21597
|
+
function probeProgram(source, rec) {
|
|
21598
|
+
const prog = expandCompact(source);
|
|
21599
|
+
const code = [...prog.code];
|
|
21600
|
+
const fns = [...prog.fns];
|
|
21601
|
+
const fx = [...prog.fx, []];
|
|
21602
|
+
const noFx = fx.length - 1;
|
|
21603
|
+
const row = (...words) => {
|
|
21604
|
+
const ip = code.length;
|
|
21605
|
+
code.push(...words);
|
|
21606
|
+
return ip;
|
|
21607
|
+
};
|
|
21608
|
+
const fn = (f) => fns.push(f) - 1;
|
|
21609
|
+
const slots = [];
|
|
21610
|
+
const extraIps = assemblyExtraIps(prog);
|
|
21611
|
+
const starts = rowStarts(prog.code, [...Object.values(prog.rules), ...extraIps]);
|
|
21612
|
+
const copies = /* @__PURE__ */ new Map();
|
|
21613
|
+
function copyOf(ip) {
|
|
21614
|
+
const hit = copies.get(ip);
|
|
21615
|
+
if (hit !== void 0) return hit;
|
|
21616
|
+
slots.length = 0;
|
|
21617
|
+
childSlotOffsets(prog.code, ip, slots);
|
|
21618
|
+
if (slots.length === 0) {
|
|
21619
|
+
copies.set(ip, ip);
|
|
21620
|
+
return ip;
|
|
21621
|
+
}
|
|
21622
|
+
const next = starts[starts.findIndex((s) => s > ip)];
|
|
21623
|
+
const at = code.length;
|
|
21624
|
+
copies.set(ip, at);
|
|
21625
|
+
for (let i = ip; i < next; i++) code.push(prog.code[i]);
|
|
21626
|
+
const own = slots.map((s) => s - ip);
|
|
21627
|
+
for (const o of own) code[at + o] = copyOf(prog.code[ip + o]);
|
|
21628
|
+
return at;
|
|
21629
|
+
}
|
|
21630
|
+
const ref2 = (r) => [copyOf(r[0]), r[1]];
|
|
21631
|
+
const scans = prog.scans?.map((s) => ({
|
|
21632
|
+
...s,
|
|
21633
|
+
skip: s.skip.map(ref2),
|
|
21634
|
+
...s.sentinel === void 0 ? {} : { sentinel: ref2(s.sentinel) },
|
|
21635
|
+
...s.recoverAt === void 0 ? {} : { recoverAt: ref2(s.recoverAt) },
|
|
21636
|
+
...s.stopAt === void 0 ? {} : { stopAt: ref2(s.stopAt) },
|
|
21637
|
+
...s.prefix === void 0 ? {} : { prefix: ref2(s.prefix) },
|
|
21638
|
+
...s.body === void 0 ? {} : { body: ref2(s.body) },
|
|
21639
|
+
...s.first === void 0 ? {} : { first: ref2(s.first) },
|
|
21640
|
+
...s.lazy === void 0 ? {} : { lazy: ref2(s.lazy) }
|
|
21641
|
+
}));
|
|
21642
|
+
const scanSkip = prog.scanSkip?.map((set) => set.map(ref2));
|
|
21643
|
+
const report = fn((v, span) => {
|
|
21644
|
+
rec.consume(span.start, span.end);
|
|
21645
|
+
return v;
|
|
21646
|
+
});
|
|
21647
|
+
const lookIn = fn(() => {
|
|
21648
|
+
rec.enterLookahead();
|
|
21649
|
+
return true;
|
|
21650
|
+
});
|
|
21651
|
+
const lookOut = fn((v) => {
|
|
21652
|
+
rec.exitLookahead();
|
|
21653
|
+
return v;
|
|
21654
|
+
});
|
|
21655
|
+
const regexTry = fn(() => {
|
|
21656
|
+
rec.regexAttempt();
|
|
21657
|
+
return true;
|
|
21658
|
+
});
|
|
21659
|
+
const lookahead = (child, fxi) => row(
|
|
21660
|
+
OP_ARMGATE,
|
|
21661
|
+
lookIn,
|
|
21662
|
+
row(OP_XFORM, lookOut, row(OP_NOT, row(OP_XFORM, lookOut, replacement(child) ?? child), fxi)),
|
|
21663
|
+
noFx
|
|
21664
|
+
);
|
|
21665
|
+
const replaced = /* @__PURE__ */ new Map();
|
|
21666
|
+
function replacement(c) {
|
|
21667
|
+
const hit = replaced.get(c);
|
|
21668
|
+
if (hit !== void 0) return hit;
|
|
21669
|
+
let r;
|
|
21670
|
+
switch (code[c]) {
|
|
21671
|
+
case OP_LIT:
|
|
21672
|
+
case OP_LIT_TRACK:
|
|
21673
|
+
case OP_LIT_CI:
|
|
21674
|
+
case OP_LIT_CI_TRACK:
|
|
21675
|
+
case OP_LEX_BODY:
|
|
21676
|
+
case OP_LEX_PROGRAM:
|
|
21677
|
+
case OP_SCAN:
|
|
21678
|
+
case OP_LIVE:
|
|
21679
|
+
r = row(OP_XFORM, report, c);
|
|
21680
|
+
break;
|
|
21681
|
+
case OP_RX:
|
|
21682
|
+
case OP_RX_TRACK: {
|
|
21683
|
+
const re = prog.k[code[c + 1]];
|
|
21684
|
+
r = hasLookaround(re) ? row(
|
|
21685
|
+
OP_ARMGATE,
|
|
21686
|
+
regexTry,
|
|
21687
|
+
row(OP_XFORM, fn((v, span) => {
|
|
21688
|
+
rec.regexMatch(re, span.start, span.end);
|
|
21689
|
+
return v;
|
|
21690
|
+
}), c),
|
|
21691
|
+
noFx
|
|
21692
|
+
) : row(OP_XFORM, report, c);
|
|
21693
|
+
break;
|
|
21694
|
+
}
|
|
21695
|
+
case OP_NOT:
|
|
21696
|
+
r = lookahead(code[c + 1], code[c + 2]);
|
|
21697
|
+
break;
|
|
21698
|
+
case OP_PEEK:
|
|
21699
|
+
r = row(OP_NOT, lookahead(code[c + 1], code[c + 2]), code[c + 2]);
|
|
21700
|
+
break;
|
|
21701
|
+
}
|
|
21702
|
+
if (r !== void 0) replaced.set(c, r);
|
|
21703
|
+
return r;
|
|
21704
|
+
}
|
|
21705
|
+
const rules = {};
|
|
21706
|
+
const stack = [];
|
|
21707
|
+
for (const [name, ip] of Object.entries(prog.rules)) {
|
|
21708
|
+
rules[name] = replacement(ip) ?? ip;
|
|
21709
|
+
stack.push(ip);
|
|
21710
|
+
}
|
|
21711
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21712
|
+
while (stack.length > 0) {
|
|
21713
|
+
const ip = stack.pop();
|
|
21714
|
+
if (seen.has(ip)) continue;
|
|
21715
|
+
seen.add(ip);
|
|
21716
|
+
slots.length = 0;
|
|
21717
|
+
if (!childSlotOffsets(code, ip, slots)) throw new Error(`backtrack probe: unknown opcode ${String(code[ip])} at ${ip}`);
|
|
21718
|
+
for (let i = 0; i < slots.length; i++) {
|
|
21719
|
+
const s = slots[i];
|
|
21720
|
+
const c = code[s];
|
|
21721
|
+
stack.push(c);
|
|
21722
|
+
if (code[ip] === OP_GREEDY && i > 0) continue;
|
|
21723
|
+
const r = replacement(c);
|
|
21724
|
+
if (r !== void 0) code[s] = r;
|
|
21725
|
+
}
|
|
21726
|
+
}
|
|
21727
|
+
const out = Object.fromEntries(Object.entries(prog));
|
|
21728
|
+
return {
|
|
21729
|
+
...out,
|
|
21730
|
+
code,
|
|
21731
|
+
fns,
|
|
21732
|
+
fx,
|
|
21733
|
+
rules,
|
|
21734
|
+
asm: [],
|
|
21735
|
+
...scans === void 0 ? {} : { scans },
|
|
21736
|
+
...scanSkip === void 0 ? {} : { scanSkip }
|
|
21737
|
+
};
|
|
21738
|
+
}
|
|
21739
|
+
|
|
21740
|
+
// src/analysis/backtrack.ts
|
|
21741
|
+
function isCombinator3(x) {
|
|
21742
|
+
return typeof x === "object" && x !== null && "_def" in x && typeof x.parse === "function";
|
|
21743
|
+
}
|
|
21744
|
+
function isProgram(x) {
|
|
21745
|
+
return Array.isArray(x.code) || Array.isArray(x.c);
|
|
21746
|
+
}
|
|
21747
|
+
function ruleEntries(grammar) {
|
|
21748
|
+
const out = [];
|
|
21749
|
+
for (const [name, value] of Object.entries(grammar)) {
|
|
21750
|
+
if (!isCombinator3(value)) continue;
|
|
21751
|
+
if (value._def.tag === "lazy") {
|
|
21752
|
+
try {
|
|
21753
|
+
value._def.thunk();
|
|
21754
|
+
} catch {
|
|
21755
|
+
continue;
|
|
21756
|
+
}
|
|
21757
|
+
}
|
|
21758
|
+
out.push([name, value]);
|
|
21759
|
+
}
|
|
21760
|
+
return out;
|
|
21761
|
+
}
|
|
21762
|
+
function outcome(r) {
|
|
21763
|
+
return digestValue({ ok: r.ok, value: r.value, span: r.span, unconsumedFrom: r.unconsumedFrom });
|
|
21764
|
+
}
|
|
21765
|
+
function tableOf(grammar) {
|
|
21766
|
+
if (isProgram(grammar)) return expandCompact(grammar);
|
|
21767
|
+
const refusals = [];
|
|
21768
|
+
const compiled = compileRuleMapRunnable(ruleEntries(grammar), { refusals });
|
|
21769
|
+
if (compiled === null) throw new Error(`backtrackProbe: this grammar could not be encoded to a table: ${refusals.join("; ")}`);
|
|
21770
|
+
return compiled.prog;
|
|
21771
|
+
}
|
|
21772
|
+
function backtrackProbe(grammar, engine = "closure") {
|
|
21773
|
+
const rec = new BacktrackRecorder();
|
|
21774
|
+
if (engine === "interpreter") {
|
|
21775
|
+
if (isProgram(grammar)) throw new TypeError("backtrackProbe: the interpreter runs a rule map of combinators, not a table program");
|
|
21776
|
+
const rules2 = Object.fromEntries(ruleEntries(grammar));
|
|
21777
|
+
const built = /* @__PURE__ */ new Map();
|
|
21778
|
+
const instrument = instrumentFor(rec);
|
|
21779
|
+
return probe(rec, "interpreter", (entry) => ruleOf(rules2, entry), (entry) => {
|
|
21780
|
+
let hit = built.get(entry);
|
|
21781
|
+
if (hit === void 0) {
|
|
21782
|
+
hit = rebuildCombinator(ruleOf(rules2, entry), /* @__PURE__ */ new Map(), { thaw: true, after: instrument }).root;
|
|
21783
|
+
built.set(entry, hit);
|
|
21784
|
+
}
|
|
21785
|
+
return hit;
|
|
21786
|
+
});
|
|
21787
|
+
}
|
|
21788
|
+
if (engine !== "closure") throw new TypeError(`backtrackProbe: no engine ${JSON.stringify(engine)}; it runs 'closure' or 'interpreter'`);
|
|
21789
|
+
const prog = tableOf(grammar);
|
|
21790
|
+
const base = tableRules({ ...prog, asm: [] });
|
|
21791
|
+
const rules = tableRules(probeProgram(prog, rec));
|
|
21792
|
+
return probe(rec, "closure", (entry) => ruleOf(base, entry), (entry) => ruleOf(rules, entry));
|
|
21793
|
+
}
|
|
21794
|
+
function probe(rec, ran, plain2, probed) {
|
|
21795
|
+
return {
|
|
21796
|
+
engine: { ran },
|
|
21797
|
+
measure(entry, input, options = {}) {
|
|
21798
|
+
const result = run(plain2(entry), input, options);
|
|
21799
|
+
rec.begin(input);
|
|
21800
|
+
const probedResult = run(probed(entry), input, options);
|
|
21801
|
+
const counts = rec.end();
|
|
21802
|
+
if (outcome(probedResult) !== outcome(result)) {
|
|
21803
|
+
throw new Error(`backtrackProbe: the probed ${ran} parse of rule ${JSON.stringify(entry)} differs from the plain one; its counts would describe another parse`);
|
|
21804
|
+
}
|
|
21805
|
+
return { result, counts };
|
|
21806
|
+
}
|
|
21807
|
+
};
|
|
21808
|
+
}
|
|
21809
|
+
function ruleOf(rules, entry) {
|
|
21810
|
+
if (!Object.hasOwn(rules, entry)) throw new Error(`backtrackProbe: the grammar has no rule ${JSON.stringify(entry)}`);
|
|
21811
|
+
return rules[entry];
|
|
21812
|
+
}
|
|
21813
|
+
function wrapped(out, parse2) {
|
|
21814
|
+
const w = { _tag: out._tag, _meta: out._meta, _def: out._def, parse: parse2 };
|
|
21815
|
+
const name = out._ruleName;
|
|
21816
|
+
if (name !== void 0) w._ruleName = name;
|
|
21817
|
+
return w;
|
|
21818
|
+
}
|
|
21819
|
+
function instrumentFor(rec) {
|
|
21820
|
+
return (_original, out) => {
|
|
21821
|
+
const d = out._def;
|
|
21822
|
+
switch (d.tag) {
|
|
21823
|
+
case "literal":
|
|
21824
|
+
case "keywords":
|
|
21825
|
+
return wrapped(out, (input, pos, ctx) => {
|
|
21826
|
+
const r = out.parse(input, pos, ctx);
|
|
21827
|
+
if (r.ok) rec.consume(r.span.start, r.span.end);
|
|
21828
|
+
return r;
|
|
21829
|
+
});
|
|
21830
|
+
case "regex": {
|
|
21831
|
+
const re = new RegExp(d.source, d.flags);
|
|
21832
|
+
if (!hasLookaround(re)) {
|
|
21833
|
+
return wrapped(out, (input, pos, ctx) => {
|
|
21834
|
+
const r = out.parse(input, pos, ctx);
|
|
21835
|
+
if (r.ok) rec.consume(r.span.start, r.span.end);
|
|
21836
|
+
return r;
|
|
21837
|
+
});
|
|
21838
|
+
}
|
|
21839
|
+
return wrapped(out, (input, pos, ctx) => {
|
|
21840
|
+
rec.regexAttempt();
|
|
21841
|
+
const r = out.parse(input, pos, ctx);
|
|
21842
|
+
if (r.ok) rec.regexMatch(re, r.span.start, r.span.end);
|
|
21843
|
+
return r;
|
|
21844
|
+
});
|
|
21845
|
+
}
|
|
21846
|
+
case "scanTo":
|
|
21847
|
+
case "lines":
|
|
21848
|
+
case "columns":
|
|
21849
|
+
case "recover":
|
|
21850
|
+
case "unknown":
|
|
21851
|
+
return wrapped(out, (input, pos, ctx) => {
|
|
21852
|
+
rec.enterOpaque();
|
|
21853
|
+
let r;
|
|
21854
|
+
try {
|
|
21855
|
+
r = out.parse(input, pos, ctx);
|
|
21856
|
+
} finally {
|
|
21857
|
+
rec.exitOpaque();
|
|
21858
|
+
}
|
|
21859
|
+
if (r.ok) rec.consume(r.span.start, r.span.end);
|
|
21860
|
+
return r;
|
|
21861
|
+
});
|
|
21862
|
+
case "not":
|
|
21863
|
+
case "peek":
|
|
21864
|
+
return wrapped(out, (input, pos, ctx) => {
|
|
21865
|
+
rec.enterLookahead();
|
|
21866
|
+
try {
|
|
21867
|
+
return out.parse(input, pos, ctx);
|
|
21868
|
+
} finally {
|
|
21869
|
+
rec.exitLookahead();
|
|
21870
|
+
}
|
|
21871
|
+
});
|
|
21872
|
+
default:
|
|
21873
|
+
return out;
|
|
21874
|
+
}
|
|
21875
|
+
};
|
|
21876
|
+
}
|
|
20874
21877
|
export {
|
|
20875
21878
|
applyFixEdits,
|
|
20876
21879
|
armFirstSets,
|
|
21880
|
+
backtrackProbe,
|
|
20877
21881
|
diagnosisLines,
|
|
20878
21882
|
fixReportLines,
|
|
20879
21883
|
groupDigits,
|