summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/forth/compiler.rs16
-rw-r--r--src/forth/vm.rs55
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(())
+ }
}