expr/ast/
operator.rs

1use crate::ast::node::Node;
2use crate::Value::{Array, Bool, Float, Map, Number, String};
3use crate::{bail, Result, Rule};
4use crate::{Context, Environment, Value};
5use pest::iterators::{Pair};
6use std::str::FromStr;
7use log::trace;
8
9#[derive(Debug, Clone, strum::EnumString, strum::Display)]
10pub enum Operator {
11    #[strum(serialize = "+")]
12    Add,
13    #[strum(serialize = "-")]
14    Subtract,
15    #[strum(serialize = "*")]
16    Multiply,
17    #[strum(serialize = "/")]
18    Divide,
19    #[strum(serialize = "%")]
20    Modulo,
21    #[strum(serialize = "^")]
22    Pow,
23    #[strum(serialize = "==")]
24    Equal,
25    #[strum(serialize = "!=")]
26    NotEqual,
27    #[strum(serialize = ">")]
28    GreaterThan,
29    #[strum(serialize = ">=")]
30    GreaterThanOrEqual,
31    #[strum(serialize = "<")]
32    LessThan,
33    #[strum(serialize = "<=")]
34    LessThanOrEqual,
35    #[strum(serialize = "&&", serialize = "and")]
36    And,
37    #[strum(serialize = "||", serialize = "or")]
38    Or,
39    #[strum(serialize = "in")]
40    In,
41    #[strum(serialize = "contains")]
42    Contains,
43    #[strum(serialize = "startsWith")]
44    StartsWith,
45    #[strum(serialize = "endsWith")]
46    EndsWith,
47    #[strum(serialize = "matches")]
48    Matches,
49}
50
51impl From<Pair<'_, Rule>> for Operator {
52    fn from(pair: Pair<Rule>) -> Self {
53        trace!("[operator] {pair:?}");
54        match pair.as_str() {
55            "**" => Operator::Pow,
56            op => Operator::from_str(op).unwrap_or_else(|_| unreachable!("Invalid operator {op}")),
57        }
58    }
59}
60
61impl Environment<'_> {
62    pub fn eval_operator(
63        &self,
64        ctx: &Context,
65        operator: Operator,
66        left: Node,
67        right: Node,
68    ) -> Result<Value> {
69        let left = self.eval_expr(ctx, left)?;
70        let right = self.eval_expr(ctx, right)?;
71        let result = match operator {
72            Operator::Add => match (left, right) {
73                (Number(left), Number(right)) => (left + right).into(),
74                (Float(left), Float(right)) => (left + right).into(),
75                (String(left), String(right)) => format!("{left}{right}").into(),
76                _ => bail!("Invalid operands for operator +"),
77            },
78            Operator::Subtract => match (left, right) {
79                (Number(left), Number(right)) => Number(left - right),
80                (Float(left), Float(right)) => Float(left - right),
81                _ => bail!("Invalid operands for operator -"),
82            },
83            Operator::Multiply => match (left, right) {
84                (Number(left), Number(right)) => Number(left * right),
85                (Float(left), Float(right)) => Float(left * right),
86                _ => bail!("Invalid operands for operator *"),
87            },
88            Operator::Divide => match (left, right) {
89                (Number(left), Number(right)) => Number(left / right),
90                (Float(left), Float(right)) => Float(left / right),
91                _ => bail!("Invalid operands for operator /"),
92            },
93            Operator::Modulo => match (left, right) {
94                    (Number(left), Number(right)) => Number(left % right),
95                    _ => bail!("Invalid operands for operator %"),
96                },
97            Operator::Pow => match (left, right) {
98                (Number(left), Number(right)) => Number(left.pow(right as u32)),
99                (Float(left), Float(right)) => Float(left.powf(right)),
100                _ => bail!("Invalid operands for operator {operator}"),
101            },
102            Operator::Equal => Bool(left == right),
103            Operator::NotEqual => Bool(left != right),
104            Operator::GreaterThan => match (left, right) {
105                (Number(left), Number(right)) => (left > right).into(),
106                (Float(left), Float(right)) => (left > right).into(),
107                (String(left), String(right)) => (left > right).into(),
108                _ => bail!("Invalid operands for operator {operator}"),
109            },
110            Operator::GreaterThanOrEqual => match (left, right) {
111                (Number(left), Number(right)) => (left >= right).into(),
112                (Float(left), Float(right)) => (left >= right).into(),
113                (String(left), String(right)) => (left >= right).into(),
114                _ => bail!("Invalid operands for operator {operator}"),
115            },
116            Operator::LessThan => match (left, right) {
117                (Number(left), Number(right)) => (left < right).into(),
118                (Float(left), Float(right)) => (left < right).into(),
119                (String(left), String(right)) => (left < right).into(),
120                _ => bail!("Invalid operands for operator {operator}"),
121            },
122            Operator::LessThanOrEqual => match (left, right) {
123                (Number(left), Number(right)) => (left <= right).into(),
124                (Float(left), Float(right)) => (left <= right).into(),
125                (String(left), String(right)) => (left <= right).into(),
126                _ => bail!("Invalid operands for operator {operator}"),
127            },
128            Operator::And => Bool(left.as_bool() == Some(true) && right.as_bool() == Some(true)),
129            Operator::Or => Bool(left.as_bool() == Some(true) || right.as_bool() == Some(true)),
130            Operator::In => match (left, right) {
131                (String(left), Map(right)) => right.contains_key(&left).into(),
132                (left, Array(right)) => right.contains(&left).into(),
133                _ => bail!("Invalid operands for operator {operator}"),
134            },
135            Operator::Contains => match (left, right) {
136                (String(left), String(right)) => left.contains(&right).into(),
137                (Array(left), right) => left.contains(&right).into(),
138                (Map(left), String(right)) => left.contains_key(&right).into(),
139                _ => bail!("Invalid operands for operator contains"),
140            },
141            Operator::StartsWith => match (left, right) {
142                (String(left), String(right)) => Bool(left.starts_with(&right)),
143                _ => bail!("Invalid operands for operator startsWith"),
144            },
145            Operator::EndsWith => match (left, right) {
146                (String(left), String(right)) => Bool(left.ends_with(&right)),
147                _ => bail!("Invalid operands for operator endsWith"),
148            },
149            Operator::Matches => match (left, right) {
150                (String(left), String(right)) => {
151                    let re = regex::Regex::new(&right)?;
152                    Bool(re.is_match(&left))
153                }
154                _ => bail!("Invalid operands for operator matches"),
155            },
156        };
157        
158        Ok(result)
159    }
160}