1
use conjure_cp::{
2
    ast::{Domain, Expression as Expr, Metadata, Moo, Range, SymbolTable},
3
    matrix_expr,
4
    rule_engine::{
5
        ApplicationError::RuleNotApplicable, ApplicationResult, RuleEffect, register_rule,
6
    },
7
};
8

            
9
/// `catchUndef({v @ c}, d)` ~~> `[d, v][toInt(c)]`.
10
///
11
/// The bubble rules turn a partial expression into its total form guarded by a definedness
12
/// condition, which is exactly what `catchUndef` needs: pick the value where the condition holds
13
/// and the default where it does not.
14
#[register_rule("Base", 8800, [CatchUndef])]
15
68688
fn catch_undef_bubble(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
16
68688
    let Expr::CatchUndef(_, inner, default) = expr else {
17
4421
        return Err(RuleNotApplicable);
18
    };
19

            
20
64267
    let Expr::Bubble(_, value, condition) = inner.as_ref() else {
21
58898
        return Err(RuleNotApplicable);
22
    };
23

            
24
5369
    let value = Moo::unwrap_or_clone(Moo::clone(value));
25
5369
    let condition = Moo::unwrap_or_clone(Moo::clone(condition));
26
5369
    let default = Moo::unwrap_or_clone(Moo::clone(default));
27

            
28
5369
    Ok(RuleEffect::pure(Expr::UnsafeIndex(
29
5369
        Metadata::new(),
30
5369
        Moo::new(matrix_expr![default, value; Domain::int(vec![Range::Bounded(0, 1)])]),
31
5369
        vec![Expr::ToInt(Metadata::new(), Moo::new(condition))],
32
5369
    )))
33
68688
}
34

            
35
/// `catchUndef(e, d)` ~~> `e` when `e` is total.
36
///
37
/// Nothing wrapped the expression in a bubble, so it is defined everywhere and the default can
38
/// never be reached.
39
#[register_rule("Base", 8700, [CatchUndef])]
40
61994
fn catch_undef_total(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
41
61994
    let Expr::CatchUndef(_, inner, _) = expr else {
42
4083
        return Err(RuleNotApplicable);
43
    };
44

            
45
57911
    if !inner.is_safe() {
46
50498
        return Err(RuleNotApplicable);
47
7413
    }
48

            
49
7413
    Ok(RuleEffect::pure(Moo::unwrap_or_clone(Moo::clone(inner))))
50
61994
}