diff --git a/src/bytecode.rs b/src/bytecode.rs index b6f100a..bf39e11 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -67,8 +67,8 @@ pub enum Instr { /// Println the value on top of the stack Print, - /// If the current stack value is true, skip `usize` instructions. When jumping backwards - JumpFalse(isize), - /// Same as `JumpCond`, but unconditional + /// If the current stack value is false, skip `usize` instructions. + JmpFalse(isize), + /// Same as `JmpFalse`, but unconditional Jmp(isize), } diff --git a/src/compile.rs b/src/compile.rs index 2273d23..9a0166e 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -163,7 +163,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> { self.compile_expr(&if_stmt.cond)?; // the offset will be fixed later - let jmp_idx = self.push_instr(Instr::JumpFalse(0), StackChange::Shrink, if_stmt.span); + let jmp_idx = self.push_instr(Instr::JmpFalse(0), StackChange::Shrink, if_stmt.span); self.compile_block(&if_stmt.body)?; @@ -172,7 +172,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> { let jmp_pos = self.forward_jmp_offset(jmp_idx as isize); - self.change_instr(jmp_idx, Instr::JumpFalse(jmp_pos)); + self.change_instr(jmp_idx, Instr::JmpFalse(jmp_pos)); match else_part { ElsePart::Else(block, _) => { @@ -188,7 +188,7 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> { self.change_instr(else_skip_jmp_idx, Instr::Jmp(jmp_pos)); } else { let jmp_pos = self.forward_jmp_offset(jmp_idx as isize); - self.change_instr(jmp_idx, Instr::JumpFalse(jmp_pos)); + self.change_instr(jmp_idx, Instr::JmpFalse(jmp_pos)); } Ok(()) @@ -222,17 +222,18 @@ impl<'ast, 'bc, 'gc> Compiler<'ast, 'bc, 'gc> { let cond_index = self.code_len(); self.compile_expr(&while_stmt.cond)?; - let cond_jmp_index = self.push_instr(Instr::Jmp(0), StackChange::Shrink, while_stmt.span); + let jmp_false_idx = + self.push_instr(Instr::JmpFalse(0), StackChange::Shrink, while_stmt.span); self.compile_block(&while_stmt.body)?; - let index_of_jmp = self.code_len(); - let jmp_offset = -(index_of_jmp - (cond_index as isize) + 1); + let jmp_offset = self.back_jmp_offset(cond_index); self.push_instr(Instr::Jmp(jmp_offset), StackChange::None, while_stmt.span); - let skip_amount = self.back_jmp_offset(cond_jmp_index as isize); - self.change_instr(cond_jmp_index, Instr::Jmp(skip_amount)); - todo!() + let jmp_offset = self.forward_jmp_offset(jmp_false_idx as isize); + self.change_instr(jmp_false_idx, Instr::JmpFalse(jmp_offset)); + + Ok(()) } fn compile_break(&mut self, _: Span) -> CResult { diff --git a/src/vm.rs b/src/vm.rs index b19a21e..b7abf83 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -151,7 +151,7 @@ impl<'bc> Vm<'bc, '_> { let val = self.stack.pop().unwrap(); writeln!(self.stdout, "{}", val).map_err(|_| "failed to write to stdout")?; } - Instr::JumpFalse(pos) => { + Instr::JmpFalse(pos) => { let val = self.stack.pop().unwrap(); match val { Value::Bool(false) => self.pc = (self.pc as isize + pos) as usize, diff --git a/test.dil b/test.dil index 314fd76..6166ab9 100644 --- a/test.dil +++ b/test.dil @@ -1,3 +1,8 @@ -if 54 > 53 { - print "hallo conny"; -} \ No newline at end of file +let i = 0; + +while i < 100 { + print i; + i = i + 1; +} + +print "done"; \ No newline at end of file diff --git a/tests/control_flow.rs b/tests/control_flow.rs index f4101b7..ba3dbdd 100644 --- a/tests/control_flow.rs +++ b/tests/control_flow.rs @@ -78,3 +78,45 @@ if string == "no" { } "# ); + +run_test!( + while_single_loop, + r#" +let x = true; +while x { + x = false; + print "iter"; +} +print "done"; +"# +); + +run_test!( + while_count_to_100, + r#" +let i = 0; + +while i < 100 { + print i; + i = i + 1; +} + +print "done"; + "# +); + +run_test!( + while_run_never, + r#" +let not_run = true; + +while false { + print "WRONG"; + not_run = false; +} + +if not_run { + print "good."; +} +"# +); diff --git a/tests/snapshots/control_flow__while_count_to_100.snap b/tests/snapshots/control_flow__while_count_to_100.snap new file mode 100644 index 0000000..3d8ab3d --- /dev/null +++ b/tests/snapshots/control_flow__while_count_to_100.snap @@ -0,0 +1,7 @@ +--- +source: tests/control_flow.rs +assertion_line: 94 +expression: output + +--- +"0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n52\n53\n54\n55\n56\n57\n58\n59\n60\n61\n62\n63\n64\n65\n66\n67\n68\n69\n70\n71\n72\n73\n74\n75\n76\n77\n78\n79\n80\n81\n82\n83\n84\n85\n86\n87\n88\n89\n90\n91\n92\n93\n94\n95\n96\n97\n98\n99\ndone\n" diff --git a/tests/snapshots/control_flow__while_run_never.snap b/tests/snapshots/control_flow__while_run_never.snap new file mode 100644 index 0000000..63030f7 --- /dev/null +++ b/tests/snapshots/control_flow__while_run_never.snap @@ -0,0 +1,7 @@ +--- +source: tests/control_flow.rs +assertion_line: 108 +expression: output + +--- +"good.\n" diff --git a/tests/snapshots/control_flow__while_single_loop.snap b/tests/snapshots/control_flow__while_single_loop.snap new file mode 100644 index 0000000..5bb6ece --- /dev/null +++ b/tests/snapshots/control_flow__while_single_loop.snap @@ -0,0 +1,7 @@ +--- +source: tests/control_flow.rs +assertion_line: 82 +expression: output + +--- +"iter\ndone\n"