diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/forth/compiler.rs | 16 | ||||
| -rw-r--r-- | src/forth/vm.rs | 55 |
2 files changed, 66 insertions, 5 deletions
diff --git a/src/forth/compiler.rs b/src/forth/compiler.rs index 97e94a9..89964e1 100644 --- a/src/forth/compiler.rs +++ b/src/forth/compiler.rs @@ -199,6 +199,8 @@ impl<'a> Compiler<'a> { "/" => self.bc_push(OpCode::Div, anno), "dup" => self.bc_push(OpCode::Dup, anno), "drop" => self.bc_push(OpCode::Drop, anno), + "rot" => self.bc_push(OpCode::Rot, anno), + "swap" => self.bc_push(OpCode::Swap, anno), "=" => self.bc_push(OpCode::EQ, anno), ">" => self.bc_push(OpCode::GT, anno), ">=" => self.bc_push(OpCode::GTE, anno), @@ -258,6 +260,20 @@ mod tests { } #[test] + fn rot_opcode() { + let comp = compiler_for("rot\n"); + let main = &comp.wordlist.0[0]; + assert_eq!(main, vec![OpCode::Rot]); + } + + #[test] + fn swap_opcode() { + let comp = compiler_for("swap\n"); + let main = &comp.wordlist.0[0]; + assert_eq!(main, vec![OpCode::Swap]); + } + + #[test] fn def_word() { let comp = compiler_for(": add2 2 + ; 3 add2\n"); let main = &comp.wordlist.0[0]; 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(()) + } } |
