44 lines
1.6 KiB
Rust

use prometeu_bytecode::decode_next;
use prometeu_bytecode::isa::core::{CoreOpCode, CoreOpCodeSpecExt};
fn emit(op: CoreOpCode, imm: Option<&[u8]>, out: &mut Vec<u8>) {
let code = op as u16;
out.extend_from_slice(&code.to_le_bytes());
let need = op.spec().imm_bytes as usize;
match (need, imm) {
(0, None) => {}
(n, Some(bytes)) if bytes.len() == n => out.extend_from_slice(bytes),
(n, Some(bytes)) => {
panic!("immediate size mismatch for {:?}: expected {}, got {}", op, n, bytes.len())
}
(n, None) => panic!("missing immediate for {:?}: need {} bytes", op, n),
}
}
#[test]
fn encode_decode_edge_immediates_roundtrip() {
let mut rom = Vec::new();
emit(CoreOpCode::PushI32, Some(&i32::MIN.to_le_bytes()), &mut rom);
emit(CoreOpCode::PushI32, Some(&i32::MAX.to_le_bytes()), &mut rom);
emit(CoreOpCode::FrameSync, None, &mut rom);
emit(CoreOpCode::Halt, None, &mut rom);
// Decode sequentially and validate structure + immediates
let mut pc = 0usize;
let mut seen = Vec::new();
while pc < rom.len() {
let instr = decode_next(pc, &rom).expect("decode ok");
seen.push(instr);
pc = instr.next_pc;
}
assert_eq!(seen.len(), 4);
assert_eq!(seen[0].opcode, CoreOpCode::PushI32);
assert_eq!(seen[0].imm_i32().unwrap(), i32::MIN);
assert_eq!(seen[1].opcode, CoreOpCode::PushI32);
assert_eq!(seen[1].imm_i32().unwrap(), i32::MAX);
assert_eq!(seen[2].opcode, CoreOpCode::FrameSync);
assert_eq!(seen[3].opcode, CoreOpCode::Halt);
assert_eq!(seen.last().unwrap().next_pc, rom.len());
}