1use crate::{Error, ctx::Context};
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum Expr {
5 Field(String),
6 Value(ExprValue),
7
8 FuncCall(String, Vec<Expr>),
9
10 Gt(Box<Expr>, Box<Expr>),
11 Lt(Box<Expr>, Box<Expr>),
12 Ge(Box<Expr>, Box<Expr>),
13 Le(Box<Expr>, Box<Expr>),
14 Eq(Box<Expr>, Box<Expr>),
15 Ne(Box<Expr>, Box<Expr>),
16 In(Box<Expr>, Box<Expr>),
17
18 And(Vec<Expr>),
19 Or(Vec<Expr>),
20 Not(Box<Expr>),
21}
22
23impl Expr {
24 pub(crate) fn field<T: Into<String>>(field: T) -> Self {
25 Self::Field(field.into())
26 }
27
28 #[cfg(test)]
29 pub(crate) fn field_boxed<T: Into<String>>(field: T) -> Box<Self> {
30 Box::new(Self::field(field))
31 }
32
33 pub(crate) fn value<T: Into<ExprValue>>(value: T) -> Self {
34 Self::Value(value.into())
35 }
36
37 #[cfg(test)]
38 pub(crate) fn value_boxed<T: Into<ExprValue>>(value: T) -> Box<Self> {
39 Box::new(Self::value(value))
40 }
41
42 pub(crate) async fn eval(&self, ctx: &dyn Context) -> Result<ExprValue, Error> {
43 match self {
44 Self::Field(field) => {
45 let value = ctx.get_var(field).await?;
46 Ok(value)
47 }
48 Self::Value(value) => Ok(value.clone()),
49
50 Self::FuncCall(func, args) => self.eval_func_call(func, args, ctx).await,
51
52 Self::Gt(left, right) => {
53 let left_value = Box::pin(left.eval(ctx)).await?;
54 let right_value = Box::pin(right.eval(ctx)).await?;
55 match left_value.partial_cmp(&right_value) {
56 Some(ordering) => Ok(ExprValue::Bool(ordering == std::cmp::Ordering::Greater)),
57 None => Err(Error::TypeMismatch(
58 format!("{:?}", left_value),
59 format!("{:?}", right_value),
60 )),
61 }
62 }
63 Self::Lt(left, right) => {
64 let left_value = Box::pin(left.eval(ctx)).await?;
65 let right_value = Box::pin(right.eval(ctx)).await?;
66 match left_value.partial_cmp(&right_value) {
67 Some(ordering) => Ok(ExprValue::Bool(ordering == std::cmp::Ordering::Less)),
68 None => Err(Error::TypeMismatch(
69 format!("{:?}", left_value),
70 format!("{:?}", right_value),
71 )),
72 }
73 }
74 Self::Ge(left, right) => {
75 let left_value = Box::pin(left.eval(ctx)).await?;
76 let right_value = Box::pin(right.eval(ctx)).await?;
77 match left_value.partial_cmp(&right_value) {
78 Some(ordering) => Ok(ExprValue::Bool(
79 ordering == std::cmp::Ordering::Greater
80 || ordering == std::cmp::Ordering::Equal,
81 )),
82 None => Err(Error::TypeMismatch(
83 format!("{:?}", left_value),
84 format!("{:?}", right_value),
85 )),
86 }
87 }
88 Self::Le(left, right) => {
89 let left_value = Box::pin(left.eval(ctx)).await?;
90 let right_value = Box::pin(right.eval(ctx)).await?;
91 match left_value.partial_cmp(&right_value) {
92 Some(ordering) => Ok(ExprValue::Bool(
93 ordering == std::cmp::Ordering::Less
94 || ordering == std::cmp::Ordering::Equal,
95 )),
96 None => Err(Error::TypeMismatch(
97 format!("{:?}", left_value),
98 format!("{:?}", right_value),
99 )),
100 }
101 }
102 Self::Eq(left, right) => {
103 let left_value = Box::pin(left.eval(ctx)).await?;
104 let right_value = Box::pin(right.eval(ctx)).await?;
105 Ok(ExprValue::Bool(left_value == right_value))
106 }
107 Self::Ne(left, right) => {
108 let left_value = Box::pin(left.eval(ctx)).await?;
109 let right_value = Box::pin(right.eval(ctx)).await?;
110 Ok(ExprValue::Bool(left_value != right_value))
111 }
112 Self::In(left, right) => {
113 let left_value = Box::pin(left.eval(ctx)).await?;
114 let right_value = Box::pin(right.eval(ctx)).await?;
115 match right_value {
116 ExprValue::Array(array) => Ok(ExprValue::Bool(array.contains(&left_value))),
117 _ => Err(Error::TypeMismatch(
118 format!("{:?}", right_value),
119 format!("{:?}", left_value),
120 )),
121 }
122 }
123
124 Self::And(exprs) => {
125 let mut result = true;
126 for expr in exprs {
127 let value = Box::pin(expr.eval(ctx)).await?;
128 match value {
129 ExprValue::Bool(b) => result = result && b,
130 _ => {
131 return Err(Error::InvalidValue(format!(
132 "expected bool, got {:?}",
133 value
134 )));
135 }
136 }
137 }
138 Ok(ExprValue::Bool(result))
139 }
140 Self::Or(exprs) => {
141 let mut result = false;
142 for expr in exprs {
143 let value = Box::pin(expr.eval(ctx)).await?;
144 match value {
145 ExprValue::Bool(b) => result = result || b,
146 _ => {
147 return Err(Error::InvalidValue(format!(
148 "expected bool, got {:?}",
149 value
150 )));
151 }
152 }
153 }
154 Ok(ExprValue::Bool(result))
155 }
156 Self::Not(expr) => {
157 let value = Box::pin(expr.eval(ctx)).await?;
158 match value {
159 ExprValue::Bool(b) => Ok(ExprValue::Bool(!b)),
160 _ => Err(Error::TypeMismatch(format!("{:?}", value), format!("bool"))),
161 }
162 }
163 }
164 }
165
166 pub(crate) async fn eval_func_call(
167 &self,
168 func: &str,
169 args: &[Expr],
170 ctx: &dyn Context,
171 ) -> Result<ExprValue, Error> {
172 let mut args_values = vec![];
174 for arg in args {
175 let value = Box::pin(arg.eval(ctx)).await?;
176 args_values.push(value);
177 }
178
179 let func_name = func;
181 let func = ctx.get_fn(func).await;
182
183 if let Some(func) = func {
185 return func.call(ExprFnContext { args: args_values }).await;
186 } else {
187 match func_name {
188 "matches" => self.eval_builtin_func_call_matches(&args_values).await,
189 _ => Err(Error::NoSuchFunction(func_name.to_string())),
190 }
191 }
192 }
193
194 pub(crate) async fn eval_builtin_func_call_matches(
195 &self,
196 args: &[ExprValue],
197 ) -> Result<ExprValue, Error> {
198 if args.len() != 2 {
199 return Err(Error::InvalidArgumentCount {
200 expected: 2,
201 got: args.len(),
202 });
203 }
204 let text = match &args[0] {
205 ExprValue::Str(s) => s,
206 _ => {
207 return Err(Error::InvalidArgumentType {
208 expected: "string".to_string(),
209 got: format!("{:?}", args[0]),
210 });
211 }
212 };
213 let pattern = match &args[1] {
214 ExprValue::Str(s) => s,
215 _ => {
216 return Err(Error::InvalidArgumentType {
217 expected: "string".to_string(),
218 got: format!("{:?}", args[1]),
219 });
220 }
221 };
222 let pattern = regex::Regex::new(&pattern);
223 let pattern = match pattern {
224 Ok(pattern) => pattern,
225 Err(e) => {
226 return Err(Error::Internal(format!("failed to compile regex: {}", e)));
227 }
228 };
229
230 let matches = pattern.is_match(&text);
231 Ok(ExprValue::Bool(matches))
232 }
233}
234
235#[derive(Debug, Clone, PartialEq)]
236pub enum ExprValue {
237 Str(String),
238 Int(i64),
239 Float(f64),
240 Bool(bool),
241 Null,
242
243 Array(Vec<ExprValue>),
244}
245
246impl PartialOrd for ExprValue {
247 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
248 match (self, other) {
249 (ExprValue::Str(a), ExprValue::Str(b)) => a.partial_cmp(b),
250 (ExprValue::Int(a), ExprValue::Int(b)) => a.partial_cmp(b),
251 (ExprValue::Float(a), ExprValue::Float(b)) => a.partial_cmp(b),
252 (ExprValue::Bool(a), ExprValue::Bool(b)) => a.partial_cmp(b),
253 (ExprValue::Null, ExprValue::Null) => Some(std::cmp::Ordering::Equal),
254
255 (ExprValue::Float(a), ExprValue::Int(b)) => a.partial_cmp(&(*b as f64)),
256 (ExprValue::Int(a), ExprValue::Float(b)) => (*a as f64).partial_cmp(b),
257
258 (ExprValue::Array(a), ExprValue::Array(b)) => a.partial_cmp(b),
259
260 (ExprValue::Null, _) => Some(std::cmp::Ordering::Greater),
261 (_, ExprValue::Null) => Some(std::cmp::Ordering::Less),
262
263 _ => None, }
265 }
266}
267
268impl Into<ExprValue> for String {
269 fn into(self) -> ExprValue {
270 ExprValue::Str(self)
271 }
272}
273
274impl Into<ExprValue> for &str {
275 fn into(self) -> ExprValue {
276 ExprValue::Str(self.to_string())
277 }
278}
279
280impl Into<ExprValue> for i64 {
281 fn into(self) -> ExprValue {
282 ExprValue::Int(self)
283 }
284}
285
286impl Into<ExprValue> for f64 {
287 fn into(self) -> ExprValue {
288 ExprValue::Float(self)
289 }
290}
291
292impl Into<ExprValue> for bool {
293 fn into(self) -> ExprValue {
294 ExprValue::Bool(self)
295 }
296}
297
298impl<T: Into<ExprValue>> Into<ExprValue> for Vec<T> {
299 fn into(self) -> ExprValue {
300 ExprValue::Array(self.into_iter().map(|item| item.into()).collect())
301 }
302}
303
304pub struct ExprFnContext {
305 pub args: Vec<ExprValue>,
306}
307
308#[async_trait::async_trait]
309pub trait ExprFn: Send + Sync {
310 async fn call(&self, ctx: ExprFnContext) -> Result<ExprValue, Error>;
311}
312
313pub type BoxedExprFn = Box<dyn ExprFn>;
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 fn test_expr_value_ordering() {
321 assert!(ExprValue::Str("a".to_string()) < ExprValue::Str("b".to_string()));
323 assert!(ExprValue::Str("a".to_string()) <= ExprValue::Str("a".to_string()));
324 assert!(ExprValue::Str("b".to_string()) > ExprValue::Str("a".to_string()));
325
326 assert!(ExprValue::Int(1) < ExprValue::Int(2));
328 assert!(ExprValue::Int(1) <= ExprValue::Int(1));
329 assert!(ExprValue::Int(2) > ExprValue::Int(1));
330
331 assert!(ExprValue::Float(1.0) < ExprValue::Float(2.0));
333 assert!(ExprValue::Float(1.0) <= ExprValue::Float(1.0));
334 assert!(ExprValue::Float(2.0) > ExprValue::Float(1.0));
335
336 assert!(ExprValue::Bool(false) < ExprValue::Bool(true));
338 assert!(ExprValue::Bool(false) <= ExprValue::Bool(false));
339 assert!(ExprValue::Bool(true) > ExprValue::Bool(false));
340
341 assert!(ExprValue::Int(1) < ExprValue::Float(2.0));
343 assert!(ExprValue::Int(2) > ExprValue::Float(1.0));
344 assert!(ExprValue::Float(1.0) < ExprValue::Int(2));
345 assert!(ExprValue::Float(2.0) > ExprValue::Int(1));
346
347 assert!(ExprValue::Null == ExprValue::Null);
349 assert!(ExprValue::Null > ExprValue::Str("a".to_string()));
350 assert!(ExprValue::Str("a".to_string()) < ExprValue::Null);
351 assert!(ExprValue::Null > ExprValue::Int(1));
352 assert!(ExprValue::Int(1) < ExprValue::Null);
353
354 let arr1 = ExprValue::Array(vec![ExprValue::Int(1), ExprValue::Int(2)]);
356 let arr2 = ExprValue::Array(vec![ExprValue::Int(1), ExprValue::Int(3)]);
357 assert!(arr1 < arr2);
358 assert!(arr1 <= arr1);
359 assert!(arr2 > arr1);
360
361 assert!(ExprValue::Str("a".to_string()).partial_cmp(&ExprValue::Int(1)).is_none());
363 assert!(ExprValue::Int(1).partial_cmp(&ExprValue::Bool(true)).is_none());
364 assert!(ExprValue::Str("a".to_string()).partial_cmp(&ExprValue::Bool(false)).is_none());
365 assert!(ExprValue::Array(vec![]).partial_cmp(&ExprValue::Int(1)).is_none());
366 }
367}