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(Box::new(|m: &mut Meta| 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
struct Meta {
49
    num_applications: u32,
50
}
51

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

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

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

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

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