parseman 0.51.1 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/analysis/commitment.d.ts.map +1 -1
  2. package/dist/analysis/diagnostics.js +101 -35
  3. package/dist/analysis/diagnostics.js.map +1 -1
  4. package/dist/cli/index.js +103 -37
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/combinators/attempt.d.ts +11 -1
  7. package/dist/combinators/attempt.d.ts.map +1 -1
  8. package/dist/combinators/map.d.ts.map +1 -1
  9. package/dist/combinators/node.d.ts +6 -2
  10. package/dist/combinators/node.d.ts.map +1 -1
  11. package/dist/combinators/token.d.ts +8 -8
  12. package/dist/combinators/token.d.ts.map +1 -1
  13. package/dist/compiler/token-capability.js +4 -0
  14. package/dist/compiler/token-capability.js.map +1 -1
  15. package/dist/coverage.d.ts.map +1 -1
  16. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +107 -40
  20. package/dist/index.js.map +1 -1
  21. package/dist/plugin/evaluator.d.ts.map +1 -1
  22. package/dist/plugin/index.js +107 -41
  23. package/dist/plugin/index.js.map +1 -1
  24. package/dist/spec/index.js +55 -10
  25. package/dist/spec/index.js.map +1 -1
  26. package/dist/table/assemble.d.ts.map +1 -1
  27. package/dist/table/emit-assembly.d.ts.map +1 -1
  28. package/dist/table/encode-baseline.d.ts.map +1 -1
  29. package/dist/table/exec-baseline.d.ts.map +1 -1
  30. package/dist/table/exec.d.ts.map +1 -1
  31. package/dist/table/index.js +404 -371
  32. package/dist/table/index.js.map +2 -2
  33. package/dist/table/ops.d.ts +9 -5
  34. package/dist/table/ops.d.ts.map +1 -1
  35. package/dist/table/site-labels.d.ts.map +1 -1
  36. package/dist/types.d.ts +9 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/package.json +1 -1
  40. package/src/analysis/commitment.ts +3 -1
  41. package/src/analysis/duplication.ts +1 -1
  42. package/src/analysis/rebuild.ts +3 -3
  43. package/src/combinators/attempt.ts +26 -3
  44. package/src/combinators/first-set.ts +5 -1
  45. package/src/combinators/map.ts +5 -1
  46. package/src/combinators/node.ts +12 -3
  47. package/src/combinators/token.ts +46 -3
  48. package/src/compiler/ir-serialize.ts +5 -5
  49. package/src/coverage.ts +3 -4
  50. package/src/cst/trivia-kinds.ts +6 -0
  51. package/src/index.ts +2 -1
  52. package/src/plugin/evaluator.ts +8 -5
  53. package/src/table/assemble.ts +30 -11
  54. package/src/table/child-slots.ts +2 -2
  55. package/src/table/emit-assembly.ts +13 -6
  56. package/src/table/encode-baseline.ts +8 -3
  57. package/src/table/encode.ts +16 -16
  58. package/src/table/exec-baseline.ts +30 -4
  59. package/src/table/exec.ts +14 -5
  60. package/src/table/ops.ts +10 -6
  61. package/src/table/scalar-terminal.ts +5 -5
  62. package/src/table/site-labels.ts +5 -3
  63. package/src/types.ts +9 -2
  64. package/src/version.ts +1 -1
