about summary refs log tree commit diff
path: root/users/tazjin/rlox
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-02-28T13·28+0200
committertazjin <mail@tazj.in>2021-02-28T14·36+0000
commit2d9456d2474116d9a42213f692b13821eb28de81 (patch)
tree38dfd4cda140ad63f0f00185d4f80605905f49ad /users/tazjin/rlox
parent47ffa8071152bcafb4b6ff87a3142bf12dbce12b (diff)
feat(tazjin/rlox): Implement unary negation operator r/2253
Change-Id: I9a5bd3581d4ed05371651697ec496341eb7971ae
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2572
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox')
-rw-r--r--users/tazjin/rlox/src/bytecode/compiler.rs5
-rw-r--r--users/tazjin/rlox/src/bytecode/opcode.rs3
-rw-r--r--users/tazjin/rlox/src/bytecode/tests.rs9
-rw-r--r--users/tazjin/rlox/src/bytecode/value.rs10
-rw-r--r--users/tazjin/rlox/src/bytecode/vm.rs5
5 files changed, 32 insertions, 0 deletions
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs
index 95b111dba8..1ab42c705a 100644
--- a/users/tazjin/rlox/src/bytecode/compiler.rs
+++ b/users/tazjin/rlox/src/bytecode/compiler.rs
@@ -116,6 +116,10 @@ fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> {
             ParseRule::new(Some(Compiler::literal), None, Precedence::None)
         }
 
+        TokenKind::Bang => {
+            ParseRule::new(Some(Compiler::unary), None, Precedence::None)
+        }
+
         _ => ParseRule::new(None, None, Precedence::None),
     }
 }
@@ -168,6 +172,7 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
 
         // Emit operator instruction
         match kind {
+            TokenKind::Bang => self.emit_op(OpCode::OpNot),
             TokenKind::Minus => self.emit_op(OpCode::OpNegate),
             _ => unreachable!("only called for unary operator tokens"),
         }
diff --git a/users/tazjin/rlox/src/bytecode/opcode.rs b/users/tazjin/rlox/src/bytecode/opcode.rs
index 057fa76977..a4a4871a2c 100644
--- a/users/tazjin/rlox/src/bytecode/opcode.rs
+++ b/users/tazjin/rlox/src/bytecode/opcode.rs
@@ -11,6 +11,9 @@ pub enum OpCode {
     /// Return from the current function.
     OpReturn,
 
+    // Boolean operators
+    OpNot,
+
     /// Unary negation
     OpNegate,
 
diff --git a/users/tazjin/rlox/src/bytecode/tests.rs b/users/tazjin/rlox/src/bytecode/tests.rs
index d9a752b387..d02f021ff0 100644
--- a/users/tazjin/rlox/src/bytecode/tests.rs
+++ b/users/tazjin/rlox/src/bytecode/tests.rs
@@ -58,3 +58,12 @@ fn trivial_literals() {
     expect("false", Value::Bool(false));
     expect("nil", Value::Nil);
 }
+
+#[test]
+fn negation() {
+    expect("!true", Value::Bool(false));
+    expect("!false", Value::Bool(true));
+    expect("!nil", Value::Bool(true));
+    expect("!13.5", Value::Bool(false));
+    expect("!-42", Value::Bool(false));
+}
diff --git a/users/tazjin/rlox/src/bytecode/value.rs b/users/tazjin/rlox/src/bytecode/value.rs
index 88ff8a6951..dcd238a7cd 100644
--- a/users/tazjin/rlox/src/bytecode/value.rs
+++ b/users/tazjin/rlox/src/bytecode/value.rs
@@ -4,3 +4,13 @@ pub enum Value {
     Bool(bool),
     Number(f64),
 }
+
+impl Value {
+    pub fn is_falsey(&self) -> bool {
+        match self {
+            Value::Nil => true,
+            Value::Bool(false) => true,
+            _ => false,
+        }
+    }
+}
diff --git a/users/tazjin/rlox/src/bytecode/vm.rs b/users/tazjin/rlox/src/bytecode/vm.rs
index 74c3e338fc..b7a394afbe 100644
--- a/users/tazjin/rlox/src/bytecode/vm.rs
+++ b/users/tazjin/rlox/src/bytecode/vm.rs
@@ -76,6 +76,11 @@ impl VM {
                 OpCode::OpTrue => self.push(Value::Bool(true)),
                 OpCode::OpFalse => self.push(Value::Bool(false)),
 
+                OpCode::OpNot => {
+                    let v = self.pop();
+                    self.push(Value::Bool(v.is_falsey()));
+                }
+
                 OpCode::OpNegate => {
                     let v = self.pop();
                     with_type!(