From 0f33f92a5e282babf4e54ef189b1ed2237c0782c Mon Sep 17 00:00:00 2001 From: Ivan Gromov Date: Sun, 8 Oct 2023 21:47:33 +0100 Subject: [PATCH] Logical expressions --- src/ast/expr.rs | 6 ++++++ src/ast/parser.rs | 28 +++++++++++++++++++++++++++- src/interpreter/mod.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/ast/expr.rs b/src/ast/expr.rs index a6d6b54..ba7a9af 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -17,6 +17,8 @@ pub enum BinaryOp { LessEqual, EqualEqual, BangEqual, + And, + Or, } impl Display for BinaryOp { @@ -32,6 +34,8 @@ impl Display for BinaryOp { BinaryOp::LessEqual => "<=", BinaryOp::EqualEqual => "==", BinaryOp::BangEqual => "!=", + BinaryOp::And => "and", + BinaryOp::Or => "or", }; write!(f, "{}", s) } @@ -48,6 +52,8 @@ impl From for BinaryOp { TokenType::GreaterEqual => Self::GreaterEqual, TokenType::Less => Self::Less, TokenType::LessEqual => Self::LessEqual, + TokenType::And => Self::And, + TokenType::Or => Self::Or, _ => unreachable!( "Cannot create binary operator from {} at {:?}", t.type_, t.position diff --git a/src/ast/parser.rs b/src/ast/parser.rs index 2096111..55c75dc 100644 --- a/src/ast/parser.rs +++ b/src/ast/parser.rs @@ -189,7 +189,7 @@ impl Parser<'_> { } fn assignment(&mut self) -> Result { - let expr = self.equality()?; + let expr = self.or()?; if let Some(_equals) = self.consume_if_matches(&[TokenType::Equal]) { let value = self.assignment()?; @@ -211,6 +211,32 @@ impl Parser<'_> { } } + fn or(&mut self) -> Result { + let mut left = self.and()?; + while let Some(operator) = self.consume_if_matches(&[TokenType::Or]) { + let right = self.and()?; + left = Expr { + expr_type: ExprType::Binary( + left.boxed(), BinaryOp::from(operator), right.boxed() + ), + position: PositionRange::from_bounds(&left.position, &right.position) + } + } + Ok(left) + } + + fn and(&mut self) -> Result { + let mut left = self.equality()?; + while let Some(operator) = self.consume_if_matches(&[TokenType::And]) { + let right = self.equality()?; + left = Expr { + expr_type: ExprType::Binary(left.boxed(), BinaryOp::from(operator), right.boxed()), + position: PositionRange::from_bounds(&left.position, &right.position), + } + } + Ok(left) + } + fn equality(&mut self) -> Result { let mut left = self.comparison()?; while let Some(operator) = diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 453856b..cf71a7c 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -65,6 +65,7 @@ impl<'a> Interpreter<'a> { match value { Value::Nil => false, Value::Boolean(b) => *b, + Value::Number(f) => *f > 0.0, _ => true, } } @@ -90,6 +91,8 @@ impl<'a> Interpreter<'a> { } (_, BinaryOp::EqualEqual, _) => Ok(Value::Boolean(left_value == right_value)), (_, BinaryOp::BangEqual, _) => Ok(Value::Boolean(left_value != right_value)), + (_, BinaryOp::And, _) => Ok(Value::Boolean(Self::is_truthy(&left_value) && Self::is_truthy(&right_value))), + (_, BinaryOp::Or, _) => Ok(Value::Boolean(Self::is_truthy(&left_value) || Self::is_truthy(&right_value))), _ => Err(LoxError { kind: LoxErrorKind::Runtime, position: position.clone(), @@ -120,6 +123,8 @@ impl<'a> Interpreter<'a> { BinaryOp::LessEqual => Value::Boolean(left <= right), BinaryOp::EqualEqual => Value::Boolean(left == right), BinaryOp::BangEqual => Value::Boolean(left != right), + BinaryOp::And => Value::Boolean((left > 0.) && (right > 0.)), + BinaryOp::Or => Value::Boolean((left > 0.) || (right > 0.)), } } @@ -428,5 +433,33 @@ global c Ok(()), "false\n", ), + or_statement: ( + "var a = true; + var b = false; + print a or b;", + Ok(()), + "true\n", + ), + or_statement_false: ( + "var a = false; + var b = false; + print a or b;", + Ok(()), + "false\n", + ), + and_statement: ( + "var a = true; + var b = true; + print a and b;", + Ok(()), + "true\n", + ), + and_statement_false: ( + "var a = true; + var b = false; + print a and b;", + Ok(()), + "false\n", + ), ); }