1
use super::errors::ReprUpError;
2
use super::types::LookupFn;
3
use crate::ast::{GroundDomain, Literal, Name};
4
use conjure_cp_core::ast::DeclarationPtr;
5
use std::collections::HashMap;
6

            
7
339464761
pub fn try_up_via(decl: DeclarationPtr, lu: &LookupFn<'_>) -> Result<Literal, ReprUpError> {
8
    // Look up the variable directly
9
339464761
    if let Some(mut result) = lu(&decl) {
10
276871280
        if decl
11
276871280
            .domain()
12
276871280
            .and_then(|domain| domain.resolve().ok())
13
276871280
            .is_some_and(|domain| domain.as_ref() == &GroundDomain::Bool)
14
        {
15
274186272
            result = match result {
16
215601536
                Literal::Int(0) => Literal::Bool(false),
17
58509684
                Literal::Int(1) => Literal::Bool(true),
18
75052
                result => result,
19
            };
20
2685008
        }
21
276871280
        return Ok(result);
22
62593481
    }
23

            
24
    // Variable not mapped to a value and has no representations
25
62593481
    let reprs = decl.reprs();
26
62593481
    if reprs.is_empty() {
27
45240
        return Err(ReprUpError::NotFound(decl.clone()));
28
62548241
    }
29

            
30
    // Go up via the first representation
31
62548241
    let mut itr = reprs.iter();
32
62548241
    let (_fst_name, fst) = itr.next().expect("checked that reprs is non-empty");
33
62548241
    let fst_res = fst.up_via(lu)?;
34

            
35
    // In debug mode, check that all other representations agree
36
    #[cfg(debug_assertions)]
37
62503001
    for (repr_name, repr) in itr {
38
        let res = repr.up_via(lu)?;
39
        assert_eq!(
40
            res,
41
            fst_res,
42
            "representations `{}` and `{}` disagree for variable `{}`",
43
            _fst_name,
44
            repr_name,
45
            decl.name()
46
        );
47
    }
48

            
49
62503001
    Ok(fst_res)
50
339464761
}
51

            
52
33556285
pub fn try_up(
53
33556285
    decl: DeclarationPtr,
54
33556285
    raw_assignment: &HashMap<Name, Literal>,
55
33556285
) -> Result<Literal, ReprUpError> {
56
    let lu: LookupFn<'_> =
57
338025895
        Box::new(|decl: &DeclarationPtr| raw_assignment.get(&decl.name()).cloned());
58
33556285
    try_up_via(decl, &lu)
59
33556285
}
60

            
61
#[cfg(test)]
62
mod tests {
63
    use super::*;
64
    use crate::ast::{DeclarationPtr, Domain};
65
    use crate::{domain_int, range};
66

            
67
    #[test]
68
1
    fn represented_boolean_leaf_coerces_minion_zero_one_values() {
69
1
        let declaration = DeclarationPtr::new_find(Name::user("flag"), Domain::bool());
70
1
        let lookup: LookupFn<'_> = Box::new(|_| Some(Literal::Int(1)));
71
1
        assert_eq!(
72
1
            try_up_via(declaration, &lookup).unwrap(),
73
1
            Literal::Bool(true)
74
        );
75
1
    }
76

            
77
    #[test]
78
1
    fn integer_zero_one_leaf_remains_an_integer() {
79
1
        let declaration = DeclarationPtr::new_find(Name::user("value"), domain_int!(0..1));
80
1
        let lookup: LookupFn<'_> = Box::new(|_| Some(Literal::Int(1)));
81
1
        assert_eq!(try_up_via(declaration, &lookup).unwrap(), Literal::Int(1));
82
1
    }
83
}