1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 17:06:04 +00:00

CLI: --dump-ir flag + IrProgram::pretty

Adds \`IrProgram::pretty()\` for a readable IR dump and wires it to a
new \`--dump-ir\` build flag. Useful for debugging IR-level issues
(optimizer, lowering). Refactored \`compile()\` to take a
\`CompileOptions\` struct to keep clippy's \`fn-params-excessive-bools\`
lint happy.

https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
Claude 2026-04-12 11:31:01 +00:00
parent 8b35ba9e13
commit ae051f5909
No known key found for this signature in database
2 changed files with 66 additions and 2 deletions

View file

@ -166,6 +166,41 @@ impl IrProgram {
.map(|b| b.ops.len())
.sum()
}
/// Human-readable pretty-print of the entire program — used by
/// the `--dump-ir` CLI flag and by debugging sessions.
pub fn pretty(&self) -> String {
use std::fmt::Write;
let mut out = String::new();
out.push_str("# IR Program\n");
let _ = writeln!(out, "# start_state = {}", self.start_state);
let _ = writeln!(out, "# states = {:?}", self.states);
if !self.globals.is_empty() {
out.push_str("\n# Globals\n");
for g in &self.globals {
let _ = writeln!(
out,
" {} {} (size={}) = {:?}",
g.var_id, g.name, g.size, g.init_value
);
}
}
for func in &self.functions {
let _ = writeln!(
out,
"\nfn {}({} params, has_return={}):",
func.name, func.param_count, func.has_return
);
for block in &func.blocks {
let _ = writeln!(out, " {}:", block.label);
for op in &block.ops {
let _ = writeln!(out, " {op:?}");
}
let _ = writeln!(out, " -> {:?}", block.terminator);
}
}
out
}
}
impl IrFunction {

View file

@ -29,6 +29,10 @@ enum Cli {
#[arg(long)]
asm_dump: bool,
/// Dump the lowered IR program to stdout (after optimization)
#[arg(long)]
dump_ir: bool,
/// Use the legacy AST-based codegen. The default is the IR-based
/// codegen, which runs the optimizer passes before emitting 6502.
#[arg(long)]
@ -50,10 +54,19 @@ fn main() {
output,
debug,
asm_dump,
dump_ir,
use_ast,
} => {
let output = output.unwrap_or_else(|| input.with_extension("nes"));
match compile(&input, debug, asm_dump, use_ast) {
match compile(
&input,
&CompileOptions {
debug,
asm_dump,
dump_ir,
use_ast,
},
) {
Ok(rom) => {
std::fs::write(&output, rom).unwrap_or_else(|e| {
eprintln!("error: failed to write {}: {e}", output.display());
@ -86,7 +99,19 @@ fn dump_asm(instructions: &[nescript::asm::Instruction]) {
}
}
fn compile(input: &PathBuf, debug: bool, asm_dump: bool, use_ast: bool) -> Result<Vec<u8>, ()> {
#[allow(clippy::struct_excessive_bools)]
struct CompileOptions {
debug: bool,
asm_dump: bool,
dump_ir: bool,
use_ast: bool,
}
fn compile(input: &PathBuf, opts: &CompileOptions) -> Result<Vec<u8>, ()> {
let debug = opts.debug;
let asm_dump = opts.asm_dump;
let dump_ir = opts.dump_ir;
let use_ast = opts.use_ast;
let raw_source = std::fs::read_to_string(input).map_err(|e| {
eprintln!("error: failed to read {}: {e}", input.display());
})?;
@ -128,6 +153,10 @@ fn compile(input: &PathBuf, debug: bool, asm_dump: bool, use_ast: bool) -> Resul
let mut ir_program = ir::lower(&program, &analysis);
optimizer::optimize(&mut ir_program);
if dump_ir {
print!("{}", ir_program.pretty());
}
// Resolve sprite assets (CHR data + tile indices) relative to the
// source file's directory, so `@binary` / `@chr` paths work naturally.
let source_dir = input.parent().unwrap_or_else(|| Path::new("."));