From 8ec4edc977e0ed87f86c7e74c13d3633cb788069 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Sun, 12 May 2024 08:21:14 -0700 Subject: Revert "Use strings for errors." This reverts commit 7b87d7185fc93b92606fcacbc1ea3d7a8e02cb20. It was an interesting experiment, but String seems to be worse than Box in every way. --- bytecode/src/encoding.rs | 46 +++++++++++++++++++++---------------------- bytecode/src/heap.rs | 13 ++++++------ bytecode/src/main.rs | 51 +++++++++++++++++++++++------------------------- 3 files changed, 54 insertions(+), 56 deletions(-) (limited to 'bytecode/src') diff --git a/bytecode/src/encoding.rs b/bytecode/src/encoding.rs index 81cb29f..80fcc58 100644 --- a/bytecode/src/encoding.rs +++ b/bytecode/src/encoding.rs @@ -1,5 +1,6 @@ use crate::heap; use crate::value::Value; +use std::error::Error; #[derive(Debug, Clone, Copy)] pub enum Arg { @@ -114,30 +115,30 @@ impl Reader<'_> { self.n += size; } - fn parse_byte(&mut self) -> Result { + fn parse_byte(&mut self) -> Result> { if self.data.is_empty() { - return Err(String::from("read byte: no data")); + return Err(Box::from("read byte: no data")); } let res = self.data[0]; self.advance(1); Ok(res) } - fn parse_local(&mut self) -> Result { + fn parse_local(&mut self) -> Result> { if self.data.is_empty() { - return Err(String::from("local: no data")); + return Err(Box::from("local: no data")); } let res = self.data[0]; if usize::from(res) >= heap::NUM_LOCALS { - return Err(format!("invalid local (out of range): {}", res)); + return Err(Box::from(format!("invalid local (out of range): {}", res))); } self.advance(1); Ok(res) } - fn parse_value(&mut self) -> Result { + fn parse_value(&mut self) -> Result> { if self.data.len() < 8 { - return Err(String::from("value: no data")); + return Err(Box::from("value: no data")); } let mut res = [0; 8]; res.copy_from_slice(&self.data[..8]); @@ -145,17 +146,7 @@ impl Reader<'_> { Ok(Value(u64::from_le_bytes(res))) } - fn parse_offset(&mut self) -> Result { - 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 { + fn parse_arg(&mut self, is_const: bool) -> Result> { if is_const { Ok(Arg::Const(self.parse_value()?)) } else { @@ -165,7 +156,7 @@ impl Reader<'_> { } impl Op { - pub fn parse(data: &[u8]) -> Result<(usize, Op), String> { + 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; @@ -180,14 +171,20 @@ impl Op { } 2 => Op::Call, 3 => { - let offset = r.parse_offset()?; + let Some(ioffset) = r.parse_value()?.to_int() else { + return Err(Box::from("invalid offset")); + }; + let offset = usize::try_from(ioffset)?; 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 = r.parse_offset()?; + let Some(ioffset) = r.parse_value()?.to_int() else { + return Err(Box::from("invalid offset")); + }; + let offset = usize::try_from(ioffset)?; let val = r.parse_arg(arg1_const)?; Op::Peek(Peek { out, offset, val }) } @@ -238,11 +235,14 @@ impl Op { } 13 => { let test = r.parse_arg(arg1_const)?; - let target = r.parse_offset()?; + let Some(itarget) = r.parse_value()?.to_int() else { + return Err(Box::from("invalid target")); + }; + let target = usize::try_from(itarget)?; Op::If(If { test, target }) } _ => { - return Err(format!("invalid code {}", code)); + return Err(Box::from(format!("invalid code {}", code))); } }; diff --git a/bytecode/src/heap.rs b/bytecode/src/heap.rs index d956e2e..970db7d 100644 --- a/bytecode/src/heap.rs +++ b/bytecode/src/heap.rs @@ -1,4 +1,5 @@ use crate::value::Value; +use std::error::Error; pub const NUM_LOCALS: usize = 256; @@ -107,9 +108,9 @@ impl Heap { self.buf.resize(new_size * 2, 0); } - pub fn alloc(&mut self, size: i64) -> Result { + pub fn alloc(&mut self, size: i64) -> Result> { if size <= 0 { - return Err(String::from("alloc of zero size")); + return Err(Box::from("alloc of zero size")); } let usize = usize::try_from(size).expect("32 bits in 2024 LULW"); self.collect_garbage(); @@ -124,16 +125,16 @@ impl Heap { Ok(p) } - pub fn peek(&self, p: usize) -> Result { + pub fn peek(&self, p: usize) -> Result> { if p >= self.buf.len() { - return Err(String::from("peek: out of range")); + return Err(Box::from("peek: out of range")); } Ok(Value(self.buf[p])) } - pub fn poke(&mut self, p: usize, val: Value) -> Result<(), String> { + pub fn poke(&mut self, p: usize, val: Value) -> Result<(), Box> { if p >= self.buf.len() { - return Err(String::from("poke: out of range")); + return Err(Box::from("poke: out of range")); } self.buf[p] = val.repr(); Ok(()) diff --git a/bytecode/src/main.rs b/bytecode/src/main.rs index 4981734..4cba4ef 100644 --- a/bytecode/src/main.rs +++ b/bytecode/src/main.rs @@ -4,6 +4,7 @@ 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; @@ -21,32 +22,29 @@ impl State { } } - fn op(&mut self, op: Op) -> Result<(), String> { + fn op(&mut self, op: Op) -> Result<(), Box> { match op { Op::Alloc(op) => { let Some(i) = self.read_arg(op.size).to_int() else { - return Err(String::from("alloc needs an int")); + return Err(Box::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(String::from("call needs an int")); + return Err(Box::from("call needs an int")); }; - let Ok(u) = usize::try_from(i) else { - return Err(String::from("call needs a positive int")); - }; - self.i = u; + self.i = usize::try_from(i)?; } Op::Poke(op) => { let Some(p) = self.heap.locals[usize::from(op.ptr)].to_pointer() else { - return Err(String::from("poke needs a pointer")); + return Err(Box::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(String::from("peek needs a pointer")); + return Err(Box::from("peek needs a pointer")); }; self.heap.locals[usize::from(op.out)] = self.heap.peek(p + op.offset)?; } @@ -61,66 +59,66 @@ impl State { } Op::Add(op) => { let Some(v1) = self.read_arg(op.val1).to_int() else { - return Err(String::from("add needs an int")); + return Err(Box::from("add needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(String::from("add needs an int")); + return Err(Box::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(String::from("sub needs an int")); + return Err(Box::from("sub needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(String::from("sub needs an int")); + return Err(Box::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(String::from("mul needs an int")); + return Err(Box::from("mul needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(String::from("mul needs an int")); + return Err(Box::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(String::from("div needs an int")); + return Err(Box::from("div needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(String::from("div needs an int")); + return Err(Box::from("div needs an int")); }; let Some(res) = v1.checked_div(v2) else { - return Err(String::from("division by zero")); + return Err(Box::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(String::from("less needs an int")); + return Err(Box::from("less needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(String::from("less needs an int")); + return Err(Box::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(String::from("eq needs an int")); + return Err(Box::from("eq needs an int")); }; let Some(v2) = self.read_arg(op.val2).to_int() else { - return Err(String::from("eq needs an int")); + return Err(Box::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(String::from("if needs an int")); + return Err(Box::from("if needs an int")); }; if t != 0 { self.i = op.target; @@ -131,13 +129,12 @@ impl State { } } -fn run() -> Result<(), String> { +fn run() -> Result<(), Box> { let args: Vec = std::env::args_os().collect(); if args.len() != 2 { - return Err(String::from("usage: bytecode ")); + return Err(Box::from("usage: bytecode ")); } - let prog = std::fs::read(&args[1]) - .map_err(|err| format!("read program from {:?}: {}", args[1], err))?; + let prog = std::fs::read(&args[1])?; let mut st = State { i: 0, heap: Heap::new(), -- cgit v1.3.1