use crate::bytecode::Op; use std::io::Read; fn read_tag(prog: &mut T) -> Result { let mut buf = [0; 8]; match prog.read_exact(&mut buf) { Ok(()) => (), Err(_) => { return Err(String::from("error reading input")); } }; Ok(u64::from_le_bytes(buf)) } fn read_i64(prog: &mut T) -> Result { let mut buf = [0; 8]; match prog.read_exact(&mut buf) { Ok(()) => (), Err(_) => { return Err(String::from("error reading input")); } }; Ok(i64::from_le_bytes(buf)) } fn read_u8(prog: &mut T) -> Result { let mut buf = vec![0]; match prog.read_exact(&mut buf) { Ok(()) => (), Err(_) => { return Err(String::from("error reading input")); } }; Ok(buf[0]) } fn op_decoding(prog: &mut T) -> Result { let op = match read_tag(prog)? { 1010 => Op::Const(read_i64(prog)?), 1020 => Op::Add, 1030 => Op::Sub, 1040 => Op::Mul, 1050 => Op::Div, 1060 => Op::Mod, 2010 => Op::Alloc, 2020 => Op::Peek, 2030 => Op::Poke, 2040 => Op::PeekByte, 2050 => Op::PokeByte, 3010 => Op::Pop, 3020 => Op::Local(read_u8(prog)?), 4010 => Op::If(read_i64(prog)?), 4020 => Op::Call(read_u8(prog)?), 4030 => Op::Ret, 4040 => Op::Exit, 5010 => Op::PutC, 5020 => Op::GetC, _ => { return Err(String::from("invalid opcode")); } }; Ok(op) } pub fn decode(prog: &[u8]) -> Result, String> { let mut reader = prog; let mut out = Vec::new(); while reader.len() > 0 { out.push(op_decoding(&mut reader)?); } Ok(out) } mod tests { use super::*; #[test] fn decode_const() { assert_eq!( Ok(vec![Op::Const(10)]), decode(&vec![0xf2, 0x3, 0, 0, 0, 0, 0, 0, 0xa, 0, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_add() { assert_eq!( Ok(vec![Op::Add]), decode(&vec![0xfc, 0x3, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_sub() { assert_eq!(Ok(vec![Op::Sub]), decode(&vec![0x6, 0x4, 0, 0, 0, 0, 0, 0])); } #[test] fn decode_mul() { assert_eq!( Ok(vec![Op::Mul]), decode(&vec![0x10, 0x4, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_div() { assert_eq!( Ok(vec![Op::Div]), decode(&vec![0x1a, 0x4, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_mod() { assert_eq!( Ok(vec![Op::Mod]), decode(&vec![0x24, 0x4, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_alloc() { assert_eq!( Ok(vec![Op::Alloc]), decode(&vec![0xda, 0x7, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_peek() { assert_eq!( Ok(vec![Op::Peek]), decode(&vec![0xe4, 0x7, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_poke() { assert_eq!( Ok(vec![Op::Poke]), decode(&vec![0xee, 0x7, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_peek_byte() { assert_eq!( Ok(vec![Op::PeekByte]), decode(&vec![0xf8, 0x7, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_poke_byte() { assert_eq!( Ok(vec![Op::PokeByte]), decode(&vec![0x2, 0x8, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_pop() { assert_eq!( Ok(vec![Op::Pop]), decode(&vec![0xc2, 0xb, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_local() { assert_eq!( Ok(vec![Op::Local(10)]), decode(&vec![0xcc, 0xb, 0, 0, 0, 0, 0, 0, 0xa]) ); } #[test] fn decode_if() { assert_eq!( Ok(vec![Op::If(10)]), decode(&vec![0xaa, 0xf, 0, 0, 0, 0, 0, 0, 0xa, 0, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_call() { assert_eq!( Ok(vec![Op::Call(10)]), decode(&vec![0xb4, 0xf, 0, 0, 0, 0, 0, 0, 0xa]) ); } #[test] fn decode_ret() { assert_eq!( Ok(vec![Op::Ret]), decode(&vec![0xbe, 0xf, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_exit() { assert_eq!( Ok(vec![Op::Exit]), decode(&vec![0xc8, 0xf, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_putc() { assert_eq!( Ok(vec![Op::PutC]), decode(&vec![0x92, 0x13, 0, 0, 0, 0, 0, 0]) ); } #[test] fn decode_getc() { assert_eq!( Ok(vec![Op::GetC]), decode(&vec![0x9c, 0x13, 0, 0, 0, 0, 0, 0]) ); } }