Skip to content

feat(compile): add --trace/--focus debugging flags#1738

Merged
proggeramlug merged 2 commits into
mainfrom
worktree-feat+compile-trace-flag
May 25, 2026
Merged

feat(compile): add --trace/--focus debugging flags#1738
proggeramlug merged 2 commits into
mainfrom
worktree-feat+compile-trace-flag

Conversation

@proggeramlug
Copy link
Copy Markdown
Contributor

What

Adds --trace/--focus debug flags that consolidate the scattered
compiler-introspection knobs (--print-hir, PERRY_SAVE_LL,
PERRY_LLVM_KEEP_IR) into one CLI surface, plus a focus filter for
localizing "compiled to the wrong thing" bugs — the dominant Perry debug
workflow.

  • --trace <stages> — comma-separated hir, llvm, or all.
    • hir: post-transform HIR dump (same data as --print-hir).
    • llvm: writes per-module .ll into .perry-trace/llvm/ by promoting
      the PERRY_SAVE_LL/PERRY_LLVM_KEEP_IR env vars, and forces
      PERRY_NO_CACHE so the per-module object cache can't skip codegen and
      leave the trace dir empty (the same cache-bypass --verify-native-regions
      already does).
  • --focus <name> — substring filter on --trace hir: only matching
    functions, class methods, and classes are printed, and the
    imports/exports/init sections are suppressed. One function's lowered body
    is ~40 lines instead of buried in a 10k-line full-module dump. Implies
    hir when no stage is given.

--print-hir keeps its exact historical full-dump behavior (it maps to
focus = None).

Why

When a TypeScript program compiles to the wrong result, ~30% of debug time
is just localizing which stage corrupted a value. The pipeline has clean
stage boundaries but the introspection for them was a scattered set of
undocumented env vars. This makes "dump stage X, focused on function Y" a
one-liner.

Test evidence

$ perry compile demo.ts --trace hir --focus parseRow
=== HIR trace (focus: "parseRow"): demo.ts ===
Functions: 1
  - parseRow (params: 1, ...)
      [0] Let { id: 2, name: "n", ... PropertyGet { ... "length" } }
      [1] Return(Some(Binary { op: Mul, left: LocalGet(2), right: Integer(2) }))
Classes: 1
  - Parser (...)
    - parseRowImpl (params: 1, ...)
        [0] Return(Some(PropertyGet { object: LocalGet(5), property: "length" }))

Verified manually:

  • --trace hir --focus NAME → focused dump (functions + matching class methods)
  • --focus NAME alone → implies hir
  • --trace llvm.perry-trace/llvm/*.ll written (cache-bypass confirmed)
  • --trace all → full HIR + llvm
  • --print-hir → unchanged full dump (imports/exports/init present)

cargo fmt --all -- --check clean; new code clippy-clean; cargo build -p perry --tests clean.

Scope / follow-ups (deliberately out of this slice)

  • --focus on the LLVM stage (extract just the matching defines post-codegen)
  • An ast stage (pre-lowering SWC dump)
  • --timings (per-stage wall time)

Per worktree-PR convention this PR omits the version bump + CHANGELOG entry;
fold those in at merge.

Consolidate the scattered compiler-introspection knobs into one CLI
surface and add a focus filter for localizing "compiled to the wrong
thing" bugs.

- `--trace <stages>`: comma-separated `hir`, `llvm`, or `all`.
  - `hir` dumps post-transform HIR (same data as `--print-hir`).
  - `llvm` wires up PERRY_SAVE_LL + PERRY_LLVM_KEEP_IR to write
    per-module .ll into `.perry-trace/llvm/`, and forces PERRY_NO_CACHE
    for the build so the object cache can't skip codegen and leave the
    trace dir empty.
- `--focus <name>`: substring filter on `--trace hir`, restricting
  output to matching functions / class methods / classes and
  suppressing import/export/init noise (one function's body is ~40
  lines instead of buried in a full-module dump). Implies `hir` when no
  stage is given.

`--print-hir` keeps its exact historical full-dump behavior (focus
None). `dump_hir_for_debug` now takes an `Option<&str>` focus arg and
shares a `dump_hir_function` helper between free functions and methods.

Adds `.perry-trace/` to .gitignore and documents the flags in
docs/src/cli/flags.md.
Make the new debug flags discoverable to future LLM sessions, which load
CLAUDE.md for orientation. Adds them next to --print-hir and a short note
to reach for --trace hir --focus <fn> when localizing a miscompile.
Version line untouched (worktree-PR convention).
@proggeramlug proggeramlug merged commit eff181e into main May 25, 2026
10 checks passed
@proggeramlug proggeramlug deleted the worktree-feat+compile-trace-flag branch May 25, 2026 04:51
proggeramlug added a commit that referenced this pull request May 25, 2026
7 PRs landed on main after the v0.5.1027 bump (50c391f) without
per-PR tags. Neither v0.5.1026 nor v0.5.1027 were tagged on the
remote — v0.5.1028 is the first tag in this window.

- #1738 feat(compile): --trace/--focus debugging flags.
- #1723/#1741 fix(lockdown): #503 ns[dynamicKey].staticMember.
- #1673/#1742 fix(dynamic-import): literal node: builtin specifier.
- #1724/#1747 fix(node): Blob/URL globals trigger http-client feature.
- #1728/#1749 fix(node:path): win32 normalize/basename/toNamespacedPath.
- #1751 test(parity): stream consumers/promises/static batch.
- #1754 test(node-core): enrich common shim for #800.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant