Rule

Trait Rule 

Source
pub trait Rule<T: Uniplate, M> {
    // Required method
    fn apply(
        &self,
        commands: &mut Commands<T, M>,
        subtree: &T,
        meta: &M,
    ) -> Option<T>;
}
Expand description

Trait implemented by rules to transform parts of a tree.

Rules contain a method apply which accepts a Commands instance, a subtree, and global metadata. If the rule is applicable to the subtree, it should return Some(<new_tree>), otherwise it should return None.

§Rule Application

As the engine traverses the tree (in left-most, outer-most order), it will apply rules to each node. The subtree argument passed to the rule is the current node being visited.

If a rule is applicable to the given node/subtree (i.e. can transform it), then it should return the resulting new subtree, which will be inserted into the tree in place of the original node.

§Side-Effects

The Commands instance passed to the rule can be used to apply side-effects after the rule has been applied. This can be used to update global metadata, or to apply transformations to the entire tree.

§Global Metadata

In contrast to the subtree argument given to rules, the meta argument is a reference to a global value which is available to all rules regardless of where in the tree they are applied. This user-defined value can be used to store information such as a symbol table, or the number of times a specific rule has been applied.

The global metadata may be mutated as a side-effect of applying a rule, using the Commands::mut_meta method.

§Provided Implementations

This trait is automatically implemented by all types which implement Fn(&mut Commands<T, M>, &T, &M) -> Option<T> for types T: Uniplate and M. This allows function pointers and closures with the correct signatures to be used as rules directly.

§Example

use tree_morph::prelude::*;
use uniplate::Uniplate;


#[derive(Debug, Clone, PartialEq, Eq, Uniplate)]
#[uniplate()]
enum Term {
    A,
    B,
}

// Functions and closures automatically implement the Rule trait
fn my_rule_fn(_: &mut Commands<Term, ()>, _: &Term, _: &()) -> Option<Term> {
    None // Never applicable
}

let engine = EngineBuilder::new()
    .add_rule_group(rule_fns![my_rule_fn])
    .build();
let (result, _) = engine.morph(Term::A, ());
assert_eq!(result, Term::A);


// Custom types can implement the Rule trait to allow more complex behaviour
// Here a rule can be "toggled" to change whether it is applicable
struct CustomRule(bool);

impl Rule<Term, ()> for CustomRule {
    fn apply(&self, _: &mut Commands<Term, ()>, t: &Term, _: &()) -> Option<Term> {
        if self.0 && matches!(t, Term::A) {
            Some(Term::B)
        } else {
            None
        }
    }
}

let engine = EngineBuilder::new()
    .add_rule(CustomRule(false))
    .build();
let (result, _) = engine.morph(Term::A, ());
assert_eq!(result, Term::A);

let engine = EngineBuilder::new()
    .add_rule(CustomRule(true))
    .build();
let (result, _) = engine.morph(Term::A, ());
assert_eq!(result, Term::B);

Required Methods§

Source

fn apply( &self, commands: &mut Commands<T, M>, subtree: &T, meta: &M, ) -> Option<T>

Applies the rule to the given subtree and returns the result if applicable.

See the Rule trait documentation for more information.

Implementors§

Source§

impl<T, M, F> Rule<T, M> for F
where T: Uniplate, F: Fn(&mut Commands<T, M>, &T, &M) -> Option<T>,