From f389f7e42299c883964a70405713788fbb851619 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 9 Aug 2024 07:15:09 -0400 Subject: [PATCH] Implement equality operation --- dust-lang/src/abstract_tree.rs | 2 ++ dust-lang/src/lex.rs | 25 ++++++++++++++++++++-- dust-lang/src/parse.rs | 38 ++++++++++++++++++++++++++++++++++ dust-lang/src/token.rs | 8 +++++++ dust-lang/src/vm.rs | 21 +++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs index b095ac8..78042d1 100644 --- a/dust-lang/src/abstract_tree.rs +++ b/dust-lang/src/abstract_tree.rs @@ -238,6 +238,7 @@ pub enum BinaryOperator { Subtract, // Comparison + Equal, Greater, GreaterOrEqual, Less, @@ -254,6 +255,7 @@ impl Display for BinaryOperator { BinaryOperator::Add => write!(f, "+"), BinaryOperator::And => write!(f, "&&"), BinaryOperator::Divide => write!(f, "/"), + BinaryOperator::Equal => write!(f, "=="), BinaryOperator::Greater => write!(f, ">"), BinaryOperator::GreaterOrEqual => write!(f, ">="), BinaryOperator::Less => write!(f, "<"), diff --git a/dust-lang/src/lex.rs b/dust-lang/src/lex.rs index 089b47e..be01b29 100644 --- a/dust-lang/src/lex.rs +++ b/dust-lang/src/lex.rs @@ -143,9 +143,15 @@ impl Lexer { (Token::RightParenthesis, (self.position - 1, self.position)) } '=' => { - self.position += 1; + if let Some('=') = self.peek_second_char(source) { + self.position += 2; - (Token::Equal, (self.position - 1, self.position)) + (Token::DoubleEqual, (self.position - 2, self.position)) + } else { + self.position += 1; + + (Token::Equal, (self.position - 1, self.position)) + } } '[' => { self.position += 1; @@ -435,6 +441,21 @@ impl From for LexError { mod tests { use super::*; + #[test] + fn equal() { + let input = "42 == 42"; + + assert_eq!( + lex(input), + Ok(vec![ + (Token::Integer(42), (0, 2)), + (Token::DoubleEqual, (3, 5)), + (Token::Integer(42), (6, 8)), + (Token::Eof, (8, 8)), + ]) + ) + } + #[test] fn modulo() { let input = "42 % 2"; diff --git a/dust-lang/src/parse.rs b/dust-lang/src/parse.rs index 50e66e4..f0a6995 100644 --- a/dust-lang/src/parse.rs +++ b/dust-lang/src/parse.rs @@ -319,6 +319,23 @@ impl<'src> Parser<'src> { (left_start, right_end), )); } + (Token::DoubleEqual, _) => { + let operator = Node::new(BinaryOperator::Equal, self.current.1); + + self.next_token()?; + + let right_node = self.parse_node(self.current_precedence())?; + let right_end = right_node.position.1; + + return Ok(Node::new( + Statement::BinaryOperation { + left: Box::new(left_node), + operator, + right: Box::new(right_node), + }, + (left_start, right_end), + )); + } _ => {} } } @@ -539,6 +556,7 @@ impl<'src> Parser<'src> { fn current_precedence(&self) -> u8 { match self.current.0 { + Token::DoubleEqual => 6, Token::Greater | Token::GreaterEqual | Token::Less | Token::LessEqual => 5, Token::Dot => 4, Token::Percent => 3, @@ -613,6 +631,26 @@ mod tests { use super::*; + #[test] + fn equal() { + let input = "42 == 42"; + + assert_eq!( + parse(input), + Ok(AbstractSyntaxTree { + nodes: [Node::new( + Statement::BinaryOperation { + left: Box::new(Node::new(Statement::Constant(Value::integer(42)), (0, 2))), + operator: Node::new(BinaryOperator::Equal, (3, 5)), + right: Box::new(Node::new(Statement::Constant(Value::integer(42)), (6, 8))) + }, + (0, 8) + )] + .into() + }) + ); + } + #[test] fn modulo() { let input = "42 % 2"; diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index eb1da3f..6d60855 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -27,6 +27,7 @@ pub enum Token<'src> { Comma, Dot, DoubleAmpersand, + DoubleEqual, DoublePipe, Equal, Greater, @@ -53,6 +54,7 @@ impl<'src> Token<'src> { Token::Comma => TokenOwned::Comma, Token::Dot => TokenOwned::Dot, Token::DoubleAmpersand => TokenOwned::DoubleAmpersand, + Token::DoubleEqual => TokenOwned::DoubleEqual, Token::DoublePipe => TokenOwned::DoublePipe, Token::Eof => TokenOwned::Eof, Token::Equal => TokenOwned::Equal, @@ -89,6 +91,7 @@ impl<'src> Token<'src> { Token::Comma => ",", Token::Dot => ".", Token::DoubleAmpersand => "&&", + Token::DoubleEqual => "==", Token::DoublePipe => "||", Token::Eof => "EOF", Token::Equal => "=", @@ -136,6 +139,9 @@ impl<'src> PartialEq for Token<'src> { (Token::Boolean(left), Token::Boolean(right)) => left == right, (Token::Comma, Token::Comma) => true, (Token::Dot, Token::Dot) => true, + (Token::DoubleAmpersand, Token::DoubleAmpersand) => true, + (Token::DoubleEqual, Token::DoubleEqual) => true, + (Token::DoublePipe, Token::DoublePipe) => true, (Token::Eof, Token::Eof) => true, (Token::Equal, Token::Equal) => true, (Token::Greater, Token::Greater) => true, @@ -192,6 +198,7 @@ pub enum TokenOwned { Comma, Dot, DoubleAmpersand, + DoubleEqual, DoublePipe, Equal, Greater, @@ -218,6 +225,7 @@ impl Display for TokenOwned { TokenOwned::Comma => Token::Comma.fmt(f), TokenOwned::Dot => Token::Dot.fmt(f), TokenOwned::DoubleAmpersand => Token::DoubleAmpersand.fmt(f), + TokenOwned::DoubleEqual => Token::DoubleEqual.fmt(f), TokenOwned::DoublePipe => Token::DoublePipe.fmt(f), TokenOwned::Eof => Token::Eof.fmt(f), TokenOwned::Equal => Token::Equal.fmt(f), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 9d56baa..173b48b 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -96,6 +96,7 @@ impl Vm { BinaryOperator::Add => left_value.add(&right_value), BinaryOperator::And => left_value.and(&right_value), BinaryOperator::Divide => left_value.divide(&right_value), + BinaryOperator::Equal => Ok(Value::boolean(left_value == right_value)), BinaryOperator::Greater => left_value.greater_than(&right_value), BinaryOperator::GreaterOrEqual => { left_value.greater_than_or_equal(&right_value) @@ -433,6 +434,26 @@ impl Display for VmError { mod tests { use super::*; + #[test] + fn map_equal() { + let input = "{ y = 'foo' } == { y = 'foo' }"; + + assert_eq!( + run(input, &mut HashMap::new()), + Ok(Some(Value::boolean(true))) + ); + } + + #[test] + fn integer_equal() { + let input = "42 == 42"; + + assert_eq!( + run(input, &mut HashMap::new()), + Ok(Some(Value::boolean(true))) + ); + } + #[test] fn modulo() { let input = "42 % 2";