1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
use ergotree_ir::mir::coll_exists::Exists; use ergotree_ir::mir::constant::TryExtractInto; use ergotree_ir::mir::value::Value; use crate::eval::env::Env; use crate::eval::EvalContext; use crate::eval::EvalError; use crate::eval::Evaluable; impl Evaluable for Exists { fn eval(&self, env: &Env, ctx: &mut EvalContext) -> Result<Value, EvalError> { let input_v = self.input.eval(env, ctx)?; let condition_v = self.condition.eval(env, ctx)?; let input_v_clone = input_v.clone(); let mut condition_call = |arg: Value| match &condition_v { Value::Lambda(func_value) => { let func_arg = func_value.args.first().ok_or_else(|| { EvalError::NotFound( "Exists: evaluated condition has empty arguments list".to_string(), ) })?; let env1 = env.clone().extend(func_arg.idx, arg); func_value.body.eval(&env1, ctx) } _ => Err(EvalError::UnexpectedValue(format!( "expected Exists::condition to be Value::FuncValue got: {0:?}", input_v_clone ))), }; let normalized_input_vals: Vec<Value> = match input_v { Value::Coll(coll) => { if *coll.elem_tpe() != self.elem_tpe { return Err(EvalError::UnexpectedValue(format!( "expected Exists input element type to be {0:?}, got: {1:?}", self.elem_tpe, coll.elem_tpe() ))); }; Ok(coll.as_vec()) } _ => Err(EvalError::UnexpectedValue(format!( "expected Map input to be Value::Coll, got: {0:?}", input_v ))), }?; for item in normalized_input_vals.into_iter() { let res = condition_call(item)?.try_extract_into::<bool>()?; if res { return Ok(true.into()); } } Ok(false.into()) } } #[cfg(test)] mod tests { use crate::eval::tests::eval_out_wo_ctx; use super::*; use ergotree_ir::mir::bin_op::BinOp; use ergotree_ir::mir::bin_op::RelationOp; use ergotree_ir::mir::expr::Expr; use ergotree_ir::mir::func_value::FuncArg; use ergotree_ir::mir::func_value::FuncValue; use ergotree_ir::mir::val_use::ValUse; use ergotree_ir::types::stype::SType; fn check(coll: Vec<i32>) { let body: Expr = BinOp { kind: RelationOp::Le.into(), left: Box::new(Expr::Const(1i32.into())), right: Box::new( ValUse { val_id: 1.into(), tpe: SType::SBox, } .into(), ), } .into(); let expr: Expr = Exists::new( coll.clone().into(), FuncValue::new( vec![FuncArg { idx: 1.into(), tpe: SType::SInt, }], body, ) .into(), ) .unwrap() .into(); assert_eq!( eval_out_wo_ctx::<bool>(&expr), coll.iter().any(|it| 1 <= *it) ); } #[test] fn eval_emty_coll() { check(Vec::<i32>::new()); } #[test] fn eval_true() { check(vec![1, 2]); } #[test] fn eval_false() { check(vec![2, 2]); } }