From 8275403e955e8998c61ecaa07d70949e3bd53a66 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Mon, 25 Aug 2025 12:25:30 -0400 Subject: tail-position if no longer needs ret --- src/forth/compiler.rs | 6 +++--- src/forth/vm.rs | 34 +++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'src') 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(()) + } } -- cgit v1.3