mirror of
https://github.com/imjasonh/nescript
synced 2026-07-10 09:42:37 +00:00
Fix bugs found during code review
Issues found by systematic review of all compiler modules. Each fix includes a regression test. Parser fixes: - Add EOF checks to function call arg parsing loops (lines 984, 1269) to prevent infinite loops on unterminated call expressions - Fix span end positions: use .end instead of .start for 9 declaration span computations (var, const, fun, state, bank, sprite, palette, background, block) - Add missing compound assignment operators (&= |= ^=) to parse_assign_op() for array element assignments Codegen fix: - Fix NOT operator: old code used EOR #$FF + AND #$01 which produced wrong results for non-boolean inputs (e.g., NOT 0x42 returned 1 instead of 0). New code uses BEQ/branch to properly map any nonzero value to 0 and zero to 1. Assembler fixes: - Add branch offset range validation: assert offset is in -128..127 range instead of silently wrapping on overflow - Panic on unresolved labels instead of silently leaving placeholder 0x00 bytes in the output Verified non-issues (reviewer false positives): - NMI P register: 6502 hardware pushes P automatically on NMI entry; RTI restores it. PHP/PLP not needed. - Controller read buffer: 8 iterations of LSR+ROL fully replace all 8 bits, so prior contents don't matter. - advance() panic: tokens always has at least Eof from lexer. 4 new regression tests, 225 total. https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
parent
07dd5bd7e8
commit
bc165ed647
5 changed files with 96 additions and 14 deletions
|
|
@ -145,7 +145,12 @@ impl Assembler {
|
|||
let from = i32::from(self.base_address) + fixup.offset as i32 + 1;
|
||||
let to = i32::from(addr);
|
||||
let offset = to - from;
|
||||
self.output[fixup.offset] = offset.cast_unsigned().to_le_bytes()[0];
|
||||
assert!(
|
||||
(-128..=127).contains(&offset),
|
||||
"branch offset {offset} out of range (-128..127) for label '{}'",
|
||||
fixup.label
|
||||
);
|
||||
self.output[fixup.offset] = (offset as i8).cast_unsigned();
|
||||
}
|
||||
FixupKind::Lo => {
|
||||
self.output[fixup.offset] = addr as u8;
|
||||
|
|
@ -154,6 +159,8 @@ impl Assembler {
|
|||
self.output[fixup.offset] = (addr >> 8) as u8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("unresolved label: '{}'", fixup.label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -373,3 +373,29 @@ fn assemble_add_immediate() {
|
|||
let result = assemble(&instructions, 0x8000);
|
||||
assert_eq!(result.bytes, vec![0xA5, 0x10, 0x18, 0x69, 0x02, 0x85, 0x10]);
|
||||
}
|
||||
|
||||
// ── Code review regression tests ──
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "branch offset")]
|
||||
fn branch_out_of_range_panics() {
|
||||
// Regression: branch offsets > 127 bytes used to silently wrap
|
||||
let mut instructions = vec![Instruction::new(NOP, AM::Label("start".into()))];
|
||||
// Insert 200 NOPs to push the branch target out of range
|
||||
for _ in 0..200 {
|
||||
instructions.push(Instruction::implied(NOP));
|
||||
}
|
||||
instructions.push(Instruction::new(BEQ, AM::LabelRelative("start".into())));
|
||||
let _ = assemble(&instructions, 0x8000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "unresolved label")]
|
||||
fn unresolved_label_panics() {
|
||||
// Regression: unresolved labels used to silently produce offset 0
|
||||
let instructions = vec![Instruction::new(
|
||||
BEQ,
|
||||
AM::LabelRelative("nonexistent".into()),
|
||||
)];
|
||||
let _ = assemble(&instructions, 0x8000);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue