From 53c7dfb1cee5da187545b0b115ed0d48e57d61f7 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Sun, 30 Jun 2019 23:17:49 -0500 Subject: [PATCH] DEV: Conditional Jumps --- src/build/opcode/mod.rs | 22 +++++++++++++---- src/build/opcode/test.rs | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/build/opcode/mod.rs b/src/build/opcode/mod.rs index 6b19890..0f70f92 100644 --- a/src/build/opcode/mod.rs +++ b/src/build/opcode/mod.rs @@ -79,6 +79,7 @@ pub enum Op { // Control Flow Bang, Jump(usize), + JumpIfTrue(usize), Noop, // Pending Computation InitThunk(usize), @@ -139,12 +140,14 @@ impl VM { Op::Bang => return Err(Error {}), Op::InitThunk(jp) => self.op_thunk(idx, *jp)?, Op::Noop => { + self.stack.last(); // Do nothing } Op::Return => { // TODO(jwall): This means we return back to the start of the frame. } - Op::Jump(jp) => self.ops.jump(self.ops.ptr.map(|v| v + jp).unwrap_or(*jp))?, + Op::Jump(jp) => self.op_jump(*jp)?, + Op::JumpIfTrue(jp) => self.op_jump_if_true(*jp)?, Op::Pop => { self.pop()?; } @@ -152,12 +155,23 @@ impl VM { } Ok(()) } + fn op_jump(&mut self, jp: usize) -> Result<(), Error> { + self.ops.jump(self.ops.ptr.map(|v| v + jp).unwrap_or(jp))?; + Ok(()) + } + + fn op_jump_if_true(&mut self, jp: usize) -> Result<(), Error> { + if let P(Bool(cond)) = self.pop()? { + if cond { + self.op_jump(jp)?; + } + } + Ok(()) + } fn op_thunk(&mut self, idx: usize, jp: usize) -> Result<(), Error> { self.push(Value::T(idx))?; - self.ops.jump(self.ops.ptr.map(|v| v + jp).unwrap_or(jp))?; - // TODO(jwall): Skip over the rest until we reach the return? - Ok(()) + self.op_jump(jp) } fn op_equal(&mut self) -> Result<(), Error> { diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index 8dea34f..8d12fe2 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -289,3 +289,55 @@ fn test_equality_ops() { assert_eq!(vm.pop().unwrap(), case.1); } } + +#[test] +fn test_conditional_jump_ops() { + let mut cases = vec![ + ( + vec![ + Val(Bool(false)), + JumpIfTrue(2), + Val(Bool(true)), + JumpIfTrue(2), + Val(Int(1)), + Jump(1), + Val(Int(2)), + Noop, + ], + P(Int(2)), + ), + ( + vec![ + Val(Bool(true)), + JumpIfTrue(2), + Val(Bool(false)), + JumpIfTrue(2), + Val(Int(1)), + Jump(1), + Val(Int(2)), + Noop, + ], + P(Int(1)), + ), + ( + vec![ + Val(Int(1)), + Val(Int(1)), + Equal, + JumpIfTrue(2), + Val(Bool(false)), + JumpIfTrue(2), + Val(Int(1)), + Jump(1), + Val(Int(2)), + Noop, + ], + P(Int(1)), + ), + ]; + for case in cases.drain(0..) { + let mut vm = VM::new(case.0); + vm.run().unwrap(); + assert_eq!(vm.pop().unwrap(), case.1); + } +}