From c58fe2093e2a2870fc76ea55aa2de8e5aa6dab7d Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Sun, 28 Feb 2021 15:57:08 +0200 Subject: [PATCH] feat(tazjin/rlox): Implement equality operator Change-Id: I5587a11646e228c5af4dc7ca6da026bb4a2592a6 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2574 Reviewed-by: tazjin Tested-by: BuildkiteCI --- users/tazjin/rlox/src/bytecode/compiler.rs | 16 +++++++++++ users/tazjin/rlox/src/bytecode/opcode.rs | 3 ++- users/tazjin/rlox/src/bytecode/tests.rs | 31 ++++++++++++++++++---- users/tazjin/rlox/src/bytecode/vm.rs | 6 +++++ 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 1ab42c705..8eef40f0e 100644 --- a/users/tazjin/rlox/src/bytecode/compiler.rs +++ b/users/tazjin/rlox/src/bytecode/compiler.rs @@ -120,6 +120,14 @@ fn rule_for>(token: &TokenKind) -> ParseRule { 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> Compiler { 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 a4a4871a2..e50fdfed9 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 d02f021ff..500779301 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 acfb522a9..0b24dc46c 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!(