parseman 0.51.0 → 0.51.2
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/diagnostics.js +48 -15
- package/dist/analysis/diagnostics.js.map +1 -1
- package/dist/cli/index.js +50 -17
- package/dist/cli/index.js.map +1 -1
- package/dist/combinators/token.d.ts +8 -8
- package/dist/combinators/token.d.ts.map +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -21
- package/dist/index.js.map +1 -1
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.js +59 -22
- package/dist/plugin/index.js.map +1 -1
- package/dist/spec/index.js +27 -5
- package/dist/spec/index.js.map +1 -1
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/encode-baseline.d.ts.map +1 -1
- package/dist/table/exec-baseline.d.ts.map +1 -1
- package/dist/table/exec.d.ts.map +1 -1
- package/dist/table/index.js +373 -362
- package/dist/table/index.js.map +2 -2
- package/dist/table/ops.d.ts +2 -0
- package/dist/table/ops.d.ts.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/analysis/duplication.ts +1 -1
- package/src/analysis/rebuild.ts +2 -2
- package/src/combinators/token.ts +46 -3
- package/src/compiler/ir-serialize.ts +11 -7
- package/src/coverage.ts +2 -3
- package/src/index.ts +1 -1
- package/src/plugin/evaluator.ts +7 -4
- package/src/table/assemble.ts +8 -3
- package/src/table/child-slots.ts +2 -2
- package/src/table/emit-assembly.ts +5 -3
- package/src/table/encode-baseline.ts +3 -2
- package/src/table/encode.ts +3 -3
- package/src/table/exec-baseline.ts +30 -4
- package/src/table/exec.ts +8 -3
- package/src/table/ops.ts +3 -1
- package/src/table/scalar-terminal.ts +5 -5
- package/src/table/site-labels.ts +2 -2
- package/src/types.ts +1 -1
- package/src/version.ts +1 -1
package/dist/table/index.js
CHANGED
|
@@ -3434,6 +3434,271 @@ function ref() {
|
|
|
3434
3434
|
return slot;
|
|
3435
3435
|
}
|
|
3436
3436
|
|
|
3437
|
+
// src/compiler/degradation.ts
|
|
3438
|
+
function formatDegradation(d) {
|
|
3439
|
+
return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
|
|
3440
|
+
}
|
|
3441
|
+
var DETAIL_CAP = 8;
|
|
3442
|
+
function formatDegradations(list) {
|
|
3443
|
+
const byCode = /* @__PURE__ */ new Map();
|
|
3444
|
+
for (const d of list) {
|
|
3445
|
+
const bucket = byCode.get(d.code);
|
|
3446
|
+
if (bucket) bucket.push(d);
|
|
3447
|
+
else byCode.set(d.code, [d]);
|
|
3448
|
+
}
|
|
3449
|
+
const out = [];
|
|
3450
|
+
for (const [code, items] of byCode) {
|
|
3451
|
+
for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
|
|
3452
|
+
if (items.length > DETAIL_CAP) {
|
|
3453
|
+
out.push(
|
|
3454
|
+
`[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
|
|
3455
|
+
);
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
return out;
|
|
3459
|
+
}
|
|
3460
|
+
var _sinks = [];
|
|
3461
|
+
function beginDegradationCapture() {
|
|
3462
|
+
_sinks.push(/* @__PURE__ */ new Map());
|
|
3463
|
+
}
|
|
3464
|
+
function degradationCaptureDepth() {
|
|
3465
|
+
return _sinks.length;
|
|
3466
|
+
}
|
|
3467
|
+
function unwindDegradationCapture(depth) {
|
|
3468
|
+
const found = [];
|
|
3469
|
+
while (_sinks.length > depth) {
|
|
3470
|
+
const sink = _sinks.pop();
|
|
3471
|
+
found.unshift(...sink.values());
|
|
3472
|
+
}
|
|
3473
|
+
return found;
|
|
3474
|
+
}
|
|
3475
|
+
function resolveDegradationLevel(explicit) {
|
|
3476
|
+
if (explicit !== void 0) return explicit;
|
|
3477
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
|
|
3478
|
+
if (env === "off" || env === "warn" || env === "error") return env;
|
|
3479
|
+
return "warn";
|
|
3480
|
+
}
|
|
3481
|
+
function degradationKey(d) {
|
|
3482
|
+
return JSON.stringify([d.code, d.where, d.subject]);
|
|
3483
|
+
}
|
|
3484
|
+
function recordDegradation(d) {
|
|
3485
|
+
const level = resolveDegradationLevel();
|
|
3486
|
+
if (level === "off") return;
|
|
3487
|
+
const key = degradationKey(d);
|
|
3488
|
+
const sink = _sinks[_sinks.length - 1];
|
|
3489
|
+
if (sink) {
|
|
3490
|
+
if (!sink.has(key)) sink.set(key, d);
|
|
3491
|
+
return;
|
|
3492
|
+
}
|
|
3493
|
+
if (_immediate.has(key)) return;
|
|
3494
|
+
_immediate.add(key);
|
|
3495
|
+
if (level === "error") throw new Error(`parseman: degraded compilation path
|
|
3496
|
+
${formatDegradation(d)}`);
|
|
3497
|
+
console.warn(formatDegradation(d));
|
|
3498
|
+
}
|
|
3499
|
+
var _immediate = /* @__PURE__ */ new Set();
|
|
3500
|
+
function beginCompileDegradationDrain() {
|
|
3501
|
+
if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
|
|
3502
|
+
};
|
|
3503
|
+
const depth = degradationCaptureDepth();
|
|
3504
|
+
beginDegradationCapture();
|
|
3505
|
+
return (report) => {
|
|
3506
|
+
const found = unwindDegradationCapture(depth);
|
|
3507
|
+
if (!report || found.length === 0) return;
|
|
3508
|
+
const fresh = found.filter((d) => {
|
|
3509
|
+
const k = degradationKey(d);
|
|
3510
|
+
if (_immediate.has(k)) return false;
|
|
3511
|
+
_immediate.add(k);
|
|
3512
|
+
return true;
|
|
3513
|
+
});
|
|
3514
|
+
if (fresh.length === 0) return;
|
|
3515
|
+
const lines = formatDegradations(fresh);
|
|
3516
|
+
if (resolveDegradationLevel() === "error") {
|
|
3517
|
+
throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
|
|
3518
|
+
${lines.join("\n")}`);
|
|
3519
|
+
}
|
|
3520
|
+
for (const l of lines) console.warn(l);
|
|
3521
|
+
};
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
// src/compiler/build-arity.ts
|
|
3525
|
+
function cstOutputHost(build) {
|
|
3526
|
+
return build?._parsemanCstOutput === true;
|
|
3527
|
+
}
|
|
3528
|
+
var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
|
|
3529
|
+
var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
|
|
3530
|
+
var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
|
|
3531
|
+
var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
|
|
3532
|
+
function confirmedBuildArity(src) {
|
|
3533
|
+
const s = src.trim();
|
|
3534
|
+
if (NATIVE_CODE_RE.test(s)) return null;
|
|
3535
|
+
if (/\barguments\b/.test(s)) return null;
|
|
3536
|
+
if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
|
|
3537
|
+
const inner = paramListText(s);
|
|
3538
|
+
if (inner === null) return null;
|
|
3539
|
+
if (inner.trim() === "") return 0;
|
|
3540
|
+
const parts = splitTopLevel(inner);
|
|
3541
|
+
if (parts === null) return null;
|
|
3542
|
+
for (const part of parts) {
|
|
3543
|
+
if (!isConfirmableParam(part.trim())) return null;
|
|
3544
|
+
}
|
|
3545
|
+
return parts.length;
|
|
3546
|
+
}
|
|
3547
|
+
function paramListText(s) {
|
|
3548
|
+
const open = PARAM_LIST_OPEN_RE.exec(s);
|
|
3549
|
+
if (!open) return null;
|
|
3550
|
+
const start = open[0].length;
|
|
3551
|
+
const end = matchingParen(s, start);
|
|
3552
|
+
if (end === null) return null;
|
|
3553
|
+
if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
|
|
3554
|
+
return s.slice(start, end);
|
|
3555
|
+
}
|
|
3556
|
+
function matchingParen(s, start) {
|
|
3557
|
+
let depth = 0;
|
|
3558
|
+
for (let i = start; i < s.length; i++) {
|
|
3559
|
+
const c = s[i];
|
|
3560
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3561
|
+
const close = skipString(s, i);
|
|
3562
|
+
if (close === null) return null;
|
|
3563
|
+
i = close;
|
|
3564
|
+
continue;
|
|
3565
|
+
}
|
|
3566
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3567
|
+
else if (c === "]" || c === "}") {
|
|
3568
|
+
if (--depth < 0) return null;
|
|
3569
|
+
} else if (c === ")") {
|
|
3570
|
+
if (depth === 0) return i;
|
|
3571
|
+
depth--;
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
return null;
|
|
3575
|
+
}
|
|
3576
|
+
function skipString(s, open) {
|
|
3577
|
+
const quote = s[open];
|
|
3578
|
+
for (let i = open + 1; i < s.length; i++) {
|
|
3579
|
+
if (s[i] === "\\") {
|
|
3580
|
+
i++;
|
|
3581
|
+
continue;
|
|
3582
|
+
}
|
|
3583
|
+
if (s[i] === quote) return i;
|
|
3584
|
+
}
|
|
3585
|
+
return null;
|
|
3586
|
+
}
|
|
3587
|
+
function splitTopLevel(inner) {
|
|
3588
|
+
const parts = [];
|
|
3589
|
+
let depth = 0;
|
|
3590
|
+
let angle = 0;
|
|
3591
|
+
let last = 0;
|
|
3592
|
+
for (let i = 0; i < inner.length; i++) {
|
|
3593
|
+
const c = inner[i];
|
|
3594
|
+
if (c === "=" && inner[i + 1] === ">") {
|
|
3595
|
+
i++;
|
|
3596
|
+
continue;
|
|
3597
|
+
}
|
|
3598
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
3599
|
+
const close = skipString(inner, i);
|
|
3600
|
+
if (close === null) return null;
|
|
3601
|
+
i = close;
|
|
3602
|
+
continue;
|
|
3603
|
+
}
|
|
3604
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3605
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
3606
|
+
if (--depth < 0) return null;
|
|
3607
|
+
} else if (c === "<") angle++;
|
|
3608
|
+
else if (c === ">") {
|
|
3609
|
+
if (--angle < 0) return null;
|
|
3610
|
+
} else if (c === "," && depth === 0 && angle === 0) {
|
|
3611
|
+
parts.push(inner.slice(last, i));
|
|
3612
|
+
last = i + 1;
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
if (depth !== 0 || angle !== 0) return null;
|
|
3616
|
+
parts.push(inner.slice(last));
|
|
3617
|
+
return parts;
|
|
3618
|
+
}
|
|
3619
|
+
function isConfirmableParam(part) {
|
|
3620
|
+
const head = PARAM_HEAD_RE.exec(part);
|
|
3621
|
+
if (!head) return false;
|
|
3622
|
+
const rest = part.slice(head[0].length);
|
|
3623
|
+
if (rest === "") return true;
|
|
3624
|
+
if (rest[0] !== ":") return false;
|
|
3625
|
+
return !hasDefaultAssign(rest.slice(1));
|
|
3626
|
+
}
|
|
3627
|
+
function hasDefaultAssign(annotation) {
|
|
3628
|
+
for (let i = 0; i < annotation.length; i++) {
|
|
3629
|
+
if (annotation[i] !== "=") continue;
|
|
3630
|
+
if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
|
|
3631
|
+
i++;
|
|
3632
|
+
continue;
|
|
3633
|
+
}
|
|
3634
|
+
const prev = annotation[i - 1];
|
|
3635
|
+
if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
|
|
3636
|
+
return true;
|
|
3637
|
+
}
|
|
3638
|
+
return false;
|
|
3639
|
+
}
|
|
3640
|
+
function buildAnalysisSrc(def) {
|
|
3641
|
+
return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
|
|
3642
|
+
}
|
|
3643
|
+
var RESOLVER_REASONS = {
|
|
3644
|
+
"rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
|
|
3645
|
+
"arguments": "its body references `arguments`",
|
|
3646
|
+
"reassigned": "the binding it names is reassigned, so the function read here is not decidable",
|
|
3647
|
+
"not-a-function": "the binding it names is not a function declaration",
|
|
3648
|
+
"unresolved-import": "its module could not be resolved or parsed",
|
|
3649
|
+
"not-found": "the name did not resolve to any binding",
|
|
3650
|
+
"computed": "it is a computed expression",
|
|
3651
|
+
"foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
|
|
3652
|
+
"ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
|
|
3653
|
+
};
|
|
3654
|
+
function unconfirmableReason(def, src) {
|
|
3655
|
+
const declared = def.buildArityUnresolved;
|
|
3656
|
+
if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
|
|
3657
|
+
const s = src.trim();
|
|
3658
|
+
const params = s.slice(0, s.indexOf(")") + 1);
|
|
3659
|
+
if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
|
|
3660
|
+
if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
|
|
3661
|
+
if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
|
|
3662
|
+
return "it names a binding this build could not resolve to a function declaration";
|
|
3663
|
+
}
|
|
3664
|
+
return "its parameter list could not be parsed";
|
|
3665
|
+
}
|
|
3666
|
+
function confirmedArityForDef(def) {
|
|
3667
|
+
if (def.buildArity !== void 0) return def.buildArity;
|
|
3668
|
+
const src = buildAnalysisSrc(def);
|
|
3669
|
+
const arity = confirmedBuildArity(src);
|
|
3670
|
+
if (arity !== null) return arity;
|
|
3671
|
+
const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
|
|
3672
|
+
recordDegradation({
|
|
3673
|
+
code: "build-arity-unconfirmed",
|
|
3674
|
+
severity: "warn",
|
|
3675
|
+
where: `node("${def.type ?? "<inferred>"}")`,
|
|
3676
|
+
subject,
|
|
3677
|
+
fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and clones \`_ctx.state\` on every match`,
|
|
3678
|
+
otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
|
|
3679
|
+
});
|
|
3680
|
+
return null;
|
|
3681
|
+
}
|
|
3682
|
+
function buildReadsRaw(def) {
|
|
3683
|
+
if (!def.build) return true;
|
|
3684
|
+
if (def.buildRawUnused === true) return false;
|
|
3685
|
+
const arity = confirmedArityForDef(def);
|
|
3686
|
+
if (arity === null) return true;
|
|
3687
|
+
return arity >= 4;
|
|
3688
|
+
}
|
|
3689
|
+
function buildReadsTrivia(def) {
|
|
3690
|
+
if (!def.build) return true;
|
|
3691
|
+
const arity = confirmedArityForDef(def);
|
|
3692
|
+
if (arity === null) return true;
|
|
3693
|
+
return arity >= 5;
|
|
3694
|
+
}
|
|
3695
|
+
function buildReadsState(def) {
|
|
3696
|
+
if (!def.build) return true;
|
|
3697
|
+
const arity = confirmedArityForDef(def);
|
|
3698
|
+
if (arity === null) return true;
|
|
3699
|
+
return arity >= 6;
|
|
3700
|
+
}
|
|
3701
|
+
|
|
3437
3702
|
// src/combinators/token.ts
|
|
3438
3703
|
function token(root) {
|
|
3439
3704
|
const meta = {
|
|
@@ -3632,369 +3897,104 @@ function scanTo(sentinel, { skip, raw = false, orEOF = false, recoverAt, stopAt
|
|
|
3632
3897
|
const recover = recoverAt.parse(input, cur, probeCtx);
|
|
3633
3898
|
const errors = ctx._errors;
|
|
3634
3899
|
if (errors !== void 0 && errorCount >= 0 && errors.length > errorCount) {
|
|
3635
|
-
errors.length = errorCount;
|
|
3636
|
-
}
|
|
3637
|
-
if (recover.ok) {
|
|
3638
|
-
if (recover.span.end <= cur) {
|
|
3639
|
-
throw new TypeError("scanTo recoverAt must consume input");
|
|
3640
|
-
}
|
|
3641
|
-
if (recovery < 0) {
|
|
3642
|
-
recovery = cur;
|
|
3643
|
-
recoveryErrorCount = errorCount;
|
|
3644
|
-
}
|
|
3645
|
-
if (firstSentinel >= 0 && (sentinelCount & 1) === 1) {
|
|
3646
|
-
return succeed(recoveredEnd());
|
|
3647
|
-
}
|
|
3648
|
-
cur = recover.span.end;
|
|
3649
|
-
continue;
|
|
3650
|
-
}
|
|
3651
|
-
}
|
|
3652
|
-
cur++;
|
|
3653
|
-
}
|
|
3654
|
-
if (recovery >= 0) return succeed(recoveredEnd());
|
|
3655
|
-
if (orEOF) {
|
|
3656
|
-
return succeed(cur);
|
|
3657
|
-
}
|
|
3658
|
-
const sentDef = sentinel._def;
|
|
3659
|
-
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
3660
|
-
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
3661
|
-
}
|
|
3662
|
-
};
|
|
3663
|
-
}
|
|
3664
|
-
function markSpec(outer, open, close, ownSkip, strict, raw) {
|
|
3665
|
-
;
|
|
3666
|
-
outer._balancedSpec = { open, close, ownSkip, strict, raw };
|
|
3667
|
-
return outer;
|
|
3668
|
-
}
|
|
3669
|
-
function balanced(open, close, options = {}) {
|
|
3670
|
-
const ownSkip = options.skip ?? [];
|
|
3671
|
-
const strict = options.strict ?? false;
|
|
3672
|
-
const combi = buildBalancedInterior(open, close, ownSkip, strict);
|
|
3673
|
-
if (options.raw) return markSpec(token(combi), open, close, ownSkip, strict, true);
|
|
3674
|
-
const eagerParse = combi.parse.bind(combi);
|
|
3675
|
-
const cache = /* @__PURE__ */ new Map();
|
|
3676
|
-
combi._balancedAmbient = { open, close, ownSkip, strict };
|
|
3677
|
-
combi.parse = (input, pos, ctx) => {
|
|
3678
|
-
const amb = ctx.scanSkip;
|
|
3679
|
-
if (!amb || amb.length === 0) return eagerParse(input, pos, ctx);
|
|
3680
|
-
let interior = cache.get(amb);
|
|
3681
|
-
if (!interior) {
|
|
3682
|
-
interior = buildBalancedInterior(open, close, [...amb, ...ownSkip], strict);
|
|
3683
|
-
cache.set(amb, interior);
|
|
3684
|
-
}
|
|
3685
|
-
return interior.parse(input, pos, ctx);
|
|
3686
|
-
};
|
|
3687
|
-
return markSpec(token(combi), open, close, ownSkip, strict, false);
|
|
3688
|
-
}
|
|
3689
|
-
function buildBalancedInterior(open, close, skips, strict = false) {
|
|
3690
|
-
const self = ref();
|
|
3691
|
-
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
3692
|
-
let bounded = true;
|
|
3693
|
-
for (const sk of skips) {
|
|
3694
|
-
const cs = firstSetClassChars(sk);
|
|
3695
|
-
if (cs === null) {
|
|
3696
|
-
bounded = false;
|
|
3697
|
-
break;
|
|
3698
|
-
}
|
|
3699
|
-
for (const ch2 of cs) stop.add(ch2);
|
|
3700
|
-
}
|
|
3701
|
-
const cls = [...stop].map(escapeClassChar).join("");
|
|
3702
|
-
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
3703
|
-
const inner = many(choice(self, ...skips, content));
|
|
3704
|
-
const closer = strict ? literal(close) : expect(literal(close));
|
|
3705
|
-
const combi = transform(
|
|
3706
|
-
sequence(literal(open), inner, closer),
|
|
3707
|
-
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
3708
|
-
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
3709
|
-
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
3710
|
-
);
|
|
3711
|
-
if (combi._def.tag === "transform") {
|
|
3712
|
-
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
3713
|
-
combi._def.recognitionOnly = true;
|
|
3714
|
-
}
|
|
3715
|
-
;
|
|
3716
|
-
combi._balanced = { open, close };
|
|
3717
|
-
self.define(combi);
|
|
3718
|
-
return combi;
|
|
3719
|
-
}
|
|
3720
|
-
function firstSetClassChars(c) {
|
|
3721
|
-
const fs = c._meta.firstSet;
|
|
3722
|
-
if (fs.kind === "empty") return [];
|
|
3723
|
-
if (fs.kind !== "ranges") return null;
|
|
3724
|
-
const out = [];
|
|
3725
|
-
for (const { lo, hi } of fs.ranges) {
|
|
3726
|
-
if (hi - lo > 8) return null;
|
|
3727
|
-
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
3728
|
-
}
|
|
3729
|
-
return out;
|
|
3730
|
-
}
|
|
3731
|
-
function escapeClassChar(ch2) {
|
|
3732
|
-
return ch2.replace(/[\\\]^-]/g, "\\$&");
|
|
3733
|
-
}
|
|
3734
|
-
|
|
3735
|
-
// src/compiler/degradation.ts
|
|
3736
|
-
function formatDegradation(d) {
|
|
3737
|
-
return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
|
|
3738
|
-
}
|
|
3739
|
-
var DETAIL_CAP = 8;
|
|
3740
|
-
function formatDegradations(list) {
|
|
3741
|
-
const byCode = /* @__PURE__ */ new Map();
|
|
3742
|
-
for (const d of list) {
|
|
3743
|
-
const bucket = byCode.get(d.code);
|
|
3744
|
-
if (bucket) bucket.push(d);
|
|
3745
|
-
else byCode.set(d.code, [d]);
|
|
3746
|
-
}
|
|
3747
|
-
const out = [];
|
|
3748
|
-
for (const [code, items] of byCode) {
|
|
3749
|
-
for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
|
|
3750
|
-
if (items.length > DETAIL_CAP) {
|
|
3751
|
-
out.push(
|
|
3752
|
-
`[parseman] degraded [${code}] +${items.length - DETAIL_CAP} more site(s) not listed (${items.length} total). Set PARSEMAN_DEGRADATION=error to fail the build on these.`
|
|
3753
|
-
);
|
|
3754
|
-
}
|
|
3755
|
-
}
|
|
3756
|
-
return out;
|
|
3757
|
-
}
|
|
3758
|
-
var _sinks = [];
|
|
3759
|
-
function beginDegradationCapture() {
|
|
3760
|
-
_sinks.push(/* @__PURE__ */ new Map());
|
|
3761
|
-
}
|
|
3762
|
-
function degradationCaptureDepth() {
|
|
3763
|
-
return _sinks.length;
|
|
3764
|
-
}
|
|
3765
|
-
function unwindDegradationCapture(depth) {
|
|
3766
|
-
const found = [];
|
|
3767
|
-
while (_sinks.length > depth) {
|
|
3768
|
-
const sink = _sinks.pop();
|
|
3769
|
-
found.unshift(...sink.values());
|
|
3770
|
-
}
|
|
3771
|
-
return found;
|
|
3772
|
-
}
|
|
3773
|
-
function resolveDegradationLevel(explicit) {
|
|
3774
|
-
if (explicit !== void 0) return explicit;
|
|
3775
|
-
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
|
|
3776
|
-
if (env === "off" || env === "warn" || env === "error") return env;
|
|
3777
|
-
return "warn";
|
|
3778
|
-
}
|
|
3779
|
-
function degradationKey(d) {
|
|
3780
|
-
return JSON.stringify([d.code, d.where, d.subject]);
|
|
3781
|
-
}
|
|
3782
|
-
function recordDegradation(d) {
|
|
3783
|
-
const level = resolveDegradationLevel();
|
|
3784
|
-
if (level === "off") return;
|
|
3785
|
-
const key = degradationKey(d);
|
|
3786
|
-
const sink = _sinks[_sinks.length - 1];
|
|
3787
|
-
if (sink) {
|
|
3788
|
-
if (!sink.has(key)) sink.set(key, d);
|
|
3789
|
-
return;
|
|
3790
|
-
}
|
|
3791
|
-
if (_immediate.has(key)) return;
|
|
3792
|
-
_immediate.add(key);
|
|
3793
|
-
if (level === "error") throw new Error(`parseman: degraded compilation path
|
|
3794
|
-
${formatDegradation(d)}`);
|
|
3795
|
-
console.warn(formatDegradation(d));
|
|
3796
|
-
}
|
|
3797
|
-
var _immediate = /* @__PURE__ */ new Set();
|
|
3798
|
-
function beginCompileDegradationDrain() {
|
|
3799
|
-
if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
|
|
3800
|
-
};
|
|
3801
|
-
const depth = degradationCaptureDepth();
|
|
3802
|
-
beginDegradationCapture();
|
|
3803
|
-
return (report) => {
|
|
3804
|
-
const found = unwindDegradationCapture(depth);
|
|
3805
|
-
if (!report || found.length === 0) return;
|
|
3806
|
-
const fresh = found.filter((d) => {
|
|
3807
|
-
const k = degradationKey(d);
|
|
3808
|
-
if (_immediate.has(k)) return false;
|
|
3809
|
-
_immediate.add(k);
|
|
3810
|
-
return true;
|
|
3811
|
-
});
|
|
3812
|
-
if (fresh.length === 0) return;
|
|
3813
|
-
const lines = formatDegradations(fresh);
|
|
3814
|
-
if (resolveDegradationLevel() === "error") {
|
|
3815
|
-
throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
|
|
3816
|
-
${lines.join("\n")}`);
|
|
3900
|
+
errors.length = errorCount;
|
|
3901
|
+
}
|
|
3902
|
+
if (recover.ok) {
|
|
3903
|
+
if (recover.span.end <= cur) {
|
|
3904
|
+
throw new TypeError("scanTo recoverAt must consume input");
|
|
3905
|
+
}
|
|
3906
|
+
if (recovery < 0) {
|
|
3907
|
+
recovery = cur;
|
|
3908
|
+
recoveryErrorCount = errorCount;
|
|
3909
|
+
}
|
|
3910
|
+
if (firstSentinel >= 0 && (sentinelCount & 1) === 1) {
|
|
3911
|
+
return succeed(recoveredEnd());
|
|
3912
|
+
}
|
|
3913
|
+
cur = recover.span.end;
|
|
3914
|
+
continue;
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
cur++;
|
|
3918
|
+
}
|
|
3919
|
+
if (recovery >= 0) return succeed(recoveredEnd());
|
|
3920
|
+
if (orEOF) {
|
|
3921
|
+
return succeed(cur);
|
|
3922
|
+
}
|
|
3923
|
+
const sentDef = sentinel._def;
|
|
3924
|
+
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
3925
|
+
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
3817
3926
|
}
|
|
3818
|
-
for (const l of lines) console.warn(l);
|
|
3819
3927
|
};
|
|
3820
3928
|
}
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
return
|
|
3825
|
-
}
|
|
3826
|
-
var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
|
|
3827
|
-
var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
|
|
3828
|
-
var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
|
|
3829
|
-
var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
|
|
3830
|
-
function confirmedBuildArity(src) {
|
|
3831
|
-
const s = src.trim();
|
|
3832
|
-
if (NATIVE_CODE_RE.test(s)) return null;
|
|
3833
|
-
if (/\barguments\b/.test(s)) return null;
|
|
3834
|
-
if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
|
|
3835
|
-
const inner = paramListText(s);
|
|
3836
|
-
if (inner === null) return null;
|
|
3837
|
-
if (inner.trim() === "") return 0;
|
|
3838
|
-
const parts = splitTopLevel(inner);
|
|
3839
|
-
if (parts === null) return null;
|
|
3840
|
-
for (const part of parts) {
|
|
3841
|
-
if (!isConfirmableParam(part.trim())) return null;
|
|
3842
|
-
}
|
|
3843
|
-
return parts.length;
|
|
3844
|
-
}
|
|
3845
|
-
function paramListText(s) {
|
|
3846
|
-
const open = PARAM_LIST_OPEN_RE.exec(s);
|
|
3847
|
-
if (!open) return null;
|
|
3848
|
-
const start = open[0].length;
|
|
3849
|
-
const end = matchingParen(s, start);
|
|
3850
|
-
if (end === null) return null;
|
|
3851
|
-
if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
|
|
3852
|
-
return s.slice(start, end);
|
|
3853
|
-
}
|
|
3854
|
-
function matchingParen(s, start) {
|
|
3855
|
-
let depth = 0;
|
|
3856
|
-
for (let i = start; i < s.length; i++) {
|
|
3857
|
-
const c = s[i];
|
|
3858
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
3859
|
-
const close = skipString(s, i);
|
|
3860
|
-
if (close === null) return null;
|
|
3861
|
-
i = close;
|
|
3862
|
-
continue;
|
|
3863
|
-
}
|
|
3864
|
-
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3865
|
-
else if (c === "]" || c === "}") {
|
|
3866
|
-
if (--depth < 0) return null;
|
|
3867
|
-
} else if (c === ")") {
|
|
3868
|
-
if (depth === 0) return i;
|
|
3869
|
-
depth--;
|
|
3870
|
-
}
|
|
3871
|
-
}
|
|
3872
|
-
return null;
|
|
3929
|
+
function markSpec(outer, open, close, ownSkip, strict, raw) {
|
|
3930
|
+
;
|
|
3931
|
+
outer._balancedSpec = { open, close, ownSkip, strict, raw };
|
|
3932
|
+
return outer;
|
|
3873
3933
|
}
|
|
3874
|
-
function
|
|
3875
|
-
const
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3934
|
+
function balanced(open, close, options = {}) {
|
|
3935
|
+
const ownSkip = options.skip ?? [];
|
|
3936
|
+
const strict = options.strict ?? false;
|
|
3937
|
+
const combi = buildBalancedInterior(open, close, ownSkip, strict);
|
|
3938
|
+
if (options.raw) return markSpec(token(combi), open, close, ownSkip, strict, true);
|
|
3939
|
+
const eagerParse = combi.parse.bind(combi);
|
|
3940
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3941
|
+
combi._balancedAmbient = { open, close, ownSkip, strict };
|
|
3942
|
+
combi.parse = (input, pos, ctx) => {
|
|
3943
|
+
const amb = ctx.scanSkip;
|
|
3944
|
+
if (!amb || amb.length === 0) return eagerParse(input, pos, ctx);
|
|
3945
|
+
let interior = cache.get(amb);
|
|
3946
|
+
if (!interior) {
|
|
3947
|
+
interior = buildBalancedInterior(open, close, [...amb, ...ownSkip], strict);
|
|
3948
|
+
cache.set(amb, interior);
|
|
3880
3949
|
}
|
|
3881
|
-
|
|
3882
|
-
}
|
|
3883
|
-
return
|
|
3950
|
+
return interior.parse(input, pos, ctx);
|
|
3951
|
+
};
|
|
3952
|
+
return markSpec(token(combi), open, close, ownSkip, strict, false);
|
|
3884
3953
|
}
|
|
3885
|
-
function
|
|
3886
|
-
const
|
|
3887
|
-
|
|
3888
|
-
let
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
continue;
|
|
3895
|
-
}
|
|
3896
|
-
if (c === '"' || c === "'" || c === "`") {
|
|
3897
|
-
const close = skipString(inner, i);
|
|
3898
|
-
if (close === null) return null;
|
|
3899
|
-
i = close;
|
|
3900
|
-
continue;
|
|
3901
|
-
}
|
|
3902
|
-
if (c === "(" || c === "[" || c === "{") depth++;
|
|
3903
|
-
else if (c === ")" || c === "]" || c === "}") {
|
|
3904
|
-
if (--depth < 0) return null;
|
|
3905
|
-
} else if (c === "<") angle++;
|
|
3906
|
-
else if (c === ">") {
|
|
3907
|
-
if (--angle < 0) return null;
|
|
3908
|
-
} else if (c === "," && depth === 0 && angle === 0) {
|
|
3909
|
-
parts.push(inner.slice(last, i));
|
|
3910
|
-
last = i + 1;
|
|
3954
|
+
function buildBalancedInterior(open, close, skips, strict = false) {
|
|
3955
|
+
const self = ref();
|
|
3956
|
+
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
3957
|
+
let bounded = true;
|
|
3958
|
+
for (const sk of skips) {
|
|
3959
|
+
const cs = firstSetClassChars(sk);
|
|
3960
|
+
if (cs === null) {
|
|
3961
|
+
bounded = false;
|
|
3962
|
+
break;
|
|
3911
3963
|
}
|
|
3964
|
+
for (const ch2 of cs) stop.add(ch2);
|
|
3912
3965
|
}
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
for (let i = 0; i < annotation.length; i++) {
|
|
3927
|
-
if (annotation[i] !== "=") continue;
|
|
3928
|
-
if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
|
|
3929
|
-
i++;
|
|
3930
|
-
continue;
|
|
3931
|
-
}
|
|
3932
|
-
const prev = annotation[i - 1];
|
|
3933
|
-
if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
|
|
3934
|
-
return true;
|
|
3966
|
+
const cls = [...stop].map(escapeClassChar).join("");
|
|
3967
|
+
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
3968
|
+
const inner = many(choice(self, ...skips, content));
|
|
3969
|
+
const closer = strict ? literal(close) : expect(literal(close));
|
|
3970
|
+
const combi = transform(
|
|
3971
|
+
sequence(literal(open), inner, closer),
|
|
3972
|
+
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
3973
|
+
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
3974
|
+
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
3975
|
+
);
|
|
3976
|
+
if (combi._def.tag === "transform") {
|
|
3977
|
+
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
3978
|
+
combi._def.recognitionOnly = true;
|
|
3935
3979
|
}
|
|
3936
|
-
|
|
3937
|
-
}
|
|
3938
|
-
|
|
3939
|
-
return
|
|
3980
|
+
;
|
|
3981
|
+
combi._balanced = { open, close };
|
|
3982
|
+
self.define(combi);
|
|
3983
|
+
return combi;
|
|
3940
3984
|
}
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
"
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
"foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
|
|
3950
|
-
"ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
|
|
3951
|
-
};
|
|
3952
|
-
function unconfirmableReason(def, src) {
|
|
3953
|
-
const declared = def.buildArityUnresolved;
|
|
3954
|
-
if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
|
|
3955
|
-
const s = src.trim();
|
|
3956
|
-
const params = s.slice(0, s.indexOf(")") + 1);
|
|
3957
|
-
if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
|
|
3958
|
-
if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
|
|
3959
|
-
if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
|
|
3960
|
-
return "it names a binding this build could not resolve to a function declaration";
|
|
3985
|
+
function firstSetClassChars(c) {
|
|
3986
|
+
const fs = c._meta.firstSet;
|
|
3987
|
+
if (fs.kind === "empty") return [];
|
|
3988
|
+
if (fs.kind !== "ranges") return null;
|
|
3989
|
+
const out = [];
|
|
3990
|
+
for (const { lo, hi } of fs.ranges) {
|
|
3991
|
+
if (hi - lo > 8) return null;
|
|
3992
|
+
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
3961
3993
|
}
|
|
3962
|
-
return
|
|
3963
|
-
}
|
|
3964
|
-
function confirmedArityForDef(def) {
|
|
3965
|
-
if (def.buildArity !== void 0) return def.buildArity;
|
|
3966
|
-
const src = buildAnalysisSrc(def);
|
|
3967
|
-
const arity = confirmedBuildArity(src);
|
|
3968
|
-
if (arity !== null) return arity;
|
|
3969
|
-
const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
|
|
3970
|
-
recordDegradation({
|
|
3971
|
-
code: "build-arity-unconfirmed",
|
|
3972
|
-
severity: "warn",
|
|
3973
|
-
where: `node("${def.type ?? "<inferred>"}")`,
|
|
3974
|
-
subject,
|
|
3975
|
-
fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and clones \`_ctx.state\` on every match`,
|
|
3976
|
-
otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
|
|
3977
|
-
});
|
|
3978
|
-
return null;
|
|
3979
|
-
}
|
|
3980
|
-
function buildReadsRaw(def) {
|
|
3981
|
-
if (!def.build) return true;
|
|
3982
|
-
if (def.buildRawUnused === true) return false;
|
|
3983
|
-
const arity = confirmedArityForDef(def);
|
|
3984
|
-
if (arity === null) return true;
|
|
3985
|
-
return arity >= 4;
|
|
3986
|
-
}
|
|
3987
|
-
function buildReadsTrivia(def) {
|
|
3988
|
-
if (!def.build) return true;
|
|
3989
|
-
const arity = confirmedArityForDef(def);
|
|
3990
|
-
if (arity === null) return true;
|
|
3991
|
-
return arity >= 5;
|
|
3994
|
+
return out;
|
|
3992
3995
|
}
|
|
3993
|
-
function
|
|
3994
|
-
|
|
3995
|
-
const arity = confirmedArityForDef(def);
|
|
3996
|
-
if (arity === null) return true;
|
|
3997
|
-
return arity >= 6;
|
|
3996
|
+
function escapeClassChar(ch2) {
|
|
3997
|
+
return ch2.replace(/[\\\]^-]/g, "\\$&");
|
|
3998
3998
|
}
|
|
3999
3999
|
|
|
4000
4000
|
// src/compiler/fields.ts
|
|
@@ -4181,6 +4181,7 @@ var OP_COV = 40;
|
|
|
4181
4181
|
var OP_SCOPE_PLAIN = 41;
|
|
4182
4182
|
var OP_LEX_BODY = 42;
|
|
4183
4183
|
var OP_LEX_PROGRAM = 43;
|
|
4184
|
+
var OP_SOURCE_LEAF = 44;
|
|
4184
4185
|
var OP_DISPATCH = 25;
|
|
4185
4186
|
var OP_ROUTED = 26;
|
|
4186
4187
|
var OP_NAMES = {
|
|
@@ -4199,6 +4200,7 @@ var OP_NAMES = {
|
|
|
4199
4200
|
[OP_NOT]: "NOT",
|
|
4200
4201
|
[OP_PEEK]: "PEEK",
|
|
4201
4202
|
[OP_LEAF]: "LEAF",
|
|
4203
|
+
[OP_SOURCE_LEAF]: "SOURCE_LEAF",
|
|
4202
4204
|
[OP_EMPTY]: "EMPTY",
|
|
4203
4205
|
[OP_LIT_TRACK]: "LIT_TRACK",
|
|
4204
4206
|
[OP_RX_TRACK]: "RX_TRACK",
|
|
@@ -6047,6 +6049,7 @@ function childSlots(code, ip, out) {
|
|
|
6047
6049
|
case OP_NODE_TRACK:
|
|
6048
6050
|
case OP_FIELD:
|
|
6049
6051
|
case OP_LEAF:
|
|
6052
|
+
case OP_SOURCE_LEAF:
|
|
6050
6053
|
case OP_ARMGATE:
|
|
6051
6054
|
out.push(code[ip + 2]);
|
|
6052
6055
|
return true;
|
|
@@ -6155,7 +6158,7 @@ function transfer(code, ip, at, hostCst) {
|
|
|
6155
6158
|
if (at.tri === TRI_NONE && !at.buf) return at;
|
|
6156
6159
|
return { tri: TRI_NONE, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
|
|
6157
6160
|
}
|
|
6158
|
-
if (op === OP_LEAF) {
|
|
6161
|
+
if (op === OP_LEAF || op === OP_SOURCE_LEAF) {
|
|
6159
6162
|
if (!at.buf) return at;
|
|
6160
6163
|
return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
|
|
6161
6164
|
}
|
|
@@ -6242,7 +6245,7 @@ function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, th
|
|
|
6242
6245
|
depth++;
|
|
6243
6246
|
continue;
|
|
6244
6247
|
}
|
|
6245
|
-
if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
|
|
6248
|
+
if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || (op === OP_LEAF || op === OP_SOURCE_LEAF)) {
|
|
6246
6249
|
at = code[at + 2];
|
|
6247
6250
|
depth++;
|
|
6248
6251
|
continue;
|
|
@@ -6275,7 +6278,7 @@ function leadingScalarSequence(code, ip) {
|
|
|
6275
6278
|
at2 = code[at2 + 1];
|
|
6276
6279
|
continue;
|
|
6277
6280
|
}
|
|
6278
|
-
if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
|
|
6281
|
+
if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || (op === OP_LEAF || op === OP_SOURCE_LEAF)) {
|
|
6279
6282
|
at2 = code[at2 + 2];
|
|
6280
6283
|
continue;
|
|
6281
6284
|
}
|
|
@@ -6308,7 +6311,7 @@ function leadingScalarSequence(code, ip) {
|
|
|
6308
6311
|
at = code[at + 2];
|
|
6309
6312
|
continue;
|
|
6310
6313
|
}
|
|
6311
|
-
if (op === OP_GATE || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
|
|
6314
|
+
if (op === OP_GATE || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || (op === OP_LEAF || op === OP_SOURCE_LEAF)) {
|
|
6312
6315
|
at = code[at + 2];
|
|
6313
6316
|
continue;
|
|
6314
6317
|
}
|
|
@@ -6338,7 +6341,7 @@ function leadingLiteralFamily(code, constants, ip, minDepth = 2, limit = 4) {
|
|
|
6338
6341
|
if (op === OP_RULE || op === OP_LABEL || op === OP_TOKEN || op === OP_ATTEMPT || op === OP_PEEK) {
|
|
6339
6342
|
return walk(code[at + 1], depth + 1);
|
|
6340
6343
|
}
|
|
6341
|
-
if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
|
|
6344
|
+
if (op === OP_GATE || op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || (op === OP_LEAF || op === OP_SOURCE_LEAF)) {
|
|
6342
6345
|
return walk(code[at + 2], depth + 1);
|
|
6343
6346
|
}
|
|
6344
6347
|
if (op === OP_SEQ || op === OP_SEQV) {
|
|
@@ -7224,8 +7227,10 @@ ${rootCap ? "ctx._rootTriviaCapture=sR\n" : ""}return v
|
|
|
7224
7227
|
}
|
|
7225
7228
|
/* ── boundaries ──────────────────────────────────────────────────────── */
|
|
7226
7229
|
case OP_TOKEN:
|
|
7227
|
-
case OP_LEAF:
|
|
7230
|
+
case OP_LEAF:
|
|
7231
|
+
case OP_SOURCE_LEAF: {
|
|
7228
7232
|
const isToken = op === OP_TOKEN;
|
|
7233
|
+
const capturesSource = isToken || op === OP_SOURCE_LEAF && hostCst;
|
|
7229
7234
|
const fn = isToken ? void 0 : fnRef(code[ip + 1]);
|
|
7230
7235
|
const child = link(isToken ? code[ip + 1] : code[ip + 2]);
|
|
7231
7236
|
const wasCap = L.buf ? "true" : "(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)";
|
|
@@ -7258,7 +7263,7 @@ ctx._triviaLog=sOtl
|
|
|
7258
7263
|
if(v===FAIL)return FAIL
|
|
7259
7264
|
const e=EC.e
|
|
7260
7265
|
const out=${isToken ? "input.slice(pos,e)" : `${fn}(v,{start:pos,end:e})`}
|
|
7261
|
-
if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:out,span:{start:pos,end:e}})
|
|
7266
|
+
if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:${capturesSource ? "input.slice(pos,e)" : "out"},span:{start:pos,end:e}})
|
|
7262
7267
|
EC.e=e
|
|
7263
7268
|
return out
|
|
7264
7269
|
}`;
|
|
@@ -9691,7 +9696,8 @@ function assemble(t, prog, cfg) {
|
|
|
9691
9696
|
return value;
|
|
9692
9697
|
};
|
|
9693
9698
|
}
|
|
9694
|
-
case OP_LEAF:
|
|
9699
|
+
case OP_LEAF:
|
|
9700
|
+
case OP_SOURCE_LEAF: {
|
|
9695
9701
|
const fn = fns[code[ip + 1]];
|
|
9696
9702
|
const child = link(code[ip + 2]);
|
|
9697
9703
|
return (input, pos, ctx) => {
|
|
@@ -9719,7 +9725,11 @@ function assemble(t, prog, cfg) {
|
|
|
9719
9725
|
if (v === FAIL) return FAIL;
|
|
9720
9726
|
const end = EC.e;
|
|
9721
9727
|
const out = fn(v, { start: pos, end });
|
|
9722
|
-
if (wasCapturing) pushCstLeaf(ctx, {
|
|
9728
|
+
if (wasCapturing) pushCstLeaf(ctx, {
|
|
9729
|
+
_tag: "leaf",
|
|
9730
|
+
value: op === OP_SOURCE_LEAF && hostCst ? input.slice(pos, end) : out,
|
|
9731
|
+
span: { start: pos, end }
|
|
9732
|
+
});
|
|
9723
9733
|
EC.e = end;
|
|
9724
9734
|
return out;
|
|
9725
9735
|
};
|
|
@@ -13136,7 +13146,7 @@ var Encoder = class {
|
|
|
13136
13146
|
}
|
|
13137
13147
|
case "leaf": {
|
|
13138
13148
|
const child = this.node(d.parser).ip;
|
|
13139
|
-
return this.emit(OP_LEAF, this.fn(d.fn, d.fnSrc ?? null), child);
|
|
13149
|
+
return this.emit(d.cstValue === "source" ? OP_SOURCE_LEAF : OP_LEAF, this.fn(d.fn, d.fnSrc ?? null), child);
|
|
13140
13150
|
}
|
|
13141
13151
|
case "node": {
|
|
13142
13152
|
if (d.type === void 0) missingInferredType();
|
|
@@ -13361,6 +13371,7 @@ var Encoder = class {
|
|
|
13361
13371
|
case OP_WITHCTX:
|
|
13362
13372
|
case OP_XFORM:
|
|
13363
13373
|
case OP_LEAF:
|
|
13374
|
+
case OP_SOURCE_LEAF:
|
|
13364
13375
|
case OP_NODE:
|
|
13365
13376
|
case OP_NODE_TRACK:
|
|
13366
13377
|
return [ip + 2];
|
|
@@ -13853,7 +13864,7 @@ function payloadKey(p, d) {
|
|
|
13853
13864
|
case "transform":
|
|
13854
13865
|
return `transform\0${fnKey(d.fnSrc, d.fn)}\0${d.recognitionOnly === true}`;
|
|
13855
13866
|
case "leaf":
|
|
13856
|
-
return `leaf\0${fnKey(d.fnSrc, d.fn)}`;
|
|
13867
|
+
return `leaf\0${d.cstValue ?? "value"}\0${fnKey(d.fnSrc, d.fn)}`;
|
|
13857
13868
|
case "many":
|
|
13858
13869
|
case "oneOrMore":
|
|
13859
13870
|
return `${d.tag}\0${d.min}\0${d.max ?? ""}`;
|