64 lines
2.2 KiB
Rust

use crate::common::symbols::Symbol;
use anyhow::{anyhow, Context, Result};
use prometeu_bytecode::disasm::disasm;
use std::fs;
use std::path::Path;
pub struct Artifacts {
pub rom: Vec<u8>,
pub symbols: Vec<Symbol>,
}
impl Artifacts {
pub fn new(rom: Vec<u8>, symbols: Vec<Symbol>) -> Self {
Self { rom, symbols }
}
pub fn export(&self, out: &Path, emit_disasm: bool, emit_symbols: bool) -> Result<()> {
// 1. Save the main binary
fs::write(out, &self.rom).with_context(|| format!("Failed to write PBC to {:?}", out))?;
// 2. Export symbols for the HostDebugger
if emit_symbols {
let symbols_path = out.with_file_name("symbols.json");
let symbols_json = serde_json::to_string_pretty(&self.symbols)?;
fs::write(&symbols_path, symbols_json)?;
}
// 3. Export human-readable disassembly for developer inspection
if emit_disasm {
let disasm_path = out.with_extension("disasm.txt");
// Extract the actual bytecode (stripping the PBC header if present)
let rom_to_disasm = if let Ok(pbc) = prometeu_bytecode::pbc::parse_pbc(&self.rom) {
pbc.rom
} else {
self.rom.clone()
};
let instructions = disasm(&rom_to_disasm).map_err(|e| anyhow!("Disassembly failed: {}", e))?;
let mut disasm_text = String::new();
for instr in instructions {
// Find a matching symbol to show which source line generated this instruction
let symbol = self.symbols.iter().find(|s| s.pc == instr.pc);
let comment = if let Some(s) = symbol {
format!(" ; {}:{}", s.file, s.line)
} else {
"".to_string()
};
let operands_str = instr.operands.iter()
.map(|o| format!("{:?}", o))
.collect::<Vec<_>>()
.join(" ");
disasm_text.push_str(&format!("{:08X} {:?} {}{}\n", instr.pc, instr.opcode, operands_str, comment));
}
fs::write(disasm_path, disasm_text)?;
}
Ok(())
}
}