@@ -257,6 +257,10 @@ function firstSetBody(p, seen, resolve, activeTrivia) {
257
257
  case "node":
258
258
  case "sepBy":
259
259
  case "expect":
260
+ // A transaction accepts exactly what its inner accepts. Its own `_meta` is
261
+ // the inner's construction-time set, which reads `any` when the inner opens
262
+ // with a rule reference — resolve through it like any other wrapper.
263
+ case "attempt":
260
264
  return fs(d.parser);
261
265
  case "grammar":
262
266
  return firstSetOf(
@@ -1621,6 +1625,10 @@ function peelLabel(p) {
1621
1625
  return null;
1622
1626
  }
1623
1627
  function analyzeLabeledTrivia(trivia2) {
1628
+ if (trivia2._def.tag === "trivia") {
1629
+ const own = trivia2._meta.labeledTriviaSpec;
1630
+ if (own !== void 0) return own;
1631
+ }
1624
1632
  if (trivia2 === labeledTrivia0) return labeledSpec0;
1625
1633
  if (trivia2 === labeledTrivia1) return labeledSpec1;
1626
1634
  if (trivia2 === labeledTrivia2) return labeledSpec2;
@@ -3286,13 +3294,17 @@ function transform(combinator, fn) {
3286
3294
  };
3287
3295
  }
3288
3296
  function trivia(combinator) {
3289
- const kindLabels = analyzeLabeledTrivia(combinator)?.labels;
3297
+ const labeled = analyzeLabeledTrivia(combinator);
3298
+ const kindLabels = labeled?.labels;
3290
3299
  return {
3291
3300
  _tag: combinator._tag,
3292
3301
  _meta: {
3293
3302
  ...combinator._meta,
3294
3303
  isTrivia: true,
3295
3304
  triviaScanner: fastTriviaScanner(combinator),
3305
+ // Every labeled scan of this trivia reads its spec; the module's four-slot
3306
+ // memo alone thrashes on a grammar with more than four trivia tables.
3307
+ labeledTriviaSpec: labeled,
3296
3308
  ...kindLabels ? { triviaKindLabels: kindLabels } : {}
3297
3309
  },
3298
3310
  _def: { tag: "trivia", parser: combinator },
@@ -3434,6 +3446,271 @@ function ref() {
3434
3446
  return slot;
3435
3447
  }
3436
3448
 
3449
+ // src/compiler/degradation.ts
3450
+ function formatDegradation(d) {
3451
+ return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
3452
+ }
3453
+ var DETAIL_CAP = 8;
3454
+ function formatDegradations(list) {
3455
+ const byCode = /* @__PURE__ */ new Map();
3456
+ for (const d of list) {
3457
+ const bucket = byCode.get(d.code);
3458
+ if (bucket) bucket.push(d);
3459
+ else byCode.set(d.code, [d]);
3460
+ }
3461
+ const out = [];
3462
+ for (const [code, items] of byCode) {
3463
+ for (const d of items.slice(0, DETAIL_CAP)) out.push(formatDegradation(d));
3464
+ if (items.length > DETAIL_CAP) {
3465
+ out.push(
3466
+ `[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.`
3467
+ );
3468
+ }
3469
+ }
3470
+ return out;
3471
+ }
3472
+ var _sinks = [];
3473
+ function beginDegradationCapture() {
3474
+ _sinks.push(/* @__PURE__ */ new Map());
3475
+ }
3476
+ function degradationCaptureDepth() {
3477
+ return _sinks.length;
3478
+ }
3479
+ function unwindDegradationCapture(depth) {
3480
+ const found = [];
3481
+ while (_sinks.length > depth) {
3482
+ const sink = _sinks.pop();
3483
+ found.unshift(...sink.values());
3484
+ }
3485
+ return found;
3486
+ }
3487
+ function resolveDegradationLevel(explicit) {
3488
+ if (explicit !== void 0) return explicit;
3489
+ const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
3490
+ if (env === "off" || env === "warn" || env === "error") return env;
3491
+ return "warn";
3492
+ }
3493
+ function degradationKey(d) {
3494
+ return JSON.stringify([d.code, d.where, d.subject]);
3495
+ }
3496
+ function recordDegradation(d) {
3497
+ const level = resolveDegradationLevel();
3498
+ if (level === "off") return;
3499
+ const key = degradationKey(d);
3500
+ const sink = _sinks[_sinks.length - 1];
3501
+ if (sink) {
3502
+ if (!sink.has(key)) sink.set(key, d);
3503
+ return;
3504
+ }
3505
+ if (_immediate.has(key)) return;
3506
+ _immediate.add(key);
3507
+ if (level === "error") throw new Error(`parseman: degraded compilation path
3508
+ ${formatDegradation(d)}`);
3509
+ console.warn(formatDegradation(d));
3510
+ }
3511
+ var _immediate = /* @__PURE__ */ new Set();
3512
+ function beginCompileDegradationDrain() {
3513
+ if (resolveDegradationLevel() === "off" || _sinks.length > 0) return () => {
3514
+ };
3515
+ const depth = degradationCaptureDepth();
3516
+ beginDegradationCapture();
3517
+ return (report) => {
3518
+ const found = unwindDegradationCapture(depth);
3519
+ if (!report || found.length === 0) return;
3520
+ const fresh = found.filter((d) => {
3521
+ const k = degradationKey(d);
3522
+ if (_immediate.has(k)) return false;
3523
+ _immediate.add(k);
3524
+ return true;
3525
+ });
3526
+ if (fresh.length === 0) return;
3527
+ const lines = formatDegradations(fresh);
3528
+ if (resolveDegradationLevel() === "error") {
3529
+ throw new Error(`parseman: ${fresh.length} degraded compilation path(s)
3530
+ ${lines.join("\n")}`);
3531
+ }
3532
+ for (const l of lines) console.warn(l);
3533
+ };
3534
+ }
3535
+
3536
+ // src/compiler/build-arity.ts
3537
+ function cstOutputHost(build) {
3538
+ return build?._parsemanCstOutput === true;
3539
+ }
3540
+ var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
3541
+ var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
3542
+ var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
3543
+ var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
3544
+ function confirmedBuildArity(src) {
3545
+ const s = src.trim();
3546
+ if (NATIVE_CODE_RE.test(s)) return null;
3547
+ if (/\barguments\b/.test(s)) return null;
3548
+ if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
3549
+ const inner = paramListText(s);
3550
+ if (inner === null) return null;
3551
+ if (inner.trim() === "") return 0;
3552
+ const parts = splitTopLevel(inner);
3553
+ if (parts === null) return null;
3554
+ for (const part of parts) {
3555
+ if (!isConfirmableParam(part.trim())) return null;
3556
+ }
3557
+ return parts.length;
3558
+ }
3559
+ function paramListText(s) {
3560
+ const open = PARAM_LIST_OPEN_RE.exec(s);
3561
+ if (!open) return null;
3562
+ const start = open[0].length;
3563
+ const end = matchingParen(s, start);
3564
+ if (end === null) return null;
3565
+ if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
3566
+ return s.slice(start, end);
3567
+ }
3568
+ function matchingParen(s, start) {
3569
+ let depth = 0;
3570
+ for (let i = start; i < s.length; i++) {
3571
+ const c = s[i];
3572
+ if (c === '"' || c === "'" || c === "`") {
3573
+ const close = skipString(s, i);
3574
+ if (close === null) return null;
3575
+ i = close;
3576
+ continue;
3577
+ }
3578
+ if (c === "(" || c === "[" || c === "{") depth++;
3579
+ else if (c === "]" || c === "}") {
3580
+ if (--depth < 0) return null;
3581
+ } else if (c === ")") {
3582
+ if (depth === 0) return i;
3583
+ depth--;
3584
+ }
3585
+ }
3586
+ return null;
3587
+ }
3588
+ function skipString(s, open) {
3589
+ const quote = s[open];
3590
+ for (let i = open + 1; i < s.length; i++) {
3591
+ if (s[i] === "\\") {
3592
+ i++;
3593
+ continue;
3594
+ }
3595
+ if (s[i] === quote) return i;
3596
+ }
3597
+ return null;
3598
+ }
3599
+ function splitTopLevel(inner) {
3600
+ const parts = [];
3601
+ let depth = 0;
3602
+ let angle = 0;
3603
+ let last = 0;
3604
+ for (let i = 0; i < inner.length; i++) {
3605
+ const c = inner[i];
3606
+ if (c === "=" && inner[i + 1] === ">") {
3607
+ i++;
3608
+ continue;
3609
+ }
3610
+ if (c === '"' || c === "'" || c === "`") {
3611
+ const close = skipString(inner, i);
3612
+ if (close === null) return null;
3613
+ i = close;
3614
+ continue;
3615
+ }
3616
+ if (c === "(" || c === "[" || c === "{") depth++;
3617
+ else if (c === ")" || c === "]" || c === "}") {
3618
+ if (--depth < 0) return null;
3619
+ } else if (c === "<") angle++;
3620
+ else if (c === ">") {
3621
+ if (--angle < 0) return null;
3622
+ } else if (c === "," && depth === 0 && angle === 0) {
3623
+ parts.push(inner.slice(last, i));
3624
+ last = i + 1;
3625
+ }
3626
+ }
3627
+ if (depth !== 0 || angle !== 0) return null;
3628
+ parts.push(inner.slice(last));
3629
+ return parts;
3630
+ }
3631
+ function isConfirmableParam(part) {
3632
+ const head = PARAM_HEAD_RE.exec(part);
3633
+ if (!head) return false;
3634
+ const rest = part.slice(head[0].length);
3635
+ if (rest === "") return true;
3636
+ if (rest[0] !== ":") return false;
3637
+ return !hasDefaultAssign(rest.slice(1));
3638
+ }
3639
+ function hasDefaultAssign(annotation) {
3640
+ for (let i = 0; i < annotation.length; i++) {
3641
+ if (annotation[i] !== "=") continue;
3642
+ if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
3643
+ i++;
3644
+ continue;
3645
+ }
3646
+ const prev = annotation[i - 1];
3647
+ if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
3648
+ return true;
3649
+ }
3650
+ return false;
3651
+ }
3652
+ function buildAnalysisSrc(def) {
3653
+ return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
3654
+ }
3655
+ var RESOLVER_REASONS = {
3656
+ "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
3657
+ "arguments": "its body references `arguments`",
3658
+ "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
3659
+ "not-a-function": "the binding it names is not a function declaration",
3660
+ "unresolved-import": "its module could not be resolved or parsed",
3661
+ "not-found": "the name did not resolve to any binding",
3662
+ "computed": "it is a computed expression",
3663
+ "foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
3664
+ "ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
3665
+ };
3666
+ function unconfirmableReason(def, src) {
3667
+ const declared = def.buildArityUnresolved;
3668
+ if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
3669
+ const s = src.trim();
3670
+ const params = s.slice(0, s.indexOf(")") + 1);
3671
+ if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
3672
+ if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
3673
+ if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
3674
+ return "it names a binding this build could not resolve to a function declaration";
3675
+ }
3676
+ return "its parameter list could not be parsed";
3677
+ }
3678
+ function confirmedArityForDef(def) {
3679
+ if (def.buildArity !== void 0) return def.buildArity;
3680
+ const src = buildAnalysisSrc(def);
3681
+ const arity = confirmedBuildArity(src);
3682
+ if (arity !== null) return arity;
3683
+ const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
3684
+ recordDegradation({
3685
+ code: "build-arity-unconfirmed",
3686
+ severity: "warn",
3687
+ where: `node("${def.type ?? "<inferred>"}")`,
3688
+ subject,
3689
+ 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`,
3690
+ 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"
3691
+ });
3692
+ return null;
3693
+ }
3694
+ function buildReadsRaw(def) {
3695
+ if (!def.build) return true;
3696
+ if (def.buildRawUnused === true) return false;
3697
+ const arity = confirmedArityForDef(def);
3698
+ if (arity === null) return true;
3699
+ return arity >= 4;
3700
+ }
3701
+ function buildReadsTrivia(def) {
3702
+ if (!def.build) return true;
3703
+ const arity = confirmedArityForDef(def);
3704
+ if (arity === null) return true;
3705
+ return arity >= 5;
3706
+ }
3707
+ function buildReadsState(def) {
3708
+ if (!def.build) return true;
3709
+ const arity = confirmedArityForDef(def);
3710
+ if (arity === null) return true;
3711
+ return arity >= 6;
3712
+ }
3713
+
3437
3714
  // src/combinators/token.ts
3438
3715
  function token(root) {
3439
3716
  const meta = {
@@ -3638,363 +3915,98 @@ function scanTo(sentinel, { skip, raw = false, orEOF = false, recoverAt, stopAt
3638
3915
  if (recover.span.end <= cur) {
3639
3916
  throw new TypeError("scanTo recoverAt must consume input");
3640
3917
  }
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")}`);
3918
+ if (recovery < 0) {
3919
+ recovery = cur;
3920
+ recoveryErrorCount = errorCount;
3921
+ }
3922
+ if (firstSentinel >= 0 && (sentinelCount & 1) === 1) {
3923
+ return succeed(recoveredEnd());
3924
+ }
3925
+ cur = recover.span.end;
3926
+ continue;
3927
+ }
3928
+ }
3929
+ cur++;
3930
+ }
3931
+ if (recovery >= 0) return succeed(recoveredEnd());
3932
+ if (orEOF) {
3933
+ return succeed(cur);
3934
+ }
3935
+ const sentDef = sentinel._def;
3936
+ const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
3937
+ return { ok: false, expected, span: { start: pos, end: cur } };
3817
3938
  }
