diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2024-02-04 16:46:20 -0800 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2024-02-04 16:46:20 -0800 |
| commit | 17face3633686e374aa0859271ccf462a48e60aa (patch) | |
| tree | 6a5482717ef1b8194ccf347a6d8af06d664902cd /bytecode/src/main.rs | |
| parent | d940187fd8720e0ab3c00e5a6a7ae8f181c7752d (diff) | |
| download | sml-17face3633686e374aa0859271ccf462a48e60aa.tar.zst | |
Rewrite the bytecode interpreter in Rust.
Diffstat (limited to 'bytecode/src/main.rs')
| -rw-r--r-- | bytecode/src/main.rs | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/bytecode/src/main.rs b/bytecode/src/main.rs new file mode 100644 index 0000000..a4970e0 --- /dev/null +++ b/bytecode/src/main.rs @@ -0,0 +1,87 @@ +mod encoding; +mod heap; +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; + +struct State { + i: usize, + heap: Heap, +} + +impl State { + fn read_arg(&self, a: Arg) -> Value { + match a { + Arg::Local(l) => self.heap.locals[usize::from(l)], + Arg::Const(c) => c, + } + } + + 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(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(Box::from("call needs an int")); + }; + self.i = usize::try_from(i)?; + } + Op::Poke(op) => { + let Some(p) = self.heap.locals[usize::from(op.ptr)].to_pointer() else { + 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(Box::from("peek needs a pointer")); + }; + self.heap.locals[usize::from(op.out)] = self.heap.peek(p + op.offset)?; + } + Op::Shuf(op) => { + self.heap.locals[usize::from(op.out)] = self.read_arg(op.val); + } + Op::Exit(op) => { + let Some(i) = self.read_arg(op.val).to_int() else { + std::process::exit(255); + }; + std::process::exit(i as i32); + } + } + Ok(()) + } +} + +fn run() -> Result<(), Box<dyn Error>> { + let args: Vec<OsString> = std::env::args_os().collect(); + if args.len() != 2 { + return Err(Box::from("usage: bytecode <file>")); + } + let prog = std::fs::read(&args[1])?; + let mut st = State { + i: 0, + heap: Heap::new(), + }; + loop { + let (n, op) = Op::parse(&prog[st.i..])?; + st.i += n; + st.op(op)?; + } +} + +fn main() { + if let Err(err) = run() { + let _ = writeln!(stderr(), "FAIL: {}", err); + std::process::exit(255); + } +} |
