diff options
| author | Brian Cully <bjc@spork.org> | 2025-08-25 10:24:00 -0400 |
|---|---|---|
| committer | Brian Cully <bjc@spork.org> | 2025-08-25 10:24:00 -0400 |
| commit | 275ee10822d8d5108e34166dbaf486ddb5a56a59 (patch) | |
| tree | 26473e7154bbf03ed63ff0699f274a8db05a64c6 /src/forth/vm.rs | |
| parent | b059c2364d54c34d85ce791546aeeefd0a3c43b6 (diff) | |
| download | automathon-275ee10822d8d5108e34166dbaf486ddb5a56a59.tar.gz automathon-275ee10822d8d5108e34166dbaf486ddb5a56a59.zip | |
add rot and swap
Diffstat (limited to 'src/forth/vm.rs')
| -rw-r--r-- | src/forth/vm.rs | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/src/forth/vm.rs b/src/forth/vm.rs index e4c01f2..7ce9c03 100644 --- a/src/forth/vm.rs +++ b/src/forth/vm.rs @@ -18,6 +18,8 @@ pub enum OpCode { Div, Dup, Drop, + Swap, + Rot, EQ, GT, GTE, @@ -177,6 +179,20 @@ impl VM { 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); + }, + 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); + }, OpCode::EQ => { let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?; @@ -257,6 +273,12 @@ mod tests { use super::*; use super::OpCode; + fn wl_for(v: Vec<Vec<OpCode>>) -> WordList { + WordList(v.into_iter() + .map(|x| ByteCode(x)) + .collect()) + } + #[test] fn simple_ticks() -> Result<(), RuntimeError> { let mut wordlist = WordList(vec![]); @@ -532,11 +554,12 @@ mod tests { #[test] fn tail_if_else_then_false() -> Result<(), RuntimeError> { - let mut wordlist = WordList(vec![]); - wordlist.0.push(ByteCode(vec![OpCode::Call(1), OpCode::Num(-2)])); - wordlist.0.push(ByteCode(vec![OpCode::Num(0), 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 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()?; @@ -554,4 +577,26 @@ mod tests { Ok(()) } + + #[test] + fn opcode_swap() -> Result<(), RuntimeError> { + let wordlist = wl_for(vec![ + vec![OpCode::Num(1), OpCode::Num(2), OpCode::Swap], + ]); + let mut vm = VM::new(wordlist); + vm.run()?; + assert_eq!(vm.stack.0, vec![2, 1]); + Ok(()) + } + + #[test] + fn opcode_rot() -> Result<(), RuntimeError> { + 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()?; + assert_eq!(vm.stack.0, vec![2, 3, 1]); + Ok(()) + } } |
