From 091b7cc7d748624b455be2a4579a6870e94cac09 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Mon, 25 Aug 2025 14:46:15 -0400 Subject: do in-place memory manipulation for rot/dup/swap --- src/forth/vm.rs | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/forth/vm.rs b/src/forth/vm.rs index 9c7f203..e5973dd 100644 --- a/src/forth/vm.rs +++ b/src/forth/vm.rs @@ -172,26 +172,33 @@ impl VM { self.stack.0.push(n2 / n1); }, OpCode::Dup => { - let n = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - self.stack.0.push(n); - self.stack.0.push(n); + let len = self.stack.0.len(); + if len < 1 { + return Err(RuntimeError::StackUnderflow) + } + self.stack.0.push(self.stack.0[len-1]); }, OpCode::Drop => { self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; }, OpCode::Swap => { - let v1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - let v2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - self.stack.0.push(v1); - self.stack.0.push(v2); + let top = self.stack.0.len() - 1; + if top < 1 { + return Err(RuntimeError::StackUnderflow) + } + let (a, b) = + self.stack.0.split_at_mut(top); + std::mem::swap(&mut a[top-1], &mut b[0]); }, OpCode::Rot => { - let v1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - let v2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - let v3 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; - self.stack.0.push(v2); - self.stack.0.push(v1); - self.stack.0.push(v3); + let top = self.stack.0.len() - 1; + if top < 2 { + 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]); }, OpCode::EQ => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; @@ -577,6 +584,17 @@ mod tests { Ok(()) } + #[test] + fn opcode_dup() -> Result<(), RuntimeError> { + let wordlist = wl_for(vec![ + vec![OpCode::Num(1), OpCode::Dup], + ]); + let mut vm = VM::new(wordlist); + vm.run()?; + assert_eq!(vm.stack.0, vec![1, 1]); + Ok(()) + } + #[test] fn opcode_swap() -> Result<(), RuntimeError> { let wordlist = wl_for(vec![ -- cgit v1.3