From 8baea40e826431d572b91794d61cba0c9de28858 Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Sun, 1 Oct 2023 23:07:52 -0500 Subject: [PATCH] :recycle: refactor: extract `State::eval` for testing bugs the REPL finds --- Cargo.lock | 58 +++++++++++++++++++++++++++++++++++++ lunar_wave_vm/Cargo.toml | 3 ++ lunar_wave_vm/src/error.rs | 7 +++++ lunar_wave_vm/src/lib.rs | 2 ++ lunar_wave_vm/src/loader.rs | 12 ++++++-- lunar_wave_vm/src/state.rs | 24 +++++++++++---- lunar_wave_vm/src/tests.rs | 26 ++--------------- 7 files changed, 100 insertions(+), 32 deletions(-) create mode 100644 lunar_wave_vm/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index 66640e1..9bc4d44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,3 +12,61 @@ dependencies = [ [[package]] name = "lunar_wave_vm" version = "0.1.0" +dependencies = [ + "thiserror", +] + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/lunar_wave_vm/Cargo.toml b/lunar_wave_vm/Cargo.toml index f53ce0d..c72929c 100644 --- a/lunar_wave_vm/Cargo.toml +++ b/lunar_wave_vm/Cargo.toml @@ -4,3 +4,6 @@ description = "A Lua virtual machine implementation" version = "0.1.0" edition = "2021" authors = ["ReactorScram"] + +[dependencies] +thiserror = "1.0.49" diff --git a/lunar_wave_vm/src/error.rs b/lunar_wave_vm/src/error.rs new file mode 100644 index 0000000..e7e3d40 --- /dev/null +++ b/lunar_wave_vm/src/error.rs @@ -0,0 +1,7 @@ +#[derive (Debug, thiserror::Error)] +pub enum Error { + #[error ("loader")] + Loader (#[from] crate::loader::Error), + #[error ("VM step")] + VmStep (#[from] crate::state::StepError), +} diff --git a/lunar_wave_vm/src/lib.rs b/lunar_wave_vm/src/lib.rs index f7d66cd..6992250 100644 --- a/lunar_wave_vm/src/lib.rs +++ b/lunar_wave_vm/src/lib.rs @@ -1,8 +1,10 @@ +mod error; mod instruction; mod loader; mod state; mod value; +pub use error::Error as Error; pub use loader::compile_bytecode_from_file as compile_bytecode_from_file; pub use loader::compile_bytecode as compile_bytecode; pub use loader::ensure_bytecode as ensure_bytecode; diff --git a/lunar_wave_vm/src/loader.rs b/lunar_wave_vm/src/loader.rs index 16c7c15..c831147 100644 --- a/lunar_wave_vm/src/loader.rs +++ b/lunar_wave_vm/src/loader.rs @@ -29,12 +29,18 @@ pub fn compile_bytecode_from_file (path: &str) -> Vec { output.stdout.as_slice ().to_vec () } +#[derive (Debug, thiserror::Error)] +pub enum Error { + #[error ("compile")] + Compile (String) +} + /// Invoke `luac` as a subprocess /// Luckily luac is single-pass, so we can just pipe in and out /// /// `source` is a Vec because we move it to a worker thread -pub fn compile_bytecode (source: Vec ) -> Result , String> { +pub fn compile_bytecode (source: Vec ) -> Result , Error> { use std::{ io::Write, process::{ @@ -67,7 +73,7 @@ pub fn compile_bytecode (source: Vec ) -> Result , String> { Ok (output.stdout) } else { - Err (String::from_utf8 (output.stderr).unwrap ()) + Err (Error::Compile (String::from_utf8 (output.stderr).unwrap ())) } } @@ -75,7 +81,7 @@ pub fn compile_bytecode (source: Vec ) -> Result , String> { /// Lua source code. If it's source code, compiles and returns bytecode. /// If it's bytecode, just returns the input. -pub fn ensure_bytecode (buffer: Vec ) -> Result , String> { +pub fn ensure_bytecode (buffer: Vec ) -> Result , Error> { let bytecode_header = &[0x1b, 0x4c, 0x75, 0x61, 0x54, 0x00, 0x19, 0x93]; if buffer.starts_with (bytecode_header) { return Ok (buffer); diff --git a/lunar_wave_vm/src/state.rs b/lunar_wave_vm/src/state.rs index cb3e1e1..5fb9de0 100644 --- a/lunar_wave_vm/src/state.rs +++ b/lunar_wave_vm/src/state.rs @@ -133,11 +133,14 @@ pub enum StepOutput { ChunkReturned (Vec ), } -#[derive (Debug)] -pub struct StepError { - frame: StackFrame, - inst: Instruction, - msg: &'static str, +#[derive (Debug, thiserror::Error)] +pub enum StepError { + #[error ("generic")] + Generic { + frame: StackFrame, + inst: Instruction, + msg: &'static str, + }, } impl State { @@ -217,7 +220,7 @@ impl State { fn make_step_error (&self, msg: &'static str, inst: &Instruction) -> StepError { - StepError { + StepError::Generic { frame: self.stack.last ().unwrap ().clone (), inst: inst.clone (), msg, @@ -900,6 +903,15 @@ impl State { Ok (None) } + pub fn eval (&mut self, src: &str) -> Result , crate::Error> + { + let bytecode = crate::compile_bytecode (src.as_bytes ().to_vec ())?; + let chunk = crate::parse_chunk (&bytecode).unwrap (); + + self.set_chunk (chunk); + Ok (self.execute ()?) + } + pub fn execute (&mut self) -> Result , StepError> { let max_iters = 2000; diff --git a/lunar_wave_vm/src/tests.rs b/lunar_wave_vm/src/tests.rs index 5a98873..5fbae5e 100644 --- a/lunar_wave_vm/src/tests.rs +++ b/lunar_wave_vm/src/tests.rs @@ -206,29 +206,9 @@ fn function_calls () { let mut vm = crate::State::new (crate::Chunk::default (), upvalues); - { - let bc = crate::compile_bytecode (b"print (x ())".to_vec ()).unwrap (); - let chunk = crate::parse_chunk (&bc).unwrap (); - - vm.set_chunk (chunk); - vm.execute ().unwrap (); - } - - { - let bc = crate::compile_bytecode (b"x = function () return 5 end".to_vec ()).unwrap (); - let chunk = crate::parse_chunk (&bc).unwrap (); - - vm.set_chunk (chunk); - vm.execute ().unwrap (); - } - - { - let bc = crate::compile_bytecode (b"print (x ())".to_vec ()).unwrap (); - let chunk = crate::parse_chunk (&bc).unwrap (); - - vm.set_chunk (chunk); - vm.execute ().unwrap (); - } + vm.eval ("print (x ())").ok (); + vm.eval ("x = function () return 5 end").ok (); + vm.eval ("print (x ())").ok (); } #[test]