use prometeu_bytecode::decode_next; use prometeu_bytecode::isa::core::{CoreOpCode, CoreOpCodeSpecExt}; fn emit(op: CoreOpCode, imm: Option<&[u8]>, out: &mut Vec) { 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()); }