1use crate::{Error, ctx::Context};
2
3#[derive(Debug, Clone, PartialEq)]
4pub(crate) 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 _ => None, }
255 }
256}
257
258impl Into<ExprValue> for String {
259 fn into(self) -> ExprValue {
260 ExprValue::Str(self)
261 }
262}
263
264impl Into<ExprValue> for &str {
265 fn into(self) -> ExprValue {
266 ExprValue::Str(self.to_string())
267 }
268}
269
270impl Into<ExprValue> for i64 {
271 fn into(self) -> ExprValue {
272 ExprValue::Int(self)
273 }
274}
275
276impl Into<ExprValue> for f64 {
277 fn into(self) -> ExprValue {
278 ExprValue::Float(self)
279 }
280}
281
282impl Into<ExprValue> for bool {
283 fn into(self) -> ExprValue {
284 ExprValue::Bool(self)
285 }
286}
287
288impl<T: Into<ExprValue>> Into<ExprValue> for Vec<T> {
289 fn into(self) -> ExprValue {
290 ExprValue::Array(self.into_iter().map(|item| item.into()).collect())
291 }
292}
293
294pub struct ExprFnContext {
295 pub args: Vec<ExprValue>,
296}
297
298#[async_trait::async_trait]
299pub trait ExprFn: Send + Sync {
300 async fn call(&self, ctx: ExprFnContext) -> Result<ExprValue, Error>;
301}
302
303pub type BoxedExprFn = Box<dyn ExprFn>;