diff options
| author | Brian Cully <bjc@spork.org> | 2025-08-25 14:46:15 -0400 |
|---|---|---|
| committer | Brian Cully <bjc@spork.org> | 2025-08-25 14:50:18 -0400 |
| commit | 091b7cc7d748624b455be2a4579a6870e94cac09 (patch) | |
| tree | bfb903f02ce141b8427cd6f03d168cae0bd98453 | |
| parent | 37c0a0b5e4d3939656cac8d103b5a22963fbc9dd (diff) | |
| download | automathon-091b7cc7d748624b455be2a4579a6870e94cac09.tar.gz automathon-091b7cc7d748624b455be2a4579a6870e94cac09.zip | |
do in-place memory manipulation for rot/dup/swap
| -rw-r--r-- | src/forth/vm.rs | 44 |
1 files changed, 31 insertions, 13 deletions
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)?; @@ -578,6 +585,17 @@ mod tests { } #[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![ vec![OpCode::Num(1), OpCode::Num(2), OpCode::Swap], |
