use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; use tree_sitter::Node; use crate::{AbstractTree, Error, Expression, Map, Result, Type, Value}; /// Abstract representation of a logic expression. #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct Logic { left: Expression, operator: LogicOperator, right: Expression, } impl AbstractTree for Logic { fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result { Error::expect_syntax_node(source, "logic", node)?; let first_node = node.child(0).unwrap(); let (left_node, operator_node, right_node) = { if first_node.is_named() { ( first_node, node.child(1).unwrap().child(0).unwrap(), node.child(2).unwrap(), ) } else { ( node.child(1).unwrap(), node.child(2).unwrap().child(0).unwrap(), node.child(3).unwrap(), ) } }; let left = Expression::from_syntax_node(source, left_node, context)?; let operator = match operator_node.kind() { "==" => LogicOperator::Equal, "!=" => LogicOperator::NotEqual, "&&" => LogicOperator::And, "||" => LogicOperator::Or, ">" => LogicOperator::Greater, "<" => LogicOperator::Less, ">=" => LogicOperator::GreaterOrEqual, "<=" => LogicOperator::LessOrEqual, _ => { return Err(Error::UnexpectedSyntaxNode { expected: "==, !=, &&, ||, >, <, >= or <=".to_string(), actual: operator_node.kind().to_string(), location: operator_node.start_position(), relevant_source: source[operator_node.byte_range()].to_string(), }) } }; let right = Expression::from_syntax_node(source, right_node, context)?; Ok(Logic { left, operator, right, }) } fn run(&self, source: &str, context: &Map) -> Result { let left = self.left.run(source, context)?; let right = self.right.run(source, context)?; let result = match self.operator { LogicOperator::Equal => { if let (Ok(left_num), Ok(right_num)) = (left.as_number(), right.as_number()) { left_num == right_num } else { left == right } } LogicOperator::NotEqual => { if let (Ok(left_num), Ok(right_num)) = (left.as_number(), right.as_number()) { left_num != right_num } else { left != right } } LogicOperator::And => left.as_boolean()? && right.as_boolean()?, LogicOperator::Or => left.as_boolean()? || right.as_boolean()?, LogicOperator::Greater => left > right, LogicOperator::Less => left < right, LogicOperator::GreaterOrEqual => left >= right, LogicOperator::LessOrEqual => left <= right, }; Ok(Value::Boolean(result)) } fn expected_type(&self, _context: &Map) -> Result { Ok(Type::Boolean) } } impl Display for Logic { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let Logic { left, operator, right, } = self; write!(f, "{left} {operator} {right}") } } #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub enum LogicOperator { Equal, NotEqual, And, Or, Greater, Less, GreaterOrEqual, LessOrEqual, } impl Display for LogicOperator { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { LogicOperator::Equal => write!(f, "="), LogicOperator::NotEqual => write!(f, "!="), LogicOperator::And => write!(f, "&&"), LogicOperator::Or => write!(f, "||"), LogicOperator::Greater => write!(f, ">"), LogicOperator::Less => write!(f, "<"), LogicOperator::GreaterOrEqual => write!(f, ">="), LogicOperator::LessOrEqual => write!(f, "<="), } } }