1
use crate::utils::replace_expression_generator_source;
2
use conjure_cp::ast::comprehension::ComprehensionQualifier;
3
use conjure_cp::ast::{Atom, Metadata};
4
use conjure_cp::ast::{Expression as Expr, Moo, SymbolTable};
5
use conjure_cp::rule_engine::Reduction;
6
use conjure_cp::rule_engine::{
7
    ApplicationError::RuleNotApplicable, ApplicationResult, register_rule,
8
};
9

            
10
// [ return_expr | i <- A - B ] ~~> [ return_expr | i <- A, !(i in B) ]
11
#[register_rule("Base", 8700)]
12
1965557
fn difference_set(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
13
1965557
    match expr {
14
16176
        Expr::Comprehension(_, comp) => {
15
            // find if any of the generators are generating from expressions
16
26955
            for qualifier in &comp.qualifiers {
17
26955
                if let ComprehensionQualifier::ExpressionGenerator { ptr } = qualifier {
18
76
                    let gen_decl = ptr.clone();
19

            
20
                    // match on expression being of form A - B
21
76
                    let Some((a, b)) = (match ptr.as_quantified_expr() {
22
76
                        Some(expr_guard) => match &*expr_guard {
23
2
                            Expr::Minus(_, a, b) => Some((a.clone(), b.clone())),
24
74
                            _ => None,
25
                        },
26
                        None => None,
27
                    }) else {
28
74
                        continue;
29
                    };
30

            
31
                    // [ return_expr | i <- A, !(i in B), guards...]
32
2
                    let (mut comprehension, a_ptr) =
33
2
                        replace_expression_generator_source(comp.as_ref(), &gen_decl, a.into());
34

            
35
                    // add the condition !(i in B)
36
2
                    comprehension
37
2
                        .qualifiers
38
2
                        .push(ComprehensionQualifier::Condition(Expr::Not(
39
2
                            Metadata::new(),
40
2
                            Moo::new(Expr::In(
41
2
                                Metadata::new(),
42
2
                                Moo::new(Expr::Atomic(Metadata::new(), Atom::new_ref(a_ptr))),
43
2
                                b,
44
2
                            )),
45
2
                        )));
46

            
47
2
                    return Ok(Reduction::pure(Expr::Comprehension(
48
2
                        Metadata::new(),
49
2
                        comprehension.into(),
50
2
                    )));
51
26879
                }
52
            }
53

            
54
16174
            Err(RuleNotApplicable)
55
        }
56
1949381
        _ => Err(RuleNotApplicable),
57
    }
58
1965557
}