summaryrefslogtreecommitdiffstats
path: root/src/forth
diff options
context:
space:
mode:
Diffstat (limited to 'src/forth')
-rw-r--r--src/forth/compiler.rs6
-rw-r--r--src/forth/vm.rs34
2 files changed, 26 insertions, 14 deletions
diff --git a/src/forth/compiler.rs b/src/forth/compiler.rs
index f593806..e8aaa7f 100644
--- a/src/forth/compiler.rs
+++ b/src/forth/compiler.rs
@@ -133,7 +133,7 @@ impl<'a> Compiler<'a> {
self.bc_mut().0.pop();
self.bc_mut().0.push(OpCode::TIf(t, f));
// technically only needed if ‘f’ is None, but whatever.
- self.bc_push(OpCode::Ret, anno);
+ //self.bc_push(OpCode::Ret, anno);
},
_ => self.bc_push(OpCode::Ret, anno),
}
@@ -352,7 +352,7 @@ mod tests {
let main = &comp.wordlist.0[0];
assert_eq!(main, vec![OpCode::Call(1)]);
let t = &comp.wordlist.0[1];
- assert_eq!(t, vec![OpCode::TIf(2, None), OpCode::Ret]);
+ assert_eq!(t, vec![OpCode::TIf(2, None)]);
let tr = &comp.wordlist.0[2];
assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]);
}
@@ -365,7 +365,7 @@ mod tests {
let main = &comp.wordlist.0[0];
assert_eq!(main, vec![OpCode::Call(1)]);
let t = &comp.wordlist.0[1];
- assert_eq!(t, vec![OpCode::TIf(2, Some(3)), OpCode::Ret]);
+ assert_eq!(t, vec![OpCode::TIf(2, Some(3))]);
let tr = &comp.wordlist.0[2];
assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]);
let fl = &comp.wordlist.0[3];
diff --git a/src/forth/vm.rs b/src/forth/vm.rs
index 7ce9c03..9c7f203 100644
--- a/src/forth/vm.rs
+++ b/src/forth/vm.rs
@@ -254,6 +254,8 @@ impl VM {
} else if let Some(false_clause) = false_clause {
self.jmp(false_clause);
return Ok(true)
+ } else {
+ self.ip = self.callstack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
}
},
}
@@ -501,24 +503,21 @@ mod tests {
#[test]
fn tail_if_then_false() -> Result<(), RuntimeError> {
- let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Call(1), OpCode::Num(0)]));
- wordlist.0.push(ByteCode(vec![OpCode::Num(0), OpCode::TIf(2, None), OpCode::Ret]));
- wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret]));
+ let wordlist = wl_for(vec![
+ vec![OpCode::Call(1), OpCode::Num(0)],
+ vec![OpCode::Num(0), OpCode::TIf(2, None)],
+ vec![OpCode::Num(1), OpCode::Ret],
+ ]);
let mut vm = VM::new(wordlist);
vm.tick()?;
assert_eq!(vm.stack.0.len(), 0, "call(1) stack len");
vm.tick()?;
- assert_eq!(vm.stack.0.len(), 1, "push 0 stack len");
- assert_eq!(vm.stack.0[0], 0, "push 0 val");
- vm.tick()?;
- assert_eq!(vm.stack.0.len(), 0, "tif stack len");
+ assert_eq!(vm.stack.0, vec![0], "push 0 stack");
vm.tick()?;
- assert_eq!(vm.stack.0.len(), 0, "ret stack len");
+ assert_eq!(vm.stack.0, vec![], "tif stack");
vm.tick()?;
- assert_eq!(vm.stack.0.len(), 1, "push 0 stack len");
- assert_eq!(vm.stack.0[0], 0, "push 0 val");
+ assert_eq!(vm.stack.0, vec![0], "push 0 stack");
Ok(())
}
@@ -599,4 +598,17 @@ mod tests {
assert_eq!(vm.stack.0, vec![2, 3, 1]);
Ok(())
}
+
+ #[test]
+ fn tif_no_ret() -> Result<(), RuntimeError> {
+ let wordlist = wl_for(vec![
+ vec![OpCode::Call(1)],
+ vec![OpCode::Num(0), OpCode::TIf(2, None), OpCode::Num(3)],
+ vec![OpCode::Num(-2)],
+ ]);
+ let mut vm = VM::new(wordlist);
+ vm.run()?;
+ assert_eq!(vm.stack.0, vec![]);
+ Ok(())
+ }
}