about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-10-21T09·18+0200
committertazjin <mail@tazj.in>2021-10-22T09·42+0000
commit33e71ba97fd3df598daa217ec36a48334136dcfc (patch)
tree1c792910f3c3d65517a592dce9eb8d8d2b199f2d
parent670662a360447509940dac417195cf419d7f42c5 (diff)
feat(tazjin/rlox): Implement else clauses r/2987
Change-Id: I0bc2333c0b4dd3e2e584a90d0d15b28c48130f03
Reviewed-on: https://cl.tvl.fyi/c/depot/+/3740
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
-rw-r--r--users/tazjin/rlox/examples/if.lox4
-rw-r--r--users/tazjin/rlox/src/bytecode/compiler.rs14
-rw-r--r--users/tazjin/rlox/src/bytecode/opcode.rs1
-rw-r--r--users/tazjin/rlox/src/bytecode/vm.rs4
4 files changed, 22 insertions, 1 deletions
diff --git a/users/tazjin/rlox/examples/if.lox b/users/tazjin/rlox/examples/if.lox
index b59f00b201..5f335c0e8b 100644
--- a/users/tazjin/rlox/examples/if.lox
+++ b/users/tazjin/rlox/examples/if.lox
@@ -1,5 +1,7 @@
-if (true) {
+if (false) {
   print "yes";
+} else {
+  print "no";
 }
 
 print "afterwards";
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs
index 1b87e94a55..3e8a80653f 100644
--- a/users/tazjin/rlox/src/bytecode/compiler.rs
+++ b/users/tazjin/rlox/src/bytecode/compiler.rs
@@ -343,8 +343,17 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
         );
 
         let then_jump = self.emit_op(OpCode::OpJumpPlaceholder(false));
+        self.emit_op(OpCode::OpPop);
         self.statement()?;
+        let else_jump = self.emit_op(OpCode::OpJumpPlaceholder(true));
         self.patch_jump(then_jump);
+        self.emit_op(OpCode::OpPop);
+
+        if self.match_token(&TokenKind::Else) {
+            self.statement()?;
+        }
+
+        self.patch_jump(else_jump);
 
         Ok(())
     }
@@ -620,6 +629,11 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
     fn patch_jump(&mut self, idx: CodeIdx) {
         let offset = CodeOffset(self.chunk.code.len() - idx.0 - 1);
 
+        if let OpCode::OpJumpPlaceholder(true) = self.chunk.code[idx.0] {
+            self.chunk.code[idx.0] = OpCode::OpJump(offset);
+            return;
+        }
+
         if let OpCode::OpJumpPlaceholder(false) = self.chunk.code[idx.0] {
             self.chunk.code[idx.0] = OpCode::OpJumpIfFalse(offset);
             return;
diff --git a/users/tazjin/rlox/src/bytecode/opcode.rs b/users/tazjin/rlox/src/bytecode/opcode.rs
index accc6b3bac..8a106f9691 100644
--- a/users/tazjin/rlox/src/bytecode/opcode.rs
+++ b/users/tazjin/rlox/src/bytecode/opcode.rs
@@ -51,5 +51,6 @@ pub enum OpCode {
 
     // Control flow
     OpJumpPlaceholder(bool),
+    OpJump(CodeOffset),
     OpJumpIfFalse(CodeOffset),
 }
diff --git a/users/tazjin/rlox/src/bytecode/vm.rs b/users/tazjin/rlox/src/bytecode/vm.rs
index e0db97abe5..d287ec7cb8 100644
--- a/users/tazjin/rlox/src/bytecode/vm.rs
+++ b/users/tazjin/rlox/src/bytecode/vm.rs
@@ -213,6 +213,10 @@ impl VM {
                     panic!("unpatched jump detected - this is a fatal compiler error!");
                 }
 
+                OpCode::OpJump(offset) => {
+                    self.ip += offset.0;
+                }
+
                 OpCode::OpJumpIfFalse(offset) => {
                     if self
                         .stack