about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--users/tazjin/rlox/src/bytecode/compiler.rs16
-rw-r--r--users/tazjin/rlox/src/bytecode/opcode.rs3
-rw-r--r--users/tazjin/rlox/src/bytecode/tests.rs31
-rw-r--r--users/tazjin/rlox/src/bytecode/vm.rs6
4 files changed, 50 insertions, 6 deletions
diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs
index 1ab42c705ab4..8eef40f0e669 100644
--- a/users/tazjin/rlox/src/bytecode/compiler.rs
+++ b/users/tazjin/rlox/src/bytecode/compiler.rs
@@ -120,6 +120,14 @@ fn rule_for<T: Iterator<Item = Token>>(token: &TokenKind) -> ParseRule<T> {
             ParseRule::new(Some(Compiler::unary), None, Precedence::None)
         }
 
+        TokenKind::BangEqual => {
+            ParseRule::new(None, Some(Compiler::binary), Precedence::Equality)
+        }
+
+        TokenKind::EqualEqual => {
+            ParseRule::new(None, Some(Compiler::binary), Precedence::Equality)
+        }
+
         _ => ParseRule::new(None, None, Precedence::None),
     }
 }
@@ -194,6 +202,14 @@ impl<T: Iterator<Item = Token>> Compiler<T> {
             TokenKind::Plus => self.emit_op(OpCode::OpAdd),
             TokenKind::Star => self.emit_op(OpCode::OpMultiply),
             TokenKind::Slash => self.emit_op(OpCode::OpDivide),
+
+            TokenKind::BangEqual => {
+                self.emit_op(OpCode::OpEqual);
+                self.emit_op(OpCode::OpNot);
+            }
+
+            TokenKind::EqualEqual => self.emit_op(OpCode::OpEqual),
+
             _ => unreachable!("only called for binary operator tokens"),
         }
 
diff --git a/users/tazjin/rlox/src/bytecode/opcode.rs b/users/tazjin/rlox/src/bytecode/opcode.rs
index a4a4871a2cc2..e50fdfed9338 100644
--- a/users/tazjin/rlox/src/bytecode/opcode.rs
+++ b/users/tazjin/rlox/src/bytecode/opcode.rs
@@ -11,8 +11,9 @@ pub enum OpCode {
     /// Return from the current function.
     OpReturn,
 
-    // Boolean operators
+    // Boolean & comparison operators
     OpNot,
+    OpEqual,
 
     /// Unary negation
     OpNegate,
diff --git a/users/tazjin/rlox/src/bytecode/tests.rs b/users/tazjin/rlox/src/bytecode/tests.rs
index d02f021ff0fd..500779301b04 100644
--- a/users/tazjin/rlox/src/bytecode/tests.rs
+++ b/users/tazjin/rlox/src/bytecode/tests.rs
@@ -14,6 +14,10 @@ fn expect_num(code: &str, value: f64) {
     expect(code, Value::Number(value))
 }
 
+fn expect_bool(code: &str, value: bool) {
+    expect(code, Value::Bool(value))
+}
+
 #[test]
 fn numbers() {
     expect_num("1", 1.0);
@@ -61,9 +65,26 @@ fn trivial_literals() {
 
 #[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));
+    expect_bool("!true", false);
+    expect_bool("!false", true);
+    expect_bool("!nil", true);
+    expect_bool("!13.5", false);
+    expect_bool("!-42", false);
+}
+
+#[test]
+fn equality() {
+    expect_bool("42 == 42", true);
+    expect_bool("42 != 42", false);
+    expect_bool("42 == 42.0", true);
+
+    expect_bool("true == true", true);
+    expect_bool("true == false", false);
+    expect_bool("true == !false", true);
+    expect_bool("true != true", false);
+    expect_bool("true != false", true);
+
+    expect_bool("42 == false", false);
+    expect_bool("42 == true", false);
+    expect_bool("!42 == !true", true);
 }
diff --git a/users/tazjin/rlox/src/bytecode/vm.rs b/users/tazjin/rlox/src/bytecode/vm.rs
index acfb522a9c47..0b24dc46cdb9 100644
--- a/users/tazjin/rlox/src/bytecode/vm.rs
+++ b/users/tazjin/rlox/src/bytecode/vm.rs
@@ -85,6 +85,12 @@ impl VM {
                     self.push(Value::Bool(v.is_falsey()));
                 }
 
+                OpCode::OpEqual => {
+                    let b = self.pop();
+                    let a = self.pop();
+                    self.push(Value::Bool(a == b));
+                }
+
                 OpCode::OpNegate => {
                     let v = self.pop();
                     with_type!(