1
use std::sync::atomic::Ordering;
2

            
3
use std::sync::atomic::AtomicUsize;
4
use tree_morph::prelude::*;
5
use uniplate::Uniplate;
6

            
7
static GLOBAL_RULE_CHECKS: AtomicUsize = AtomicUsize::new(0);
8

            
9
#[derive(Debug, Clone, PartialEq, Eq, Uniplate)]
10
#[uniplate()]
11
enum Expr {
12
    Add(Box<Expr>, Box<Expr>),
13
    Mul(Box<Expr>, Box<Expr>),
14
    Sub(Box<Expr>, Box<Expr>),
15
    Val(i32),
16
}
17

            
18
fn rule_eval_add(_: &mut Commands<Expr, Meta>, expr: &Expr, _: &Meta) -> Option<Expr> {
19
    match expr {
20
        Expr::Add(a, b) => match (a.as_ref(), b.as_ref()) {
21
            (Expr::Val(x), Expr::Val(y)) => Some(Expr::Val(x + y)),
22
            _ => None,
23
        },
24
        _ => None,
25
    }
26
}
27

            
28
fn rule_eval_mul(_: &mut Commands<Expr, Meta>, expr: &Expr, _: &Meta) -> Option<Expr> {
29
    match expr {
30
        Expr::Mul(a, b) => match (a.as_ref(), b.as_ref()) {
31
            (Expr::Val(x), Expr::Val(y)) => Some(Expr::Val(x * y)),
32
            _ => None,
33
        },
34
        _ => None,
35
    }
36
}
37

            
38
enum MyRule {
39
    EvalAdd,
40
    EvalMul,
41
}
42

            
43
struct Meta {
44
    num_applications: u32,
45
}
46

            
47
impl Rule<Expr, Meta> for MyRule {
48
    fn apply(&self, cmd: &mut Commands<Expr, Meta>, expr: &Expr, meta: &Meta) -> Option<Expr> {
49
        cmd.mut_meta(Box::new(|m: &mut Meta| m.num_applications += 1)); // Only applied if successful
50
        // THIS IS FOR TESTING ONLY
51
        // Not meant to integrated into the main code.
52
        GLOBAL_RULE_CHECKS.fetch_add(1, Ordering::Relaxed);
53
        match self {
54
            MyRule::EvalAdd => rule_eval_add(cmd, expr, meta),
55
            MyRule::EvalMul => rule_eval_mul(cmd, expr, meta),
56
        }
57
    }
58
}
59

            
60
#[test]
61
fn left_branch_clean() {
62
    // Top Level is +
63
    // Left Branch has two Nested Subtractions which do not have any rules
64
    // So atoms
65
    // Right brigh has Mul and Add which DO have rules
66
    let expr = Expr::Add(
67
        Box::new(Expr::Sub(
68
            Box::new(Expr::Val(1)),
69
            Box::new(Expr::Val(1)),
70
            // Box::new(Expr::Sub(Box::new(Expr::Val(1)), Box::new(Expr::Val(2)))),
71
            // Box::new(Expr::Sub(Box::new(Expr::Val(3)), Box::new(Expr::Val(10)))),
72
        )),
73
        Box::new(Expr::Mul(Box::new(Expr::Val(10)), Box::new(Expr::Val(5)))),
74
    );
75

            
76
    let meta = Meta {
77
        num_applications: 0,
78
    };
79

            
80
    let engine = EngineBuilder::new()
81
        .add_rule_group(vec![MyRule::EvalAdd, MyRule::EvalMul])
82
        .build();
83
    let (expr, meta) = engine.morph(expr, meta);
84

            
85
    println!("RAN TESTS");
86
    println!("Number of applications: {}", meta.num_applications);
87
    println!(
88
        "Number of Rule Application Checks {}",
89
        GLOBAL_RULE_CHECKS.load(Ordering::Relaxed)
90
    );
91
    dbg!(expr);
92
}