1
//! Here we test rule groups with differing priorities.
2
//! Rules in a higher-index group will be applied first, even if they apply to lower nodes in the tree.
3

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

            
7
/// A simple language of two literals and a wrapper
8
#[derive(Debug, Clone, PartialEq, Eq, Uniplate)]
9
#[uniplate()]
10
enum Expr {
11
    A,               // a
12
    B,               // b
13
    Wrap(Box<Expr>), // [E]
14
}
15

            
16
/// [a] ~> a
17
fn rule_unwrap_a(_: &mut Commands<Expr, ()>, expr: &Expr, _: &()) -> Option<Expr> {
18
    if let Expr::Wrap(inner) = expr
19
        && let Expr::A = **inner
20
    {
21
        return Some(Expr::A);
22
    }
23
    None
24
}
25

            
26
/// a ~> b
27
fn rule_a_to_b(_: &mut Commands<Expr, ()>, expr: &Expr, _: &()) -> Option<Expr> {
28
    if let Expr::A = expr {
29
        return Some(Expr::B);
30
    }
31
    None
32
}
33

            
34
#[test]
35
fn same_group() {
36
    // If the rules are in the same group, unwrap_a will apply higher in the tree
37

            
38
    // [a]
39
    let expr = Expr::Wrap(Box::new(Expr::A));
40

            
41
    let engine = EngineBuilder::new()
42
        .add_rule(rule_unwrap_a as RuleFn<_, _>)
43
        .add_rule(rule_a_to_b as RuleFn<_, _>)
44
        .build();
45
    let (result, _) = engine.morph(expr, ());
46

            
47
    // [a] ~> a ~> b
48
    assert_eq!(result, Expr::B);
49
}
50

            
51
#[test]
52
fn a_to_b_first() {
53
    // a_to_b is in a higher group than unwrap_a, so it will be applied first to the lower expression
54

            
55
    // [a]
56
    let expr = Expr::Wrap(Box::new(Expr::A));
57

            
58
    let engine = EngineBuilder::new()
59
        .add_rule(rule_a_to_b as RuleFn<_, _>)
60
        .add_rule(rule_unwrap_a as RuleFn<_, _>)
61
        .build();
62
    let (result, _) = engine.morph(expr, ());
63

            
64
    // [a] ~> [b]
65
    assert_eq!(result, Expr::Wrap(Box::new(Expr::B)));
66
}