about summary refs log tree commit diff
path: root/users
diff options
context:
space:
mode:
Diffstat (limited to 'users')
-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 95b111dba824..1ab42c705ab4 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 057fa7697719..a4a4871a2cc2 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 d9a752b38788..d02f021ff0fd 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 88ff8a695138..dcd238a7cd39 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 74c3e338fce4..b7a394afbe3e 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!(