1
use std::rc::Rc;
2

            
3
use conjure_macros::register_rule;
4

            
5
use crate::{
6
    ast::{Atom, Domain, Expression as Expr, SymbolTable},
7
    bug,
8
    rule_engine::{ApplicationError::RuleNotApplicable, ApplicationResult, Reduction},
9
};
10

            
11
/// Substitutes value lettings for their values.
12
///
13
/// # Priority
14
///
15
/// This rule must have a higher priority than solver-flattening rules (which should be priority 4000).
16
///
17
/// Otherwise, the letting may be put into a flat constraint, as it is a reference. At this point
18
/// it ceases to be an expression, so we cannot match over it.
19
#[register_rule(("Base", 5000))]
20
206601
fn substitute_value_lettings(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
21
93364
    let Expr::Atomic(_, Atom::Reference(name)) = expr else {
22
148546
        return Err(RuleNotApplicable);
23
    };
24

            
25
58055
    let decl = symbols.lookup(name).ok_or(RuleNotApplicable)?;
26
57936
    let value = decl.as_value_letting().ok_or(RuleNotApplicable)?;
27

            
28
68
    Ok(Reduction::pure(value.clone()))
29
206601
}
30

            
31
/// Substitutes domain lettings for their values in the symbol table.
32
#[register_rule(("Base", 5000))]
33
206601
fn substitute_domain_lettings(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
34
206601
    let mut new_symbols = symbols.clone();
35
206601
    let mut has_changed = false;
36

            
37
3770022
    for (_, mut decl) in symbols.clone().into_iter() {
38
3770022
        let Some(mut var) = decl.as_var().cloned() else {
39
1292
            continue;
40
        };
41

            
42
3768730
        if let Domain::DomainReference(ref d) = var.domain {
43
34
            var.domain = symbols.domain(d).unwrap_or_else(|| {
44
                bug!(
45
                    "rule substitute_domain_lettings: domain reference {} does not exist",
46
                    d
47
                )
48
34
            });
49
34
            *(Rc::make_mut(&mut decl).as_var_mut().unwrap()) = var;
50
34
            has_changed = true;
51
3768696
        };
52

            
53
3768730
        new_symbols.update_insert(decl);
54
    }
55
206601
    if has_changed {
56
17
        Ok(Reduction::with_symbols(expr.clone(), new_symbols))
57
    } else {
58
206584
        Err(RuleNotApplicable)
59
    }
60
206601
}