Skip to main content

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>;

    // Provided methods
    fn name(&self) -> &str { ... }
    fn applicable_to(&self) -> Option<Vec<usize>> { ... }
}
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 mut 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
#[derive(Clone)]
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 mut engine = EngineBuilder::new()
    .add_rule(CustomRule(false))
    .build();
let (result, _) = engine.morph(Term::A, ());
assert_eq!(result, Term::A);

let mut 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.

Provided Methods§

Source

fn name(&self) -> &str

Return the name of the rule, will default to anonymous if not specified.

Source

fn applicable_to(&self) -> Option<Vec<usize>>

None -> Rule applies to all nodes Some(ids) -> Rule only applies to nodes with these discriminant ids

Implementors§

Source§

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

Source§

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