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
285624
fn substitute_value_lettings(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
21
114912
    let Expr::Atomic(_, Atom::Reference(name)) = expr else {
22
214416
        return Err(RuleNotApplicable);
23
    };
24

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

            
28
108
    Ok(Reduction::pure(value.clone()))
29
285624
}
30

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

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

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

            
53
5184324
        new_symbols.update_insert(decl);
54
    }
55
285624
    if has_changed {
56
72
        Ok(Reduction::with_symbols(expr.clone(), new_symbols))
57
    } else {
58
285552
        Err(RuleNotApplicable)
59
    }
60
285624
}