1use crate::ast::{All, Any, Expr, Not, Var};
2
3pub fn eval_with<T, F>(expr: &Expr<T>, f: &F) -> bool
4where
5 F: for<'v> Fn(&'v T) -> bool,
6{
7 match expr {
8 Expr::Any(Any(list)) => list.iter().any(|e| eval_with(e, f)),
9 Expr::All(All(list)) => list.iter().all(|e| eval_with(e, f)),
10 Expr::Not(Not(not)) => !eval_with(not, f),
11 Expr::Var(Var(var)) => f(var),
12 Expr::Const(b) => *b,
13 }
14}
15
16#[cfg(test)]
17mod tests {
18 use super::*;
19
20 use crate::ast::*;
21
22 #[test]
23 fn flatten_cfg_if() {
24 let (x0, x1, x2) = (var(0), var(1), var(2));
25 let src = expr(all((not(any((x0, x1))), x2)));
26 let dst = expr(all((not(x0), not(x1), x2)));
27
28 for i in 0..8 {
29 let assign = |x: &_| ((i >> x) & 1) == 1;
30 let lhs = eval_with(&src, &assign);
31 let rhs = eval_with(&dst, &assign);
32 assert_eq!(lhs, rhs, "i = {i}");
33 }
34 }
35}