3818
- for (const l of lines) console.warn(l);
3819
3939
  };
3820
3940
  }
3821
-
3822
- // src/compiler/build-arity.ts
3823
- function cstOutputHost(build) {
3824
- return build?._parsemanCstOutput === true;
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;
3941
+ function markSpec(outer, open, close, ownSkip, strict, raw) {
3942
+ ;
3943
+ outer._balancedSpec = { open, close, ownSkip, strict, raw };
3944
+ return outer;
3873
3945
  }
3874
- function skipString(s, open) {
3875
- const quote = s[open];
3876
- for (let i = open + 1; i < s.length; i++) {
3877
- if (s[i] === "\\") {
3878
- i++;
3879
- continue;
3946
+ function balanced(open, close, options = {}) {
3947
+ const ownSkip = options.skip ?? [];
3948
+ const strict = options.strict ?? false;
3949
+ const combi = buildBalancedInterior(open, close, ownSkip, strict);
3950
+ if (options.raw) return markSpec(token(combi), open, close, ownSkip, strict, true);
3951
+ const eagerParse = combi.parse.bind(combi);
3952
+ const cache = /* @__PURE__ */ new Map();
3953
+ combi._balancedAmbient = { open, close, ownSkip, strict };
3954
+ combi.parse = (input, pos, ctx) => {
3955
+ const amb = ctx.scanSkip;
3956
+ if (!amb || amb.length === 0) return eagerParse(input, pos, ctx);
3957
+ let interior = cache.get(amb);
3958
+ if (!interior) {
3959
+ interior = buildBalancedInterior(open, close, [...amb, ...ownSkip], strict);
3960
+ cache.set(amb, interior);
3880
3961
  }
3881
- if (s[i] === quote) return i;
3882
- }
3883
- return null;
3962
+ return interior.parse(input, pos, ctx);
3963
+ };
3964
+ return markSpec(token(combi), open, close, ownSkip, strict, false);
3884
3965
  }
3885
- function splitTopLevel(inner) {
3886
- const parts = [];
3887
- let depth = 0;
3888
- let angle = 0;
3889
- let last = 0;
3890
- for (let i = 0; i < inner.length; i++) {
3891
- const c = inner[i];
3892
- if (c === "=" && inner[i + 1] === ">") {
3893
- i++;
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;
3966
+ function buildBalancedInterior(open, close, skips, strict = false) {
3967
+ const self = ref();
3968
+ const stop = /* @__PURE__ */ new Set([open, close]);
3969
+ let bounded = true;
3970
+ for (const sk of skips) {
3971
+ const cs = firstSetClassChars(sk);
3972
+ if (cs === null) {
3973
+ bounded = false;
3974
+ break;
3911
3975
  }
3976
+ for (const ch2 of cs) stop.add(ch2);
3912
3977
  }
3913
- if (depth !== 0 || angle !== 0) return null;
3914
- parts.push(inner.slice(last));
3915
- return parts;
3916
- }
3917
- function isConfirmableParam(part) {
3918
- const head = PARAM_HEAD_RE.exec(part);
3919
- if (!head) return false;
3920
- const rest = part.slice(head[0].length);
3921
- if (rest === "") return true;
3922
- if (rest[0] !== ":") return false;
3923
- return !hasDefaultAssign(rest.slice(1));
3924
- }
3925
- function hasDefaultAssign(annotation) {
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;
3978
+ const cls = [...stop].map(escapeClassChar).join("");
3979
+ const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
3980
+ const inner = many(choice(self, ...skips, content));
3981
+ const closer = strict ? literal(close) : expect(literal(close));
3982
+ const combi = transform(
3983
+ sequence(literal(open), inner, closer),
3984
+ // parts: strings (content/self) or arrays (a sequence-shaped skip) or a
3985
+ // ParseError (recovered close). `c` is the close string or a ParseError.
3986
+ ([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
3987
+ );
3988
+ if (combi._def.tag === "transform") {
3989
+ combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
3990
+ combi._def.recognitionOnly = true;
3935
3991
  }
3936
- return false;
3937
- }
3938
- function buildAnalysisSrc(def) {
3939
- return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
3992
+ ;
3993
+ combi._balanced = { open, close };
3994
+ self.define(combi);
3995
+ return combi;
3940
3996
  }
3941
- var RESOLVER_REASONS = {
3942
- "rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
3943
- "arguments": "its body references `arguments`",
3944
- "reassigned": "the binding it names is reassigned, so the function read here is not decidable",
3945
- "not-a-function": "the binding it names is not a function declaration",
3946
- "unresolved-import": "its module could not be resolved or parsed",
3947
- "not-found": "the name did not resolve to any binding",
3948
- "computed": "it is a computed expression",
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";
3997
+ function firstSetClassChars(c) {
3998
+ const fs = c._meta.firstSet;
3999
+ if (fs.kind === "empty") return [];
4000
+ if (fs.kind !== "ranges") return null;
4001
+ const out = [];
4002
+ for (const { lo, hi } of fs.ranges) {
4003
+ if (hi - lo > 8) return null;
4004
+ for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
3961
4005
  }
3962
- return "its parameter list could not be parsed";
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;
4006
+ return out;
3992
4007
  }
3993
- function buildReadsState(def) {
3994
- if (!def.build) return true;
3995
- const arity = confirmedArityForDef(def);
3996
- if (arity === null) return true;
3997
- return arity >= 6;
4008
+ function escapeClassChar(ch2) {
4009
+ return ch2.replace(/[\\\]^-]/g, "\\$&");
3998
4010
  }
3999
4011
 
4000
4012
  // src/compiler/fields.ts
@@ -4181,6 +4193,7 @@ var OP_COV = 40;
4181
4193
  var OP_SCOPE_PLAIN = 41;
4182
4194
  var OP_LEX_BODY = 42;
4183
4195
  var OP_LEX_PROGRAM = 43;
4196
+ var OP_SOURCE_LEAF = 44;
4184
4197
  var OP_DISPATCH = 25;
4185
4198
  var OP_ROUTED = 26;
4186
4199
  var OP_NAMES = {
@@ -4199,6 +4212,7 @@ var OP_NAMES = {
4199
4212
  [OP_NOT]: "NOT",
4200
4213
  [OP_PEEK]: "PEEK",
4201
4214
  [OP_LEAF]: "LEAF",
4215
+ [OP_SOURCE_LEAF]: "SOURCE_LEAF",
4202
4216
  [OP_EMPTY]: "EMPTY",
4203
4217
  [OP_LIT_TRACK]: "LIT_TRACK",
4204
4218
  [OP_RX_TRACK]: "RX_TRACK",
@@ -6047,6 +6061,7 @@ function childSlots(code, ip, out) {
6047
6061
  case OP_NODE_TRACK:
6048
6062
  case OP_FIELD:
6049
6063
  case OP_LEAF:
6064
+ case OP_SOURCE_LEAF:
6050
6065
  case OP_ARMGATE:
6051
6066
  out.push(code[ip + 2]);
6052
6067
  return true;
@@ -6142,7 +6157,7 @@ function transfer(code, ip, at, hostCst) {
6142
6157
  }
6143
6158
  if (op === OP_NODE || op === OP_NODE_TRACK) {
6144
6159
  const flags = code[ip + 3];
6145
- const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && (flags === 2 || flags === 18 || flags === 34);
6160
+ const directChildren = !hostCst && op === OP_NODE && code[ip + 1] >= 0 && code[ip + 4] < 0 && ((flags & ~128) === 2 || flags === 18 || flags === 34);
6146
6161
  if (directChildren) {
6147
6162
  return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: CAP_OFF };
6148
6163
  }
@@ -6155,7 +6170,7 @@ function transfer(code, ip, at, hostCst) {
6155
6170
  if (at.tri === TRI_NONE && !at.buf) return at;
6156
6171
  return { tri: TRI_NONE, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
6157
6172
  }
6158
- if (op === OP_LEAF) {
6173
+ if (op === OP_LEAF || op === OP_SOURCE_LEAF) {
6159
6174
  if (!at.buf) return at;
6160
6175
  return { tri: at.tri, buf: false, raw: RAW_UNKNOWN, cap: at.cap };
6161
6176
  }
@@ -6242,7 +6257,7 @@ function leadingScalarTerminal(code, ip, minDepth = 2, throughAttempt = true, th
6242
6257
  depth++;
6243
6258
  continue;
6244
6259
  }
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) {
6260
+ 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
6261
  at = code[at + 2];
6247
6262
  depth++;
6248
6263
  continue;
@@ -6275,7 +6290,7 @@ function leadingScalarSequence(code, ip) {
6275
6290
  at2 = code[at2 + 1];
6276
6291
  continue;
6277
6292
  }
6278
- if (op === OP_GATE || op === OP_SCOPE_PLAIN || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
6293
+ 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
6294
  at2 = code[at2 + 2];
6280
6295
  continue;
6281
6296
  }
@@ -6308,7 +6323,7 @@ function leadingScalarSequence(code, ip) {
6308
6323
  at = code[at + 2];
6309
6324
  continue;
6310
6325
  }
6311
- if (op === OP_GATE || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || op === OP_LEAF) {
6326
+ if (op === OP_GATE || op === OP_XFORM || op === OP_NODE || op === OP_FIELD || (op === OP_LEAF || op === OP_SOURCE_LEAF)) {
6312
6327
  at = code[at + 2];
6313
6328
  continue;
6314
6329
  }
@@ -6338,7 +6353,7 @@ function leadingLiteralFamily(code, constants, ip, minDepth = 2, limit = 4) {
6338
6353
  if (op === OP_RULE || op === OP_LABEL || op === OP_TOKEN || op === OP_ATTEMPT || op === OP_PEEK) {
6339
6354
  return walk(code[at + 1], depth + 1);
6340
6355
  }
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) {
6356
+ 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
6357
  return walk(code[at + 2], depth + 1);
6343
6358
  }
6344
6359
  if (op === OP_SEQ || op === OP_SEQV) {
@@ -7224,8 +7239,10 @@ ${rootCap ? "ctx._rootTriviaCapture=sR\n" : ""}return v
7224
7239
  }
7225
7240
  /* ── boundaries ──────────────────────────────────────────────────────── */
7226
7241
  case OP_TOKEN:
7227
- case OP_LEAF: {
7242
+ case OP_LEAF:
7243
+ case OP_SOURCE_LEAF: {
7228
7244
  const isToken = op === OP_TOKEN;
7245
+ const capturesSource = isToken || op === OP_SOURCE_LEAF && hostCst;
7229
7246
  const fn = isToken ? void 0 : fnRef(code[ip + 1]);
7230
7247
  const child = link(isToken ? code[ip + 1] : code[ip + 2]);
7231
7248
  const wasCap = L.buf ? "true" : "(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)";
@@ -7258,7 +7275,7 @@ ctx._triviaLog=sOtl
7258
7275
  if(v===FAIL)return FAIL
7259
7276
  const e=EC.e
7260
7277
  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}})
7278
+ if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:${capturesSource ? "input.slice(pos,e)" : "out"},span:{start:pos,end:e}})
7262
7279
  EC.e=e
7263
7280
  return out
7264
7281
  }`;
@@ -7344,7 +7361,7 @@ ${clean ? "" : emitMark(p, L.buf, L.raw, sinks)}
7344
7361
  const v=${child}(input,pos,ctx)
7345
7362
  if(v!==FAIL)return v
7346
7363
  ${clean ? "" : emitRollback(p, L.buf, L.raw, sinks)}
7347
- if(ctx._fc===true)return FAIL
7364
+ ${code[ip + 2] === 1 ? "ctx._fc=false" : "if(ctx._fc===true)return FAIL"}
7348
7365
  ctx._fe=pos
7349
7366
  return FAIL
7350
7367
  }`;
@@ -7933,7 +7950,8 @@ return nd
7933
7950
  const unwrap = (flags & 64) !== 0;
7934
7951
  const trailingTrivia = (flags & 128) !== 0;
7935
7952
  const build = buildIdx >= 0 ? fnRef(buildIdx) : void 0;
7936
- if (!hostCst && !tracked && build !== void 0 && proj < 0 && (flags === 2 || flags === 18 || flags === 34)) {
7953
+ const leanFlags = flags & ~128;
7954
+ if (!hostCst && !tracked && build !== void 0 && proj < 0 && (leanFlags === 2 || (flags === 18 || flags === 34))) {
7937
7955
  const fields = flags === 18;
7938
7956
  const collapseChildren = flags === 34;
7939
7957
  const publish = L.buf && L.raw === RAW_OMIT ? "_pushNodeNoRawBuf(ctx,nd)" : L.buf && L.raw === RAW_CAPTURE ? `if(sBuf!==undefined){
@@ -7978,7 +7996,8 @@ ctx._cstTriviaLog=undefined
7978
7996
  ctx.captureTrivia=false
7979
7997
  ctx._fields=${fields ? "[]" : "undefined"}
7980
7998
  const v=${child}(input,pos,ctx)
7981
- const captured=_capturedFlatChildren(flat)
7999
+ ${trailingTrivia && L.tri !== TRI_NONE ? `if(v!==FAIL${L.tri === TRI_UNKNOWN ? "&&ctx.trivia!==undefined" : ""})EC.e=consumeTrivia(input,EC.e,ctx)
8000
+ ` : ""}const captured=_capturedFlatChildren(flat)
7982
8001
  ${fields ? "const fieldMap=buildFieldMap(ctx._fields)\n" : ""}ctx._fields=sFields
7983
8002
  ctx._cstBuf=sBuf
7984
8003
  ctx._cstChildren=sCh
@@ -8374,7 +8393,7 @@ function assemble(t, prog, cfg) {
8374
8393
  const lf = { _tag: "leaf", value, span: { start: s, end: e } };
8375
8394
  pushCstLeaf(ctx, lf);
8376
8395
  }
8377
- function plainBuildNode(child, build) {
8396
+ function plainBuildNode(child, build, trailing) {
8378
8397
  return (input, pos, ctx) => {
8379
8398
  const sCh = ctx._cstChildren;
8380
8399
  const sLv = ctx._cstLeaves;
@@ -8392,6 +8411,7 @@ function assemble(t, prog, cfg) {
8392
8411
  ctx.captureTrivia = false;
8393
8412
  ctx._fields = void 0;
8394
8413
  const value = child(input, pos, ctx);
8414
+ if (trailing && value !== FAIL && ctx.trivia !== void 0) EC.e = consumeTrivia(input, EC.e, ctx);
8395
8415
  const kids = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY_CH);
8396
8416
  const rawKids = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY_CH);
8397
8417
  ctx._fields = savedFields;
@@ -8419,7 +8439,7 @@ function assemble(t, prog, cfg) {
8419
8439
  while (first < children2.length && children2[first] === void 0) first++;
8420
8440
  return first === children2.length ? EMPTY_CH : children2.slice(first);
8421
8441
  }
8422
- function childrenOnlyBuildNode(child, build) {
8442
+ function childrenOnlyBuildNode(child, build, trailing) {
8423
8443
  return (input, pos, ctx) => {
8424
8444
  const sCh = ctx._cstChildren;
8425
8445
  const sLv = ctx._cstLeaves;
@@ -8437,6 +8457,7 @@ function assemble(t, prog, cfg) {
8437
8457
  ctx.captureTrivia = false;
8438
8458
  ctx._fields = void 0;
8439
8459
  const value = child(input, pos, ctx);
8460
+ if (trailing && value !== FAIL && ctx.trivia !== void 0) EC.e = consumeTrivia(input, EC.e, ctx);
8440
8461
  const captured = capturedFlatChildren(kids);
8441
8462
  ctx._fields = savedFields;
8442
8463
  ctx._cstBuf = sBuf;
@@ -9461,6 +9482,7 @@ function assemble(t, prog, cfg) {
9461
9482
  /* ── transaction ─────────────────────────────────────────────────────── */
9462
9483
  case OP_ATTEMPT: {
9463
9484
  const child = link(code[ip + 1]);
9485
+ const contain = code[ip + 2] === 1;
9464
9486
  return (input, pos, ctx) => {
9465
9487
  const need = markCst(ctx);
9466
9488
  const mRaw = MRAW;
@@ -9473,7 +9495,10 @@ function assemble(t, prog, cfg) {
9473
9495
  const v = child(input, pos, ctx);
9474
9496
  if (v !== FAIL) return v;
9475
9497
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
9476
- if (committed3(ctx)) return FAIL;
9498
+ if (committed3(ctx)) {
9499
+ if (!contain) return FAIL;
9500
+ ctx._fc = false;
9501
+ }
9477
9502
  ctx._fe = pos;
9478
9503
  return FAIL;
9479
9504
  };
@@ -9691,7 +9716,8 @@ function assemble(t, prog, cfg) {
9691
9716
  return value;
9692
9717
  };
9693
9718
  }
9694
- case OP_LEAF: {
9719
+ case OP_LEAF:
9720
+ case OP_SOURCE_LEAF: {
9695
9721
  const fn = fns[code[ip + 1]];
9696
9722
  const child = link(code[ip + 2]);
9697
9723
  return (input, pos, ctx) => {
@@ -9719,7 +9745,11 @@ function assemble(t, prog, cfg) {
9719
9745
  if (v === FAIL) return FAIL;
9720
9746
  const end = EC.e;
9721
9747
  const out = fn(v, { start: pos, end });
9722
- if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value: out, span: { start: pos, end } });
9748
+ if (wasCapturing) pushCstLeaf(ctx, {
9749
+ _tag: "leaf",
9750
+ value: op === OP_SOURCE_LEAF && hostCst ? input.slice(pos, end) : out,
9751
+ span: { start: pos, end }
9752
+ });
9723
9753
  EC.e = end;
9724
9754
  return out;
9725
9755
  };
@@ -10919,11 +10949,11 @@ function assemble(t, prog, cfg) {
10919
10949
  const trailingTrivia = (flags & 128) !== 0;
10920
10950
  const build = buildIdx >= 0 ? fns[buildIdx] : void 0;
10921
10951
  if (!hostCst && !tracked) {
10922
- if (build !== void 0 && proj < 0 && flags === 0) {
10923
- return plainBuildNode(child, build);
10952
+ if (build !== void 0 && proj < 0 && (flags & ~128) === 0) {
10953
+ return plainBuildNode(child, build, trailingTrivia);
10924
10954
  }
10925
- if (build !== void 0 && proj < 0 && flags === 2) {
10926
- return childrenOnlyBuildNode(child, build);
10955
+ if (build !== void 0 && proj < 0 && (flags & ~128) === 2) {
10956
+ return childrenOnlyBuildNode(child, build, trailingTrivia);
10927
10957
  }
10928
10958
  if (build !== void 0 && proj < 0 && flags === 18) {
10929
10959
  return childrenOnlyFieldsBuildNode(child, build);
@@ -11801,10 +11831,12 @@ function mayCommitFailure(p, seen = /* @__PURE__ */ new Set(), resolve) {
11801
11831
  case "choice":
11802
11832
  case "sequence":
11803
11833
  return d.parsers.some((x) => mayCommitFailure(x, seen, resolve));
11834
+ // A contained transaction reports every failure uncommitted.
11835
+ case "attempt":
11836
+ return d.contain !== true && mayCommitFailure(d.parser, seen, resolve);
11804
11837
  case "many":
11805
11838
  case "oneOrMore":
11806
11839
  case "optional":
11807
- case "attempt":
11808
11840
  case "transform":
11809
11841
  case "label":
11810
11842
  case "field":
@@ -13136,7 +13168,7 @@ var Encoder = class {
13136
13168
  }
13137
13169
  case "leaf": {
13138
13170
  const child = this.node(d.parser).ip;
13139
- return this.emit(OP_LEAF, this.fn(d.fn, d.fnSrc ?? null), child);
13171
+ return this.emit(d.cstValue === "source" ? OP_SOURCE_LEAF : OP_LEAF, this.fn(d.fn, d.fnSrc ?? null), child);
13140
13172
  }
13141
13173
  case "node": {
13142
13174
  if (d.type === void 0) missingInferredType();
@@ -13148,7 +13180,7 @@ var Encoder = class {
13148
13180
  const derivedState = d.build !== void 0 ? buildReadsState(d) : noBuildCaptures;
13149
13181
  const derivedFields = d.build !== void 0 ? buildReadsFields(d) : noBuildCaptures;
13150
13182
  const wantsFields = parserHasOwnFields(d.parser) && (cstOut || derivedFields);
13151
- const flags = (cstOut || d.captureTrivia === true || d.trailingTrivia === true || derivedTrivia ? 4 : 0) | (!cstOut && omitsRaw ? 2 : 0) | (cstOut || derivedState ? 8 : 0) | (wantsFields ? 16 : 0) | (d.collapse === true ? 32 : 0) | (d.unwrap === true ? 64 : 0) | (d.trailingTrivia === true ? 128 : 0) | (d.captureTrivia === true ? 1 : 0);
13183
+ const flags = (cstOut || d.captureTrivia === true || derivedTrivia ? 4 : 0) | (!cstOut && omitsRaw ? 2 : 0) | (cstOut || derivedState ? 8 : 0) | (wantsFields ? 16 : 0) | (d.collapse === true ? 32 : 0) | (d.unwrap === true ? 64 : 0) | (d.trailingTrivia === true ? 128 : 0) | (d.captureTrivia === true ? 1 : 0);
13152
13184
  const body = this.emit(
13153
13185
  this.track ? OP_NODE_TRACK : OP_NODE,
13154
13186
  d.build === void 0 ? -1 : this.fn(d.build, d.buildSrc ?? null),
@@ -13274,7 +13306,7 @@ var Encoder = class {
13274
13306
  // A TRANSACTION IS A ROW. See `OP_ATTEMPT` for why the transparent
13275
13307
  // lowering was correct only for a choice arm.
13276
13308
  case "attempt": {
13277
- const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip);
13309
+ const inner = this.emit(OP_ATTEMPT, this.node(d.parser).ip, d.contain === true ? 1 : 0);
13278
13310
  if (!this.failureNeedsRollback(d.parser, void 0)) this.failureRollbackCleanSites.add(inner);
13279
13311
  const fs = d.parser._def.tag === "lazy" ? firstSetOf(d.parser, /* @__PURE__ */ new Set(), this.refResolver(), this.activeTrivia) : d.parser._meta.firstSet;
13280
13312
  if (fs.kind === "any" || matchesEmpty(d.parser)) return inner;
@@ -13361,6 +13393,7 @@ var Encoder = class {
13361
13393
  case OP_WITHCTX:
13362
13394
  case OP_XFORM:
13363
13395
  case OP_LEAF:
13396
+ case OP_SOURCE_LEAF:
13364
13397
  case OP_NODE:
13365
13398
  case OP_NODE_TRACK:
13366
13399
  return [ip + 2];
@@ -13853,7 +13886,7 @@ function payloadKey(p, d) {
13853
13886
  case "transform":
13854
13887
  return `transform\0${fnKey(d.fnSrc, d.fn)}\0${d.recognitionOnly === true}`;
13855
13888
  case "leaf":
13856
- return `leaf\0${fnKey(d.fnSrc, d.fn)}`;
13889
+ return `leaf\0${d.cstValue ?? "value"}\0${fnKey(d.fnSrc, d.fn)}`;
13857
13890
  case "many":
13858
13891
  case "oneOrMore":
13859
13892
  return `${d.tag}\0${d.min}\0${d.max ?? ""}`;