diff options
| author | Brian Cully <bjc@spork.org> | 2025-08-31 15:26:10 -0400 |
|---|---|---|
| committer | Brian Cully <bjc@spork.org> | 2025-08-31 15:26:10 -0400 |
| commit | f41f180655f35e1e3da7948d736894fcc4345d51 (patch) | |
| tree | f43e4c428a0ae6480f929b2ddbcf9c4478f3a4f2 /src | |
| parent | 35c98bd145d42147520c61e8d5cf4985077daf29 (diff) | |
| download | automathon-f41f180655f35e1e3da7948d736894fcc4345d51.tar.gz automathon-f41f180655f35e1e3da7948d736894fcc4345d51.zip | |
rustfmt
Diffstat (limited to 'src')
| -rw-r--r-- | src/forth/compiler.rs | 88 | ||||
| -rw-r--r-- | src/forth/vm.rs | 215 | ||||
| -rwxr-xr-x | src/lib.rs | 47 |
3 files changed, 206 insertions, 144 deletions
diff --git a/src/forth/compiler.rs b/src/forth/compiler.rs index e8aaa7f..b518b7e 100644 --- a/src/forth/compiler.rs +++ b/src/forth/compiler.rs @@ -82,12 +82,11 @@ impl<'a> Compiler<'a> { // pull the next, whitespace-delimited word off the input stream. fn next_word(&mut self) -> Option<(&'a str, usize, usize)> { - let (start, _c) = - self.enumerator.by_ref() - .find(|(_i, c)| !c.is_whitespace())?; - let (end, _c) = - self.enumerator.by_ref() - .find(|(_i, c)| c.is_whitespace())?; + let (start, _c) = self + .enumerator + .by_ref() + .find(|(_i, c)| !c.is_whitespace())?; + let (end, _c) = self.enumerator.by_ref().find(|(_i, c)| c.is_whitespace())?; let word = &self.text[start..end]; Some((word, start, end)) } @@ -126,7 +125,7 @@ impl<'a> Compiler<'a> { let k = *i; self.bc_mut().0.pop(); self.bc_mut().0.push(OpCode::TCall(k)); - }, + } Some(OpCode::If(t, f)) => { let t = *t; let f = *f; @@ -134,7 +133,7 @@ impl<'a> Compiler<'a> { self.bc_mut().0.push(OpCode::TIf(t, f)); // technically only needed if âfâ is None, but whatever. //self.bc_push(OpCode::Ret, anno); - }, + } _ => self.bc_push(OpCode::Ret, anno), } } @@ -149,33 +148,33 @@ impl<'a> Compiler<'a> { } else { match word { r#"s""# => { - let (s_end, _) = - self.enumerator - .find(|(_i, c)| *c == '"') - .ok_or(CompileError::MissingQuote)?; - self.bc_push(OpCode::Str(end+1, s_end), anno); - }, + let (s_end, _) = self + .enumerator + .find(|(_i, c)| *c == '"') + .ok_or(CompileError::MissingQuote)?; + self.bc_push(OpCode::Str(end + 1, s_end), anno); + } "(" => { self.enumerator .find(|(_i, c)| *c == ')') .ok_or(CompileError::MissingParen)?; - }, + } "\\" => { self.enumerator .find(|(_i, c)| *c == '\n') .ok_or(CompileError::EOF)?; - }, + } ":" => { let (name, _, _) = self.next_word().ok_or(CompileError::EOF)?; self.wordalog.0.insert(name, self.wordlist.0.len()); self.defstack.push(self.wordlist.0.len()); self.wordlist.0.push(ByteCode(vec![])); self.annotations.push(vec![]); - }, + } ";" => { self.sub_tcall(anno); self.defstack.pop().ok_or(CompileError::DefStackEmpty)?; - }, + } "if" => { let i = self.wordlist.0.len(); self.wordlist.0.push(ByteCode(vec![])); @@ -183,7 +182,7 @@ impl<'a> Compiler<'a> { self.defstack.push(i); self.if_stack.push((IfClauses::True(i), anno)); - }, + } "else" => { self.sub_tcall(anno); self.defstack.pop(); @@ -195,11 +194,14 @@ impl<'a> Compiler<'a> { let (true_clause, anno) = match self.if_stack.pop() { None => return Err(CompileError::MissingIf), - Some((IfClauses::TrueFalse(_, _), _)) => return Err(CompileError::MissingIf), + Some((IfClauses::TrueFalse(_, _), _)) => { + return Err(CompileError::MissingIf); + } Some((IfClauses::True(cl), anno)) => (cl, anno), }; - self.if_stack.push((IfClauses::TrueFalse(true_clause, i), anno)); - }, + self.if_stack + .push((IfClauses::TrueFalse(true_clause, i), anno)); + } "then" => { self.sub_tcall(anno); self.defstack.pop(); @@ -208,12 +210,12 @@ impl<'a> Compiler<'a> { None => return Err(CompileError::MissingIf), Some((IfClauses::True(true_clause), anno)) => { self.bc_push(OpCode::If(true_clause, None), anno); - }, + } Some((IfClauses::TrueFalse(true_clause, false_clause), anno)) => { self.bc_push(OpCode::If(true_clause, Some(false_clause)), anno); } } - }, + } "+" => self.bc_push(OpCode::Add, anno), "-" => self.bc_push(OpCode::Sub, anno), "*" => self.bc_push(OpCode::Mul, anno), @@ -237,8 +239,8 @@ impl<'a> Compiler<'a> { #[cfg(test)] mod tests { - use super::*; use super::super::vm::OpCode; + use super::*; fn compiler_for(text: &str) -> Compiler { let mut p = Compiler::new(text); @@ -298,7 +300,11 @@ mod tests { fn def_word() { let comp = compiler_for(": add2 2 + ; 3 add2\n"); let main = &comp.wordlist.0[0]; - let add2_index = comp.wordalog.0.get("add2").expect("add2 has entry in wordlist"); + let add2_index = comp + .wordalog + .0 + .get("add2") + .expect("add2 has entry in wordlist"); assert_eq!(main, vec![OpCode::Num(3), OpCode::Call(*add2_index)]); let add2 = &comp.wordlist.0[*add2_index]; @@ -313,7 +319,10 @@ mod tests { let main = &comp.wordlist.0[0]; assert_eq!(main, vec![OpCode::If(1, None)]); let tr = &comp.wordlist.0[1]; - assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]); + assert_eq!( + tr, + vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret] + ); } #[test] @@ -326,9 +335,15 @@ mod tests { assert_eq!(main[0], OpCode::If(1, Some(2))); assert_eq!(main, vec![OpCode::If(1, Some(2))]); let tr = &comp.wordlist.0[1]; - assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]); + assert_eq!( + tr, + vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret] + ); let fl = &comp.wordlist.0[2]; - assert_eq!(fl, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret]); + assert_eq!( + fl, + vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret] + ); } #[test] @@ -354,7 +369,10 @@ mod tests { let t = &comp.wordlist.0[1]; assert_eq!(t, vec![OpCode::TIf(2, None)]); let tr = &comp.wordlist.0[2]; - assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]); + assert_eq!( + tr, + vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret] + ); } #[test] @@ -367,9 +385,15 @@ mod tests { let t = &comp.wordlist.0[1]; assert_eq!(t, vec![OpCode::TIf(2, Some(3))]); let tr = &comp.wordlist.0[2]; - assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]); + assert_eq!( + tr, + vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret] + ); let fl = &comp.wordlist.0[3]; - assert_eq!(fl, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret]); + assert_eq!( + fl, + vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret] + ); } #[test] diff --git a/src/forth/vm.rs b/src/forth/vm.rs index 5bc1835..4930514 100644 --- a/src/forth/vm.rs +++ b/src/forth/vm.rs @@ -54,8 +54,7 @@ impl ByteCode { // it there. impl PartialEq<Vec<OpCode>> for &ByteCode { fn eq(&self, other: &Vec<OpCode>) -> bool { - self.0.len() == other.len() && - std::iter::zip(&self.0, other).all(|(a, b)| a == b) + self.0.len() == other.len() && std::iter::zip(&self.0, other).all(|(a, b)| a == b) } } @@ -75,10 +74,7 @@ pub struct InstructionPointer { impl InstructionPointer { pub fn new() -> Self { - Self { - word: 0, - offset: 0, - } + Self { word: 0, offset: 0 } } } @@ -155,116 +151,114 @@ impl VM { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; self.stack.0.push(n2 + n1); - }, + } OpCode::Sub => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; self.stack.0.push(n2 - n1); - }, + } OpCode::Mul => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; self.stack.0.push(n2 * n1); - }, + } OpCode::Div => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; self.stack.0.push(n2 / n1); - }, + } OpCode::Dup => { let len = self.stack.0.len(); if len < 1 { - return Err(RuntimeError::StackUnderflow) + return Err(RuntimeError::StackUnderflow); } - self.stack.0.push(self.stack.0[len-1]); - }, + self.stack.0.push(self.stack.0[len - 1]); + } OpCode::Drop => { self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - }, + } OpCode::Swap => { let top = self.stack.0.len() - 1; if top < 1 { - return Err(RuntimeError::StackUnderflow) + return Err(RuntimeError::StackUnderflow); } - let (a, b) = - self.stack.0.split_at_mut(top); - std::mem::swap(&mut a[top-1], &mut b[0]); - }, + let (a, b) = self.stack.0.split_at_mut(top); + std::mem::swap(&mut a[top - 1], &mut b[0]); + } OpCode::Rot => { let top = self.stack.0.len() - 1; if top < 2 { - return Err(RuntimeError::StackUnderflow) + return Err(RuntimeError::StackUnderflow); } - let (a, b) = - self.stack.0.split_at_mut(top); - std::mem::swap(&mut a[top-1], &mut b[0]); - std::mem::swap(&mut a[top-2], &mut b[0]); - }, + let (a, b) = self.stack.0.split_at_mut(top); + std::mem::swap(&mut a[top - 1], &mut b[0]); + std::mem::swap(&mut a[top - 2], &mut b[0]); + } OpCode::EQ => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let v = if n2 == n1 { -1 } else { 0 }; self.stack.0.push(v); - }, + } OpCode::GT => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let v = if n2 > n1 { -1 } else { 0 }; self.stack.0.push(v); - }, + } OpCode::GTE => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let v = if n2 >= n1 { -1 } else { 0 }; self.stack.0.push(v); - }, + } OpCode::LT => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let v = if n2 < n1 { -1 } else { 0 }; self.stack.0.push(v); - }, + } OpCode::LTE => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let v = if n2 <= n1 { -1 } else { 0 }; self.stack.0.push(v); - }, + } OpCode::Ret => { self.ip = self.callstack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - }, + } OpCode::Call(i) => { self.call(i); // skip the offset increment - return Ok(true) - }, + return Ok(true); + } OpCode::TCall(i) => { self.jmp(i); // skip the offset increment - return Ok(true) - }, + return Ok(true); + } OpCode::If(true_clause, false_clause) => { let flag = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; if flag != 0 { self.call(true_clause); - return Ok(true) + return Ok(true); } else if let Some(false_clause) = false_clause { self.call(false_clause); - return Ok(true) + return Ok(true); } - }, + } OpCode::TIf(true_clause, false_clause) => { let flag = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; if flag != 0 { self.jmp(true_clause); - return Ok(true) + return Ok(true); } else if let Some(false_clause) = false_clause { self.jmp(false_clause); - return Ok(true) + return Ok(true); } else { self.ip = self.callstack.0.pop().ok_or(RuntimeError::StackUnderflow)?; } - }, + } } self.ip.offset += 1; Ok(self.ip.offset < self.wordlist.0[self.ip.word].len()) @@ -272,38 +266,52 @@ impl VM { pub fn run(&mut self) -> Result<usize, RuntimeError> { let mut count = 0; - while self.tick()? { count += 1 } + while self.tick()? { + count += 1 + } Ok(count) } } #[cfg(test)] mod tests { - use super::*; use super::OpCode; + use super::*; fn wl_for(v: Vec<Vec<OpCode>>) -> WordList { - WordList(v.into_iter() - .map(|x| ByteCode(x)) - .collect()) + WordList(v.into_iter().map(|x| ByteCode(x)).collect()) } #[test] fn simple_ticks() { let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Num(3), OpCode::Add])); + wordlist + .0 + .push(ByteCode(vec![OpCode::Num(2), OpCode::Num(3), OpCode::Add])); let mut vm = VM::new(wordlist); - assert_eq!(vm.tick().expect("should execute instruction"), true, "first arg running"); + assert_eq!( + vm.tick().expect("should execute instruction"), + true, + "first arg running" + ); assert_eq!(vm.ip.word, 0); assert_eq!(vm.ip.offset, 1); assert_eq!(vm.stack.0.len(), 1); assert_eq!(vm.stack.0[0], 2, "first argument"); - assert_eq!(vm.tick().expect("should execute instruction"), true, "second arg running"); + assert_eq!( + vm.tick().expect("should execute instruction"), + true, + "second arg running" + ); assert_eq!(vm.ip.word, 0); assert_eq!(vm.ip.offset, 2); assert_eq!(vm.stack.0.len(), 2); assert_eq!(vm.stack.0[1], 3, "second argument"); - assert_eq!(vm.tick().expect("should execute instruction"), false, "stopped after addition"); + assert_eq!( + vm.tick().expect("should execute instruction"), + false, + "stopped after addition" + ); assert_eq!(vm.ip.word, 0); assert_eq!(vm.ip.offset, 3); assert_eq!(vm.stack.0.len(), 1); @@ -314,14 +322,17 @@ mod tests { fn custom_word() { let mut wordlist = WordList(vec![]); wordlist.0.push(ByteCode(vec![ - OpCode::Num(2), OpCode::Num(3), OpCode::Call(1), OpCode::Num(-2), OpCode::Add, - OpCode::Sub, OpCode::Ret, + OpCode::Num(2), + OpCode::Num(3), + OpCode::Call(1), + OpCode::Num(-2), + OpCode::Add, + OpCode::Sub, + OpCode::Ret, ])); let mut vm = VM::new(wordlist); // "sub" definition - vm.wordlist.0.push(ByteCode(vec![ - OpCode::Sub, OpCode::Ret, - ])); + vm.wordlist.0.push(ByteCode(vec![OpCode::Sub, OpCode::Ret])); vm.tick().expect("should execute instruction"); assert_eq!(vm.ip.word, 0); @@ -367,7 +378,9 @@ mod tests { fn tail_call() { let mut wordlist = WordList(vec![]); wordlist.0.push(ByteCode(vec![OpCode::Call(1)])); - wordlist.0.push(ByteCode(vec![OpCode::TCall(2), OpCode::Ret])); + wordlist + .0 + .push(ByteCode(vec![OpCode::TCall(2), OpCode::Ret])); wordlist.0.push(ByteCode(vec![OpCode::Ret])); let mut vm = VM::new(wordlist); @@ -382,7 +395,11 @@ mod tests { #[test] fn if_then_true() { let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::If(1, None), OpCode::Num(0)])); + wordlist.0.push(ByteCode(vec![ + OpCode::Num(-1), + OpCode::If(1, None), + OpCode::Num(0), + ])); wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret])); let mut vm = VM::new(wordlist); @@ -405,7 +422,11 @@ mod tests { #[test] fn if_then_false() { let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Num(0), OpCode::If(1, None), OpCode::Num(-1)])); + wordlist.0.push(ByteCode(vec![ + OpCode::Num(0), + OpCode::If(1, None), + OpCode::Num(-1), + ])); wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret])); let mut vm = VM::new(wordlist); @@ -422,7 +443,11 @@ mod tests { #[test] fn if_else_then_true() { let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::If(1, Some(2)), OpCode::Num(-2)])); + wordlist.0.push(ByteCode(vec![ + OpCode::Num(-1), + OpCode::If(1, Some(2)), + OpCode::Num(-2), + ])); wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret])); wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Ret])); let mut vm = VM::new(wordlist); @@ -446,7 +471,11 @@ mod tests { #[test] fn if_else_then_false() { let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Num(0), OpCode::If(1, Some(2)), OpCode::Num(-2)])); + wordlist.0.push(ByteCode(vec![ + OpCode::Num(0), + OpCode::If(1, Some(2)), + OpCode::Num(-2), + ])); wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret])); wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Ret])); let mut vm = VM::new(wordlist); @@ -470,8 +499,14 @@ mod tests { #[test] fn tail_if_then_true() { let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Call(1), OpCode::Num(0)])); - wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::TIf(2, None), OpCode::Ret])); + wordlist + .0 + .push(ByteCode(vec![OpCode::Call(1), OpCode::Num(0)])); + wordlist.0.push(ByteCode(vec![ + OpCode::Num(-1), + OpCode::TIf(2, None), + OpCode::Ret, + ])); wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret])); let mut vm = VM::new(wordlist); @@ -515,8 +550,14 @@ mod tests { #[test] fn tail_if_else_then_true() { let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Call(1), OpCode::Num(-2)])); - wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::TIf(2, Some(3)), OpCode::Ret])); + wordlist + .0 + .push(ByteCode(vec![OpCode::Call(1), OpCode::Num(-2)])); + wordlist.0.push(ByteCode(vec![ + OpCode::Num(-1), + OpCode::TIf(2, Some(3)), + OpCode::Ret, + ])); wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret])); wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Ret])); let mut vm = VM::new(wordlist); @@ -541,12 +582,17 @@ mod tests { #[test] fn tail_if_else_then_false() { - let wordlist = WordList(vec![ - vec![OpCode::Call(1), OpCode::Num(-2)], - vec![OpCode::Num(0), OpCode::TIf(2, Some(3)), OpCode::Ret], - vec![OpCode::Num(1), OpCode::Ret], - vec![OpCode::Num(2), OpCode::Ret], - ].into_iter().map(|x| ByteCode(x)).collect()); + let wordlist = WordList( + vec![ + vec![OpCode::Call(1), OpCode::Num(-2)], + vec![OpCode::Num(0), OpCode::TIf(2, Some(3)), OpCode::Ret], + vec![OpCode::Num(1), OpCode::Ret], + vec![OpCode::Num(2), OpCode::Ret], + ] + .into_iter() + .map(|x| ByteCode(x)) + .collect(), + ); let mut vm = VM::new(wordlist); vm.tick().expect("should execute instruction"); @@ -565,9 +611,7 @@ mod tests { #[test] fn opcode_dup() { - let wordlist = wl_for(vec![ - vec![OpCode::Num(1), OpCode::Dup], - ]); + let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Dup]]); let mut vm = VM::new(wordlist); vm.run().expect("should run to completion"); assert_eq!(vm.stack.0, vec![1, 1]); @@ -575,18 +619,14 @@ mod tests { #[test] fn opcode_dup_underflow() { - let wordlist = wl_for(vec![ - vec![OpCode::Dup], - ]); + let wordlist = wl_for(vec![vec![OpCode::Dup]]); let mut vm = VM::new(wordlist); assert!(vm.run().is_err_and(|e| e == RuntimeError::StackUnderflow)); } #[test] fn opcode_swap() { - let wordlist = wl_for(vec![ - vec![OpCode::Num(1), OpCode::Num(2), OpCode::Swap], - ]); + let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Num(2), OpCode::Swap]]); let mut vm = VM::new(wordlist); vm.run().expect("should run to completion"); assert_eq!(vm.stack.0, vec![2, 1]); @@ -594,18 +634,19 @@ mod tests { #[test] fn opcode_swap_underflow() { - let wordlist = wl_for(vec![ - vec![OpCode::Num(1), OpCode::Swap], - ]); + let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Swap]]); let mut vm = VM::new(wordlist); assert!(vm.run().is_err_and(|e| e == RuntimeError::StackUnderflow)); } #[test] fn opcode_rot() { - let wordlist = wl_for(vec![ - vec![OpCode::Num(1), OpCode::Num(2), OpCode::Num(3), OpCode::Rot], - ]); + let wordlist = wl_for(vec![vec![ + OpCode::Num(1), + OpCode::Num(2), + OpCode::Num(3), + OpCode::Rot, + ]]); let mut vm = VM::new(wordlist); vm.run().expect("should run to completion"); assert_eq!(vm.stack.0, vec![2, 3, 1]); @@ -613,9 +654,7 @@ mod tests { #[test] fn opcode_rot_underflow() { - let wordlist = wl_for(vec![ - vec![OpCode::Num(1), OpCode::Num(2), OpCode::Rot], - ]); + let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Num(2), OpCode::Rot]]); let mut vm = VM::new(wordlist); assert!(vm.run().is_err_and(|e| e == RuntimeError::StackUnderflow)); } @@ -12,7 +12,10 @@ pub struct ExportedInstructionPointer { impl From<&forth::vm::InstructionPointer> for ExportedInstructionPointer { fn from(ip: &forth::vm::InstructionPointer) -> Self { - Self { word: ip.word, offset: ip.offset } + Self { + word: ip.word, + offset: ip.offset, + } } } @@ -108,21 +111,25 @@ pub struct ExportedVM { #[wasm_bindgen] impl ExportedVM { fn new() -> Self { - Self { annos: vec![], vm: None } + Self { + annos: vec![], + vm: None, + } } pub fn compile(&mut self, text: &str) -> bool { let mut comp = forth::compiler::Compiler::new(text); if let Err(e) = comp.compile() { error!("couldn't compile program text: {e:?}"); - return false + return false; } - self.annos = - comp.annotations.iter() - .map(|word_anno| -> ExportedWordAnnotations { - word_anno.iter().map(|a| a.into()).collect() - }) - .collect(); + self.annos = comp + .annotations + .iter() + .map(|word_anno| -> ExportedWordAnnotations { + word_anno.iter().map(|a| a.into()).collect() + }) + .collect(); let vm = forth::vm::VM::new(comp.wordlist); let _ = self.vm.insert(vm); true @@ -130,14 +137,14 @@ impl ExportedVM { pub fn tick(&mut self) -> Result<bool, String> { let Some(vm) = &mut self.vm else { - return Err("no vm".to_string()) + return Err("no vm".to_string()); }; vm.tick().map_err(|err| format!("runtime error: {err:?}")) } pub fn run(&mut self) -> Result<usize, String> { let Some(vm) = &mut self.vm else { - return Err("no vm".to_string()) + return Err("no vm".to_string()); }; vm.ip.word = 0; @@ -146,17 +153,13 @@ impl ExportedVM { } pub fn stack(&self) -> Vec<forth::vm::DataStackType> { - let Some(vm) = &self.vm else { - return vec![] - }; + let Some(vm) = &self.vm else { return vec![] }; vm.stack.0.clone() } pub fn wordlist(&self) -> Vec<ExportedByteCode> { - let Some(vm) = &self.vm else { - return vec![] - }; + let Some(vm) = &self.vm else { return vec![] }; vm.wordlist.iter().map(|bc| bc.into()).collect() } @@ -170,17 +173,13 @@ impl ExportedVM { } pub fn callstack(&self) -> Vec<ExportedInstructionPointer> { - let Some(vm) = &self.vm else { - return vec![] - }; - vm.callstack.0.iter() - .map(|ip| ip.into()) - .collect() + let Some(vm) = &self.vm else { return vec![] }; + vm.callstack.0.iter().map(|ip| ip.into()).collect() } pub fn ip(&self) -> ExportedInstructionPointer { let Some(vm) = &self.vm else { - return ExportedInstructionPointer { word: 0, offset: 0 } + return ExportedInstructionPointer { word: 0, offset: 0 }; }; (&vm.ip).into() } |
