diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2024-05-11 22:15:46 -0700 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2024-05-11 22:15:46 -0700 |
| commit | 7b87d7185fc93b92606fcacbc1ea3d7a8e02cb20 (patch) | |
| tree | b59f04fce96fc34b0c1315c67c955aa90b121e19 /bytecode/src | |
| parent | df7dab936f11310cf8e422eb4c06b2815eaf2807 (diff) | |
| download | sml-7b87d7185fc93b92606fcacbc1ea3d7a8e02cb20.tar.zst | |
Use strings for errors.
Diffstat (limited to 'bytecode/src')
| -rw-r--r-- | bytecode/src/encoding.rs | 46 | ||||
| -rw-r--r-- | bytecode/src/heap.rs | 13 | ||||
| -rw-r--r-- | bytecode/src/main.rs | 51 |
3 files changed, 56 insertions, 54 deletions
diff --git a/bytecode/src/encoding.rs b/bytecode/src/encoding.rs index 80fcc58..81cb29f 100644 --- a/bytecode/src/encoding.rs +++ b/bytecode/src/encoding.rs @@ -1,6 +1,5 @@ use crate::heap; use crate::value::Value; -use std::error::Error; #[derive(Debug, Clone, Copy)] pub enum Arg { @@ -115,30 +114,30 @@ impl Reader<'_> { self.n += size; } - fn parse_byte(&mut self) -> Result<u8, Box<dyn Error>> { + fn parse_byte(&mut self) -> Result<u8, String> { if self.data.is_empty() { - return Err(Box::from("read byte: no data")); + return Err(String::from("read byte: no data")); } let res = self.data[0]; self.advance(1); Ok(res) } - fn parse_local(&mut self) -> Result<u8, Box<dyn Error>> { + fn parse_local(&mut self) -> Result<u8, String> { if self.data.is_empty() { - return Err(Box::from("local: no data")); + return Err(String::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))); + return Err(format!("invalid local (out of range): {}", res)); } self.advance(1); Ok(res) } - fn parse_value(&mut self) -> Result<Value, Box<dyn Error>> { + fn parse_value(&mut self) -> Result<Value, String> { if self.data.len() < 8 { - return Err(Box::from("value: no data")); + return Err(String::from("value: no data")); } let mut res = [0; 8]; res.copy_from_slice(&self.data[..8]); @@ -146,7 +145,17 @@ impl Reader<'_> { Ok(Value(u64::from_le_bytes(res))) } - fn parse_arg(&mut self, is_const: bool) -> Result<Arg, Box<dyn Error>> { + fn parse_offset(&mut self) -> Result<usize, String> { + let Some(ioffset) = self.parse_value()?.to_int() else { + return Err(String::from("invalid offset")); + }; + let Ok(offset) = usize::try_from(ioffset) else { + return Err(String::from("invalid offset")); + }; + Ok(offset) + } + + fn parse_arg(&mut self, is_const: bool) -> Result<Arg, String> { if is_const { Ok(Arg::Const(self.parse_value()?)) } else { @@ -156,7 +165,7 @@ impl Reader<'_> { } impl Op { - pub fn parse(data: &[u8]) -> Result<(usize, Op), Box<dyn Error>> { + pub fn parse(data: &[u8]) -> Result<(usize, Op), String> { let mut r = Reader { data, n: 0 }; let code_byte = r.parse_byte()?; let code = code_byte >> 2; @@ -171,20 +180,14 @@ impl Op { } 2 => Op::Call, 3 => { - let Some(ioffset) = r.parse_value()?.to_int() else { - return Err(Box::from("invalid offset")); - }; - let offset = usize::try_from(ioffset)?; + let offset = r.parse_offset()?; 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 Some(ioffset) = r.parse_value()?.to_int() else { - return Err(Box::from("invalid offset")); - }; - let offset = usize::try_from(ioffset)?; + let offset = r.parse_offset()?; let val = r.parse_arg(arg1_const)?; Op::Peek(Peek { out, offset, val }) } @@ -235,14 +238,11 @@ impl Op { } 13 => { let test = r.parse_arg(arg1_const)?; - let Some(itarget) = r.parse_value()?.to_int() else { - return Err(Box::from("invalid target")); - }; - let target = usize::try_from(itarget)?; + let target = r.parse_offset()?; Op::If(If { test, target }) } _ => { - return Err(Box::from(format!("invalid code {}", code))); + return Err(format!("invalid code {}", code)); } }; diff --git a/bytecode/src/heap.rs b/bytecode/src/heap.rs index 970db7d..d956e2e 100644 --- a/bytecode/src/heap.rs +++ b/bytecode/src/heap.rs @@ -1,5 +1,4 @@ use crate::value::Value; -use std::error::Error; pub const NUM_LOCALS: usize = 256; @@ -108,9 +107,9 @@ impl Heap { self.buf.resize(new_size * 2, 0); } - pub fn alloc(&mut self, size: i64) -> Result<usize, Box<dyn Error>> { + pub fn alloc(&mut self, size: i64) -> Result<usize, String> { if size <= 0 { - return Err(Box::from("alloc of zero size")); + return Err(String::from("alloc of zero size")); } let usize = usize::try_from(size).expect("32 bits in 2024 LULW"); self.collect_garbage(); @@ -125,16 +124,16 @@ impl Heap { Ok(p) } - pub fn peek(&self, p: usize) -> Result<Value, Box<dyn Error>> { + pub fn peek(&self, p: usize) -> Result<Value, String> { if p >= self.buf.len() { - return Err(Box::from("peek: out of range")); + return Err(String::from("peek: out of range")); } Ok(Value(self.buf[p])) } - pub fn poke(&mut self, p: usize, val: Value) -> Result<(), Box<dyn Error>> { + pub fn poke(&mut self, p: usize, val: Value) -> Result<(), String> { if p >= self.buf.len() { - return Err(Box::from("poke: out of range")); + return Err(String::from("poke: out of range")); } self.buf[p] = val.repr(); Ok(()) diff --git a/bytecode/src/main.rs b/bytecode/src/main.rs index 4cba4ef..4981734 100644 --- a/bytecode/src/main.rs +++ b/bytecode/src/main.rs @@ -4,7 +4,6 @@ mod value; use encoding::{Arg, Op}; use heap::Heap; -use std::error::Error; use std::ffi::OsString; use std::io::{stderr, Write}; use value::Value; @@ -22,29 +21,32 @@ impl State { } } - fn op(&mut self, op: Op) -> Result<(), Box<dyn Error>> { + fn op(&mut self, op: Op) -> Result<(), String> { match op { Op::Alloc(op) => { let Some(i) = self.read_arg(op.size).to_int() else { - return Err(Box::from("alloc needs an int")); + return Err(String::from("alloc needs an int")); }; self.heap.locals[usize::from(op.out)] = Value::from_pointer(self.heap.alloc(i)?); } Op::Call => { let Some(i) = self.heap.locals[0].to_int() else { - return Err(Box::from("call needs an int")); + return Err(String::from("call needs an int")); }; - self.i = usize::try_from(i)?; + let Ok(u) = usize::try_from(i) else { + return Err(String::from("call needs a positive int")); + }; + self.i = u; } Op::Poke(op) => { let Some(p) = self.heap.locals[usize::from(op.ptr)].to_pointer() else { - return Err(Box::from("poke needs a pointer")); + return Err(String::from("poke needs a pointer")); }; self.heap.poke(p + op.offset, self.read_arg(op.val))?; } Op::Peek(op) => { let Some(p) = self.read_arg(op.val).to_pointer() else { - return Err(Box::from("peek needs a pointer")); + return Err(String::from("peek needs a pointer")); }; self.heap.locals[usize::from(op.out)] = self.heap.peek(p + op.offset)?; } @@ -59,66 +61,66 @@ impl State { } Op::Add(op) => { let Some(v1) = self.read_arg(op.val1).to_int() else { - return Err(Box::from("add needs an int")); + return Err(String::from("add needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(Box::from("add needs an int")); + return Err(String::from("add needs an int")); }; self.heap.locals[usize::from(op.out)] = Value::from_int(v1.wrapping_add(v2)); } Op::Sub(op) => { let Some(v1) = self.read_arg(op.val1).to_int() else { - return Err(Box::from("sub needs an int")); + return Err(String::from("sub needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(Box::from("sub needs an int")); + return Err(String::from("sub needs an int")); }; self.heap.locals[usize::from(op.out)] = Value::from_int(v1.wrapping_sub(v2)); } Op::Mul(op) => { let Some(v1) = self.read_arg(op.val1).to_int() else { - return Err(Box::from("mul needs an int")); + return Err(String::from("mul needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(Box::from("mul needs an int")); + return Err(String::from("mul needs an int")); }; self.heap.locals[usize::from(op.out)] = Value::from_int(v1.wrapping_mul(v2)); } Op::Div(op) => { let Some(v1) = self.read_arg(op.val1).to_int() else { - return Err(Box::from("div needs an int")); + return Err(String::from("div needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(Box::from("div needs an int")); + return Err(String::from("div needs an int")); }; let Some(res) = v1.checked_div(v2) else { - return Err(Box::from("division by zero")); + return Err(String::from("division by zero")); }; self.heap.locals[usize::from(op.out)] = Value::from_int(res); } Op::Less(op) => { let Some(v1) = self.read_arg(op.val1).to_int() else { - return Err(Box::from("less needs an int")); + return Err(String::from("less needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(Box::from("less needs an int")); + return Err(String::from("less needs an int")); }; let res = if v1 < v2 { 1 } else { 0 }; self.heap.locals[usize::from(op.out)] = Value::from_int(res); } Op::Eq(op) => { let Some(v1) = self.read_arg(op.val1).to_int() else { - return Err(Box::from("eq needs an int")); + return Err(String::from("eq needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(Box::from("eq needs an int")); + return Err(String::from("eq needs an int")); }; let res = if v1 == v2 { 1 } else { 0 }; self.heap.locals[usize::from(op.out)] = Value::from_int(res); } Op::If(op) => { let Some(t) = self.read_arg(op.test).to_int() else { - return Err(Box::from("if needs an int")); + return Err(String::from("if needs an int")); }; if t != 0 { self.i = op.target; @@ -129,12 +131,13 @@ impl State { } } -fn run() -> Result<(), Box<dyn Error>> { +fn run() -> Result<(), String> { let args: Vec<OsString> = std::env::args_os().collect(); if args.len() != 2 { - return Err(Box::from("usage: bytecode <file>")); + return Err(String::from("usage: bytecode <file>")); } - let prog = std::fs::read(&args[1])?; + let prog = std::fs::read(&args[1]) + .map_err(|err| format!("read program from {:?}: {}", args[1], err))?; let mut st = State { i: 0, heap: Heap::new(), |
