1use jexl_parser::{
37 ast::{Expression, OpCode},
38 Parser,
39};
40use serde_json::{json as value, Value};
41
42pub mod error;
43use error::*;
44use std::collections::HashMap;
45
46const EPSILON: f64 = 0.000001f64;
47
48trait Truthy {
49 fn is_truthy(&self) -> bool;
50}
51
52impl Truthy for Value {
53 fn is_truthy(&self) -> bool {
54 match self {
55 Value::Bool(b) => *b,
56 Value::Null => false,
57 Value::Number(f) => f.as_f64().unwrap() != 0.0,
58 Value::String(s) => !s.is_empty(),
59 Value::Array(_) => true,
63 Value::Object(_) => true,
64 }
65 }
66}
67
68impl<'b> Truthy for Result<'b, Value> {
69 fn is_truthy(&self) -> bool {
70 match self {
71 Ok(v) => v.is_truthy(),
72 _ => false,
73 }
74 }
75}
76
77type Context = Value;
78
79pub type TransformFn<'a> = Box<dyn Fn(&[Value]) -> Result<Value, anyhow::Error> + Send + Sync + 'a>;
88
89#[derive(Default)]
90pub struct Evaluator<'a> {
91 transforms: HashMap<String, TransformFn<'a>>,
92}
93
94impl<'a> Evaluator<'a> {
95 pub fn new() -> Self {
96 Self::default()
97 }
98
99 pub fn with_transform<F>(mut self, name: &str, transform: F) -> Self
127 where
128 F: Fn(&[Value]) -> Result<Value, anyhow::Error> + Send + Sync + 'a,
129 {
130 self.transforms
131 .insert(name.to_string(), Box::new(transform));
132 self
133 }
134
135 pub fn eval<'b>(&self, input: &'b str) -> Result<'b, Value> {
136 let context = value!({});
137 self.eval_in_context(input, &context)
138 }
139
140 pub fn eval_in_context<'b, T: serde::Serialize>(
141 &self,
142 input: &'b str,
143 context: T,
144 ) -> Result<'b, Value> {
145 let tree = Parser::parse(input)?;
146 let context = serde_json::to_value(context)?;
147 if !context.is_object() {
148 return Err(EvaluationError::InvalidContext);
149 }
150 self.eval_ast(tree, &context)
151 }
152
153 fn eval_ast<'b>(&self, ast: Expression, context: &Context) -> Result<'b, Value> {
154 match ast {
155 Expression::Number(n) => Ok(value!(n)),
156 Expression::Boolean(b) => Ok(value!(b)),
157 Expression::String(s) => Ok(value!(s)),
158 Expression::Array(xs) => xs.into_iter().map(|x| self.eval_ast(*x, context)).collect(),
159 Expression::Null => Ok(Value::Null),
160
161 Expression::Object(items) => {
162 let mut map = serde_json::Map::with_capacity(items.len());
163 for (key, expr) in items.into_iter() {
164 if map.contains_key(&key) {
165 return Err(EvaluationError::DuplicateObjectKey(key));
166 }
167 let value = self.eval_ast(*expr, context)?;
168 map.insert(key, value);
169 }
170 Ok(Value::Object(map))
171 }
172
173 Expression::Identifier(inner) => match context.get(&inner) {
174 Some(v) => Ok(v.clone()),
175 _ => Err(EvaluationError::UndefinedIdentifier(inner.clone())),
176 },
177
178 Expression::DotOperation { subject, ident } => {
179 let subject = self.eval_ast(*subject, context)?;
180 Ok(subject.get(&ident).unwrap_or(&value!(null)).clone())
181 }
182
183 Expression::IndexOperation { subject, index } => {
184 let subject = self.eval_ast(*subject, context)?;
185 if let Expression::Filter { ident, op, right } = *index {
186 let subject_arr = subject.as_array().ok_or(EvaluationError::InvalidFilter)?;
187 let right = self.eval_ast(*right, context)?;
188 let filtered = subject_arr
189 .iter()
190 .filter(|e| {
191 let left = e.get(&ident).unwrap_or(&value!(null));
192 Self::apply_op(op, left.clone(), right.clone())
194 .unwrap_or(value!(false))
195 .is_truthy()
196 })
197 .collect::<Vec<_>>();
198 return Ok(value!(filtered));
199 }
200
201 let index = self.eval_ast(*index, context)?;
202 match index {
203 Value::String(inner) => {
204 Ok(subject.get(&inner).unwrap_or(&value!(null)).clone())
205 }
206 Value::Number(inner) => Ok(subject
207 .get(inner.as_f64().unwrap().floor() as usize)
208 .unwrap_or(&value!(null))
209 .clone()),
210 _ => Err(EvaluationError::InvalidIndexType),
211 }
212 }
213
214 Expression::BinaryOperation {
215 left,
216 right,
217 operation,
218 } => self.eval_op(operation, left, right, context),
219 Expression::Transform {
220 name,
221 subject,
222 args,
223 } => {
224 let subject = self.eval_ast(*subject, context)?;
225 let mut args_arr = Vec::new();
226 args_arr.push(subject);
227 if let Some(args) = args {
228 for arg in args {
229 args_arr.push(self.eval_ast(*arg, context)?);
230 }
231 }
232 let f = self
233 .transforms
234 .get(&name)
235 .ok_or(EvaluationError::UnknownTransform(name))?;
236 f(&args_arr).map_err(|e| e.into())
237 }
238
239 Expression::Conditional {
240 left,
241 truthy,
242 falsy,
243 } => {
244 if self.eval_ast(*left, context).is_truthy() {
245 self.eval_ast(*truthy, context)
246 } else {
247 self.eval_ast(*falsy, context)
248 }
249 }
250
251 Expression::Filter {
252 ident: _,
253 op: _,
254 right: _,
255 } => {
256 return Err(EvaluationError::InvalidFilter);
259 }
260 }
261 }
262
263 fn eval_op<'b>(
264 &self,
265 operation: OpCode,
266 left: Box<Expression>,
267 right: Box<Expression>,
268 context: &Context,
269 ) -> Result<'b, Value> {
270 let left = self.eval_ast(*left, context);
271
272 let eval_right = || self.eval_ast(*right, context);
274 Ok(match operation {
275 OpCode::Or => {
276 if left.is_truthy() {
277 left?
278 } else {
279 eval_right()?
280 }
281 }
282 OpCode::And => {
283 if left.is_truthy() {
284 eval_right()?
285 } else {
286 left?
287 }
288 }
289 _ => Self::apply_op(operation, left?, eval_right()?)?,
290 })
291 }
292
293 fn apply_op<'b>(operation: OpCode, left: Value, right: Value) -> Result<'b, Value> {
294 match (operation, left, right) {
295 (OpCode::NotEqual, a, b) => {
296 let value = Self::apply_op(OpCode::Equal, a, b)?;
298 let equality = value
299 .as_bool()
300 .unwrap_or_else(|| unreachable!("Equality always returns a bool"));
301 Ok(value!(!equality))
302 }
303
304 (OpCode::And, a, b) => Ok(if a.is_truthy() { b } else { a }),
305 (OpCode::Or, a, b) => Ok(if a.is_truthy() { a } else { b }),
306
307 (op, Value::Number(a), Value::Number(b)) => {
308 let left = a.as_f64().unwrap();
309 let right = b.as_f64().unwrap();
310 Ok(match op {
311 OpCode::Add => value!(left + right),
312 OpCode::Subtract => value!(left - right),
313 OpCode::Multiply => value!(left * right),
314 OpCode::Divide => value!(left / right),
315 OpCode::FloorDivide => value!((left / right).floor()),
316 OpCode::Modulus => value!(left % right),
317 OpCode::Exponent => value!(left.powf(right)),
318 OpCode::Less => value!(left < right),
319 OpCode::Greater => value!(left > right),
320 OpCode::LessEqual => value!(left <= right),
321 OpCode::GreaterEqual => value!(left >= right),
322 OpCode::Equal => value!((left - right).abs() < EPSILON),
323 OpCode::NotEqual => value!((left - right).abs() >= EPSILON),
324 OpCode::In => value!(false),
325 OpCode::And | OpCode::Or => {
326 unreachable!("Covered by previous case in parent match")
327 }
328 })
329 }
330
331 (op, Value::String(a), Value::String(b)) => match op {
332 OpCode::Equal => Ok(value!(a == b)),
333
334 OpCode::Add => Ok(value!(format!("{}{}", a, b))),
335 OpCode::In => Ok(value!(b.contains(&a))),
336
337 OpCode::Less => Ok(value!(a < b)),
338 OpCode::Greater => Ok(value!(a > b)),
339 OpCode::LessEqual => Ok(value!(a <= b)),
340 OpCode::GreaterEqual => Ok(value!(a >= b)),
341
342 _ => Err(EvaluationError::InvalidBinaryOp {
343 operation,
344 left: value!(a),
345 right: value!(b),
346 }),
347 },
348
349 (OpCode::In, left, Value::Array(v)) => Ok(value!(v.contains(&left))),
350 (OpCode::In, Value::String(left), Value::Object(v)) => {
351 Ok(value!(v.contains_key(&left)))
352 }
353
354 (OpCode::Equal, a, b) => match (a, b) {
355 (Value::Bool(a), Value::Bool(b)) => Ok(value!(a == b)),
358 (Value::Null, Value::Null) => Ok(value!(true)),
359 (Value::Array(a), Value::Array(b)) => Ok(value!(a == b)),
360 (Value::Object(a), Value::Object(b)) => Ok(value!(a == b)),
361 _ => Ok(value!(false)),
363 },
364
365 (operation, left, right) => Err(EvaluationError::InvalidBinaryOp {
366 operation,
367 left,
368 right,
369 }),
370 }
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377 use serde_json::json as value;
378
379 #[test]
380 fn test_literal() {
381 assert_eq!(Evaluator::new().eval("1").unwrap(), value!(1.0));
382 }
383
384 #[test]
385 fn test_binary_expression_addition() {
386 assert_eq!(Evaluator::new().eval("1 + 2").unwrap(), value!(3.0));
387 }
388
389 #[test]
390 fn test_binary_expression_multiplication() {
391 assert_eq!(Evaluator::new().eval("2 * 3").unwrap(), value!(6.0));
392 }
393
394 #[test]
395 fn test_precedence() {
396 assert_eq!(Evaluator::new().eval("2 + 3 * 4").unwrap(), value!(14.0));
397 }
398
399 #[test]
400 fn test_parenthesis() {
401 assert_eq!(Evaluator::new().eval("(2 + 3) * 4").unwrap(), value!(20.0));
402 }
403
404 #[test]
405 fn test_string_concat() {
406 assert_eq!(
407 Evaluator::new().eval("'Hello ' + 'World'").unwrap(),
408 value!("Hello World")
409 );
410 }
411
412 #[test]
413 fn test_true_comparison() {
414 assert_eq!(Evaluator::new().eval("2 > 1").unwrap(), value!(true));
415 }
416
417 #[test]
418 fn test_false_comparison() {
419 assert_eq!(Evaluator::new().eval("2 <= 1").unwrap(), value!(false));
420 }
421
422 #[test]
423 fn test_boolean_logic() {
424 assert_eq!(
425 Evaluator::new()
426 .eval("'foo' && 6 >= 6 && 0 + 1 && true")
427 .unwrap(),
428 value!(true)
429 );
430 }
431
432 #[test]
433 fn test_identifier() {
434 let context = value!({"a": 1.0});
435 assert_eq!(
436 Evaluator::new().eval_in_context("a", context).unwrap(),
437 value!(1.0)
438 );
439 }
440
441 #[test]
442 fn test_identifier_chain() {
443 let context = value!({"a": {"b": 2.0}});
444 assert_eq!(
445 Evaluator::new().eval_in_context("a.b", context).unwrap(),
446 value!(2.0)
447 );
448 }
449
450 #[test]
451 fn test_context_filter_arrays() {
452 let context = value!({
453 "foo": {
454 "bar": [
455 {"tek": "hello"},
456 {"tek": "baz"},
457 {"tok": "baz"},
458 ]
459 }
460 });
461 assert_eq!(
462 Evaluator::new()
463 .eval_in_context("foo.bar[.tek == 'baz']", &context)
464 .unwrap(),
465 value!([{"tek": "baz"}])
466 );
467 }
468
469 #[test]
470 fn test_context_array_index() {
471 let context = value!({
472 "foo": {
473 "bar": [
474 {"tek": "hello"},
475 {"tek": "baz"},
476 {"tok": "baz"},
477 ]
478 }
479 });
480 assert_eq!(
481 Evaluator::new()
482 .eval_in_context("foo.bar[1].tek", context)
483 .unwrap(),
484 value!("baz")
485 );
486 }
487
488 #[test]
489 fn test_object_expression_properties() {
490 let context = value!({"foo": {"baz": {"bar": "tek"}}});
491 assert_eq!(
492 Evaluator::new()
493 .eval_in_context("foo['ba' + 'z'].bar", &context)
494 .unwrap(),
495 value!("tek")
496 );
497 }
498
499 #[test]
500 fn test_divfloor() {
501 assert_eq!(Evaluator::new().eval("7 // 2").unwrap(), value!(3.0));
502 }
503
504 #[test]
505 fn test_empty_object_literal() {
506 assert_eq!(Evaluator::new().eval("{}").unwrap(), value!({}));
507 }
508
509 #[test]
510 fn test_object_literal_strings() {
511 assert_eq!(
512 Evaluator::new().eval("{'foo': {'bar': 'tek'}}").unwrap(),
513 value!({"foo": {"bar": "tek"}})
514 );
515 }
516
517 #[test]
518 fn test_object_literal_identifiers() {
519 assert_eq!(
520 Evaluator::new().eval("{foo: {bar: 'tek'}}").unwrap(),
521 value!({"foo": {"bar": "tek"}})
522 );
523 }
524
525 #[test]
526 fn test_object_literal_properties() {
527 assert_eq!(
528 Evaluator::new().eval("{foo: 'bar'}.foo").unwrap(),
529 value!("bar")
530 );
531 }
532
533 #[test]
534 fn test_array_literal() {
535 assert_eq!(
536 Evaluator::new().eval("['foo', 1+2]").unwrap(),
537 value!(["foo", 3.0])
538 );
539 }
540
541 #[test]
542 fn test_array_literal_indexing() {
543 assert_eq!(Evaluator::new().eval("[1, 2, 3][1]").unwrap(), value!(2.0));
544 }
545
546 #[test]
547 fn test_in_operator_string() {
548 assert_eq!(
549 Evaluator::new().eval("'bar' in 'foobartek'").unwrap(),
550 value!(true)
551 );
552 assert_eq!(
553 Evaluator::new().eval("'baz' in 'foobartek'").unwrap(),
554 value!(false)
555 );
556 }
557
558 #[test]
559 fn test_in_operator_array() {
560 assert_eq!(
561 Evaluator::new()
562 .eval("'bar' in ['foo', 'bar', 'tek']")
563 .unwrap(),
564 value!(true)
565 );
566 assert_eq!(
567 Evaluator::new()
568 .eval("'baz' in ['foo', 'bar', 'tek']")
569 .unwrap(),
570 value!(false)
571 );
572 }
573
574 #[test]
575 fn test_in_operator_object() {
576 assert_eq!(
577 Evaluator::new()
578 .eval("'bar' in {foo: 1, bar: 2, tek: 3}")
579 .unwrap(),
580 value!(true)
581 );
582 assert_eq!(
583 Evaluator::new()
584 .eval("'baz' in {foo: 1, bar: 2, tek: 3}")
585 .unwrap(),
586 value!(false)
587 );
588 }
589
590 #[test]
591 fn test_conditional_expression() {
592 assert_eq!(
593 Evaluator::new().eval("'foo' ? 1 : 2").unwrap(),
594 value!(1f64)
595 );
596 assert_eq!(Evaluator::new().eval("'' ? 1 : 2").unwrap(), value!(2f64));
597 }
598
599 #[test]
600 fn test_arbitrary_whitespace() {
601 assert_eq!(
602 Evaluator::new().eval("(\t2\n+\n3) *\n4\n\r\n").unwrap(),
603 value!(20.0)
604 );
605 }
606
607 #[test]
608 fn test_non_integer() {
609 assert_eq!(Evaluator::new().eval("1.5 * 3.0").unwrap(), value!(4.5));
610 }
611
612 #[test]
613 fn test_string_literal() {
614 assert_eq!(
615 Evaluator::new().eval("'hello world'").unwrap(),
616 value!("hello world")
617 );
618 assert_eq!(
619 Evaluator::new().eval("\"hello world\"").unwrap(),
620 value!("hello world")
621 );
622 }
623
624 #[test]
625 fn test_string_escapes() {
626 assert_eq!(Evaluator::new().eval("'a\\'b'").unwrap(), value!("a'b"));
627 assert_eq!(Evaluator::new().eval("\"a\\\"b\"").unwrap(), value!("a\"b"));
628 }
629
630 #[test]
631 fn test_simple_transform() {
633 let evaluator = Evaluator::new().with_transform("lower", |v: &[Value]| {
634 let s = v
635 .get(0)
636 .expect("There should be one argument!")
637 .as_str()
638 .expect("Should be a string!");
639 Ok(value!(s.to_lowercase()))
640 });
641 assert_eq!(evaluator.eval("'T_T'|lower").unwrap(), value!("t_t"));
642 }
643
644 #[test]
645 fn test_missing_transform() {
647 let err = Evaluator::new().eval("'hello'|world").unwrap_err();
648 if let EvaluationError::UnknownTransform(transform) = err {
649 assert_eq!(transform, "world")
650 } else {
651 panic!("Should have thrown an unknown transform error")
652 }
653 }
654
655 #[test]
656 fn test_undefined_identifier() {
658 let err = Evaluator::new().eval("not_defined").unwrap_err();
659 if let EvaluationError::UndefinedIdentifier(id) = err {
660 assert_eq!(id, "not_defined")
661 } else {
662 panic!("Should have thrown an undefined identifier error")
663 }
664 }
665
666 #[test]
667 fn test_undefined_identifier_truthy_ops() {
669 let err = Evaluator::new().eval("not_defined").unwrap_err();
670 if let EvaluationError::UndefinedIdentifier(id) = err {
671 assert_eq!(id, "not_defined")
672 } else {
673 panic!("Should have thrown an undefined identifier error")
674 }
675
676 let evaluator = Evaluator::new();
677 let context = value!({
678 "NULL": null,
679 "DEFINED": "string",
680 });
681
682 let test = |expr: &str, is_ok: bool, exp: Value| {
683 let obs = evaluator.eval_in_context(&expr, context.clone());
684 if !is_ok {
685 assert!(obs.is_err());
686 assert!(matches!(
687 obs.unwrap_err(),
688 EvaluationError::UndefinedIdentifier(_)
689 ));
690 } else {
691 assert_eq!(obs.unwrap(), exp,);
692 }
693 };
694
695 test("UNDEFINED", false, value!(null));
696 test("UNDEFINED == 'string'", false, value!(null));
697 test("'string' == UNDEFINED", false, value!(null));
698
699 test("UNDEFINED ? 'WRONG' : 'RIGHT'", true, value!("RIGHT"));
700 test("DEFINED ? UNDEFINED : 'WRONG'", false, value!(null));
701
702 test("UNDEFINED || 'RIGHT'", true, value!("RIGHT"));
703 test("'RIGHT' || UNDEFINED", true, value!("RIGHT"));
704
705 test("'WRONG' && UNDEFINED", false, value!(null));
706 test("UNDEFINED && 'WRONG'", false, value!(null));
707
708 test("UNDEFINED && 'WRONG'", false, value!(null));
709
710 test(
711 "(UNDEFINED && UNDEFINED == 'string') || (DEFINED && DEFINED == 'string')",
712 true,
713 value!(true),
714 );
715 }
716
717 #[test]
718 fn test_add_multiple_transforms() {
719 let evaluator = Evaluator::new()
720 .with_transform("sqrt", |v: &[Value]| {
721 let num = v
722 .first()
723 .expect("There should be one argument!")
724 .as_f64()
725 .expect("Should be a valid number!");
726 Ok(value!(num.sqrt() as u64))
727 })
728 .with_transform("square", |v: &[Value]| {
729 let num = v
730 .first()
731 .expect("There should be one argument!")
732 .as_f64()
733 .expect("Should be a valid number!");
734 Ok(value!((num as u64).pow(2)))
735 });
736
737 assert_eq!(evaluator.eval("4|square").unwrap(), value!(16));
738 assert_eq!(evaluator.eval("4|sqrt").unwrap(), value!(2));
739 assert_eq!(evaluator.eval("4|square|sqrt").unwrap(), value!(4));
740 }
741
742 #[test]
743 fn test_transform_with_argument() {
744 let evaluator = Evaluator::new().with_transform("split", |args: &[Value]| {
745 let s = args
746 .first()
747 .expect("Should be a first argument!")
748 .as_str()
749 .expect("Should be a string!");
750 let c = args
751 .get(1)
752 .expect("There should be a second argument!")
753 .as_str()
754 .expect("Should be a string");
755 let res: Vec<&str> = s.split_terminator(c).collect();
756 Ok(value!(res))
757 });
758
759 assert_eq!(
760 evaluator.eval("'John Doe'|split(' ')").unwrap(),
761 value!(vec!["John", "Doe"])
762 );
763 }
764
765 #[derive(Debug, thiserror::Error)]
766 enum CustomError {
767 #[error("Invalid argument in transform!")]
768 InvalidArgument,
769 }
770
771 #[test]
772 fn test_custom_error_message() {
773 let evaluator = Evaluator::new().with_transform("error", |_: &[Value]| {
774 Err(CustomError::InvalidArgument.into())
775 });
776 let res = evaluator.eval("1234|error");
777 assert!(res.is_err());
778 if let EvaluationError::CustomError(e) = res.unwrap_err() {
779 assert_eq!(e.to_string(), "Invalid argument in transform!")
780 } else {
781 panic!("Should have returned a Custom error!")
782 }
783 }
784
785 #[test]
786 fn test_filter_collections_many_returned() {
787 let evaluator = Evaluator::new();
788 let context = value!({
789 "foo": [
790 {"bobo": 50, "fofo": 100},
791 {"bobo": 60, "baz": 90},
792 {"bobo": 10, "bar": 83},
793 {"bobo": 20, "yam": 12},
794 ]
795 });
796 let exp = "foo[.bobo >= 50]";
797 assert_eq!(
798 evaluator.eval_in_context(exp, context).unwrap(),
799 value!([{"bobo": 50, "fofo": 100}, {"bobo": 60, "baz": 90}])
800 );
801 }
802
803 #[test]
804 fn test_binary_op_eq_ne() {
805 let evaluator = Evaluator::new();
806 let context = value!({
807 "NULL": null,
808 "STRING": "string",
809 "BOOLEAN": true,
810 "NUMBER": 42,
811 "OBJECT": { "x": 1, "y": 2 },
812 "ARRAY": [ "string" ]
813 });
814
815 let test = |l: &str, r: &str, exp: bool| {
816 let expr = format!("{} == {}", l, r);
817 assert_eq!(
818 evaluator.eval_in_context(&expr, context.clone()).unwrap(),
819 value!(exp)
820 );
821
822 let expr = format!("{} != {}", l, r);
823 assert_eq!(
824 evaluator.eval_in_context(&expr, context.clone()).unwrap(),
825 value!(!exp)
826 );
827 };
828
829 test("STRING", "'string'", true);
830 test("NUMBER", "42", true);
831 test("BOOLEAN", "true", true);
832 test("OBJECT", "OBJECT", true);
833 test("ARRAY", "[ 'string' ]", true);
834 test("NULL", "null", true);
835
836 test("OBJECT", "{ 'x': 1, 'y': 2 }", false);
837
838 test("STRING", "NULL", false);
839 test("NUMBER", "NULL", false);
840 test("BOOLEAN", "NULL", false);
841 test("OBJECT", "NULL", false);
843 test("ARRAY", "NULL", false);
844
845 test("NUMBER", "STRING", false);
847 test("BOOLEAN", "STRING", false);
848 test("NULL", "STRING", false);
849 test("OBJECT", "STRING", false);
850 test("ARRAY", "STRING", false);
851
852 test("STRING", "NUMBER", false);
853 test("BOOLEAN", "NUMBER", false);
855 test("NULL", "NUMBER", false);
856 test("OBJECT", "NUMBER", false);
857 test("ARRAY", "NUMBER", false);
858
859 test("STRING", "BOOLEAN", false);
860 test("NUMBER", "BOOLEAN", false);
861 test("NULL", "BOOLEAN", false);
863 test("OBJECT", "BOOLEAN", false);
864 test("ARRAY", "BOOLEAN", false);
865
866 test("STRING", "OBJECT", false);
867 test("NUMBER", "OBJECT", false);
868 test("BOOLEAN", "OBJECT", false);
869 test("NULL", "OBJECT", false);
870 test("ARRAY", "OBJECT", false);
872
873 test("STRING", "ARRAY", false);
874 test("NUMBER", "ARRAY", false);
875 test("BOOLEAN", "ARRAY", false);
876 test("NULL", "ARRAY", false);
877 test("OBJECT", "ARRAY", false);
878 }
880
881 #[test]
882 fn test_binary_op_string_gt_lt_gte_lte() {
883 let evaluator = Evaluator::new();
884 let context = value!({
885 "A": "A string",
886 "B": "B string",
887 });
888
889 let test = |l: &str, r: &str, is_gt: bool| {
890 let expr = format!("{} > {}", l, r);
891 assert_eq!(
892 evaluator.eval_in_context(&expr, context.clone()).unwrap(),
893 value!(is_gt)
894 );
895
896 let expr = format!("{} <= {}", l, r);
897 assert_eq!(
898 evaluator.eval_in_context(&expr, context.clone()).unwrap(),
899 value!(!is_gt)
900 );
901
902 let expr = format!("{} == {}", l, r);
904 let is_eq = evaluator
905 .eval_in_context(&expr, context.clone())
906 .unwrap()
907 .as_bool()
908 .unwrap();
909
910 if is_eq {
911 let expr = format!("{} >= {}", l, r);
912 assert_eq!(
913 evaluator.eval_in_context(&expr, context.clone()).unwrap(),
914 value!(true)
915 );
916 } else {
917 let expr = format!("{} < {}", l, r);
918 assert_eq!(
919 evaluator.eval_in_context(&expr, context.clone()).unwrap(),
920 value!(!is_gt)
921 );
922 }
923 };
924
925 test("A", "B", false);
926 test("B", "A", true);
927 test("A", "A", false);
928 }
929
930 #[test]
931 fn test_lazy_eval_binary_op_and_or() {
932 let evaluator = Evaluator::new();
933 let res = evaluator.eval("42 || 0|error");
935 assert!(res.is_ok());
936 assert_eq!(res.unwrap(), value!(42.0));
937
938 let res = evaluator.eval("false || 0|error");
939 assert!(res.is_err());
940
941 let res = evaluator.eval("42 && 0|error");
942 assert!(res.is_err());
943
944 let res = evaluator.eval("false && 0|error");
945 assert!(res.is_ok());
946 assert_eq!(res.unwrap(), value!(false));
947 }
948
949 #[test]
950 fn test_lazy_eval_trinary_op() {
951 let evaluator = Evaluator::new();
952 let res = evaluator.eval("true ? 42 : 0|error");
954 assert!(res.is_ok());
955 assert_eq!(res.unwrap(), value!(42.0));
956
957 let res = evaluator.eval("true ? 0|error : 42");
958 assert!(res.is_err());
959
960 let res = evaluator.eval("true ? 0|error : 42");
961 assert!(res.is_err());
962
963 let res = evaluator.eval("false ? 0|error : 42");
964 assert!(res.is_ok());
965 assert_eq!(res.unwrap(), value!(42.0));
966 }
967}