MIT Latest Version docs Chat on Miaou

A simple binary expression tree, for parsing and preparing expressions which can be executed on dynamic contents.

An expression is built by calling the push_operator, open_par, close_par and push_atom functions.

It can then be evaluated with the eval function which takes as parameters

Normal evaluation order is left to right but is modified with parenthesis.

This library is very young. Contact me if you think it might be useful to you. I might then consider some additions (for example to deal with optional operator precedence if somebody needs it).

Example : parsing and evaluating boolean expressions

Here we parse the "(A | B) & !(C | D | E)" expression and evaluate it with different values of the A to E variables.

Then two other expressions are evaluated to display how parenthesis and evaluation work.

``` use bet::*;

/// The operators in this example are AND, OR, and NOT operating on booleans. /// And and Or are binary while Not is unary. /// Note that bet doesn't prevent an operator from being usable in both /// unary and binary contexts.

[derive(Debug, Clone, Copy, PartialEq)]

enum BoolOperator { And, Or, Not, } type BoolErr = &'static str; impl BoolOperator { fn eval(self, a: bool, b: Option) -> Result { match (self, b) { (Self::And, Some(b)) => Ok(a & b), (Self::Or, Some(b)) => Ok(a | b), (Self::Not, None) => Ok(!a), _ => { Err("unexpected operation") } } } }

fn parse(input: &str) -> BeTree { let mut expr = BeTree::new(); for c in input.chars() { match c { '&' => expr.pushoperator(BoolOperator::And), '|' => expr.pushoperator(BoolOperator::Or), '!' => expr.pushoperator(BoolOperator::Not), ' ' => {}, '(' => expr.openpar(), ')' => expr.closepar(), _ => expr.pushatom(c), } } expr }

let expr = parse("(A | B) & !(C | D | E)"); asserteq!( expr.eval( |&c| Ok(c=='A'||c=='C'||c=='E'), |op, a, b| op.eval(a, b), ), Ok(Some(false)), ); asserteq!( expr.eval( |&c| Ok(c=='A'||c=='B'), |op, a, b| op.eval(a, b), ), Ok(Some(true)), );

// Let's show the left to right evaluation order // and importance of parenthesis asserteq!( parse("(A & B) | (C & D)").eval( |&c| Ok(c=='A' || c=='B' || c=='C'), |op, a, b| op.eval(a, b), ), Ok(Some(true)), ); asserteq!( parse("A & B | C & D").eval( |&c| Ok(c=='A' || c=='B' || c=='C'), |op, a, b| op.eval(a, b), ), Ok(Some(false)), );

```