1
use conjure_cp::rule_engine::SubmodelZipper;
2
use conjure_cp::{
3
    ast::{Expression, SymbolTable},
4
    rule_engine::{ApplicationError::RuleNotApplicable, ApplicationResult, Reduction},
5
};
6

            
7
/// Converts the rule function `rule` to a rule that applies `rule` bottom-up to every expression
8
/// in the current sub-model.
9
202265
pub fn as_bottom_up(
10
202265
    rule: impl Fn(&Expression, &SymbolTable) -> ApplicationResult,
11
202265
) -> impl Fn(&Expression, &SymbolTable) -> ApplicationResult {
12
202265
    Box::new(move |expr: &Expression, symbols: &SymbolTable| {
13
        // global rule
14
202265
        if !matches!(expr, Expression::Root(_, _)) {
15
194296
            return Err(RuleNotApplicable);
16
7969
        };
17

            
18
        // traverse bottom up within the current sub-model, applying the rule.
19
7969
        let mut symbols = symbols.clone();
20
7969
        let mut new_tops = vec![];
21
7969
        let mut done_something = false;
22

            
23
7969
        let mut zipper = SubmodelZipper::new(expr.clone());
24

            
25
25715
        while zipper.go_down().is_some() {}
26

            
27
        loop {
28
            // go right and to the bottom of that subtree
29
            //
30
            // once we have ran out of siblings, go_up.
31
207794
            if zipper.go_right().is_some() {
32
182079
                while zipper.go_down().is_some() {}
33
95630
            } else if zipper.go_up().is_none() {
34
                // cannot go up anymore, at the root
35
7969
                break;
36
87661
            }
37

            
38
199825
            let expr = zipper.focus();
39

            
40
199825
            if let Ok(mut reduction) = rule(expr, &symbols) {
41
906
                zipper.replace_focus(reduction.new_expression);
42
906
                symbols.extend(reduction.symbols);
43
906
                new_tops.append(&mut reduction.new_top);
44
906
                done_something = true;
45
198919
            }
46
        }
47

            
48
7969
        let root_expr = zipper.rebuild_root();
49

            
50
7969
        if done_something {
51
243
            Ok(Reduction::new(root_expr, new_tops, symbols))
52
        } else {
53
7726
            Err(RuleNotApplicable)
54
        }
55
202265
    })
56
202265
}