mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 17:06:04 +00:00
pipeline: share a single compile function across CLI, bench, and tests
The compile bench had a hand-maintained parallel copy of `src/main.rs::compile`, and that copy went out of sync after bank switching landed — the bench kept handing the linker `PrgBank::empty(...)` slots even though the CLI started populating per-bank instruction streams + trampoline requests. The assembler then panicked with `unresolved label: '__tramp_step_animation'` on `uxrom_user_banked.ne` under `cargo test --all-targets`, which is what CI runs. A plain `cargo test --release` (what CLAUDE.md used to document) never builds the bench so the bug slipped through local validation. Fix: - New `nescript::pipeline` module with `compile_source(source, source_dir, &CompileOptions)` that owns the full `parse → analyze → lower → optimize → codegen → peephole → link` pipeline including the per-bank stream + trampoline reconstruction. Returns a `CompileOutput` carrying the ROM, the linker result, analysis, IR, assets, instructions, and source-loc markers so downstream tools have one place to pull metadata from. - `src/main.rs::compile` reduces to file I/O + preprocessing + a single `compile_source` call + CLI-only side effects (`--dump-ir`, `--call-graph`, `--asm-dump`, `--memory-map`, `--symbols`, `--source-map`). - `benches/compile.rs::compile_pipeline` becomes a one-line `compile_source` call. It is now structurally impossible for the bench to drift from the CLI path. - `tests/integration_test.rs::compile_with_debug_artifacts` likewise delegates to `compile_source`. This also fixes a latent bug in the helper where it used `Linker::with_mapper` without `.with_header(...)` — programs opting into `header: nes2` would have quietly got an iNES 1.0 header through this path. - `CLAUDE.md`: updated the "Running the basics" section to specify `cargo test --all-targets` (plain `cargo test` skips benches) and to point at `scripts/pre-commit` with the exact install command. Also installed the hook in this worktree. All 24 existing `examples/*.nes` rebuild byte-identical through the new pipeline. 624 tests + all 25 emulator goldens pass. https://claude.ai/code/session_01MaNVcDmK9gsspRkdxowQAM
This commit is contained in:
parent
889074a415
commit
2966a6ab17
6 changed files with 362 additions and 359 deletions
|
|
@ -2101,60 +2101,24 @@ fn no_opt_still_produces_valid_rom() {
|
|||
/// `--symbols`, and `--source-map` paths. Returns the ROM bytes
|
||||
/// along with the rendered `.mlb` and source-map text so the
|
||||
/// integration tests can assert against the whole chain.
|
||||
///
|
||||
/// Routes through the shared [`nescript::pipeline::compile_source`]
|
||||
/// so this helper can never drift away from the CLI compile path
|
||||
/// — the bench had a hand-maintained parallel copy and it missed
|
||||
/// the bank-switching wiring in commit `2fe943b`, which is the
|
||||
/// regression that pushed us to share a single pipeline.
|
||||
fn compile_with_debug_artifacts(source: &str, debug: bool) -> (Vec<u8>, String, String) {
|
||||
let (program, diags) = nescript::parser::parse(source);
|
||||
assert!(
|
||||
diags.is_empty(),
|
||||
"unexpected parse errors: {diags:?}\nsource:\n{source}"
|
||||
);
|
||||
let program = program.expect("parse should succeed");
|
||||
|
||||
let analysis = analyzer::analyze(&program);
|
||||
assert!(
|
||||
analysis.diagnostics.iter().all(|d| !d.is_error()),
|
||||
"unexpected analysis errors: {:?}",
|
||||
analysis.diagnostics
|
||||
);
|
||||
|
||||
let mut ir_program = ir::lower(&program, &analysis);
|
||||
optimizer::optimize(&mut ir_program);
|
||||
|
||||
let sprites = assets::resolve_sprites(&program, Path::new("."))
|
||||
.expect("sprite resolution should succeed");
|
||||
let sfx = assets::resolve_sfx(&program).expect("sfx resolution should succeed");
|
||||
let music = assets::resolve_music(&program).expect("music resolution should succeed");
|
||||
let palettes = assets::resolve_palettes(&program, Path::new("."))
|
||||
.expect("palette resolution should succeed");
|
||||
let backgrounds = assets::resolve_backgrounds(&program, Path::new("."))
|
||||
.expect("background resolution should succeed");
|
||||
|
||||
let mut codegen = IrCodeGen::new(&analysis.var_allocations, &ir_program)
|
||||
.with_sprites(&sprites)
|
||||
.with_audio(&sfx, &music)
|
||||
.with_debug(debug)
|
||||
.with_source_map(true);
|
||||
let mut instructions = codegen.generate(&ir_program);
|
||||
nescript::codegen::peephole::optimize(&mut instructions);
|
||||
|
||||
let linker = Linker::with_mapper(program.game.mirroring, program.game.mapper);
|
||||
let switchable_banks: Vec<PrgBank> = program
|
||||
.banks
|
||||
.iter()
|
||||
.filter(|b| b.bank_type == BankType::Prg)
|
||||
.map(|b| PrgBank::empty(&b.name))
|
||||
.collect();
|
||||
let link_result = linker.link_banked_with_ppu_detailed(
|
||||
&instructions,
|
||||
&sprites,
|
||||
&sfx,
|
||||
&music,
|
||||
&palettes,
|
||||
&backgrounds,
|
||||
&switchable_banks,
|
||||
);
|
||||
let mlb = nescript::linker::render_mlb(&link_result, &analysis.var_allocations);
|
||||
let map = nescript::linker::render_source_map(&link_result, codegen.source_locs(), source);
|
||||
(link_result.rom, mlb, map)
|
||||
use nescript::pipeline::{compile_source, CompileOptions};
|
||||
let opts = CompileOptions {
|
||||
debug,
|
||||
no_opt: false,
|
||||
emit_source_map: true,
|
||||
};
|
||||
let out = compile_source(source, Path::new("."), &opts)
|
||||
.unwrap_or_else(|e| panic!("pipeline failed: {e:?}"));
|
||||
let mlb = nescript::linker::render_mlb(&out.link_result, &out.analysis.var_allocations);
|
||||
let map = nescript::linker::render_source_map(&out.link_result, &out.source_locs, source);
|
||||
(out.rom, mlb, map)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue