bexeval 0.1.2

bexeval is a Rust crate for evaluating string formulas restricted to values as integers only.
Documentation
use bexeval::*;

macro_rules! op_test {
    ($t:ty, $name: ident) => {
        #[test]
        fn $name() {
            let v: Vec<(i32, i32)> = vec![(-5, 3), (5, -3), (3, 3), (-2, -2)];
            let parser = Parser::<$t>::new();
            for &(x_, y_) in &v {
                let (x, y) = (x_ as $t, y_ as $t);
                assert_eq!(parser.eval(&format!("{} + {}", x, y)).unwrap(), x.wrapping_add(y));
                assert_eq!(parser.eval(&format!("{} - {}", x, y)).unwrap(), x.wrapping_sub(y));
                assert_eq!(parser.eval(&format!("{} * {}", x, y)).unwrap(), x.wrapping_mul(y));
                assert_eq!(parser.eval(&format!("{} / {}", x, y)).unwrap(), x / y);
                assert_eq!(parser.eval(&format!("{} % {}", x, y)).unwrap(), x % y);
                assert_eq!(parser.eval(&format!("{} & {}", x, y)).unwrap(), x & y);
                assert_eq!(parser.eval(&format!("{} | {}", x, y)).unwrap(), x | y);
                assert_eq!(parser.eval(&format!("{} ^ {}", x, y)).unwrap(), x ^ y);
                assert_eq!(parser.eval(&format!("{} << {}", x, y)).unwrap(), x.wrapping_shl(y as u32));
                assert_eq!(parser.eval(&format!("{} >> {}", x, y)).unwrap(), x.wrapping_shr(y as u32));
                assert_eq!(parser.eval(&format!("-{}", x)).unwrap(), x.wrapping_neg());
                assert_eq!(parser.eval(&format!("!{}", x)).unwrap(), !x);
            }

            for &(x_, y_) in &v {
                let (x, y) = (x_ as $t, y_ as $t);
                assert_eq!(parser.eval(&format!("{} == {}", x, y)).unwrap(), (x == y) as $t);
                assert_eq!(parser.eval(&format!("{} != {}", x, y)).unwrap(), (x != y) as $t);
                assert_eq!(parser.eval(&format!("{} < {}", x, y)).unwrap(), (x < y) as $t);
                assert_eq!(parser.eval(&format!("{} <= {}", x, y)).unwrap(), (x <= y) as $t);
                assert_eq!(parser.eval(&format!("{} > {}", x, y)).unwrap(), (x > y) as $t);
                assert_eq!(parser.eval(&format!("{} >= {}", x, y)).unwrap(), (x >= y) as $t);
            }

            for &(x_, y_) in &v {
                let (x, y) = (x_ as $t, y_ as $t);
                assert_eq!(parser.eval(&format!("max({}, {})", x, y)).unwrap(), x.max(y));
                assert_eq!(parser.eval(&format!("min({}, {})", x, y)).unwrap(), x.min(y));
                assert_eq!(parser.eval(&format!("pow({}, {})", x, y)).unwrap(), x.wrapping_pow(y as u32));
                assert_eq!(parser.eval(&format!("count_ones({})", x)).unwrap(), x.count_ones() as $t);
                assert_eq!(parser.eval(&format!("count_zeros({})", x)).unwrap(), x.count_zeros() as $t);
                assert_eq!(parser.eval(&format!("leading_zeros({})", x)).unwrap(), x.leading_zeros() as $t);
                assert_eq!(parser.eval(&format!("trailing_zeros({})", x)).unwrap(), x.trailing_zeros() as $t);
                assert_eq!(parser.eval(&format!("abs({})", x)).unwrap(), if x > 0 {x} else {x.wrapping_neg()});
                assert_eq!(parser.eval(&format!("abs_diff({}, {})", x, y)).unwrap(), x.abs_diff(y) as $t);
                assert_eq!(parser.eval(&format!("rotate_left({}, {})", x, y)).unwrap(), x.rotate_left(y as u32) as $t);
                assert_eq!(parser.eval(&format!("rotate_right({}, {})", x, y)).unwrap(), x.rotate_right(y as u32) as $t);
            }

            assert_eq!(
                parser.eval("1 + 2 * 3 % 4 << 5 == 96 ^ 6 & 7 | !32").unwrap(),
                ((1 as $t + 2 * 3 % 4).wrapping_shl(5 as u32) == 96) as $t ^ 6 & 7 | !32
            );

            assert_eq!(
                parser.eval_context("-32 + x", &[("x", parser.eval("1 << 5").unwrap())]).unwrap(),
                0
            );
        }
    }
}

op_test!(i8, parser_test_i8);
op_test!(i16, parser_test_i16);
op_test!(i32, parser_test_i32);
op_test!(i64, parser_test_i64);
op_test!(isize, parser_test_isize);
op_test!(u8, parser_test_u8);
op_test!(u16, parser_test_u16);
op_test!(u32, parser_test_u32);
op_test!(u64, parser_test_u64);
op_test!(usize, parser_test_usize);

#[test]
fn context_test() {
    let mut ctx = Context::<i32>::new();
    ctx.assign("x", ctx.eval("2 + 3 * 5").unwrap());
    assert_eq!(ctx.eval("x + 3").unwrap(), 20);
    ctx.assign_stmt("y = x + 5").unwrap();
    assert_eq!(ctx.eval("y + x * 2").unwrap(), 56);

    ctx.assign("y", ctx.eval("y * 2").unwrap());
    assert_eq!(ctx.eval("y + 6").unwrap(), 50);
}