1
//! These tests use a simple constant expression tree to demonstrate the use of the `gen_reduce` crate.
2

            
3
use tree_morph::prelude::*;
4
use uniplate::Uniplate;
5

            
6
#[derive(Debug, Clone, PartialEq, Eq, Uniplate)]
7
#[uniplate()]
8
enum Expr {
9
    Add(Box<Expr>, Box<Expr>),
10
    Mul(Box<Expr>, Box<Expr>),
11
    Val(i32),
12
}
13

            
14
11
fn rule_eval_add(_: &mut Commands<Expr, Meta>, expr: &Expr, _: &Meta) -> Option<Expr> {
15
11
    match expr {
16
3
        Expr::Add(a, b) => match (a.as_ref(), b.as_ref()) {
17
3
            (Expr::Val(x), Expr::Val(y)) => Some(Expr::Val(x + y)),
18
            _ => None,
19
        },
20
8
        _ => None,
21
    }
22
11
}
23

            
24
11
fn rule_eval_mul(_: &mut Commands<Expr, Meta>, expr: &Expr, _: &Meta) -> Option<Expr> {
25
11
    match expr {
26
3
        Expr::Mul(a, b) => match (a.as_ref(), b.as_ref()) {
27
2
            (Expr::Val(x), Expr::Val(y)) => Some(Expr::Val(x * y)),
28
1
            _ => None,
29
        },
30
8
        _ => None,
31
    }
32
11
}
33

            
34
#[derive(Clone)]
35
enum MyRule {
36
    EvalAdd,
37
    EvalMul,
38
}
39

            
40
impl Rule<Expr, Meta> for MyRule {
41
22
    fn apply(&self, cmd: &mut Commands<Expr, Meta>, expr: &Expr, meta: &Meta) -> Option<Expr> {
42
22
        cmd.mut_meta(Box::new(|m: &mut Meta| m.num_applications += 1)); // Only applied if successful
43
22
        match self {
44
11
            MyRule::EvalAdd => rule_eval_add(cmd, expr, meta),
45
11
            MyRule::EvalMul => rule_eval_mul(cmd, expr, meta),
46
        }
47
22
    }
48
}
49

            
50
#[derive(Debug)]
51
struct Meta {
52
    num_applications: u32,
53
}
54

            
55
#[test]
56
1
fn single_var() {
57
1
    let expr = Expr::Val(42);
58
1
    let meta = Meta {
59
1
        num_applications: 0,
60
1
    };
61

            
62
1
    let mut engine = EngineBuilder::new()
63
1
        .add_rule_group(vec![MyRule::EvalAdd, MyRule::EvalMul])
64
1
        .build();
65
1
    let (expr, meta) = engine.morph(expr, meta);
66

            
67
1
    assert_eq!(expr, Expr::Val(42));
68
1
    assert_eq!(meta.num_applications, 0);
69
1
}
70

            
71
#[test]
72
1
fn add_zero() {
73
1
    let expr = Expr::Add(Box::new(Expr::Val(0)), Box::new(Expr::Val(42)));
74
1
    let meta = Meta {
75
1
        num_applications: 0,
76
1
    };
77

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

            
83
1
    assert_eq!(expr, Expr::Val(42));
84
1
    assert_eq!(meta.num_applications, 1);
85
1
}
86

            
87
#[test]
88
1
fn mul_one() {
89
1
    let expr = Expr::Mul(Box::new(Expr::Val(1)), Box::new(Expr::Val(42)));
90
1
    let meta = Meta {
91
1
        num_applications: 0,
92
1
    };
93

            
94
1
    let mut engine = EngineBuilder::new()
95
1
        .add_rule_group(vec![MyRule::EvalAdd, MyRule::EvalMul])
96
1
        .build();
97
1
    let (expr, meta) = engine.morph(expr, meta);
98

            
99
1
    assert_eq!(expr, Expr::Val(42));
100
1
    assert_eq!(meta.num_applications, 1);
101
1
}
102

            
103
#[test]
104
1
fn eval_add() {
105
1
    let expr = Expr::Add(Box::new(Expr::Val(1)), Box::new(Expr::Val(2)));
106
1
    let meta = Meta {
107
1
        num_applications: 0,
108
1
    };
109

            
110
1
    let mut engine = EngineBuilder::new()
111
1
        .add_rule_group(vec![MyRule::EvalAdd, MyRule::EvalMul])
112
1
        .build();
113
1
    let (expr, meta) = engine.morph(expr, meta);
114

            
115
1
    assert_eq!(expr, Expr::Val(3));
116
1
    assert_eq!(meta.num_applications, 1);
117
1
}
118

            
119
#[test]
120
1
fn eval_nested() {
121
1
    let expr = Expr::Mul(
122
1
        Box::new(Expr::Add(Box::new(Expr::Val(1)), Box::new(Expr::Val(2)))),
123
1
        Box::new(Expr::Val(3)),
124
1
    );
125
1
    let meta = Meta {
126
1
        num_applications: 0,
127
1
    };
128

            
129
1
    let mut engine = EngineBuilder::new()
130
1
        .add_rule_group(vec![MyRule::EvalAdd, MyRule::EvalMul])
131
1
        .build();
132
1
    let (expr, meta) = engine.morph(expr, meta);
133

            
134
1
    assert_eq!(expr, Expr::Val(9));
135
1
    assert_eq!(meta.num_applications, 2);
136
1
}