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::derive::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
enum MyRule {
35
    EvalAdd,
36
    EvalMul,
37
}
38

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

            
49
struct Meta {
50
    num_applications: u32,
51
}
52

            
53
#[test]
54
1
fn single_var() {
55
1
    let expr = Expr::Val(42);
56
1
    let meta = Meta {
57
1
        num_applications: 0,
58
1
    };
59
1
    let (expr, meta) = morph(
60
1
        vec![vec![MyRule::EvalAdd, MyRule::EvalMul]],
61
1
        select_first,
62
1
        expr,
63
1
        meta,
64
1
    );
65
1
    assert_eq!(expr, Expr::Val(42));
66
1
    assert_eq!(meta.num_applications, 0);
67
1
}
68

            
69
#[test]
70
1
fn add_zero() {
71
1
    let expr = Expr::Add(Box::new(Expr::Val(0)), Box::new(Expr::Val(42)));
72
1
    let meta = Meta {
73
1
        num_applications: 0,
74
1
    };
75
1
    let (expr, meta) = morph(
76
1
        vec![vec![MyRule::EvalAdd, MyRule::EvalMul]],
77
1
        select_first,
78
1
        expr,
79
1
        meta,
80
1
    );
81
1
    assert_eq!(expr, Expr::Val(42));
82
1
    assert_eq!(meta.num_applications, 1);
83
1
}
84

            
85
#[test]
86
1
fn mul_one() {
87
1
    let expr = Expr::Mul(Box::new(Expr::Val(1)), Box::new(Expr::Val(42)));
88
1
    let meta = Meta {
89
1
        num_applications: 0,
90
1
    };
91
1
    let (expr, meta) = morph(
92
1
        vec![vec![MyRule::EvalAdd, MyRule::EvalMul]],
93
1
        select_first,
94
1
        expr,
95
1
        meta,
96
1
    );
97
1
    assert_eq!(expr, Expr::Val(42));
98
1
    assert_eq!(meta.num_applications, 1);
99
1
}
100

            
101
#[test]
102
1
fn eval_add() {
103
1
    let expr = Expr::Add(Box::new(Expr::Val(1)), Box::new(Expr::Val(2)));
104
1
    let meta = Meta {
105
1
        num_applications: 0,
106
1
    };
107
1
    let (expr, meta) = morph(
108
1
        vec![vec![MyRule::EvalAdd, MyRule::EvalMul]],
109
1
        select_first,
110
1
        expr,
111
1
        meta,
112
1
    );
113
1
    assert_eq!(expr, Expr::Val(3));
114
1
    assert_eq!(meta.num_applications, 1);
115
1
}
116

            
117
#[test]
118
1
fn eval_nested() {
119
1
    let expr = Expr::Mul(
120
1
        Box::new(Expr::Add(Box::new(Expr::Val(1)), Box::new(Expr::Val(2)))),
121
1
        Box::new(Expr::Val(3)),
122
1
    );
123
1
    let meta = Meta {
124
1
        num_applications: 0,
125
1
    };
126
1
    let (expr, meta) = morph(
127
1
        vec![vec![MyRule::EvalAdd, MyRule::EvalMul]],
128
1
        select_first,
129
1
        expr,
130
1
        meta,
131
1
    );
132
1
    assert_eq!(expr, Expr::Val(9));
133
1
    assert_eq!(meta.num_applications, 2);
134
1
}