From 17face3633686e374aa0859271ccf462a48e60aa Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Sun, 4 Feb 2024 16:46:20 -0800 Subject: Rewrite the bytecode interpreter in Rust. --- bytecode/src/encoding.rs | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 bytecode/src/encoding.rs (limited to 'bytecode/src/encoding.rs') diff --git a/bytecode/src/encoding.rs b/bytecode/src/encoding.rs new file mode 100644 index 0000000..e37696d --- /dev/null +++ b/bytecode/src/encoding.rs @@ -0,0 +1,139 @@ +use crate::heap; +use crate::value::Value; +use std::error::Error; + +pub enum Arg { + Local(u8), + Const(Value), +} + +pub struct Alloc { + pub out: u8, + pub size: Arg, +} + +pub struct Poke { + pub offset: usize, + pub ptr: u8, + pub val: Arg, +} + +pub struct Peek { + pub out: u8, + pub offset: usize, + pub val: Arg, +} + +pub struct Shuf { + pub out: u8, + pub val: Arg, +} + +pub struct Exit { + pub val: Arg, +} + +pub enum Op { + Alloc(Alloc), + Call, + Poke(Poke), + Peek(Peek), + Shuf(Shuf), + Exit(Exit), +} + +struct Reader<'a> { + data: &'a [u8], + n: usize, +} + +impl Reader<'_> { + fn advance(&mut self, size: usize) { + self.data = &self.data[size..]; + self.n += size; + } + + fn parse_byte(&mut self) -> Result> { + if self.data.is_empty() { + return Err(Box::from("read byte: no data")); + } + let res = self.data[0]; + self.advance(1); + Ok(res) + } + + fn parse_local(&mut self) -> Result> { + if self.data.is_empty() { + return Err(Box::from("local: no data")); + } + let res = self.data[0]; + if usize::from(res) >= heap::NUM_LOCALS { + return Err(Box::from(format!("invalid local (out of range): {}", res))); + } + self.advance(1); + Ok(res) + } + + fn parse_u64(&mut self) -> Result> { + if self.data.len() < 8 { + return Err(Box::from("value: no data")); + } + let mut res = [0; 8]; + res.copy_from_slice(&self.data[..8]); + self.advance(8); + Ok(u64::from_le_bytes(res)) + } + + fn parse_arg(&mut self, is_const: bool) -> Result> { + if is_const { + Ok(Arg::Const(Value(self.parse_u64()?))) + } else { + Ok(Arg::Local(self.parse_local()?)) + } + } +} + +impl Op { + pub fn parse(data: &[u8]) -> Result<(usize, Op), Box> { + let mut r = Reader { data, n: 0 }; + let code_byte = r.parse_byte()?; + let code = code_byte >> 2; + let arg1_const = code_byte & 2 != 0; + // let arg2_const = code_byte & 1 != 0; + + let op = match code { + 1 => { + let out = r.parse_local()?; + let size = r.parse_arg(arg1_const)?; + Op::Alloc(Alloc { out, size }) + } + 2 => Op::Call, + 3 => { + let offset = usize::try_from(r.parse_u64()?)?; + let ptr = r.parse_local()?; + let val = r.parse_arg(arg1_const)?; + Op::Poke(Poke { offset, ptr, val }) + } + 4 => { + let out = r.parse_local()?; + let offset = usize::try_from(r.parse_u64()?)?; + let val = r.parse_arg(arg1_const)?; + Op::Peek(Peek { out, offset, val }) + } + 5 => { + let out = r.parse_local()?; + let val = r.parse_arg(arg1_const)?; + Op::Shuf(Shuf { out, val }) + } + 6 => { + let val = r.parse_arg(arg1_const)?; + Op::Exit(Exit { val }) + } + _ => { + return Err(Box::from(format!("invalid code {}", code))); + } + }; + + Ok((r.n, op)) + } +} -- cgit v1.3.1