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}