//! # Expression AST //! //! Defines the abstract syntax tree nodes produced by the parser and consumed //! by the evaluator. use std::fmt; /// A binary operator connecting two sub-expressions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BinaryOp { // Arithmetic Add, Sub, Mul, Div, Mod, // Comparison Eq, Ne, Lt, Gt, Le, Ge, // Logical And, Or, // Membership In, } impl fmt::Display for BinaryOp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { BinaryOp::Add => write!(f, "+"), BinaryOp::Sub => write!(f, "-"), BinaryOp::Mul => write!(f, "*"), BinaryOp::Div => write!(f, "/"), BinaryOp::Mod => write!(f, "%"), BinaryOp::Eq => write!(f, "=="), BinaryOp::Ne => write!(f, "!="), BinaryOp::Lt => write!(f, "<"), BinaryOp::Gt => write!(f, ">"), BinaryOp::Le => write!(f, "<="), BinaryOp::Ge => write!(f, ">="), BinaryOp::And => write!(f, "and"), BinaryOp::Or => write!(f, "or"), BinaryOp::In => write!(f, "in"), } } } /// A unary operator applied to a single sub-expression. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UnaryOp { /// Arithmetic negation: `-x` Neg, /// Logical negation: `not x` Not, } impl fmt::Display for UnaryOp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { UnaryOp::Neg => write!(f, "-"), UnaryOp::Not => write!(f, "not"), } } } /// An expression AST node. #[derive(Debug, Clone, PartialEq)] pub enum Expr { /// A literal JSON value: number, string, bool, or null. Literal(serde_json::Value), /// An array literal: `[expr, expr, ...]` Array(Vec), /// A variable reference by name (e.g., `x`, `parameters`, `item`). Ident(String), /// Binary operation: `left op right` BinaryOp { op: BinaryOp, left: Box, right: Box, }, /// Unary operation: `op operand` UnaryOp { op: UnaryOp, operand: Box, }, /// Property access: `expr.field` DotAccess { object: Box, field: String, }, /// Index/bracket access: `expr[index_expr]` IndexAccess { object: Box, index: Box, }, /// Function call: `name(arg1, arg2, ...)` FunctionCall { name: String, args: Vec, }, }