summaryrefslogtreecommitdiffstats
path: root/bytecode
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2024-05-12 08:21:14 -0700
committerRose Hogenson <rosehogenson@posteo.net>2024-05-12 08:21:14 -0700
commit8ec4edc977e0ed87f86c7e74c13d3633cb788069 (patch)
tree0a2ef1c6c89e5187e4082adf22d4ab87925cd7dd /bytecode
parent7b87d7185fc93b92606fcacbc1ea3d7a8e02cb20 (diff)
downloadsml-8ec4edc977e0ed87f86c7e74c13d3633cb788069.tar.zst
Revert "Use strings for errors."
This reverts commit 7b87d7185fc93b92606fcacbc1ea3d7a8e02cb20. It was an interesting experiment, but String seems to be worse than Box<dyn Error> in every way.
Diffstat (limited to 'bytecode')
-rw-r--r--bytecode/src/encoding.rs46
-rw-r--r--bytecode/src/heap.rs13
-rw-r--r--bytecode/src/main.rs51
3 files changed, 54 insertions, 56 deletions
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<u8, String> {
+ fn parse_byte(&mut self) -> Result<u8, Box<dyn Error>> {
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<u8, String> {
+ fn parse_local(&mut self) -> Result<u8, Box<dyn Error>> {
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<Value, String> {
+ fn parse_value(&mut self) -> Result<Value, Box<dyn Error>> {
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<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> {
+ fn parse_arg(&mut self, is_const: bool) -> Result<Arg, Box<dyn Error>> {
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<dyn Error>> {
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<usize, String> {
+ pub fn alloc(&mut self, size: i64) -> Result<usize, Box<dyn Error>> {
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<Value, String> {
+ pub fn peek(&self, p: usize) -> Result<Value, Box<dyn Error>> {
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<dyn Error>> {
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<dyn Error>> {
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<dyn Error>> {
let args: Vec<OsString> = std::env::args_os().collect();
if args.len() != 2 {
- return Err(String::from("usage: bytecode <file>"));
+ return Err(Box::from("usage: bytecode <file>"));
}
- 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(),