From b3be7f600c138b0590cb7bc30d550bd8bae9b50e Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 30 Jul 2021 17:06:23 +0300 Subject: [PATCH] Implement bitwise operators as builtin functions. Relates to #88 --- CHANGELOG.md | 2 ++ README.md | 4 ++++ src/function/builtin.rs | 22 ++++++++++++++++++++++ src/lib.rs | 4 ++++ tests/integration.rs | 8 ++++++++ 5 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b37f94..1570a62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Added + * Bitwise operators as builtin functions `bitand`, `bitor`, `bitxor`, `bitnot` (#88) + ### Removed ### Changed diff --git a/README.md b/README.md index 0b740b5..5e7b628 100644 --- a/README.md +++ b/README.md @@ -373,6 +373,10 @@ This crate offers a set of builtin functions. | `str::to_uppercase` | 1 | String | Returns the upper-case version of the string | | `str::trim` | 1 | String | Strips whitespace from the start and the end of the string | | `str::from` | >= 0 | Any | Returns passed value as string | +| `bitand` | 2 | Int | Computes the bitwise and of the given integers | +| `bitor` | 2 | Int | Computes the bitwise or of the given integers | +| `bitxor` | 2 | Int | Computes the bitwise xor of the given integers | +| `bitnot` | 1 | Int | Computes the bitwise not of the given integer | The `min` and `max` functions can deal with a mixture of integer and floating point arguments. If the maximum or minimum is an integer, then an integer is returned. diff --git a/src/function/builtin.rs b/src/function/builtin.rs index 48a9677..fd65e8e 100644 --- a/src/function/builtin.rs +++ b/src/function/builtin.rs @@ -5,6 +5,7 @@ use crate::{ value::{FloatType, IntType}, EvalexprError, Function, Value, ValueType, }; +use std::ops::{BitAnd, BitOr, BitXor, Not}; macro_rules! simple_math { ($func:ident) => { @@ -22,6 +23,22 @@ macro_rules! simple_math { }; } +macro_rules! int_function { + ($func:ident) => { + Some(Function::new(|argument| { + let int = argument.as_int()?; + Ok(Value::Int(int.$func())) + })) + }; + ($func:ident, 2) => { + Some(Function::new(|argument| { + let tuple = argument.as_fixed_len_tuple(2)?; + let (a, b) = (tuple[0].as_int()?, tuple[1].as_int()?); + Ok(Value::Int(a.$func(b))) + })) + }; +} + pub fn builtin_function(identifier: &str) -> Option { match identifier { // Log @@ -163,6 +180,11 @@ pub fn builtin_function(identifier: &str) -> Option { "str::from" => Some(Function::new(|argument| { Ok(Value::String(argument.to_string())) })), + // Bitwise operators + "bitand" => int_function!(bitand, 2), + "bitor" => int_function!(bitor, 2), + "bitxor" => int_function!(bitxor, 2), + "bitnot" => int_function!(not), _ => None, } } diff --git a/src/lib.rs b/src/lib.rs index 918fd76..f931cfa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -356,6 +356,10 @@ //! | `str::to_uppercase` | 1 | String | Returns the upper-case version of the string | //! | `str::trim` | 1 | String | Strips whitespace from the start and the end of the string | //! | `str::from` | >= 0 | Any | Returns passed value as string | +//! | `bitand` | 2 | Int | Computes the bitwise and of the given integers | +//! | `bitor` | 2 | Int | Computes the bitwise or of the given integers | +//! | `bitxor` | 2 | Int | Computes the bitwise xor of the given integers | +//! | `bitnot` | 1 | Int | Computes the bitwise not of the given integer | //! //! The `min` and `max` functions can deal with a mixture of integer and floating point arguments. //! If the maximum or minimum is an integer, then an integer is returned. diff --git a/tests/integration.rs b/tests/integration.rs index 318be2a..9d536c2 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -395,6 +395,14 @@ fn test_builtin_functions() { Ok(Value::String(String::from("(1, 2, 3)"))) ); assert_eq!(eval("str::from()"), Ok(Value::String(String::from("()")))); + assert_eq!(eval("bitand(5, -1)"), Ok(Value::Int(5))); + assert_eq!(eval("bitand(6, 5)"), Ok(Value::Int(4))); + assert_eq!(eval("bitor(5, -1)"), Ok(Value::Int(-1))); + assert_eq!(eval("bitor(6, 5)"), Ok(Value::Int(7))); + assert_eq!(eval("bitxor(5, -1)"), Ok(Value::Int(-6))); + assert_eq!(eval("bitxor(6, 5)"), Ok(Value::Int(3))); + assert_eq!(eval("bitnot(5)"), Ok(Value::Int(-6))); + assert_eq!(eval("bitnot(-1)"), Ok(Value::Int(0))); } #[test]