Add Node shortcut evaluations for Value::Empty

Relates to #28
This commit is contained in:
Sebastian Schmidt 2019-03-28 10:22:04 +01:00
parent a7b5f602d5
commit 7d36ebe8df
5 changed files with 68 additions and 12 deletions

View File

@ -12,7 +12,7 @@ pub(crate) mod builtin;
/// use evalexpr::*; /// use evalexpr::*;
/// ///
/// let mut context = HashMapContext::new(); /// let mut context = HashMapContext::new();
/// context.set_function("id", Function::new(Some(1), Box::new(|arguments| { /// context.set_function("id".into(), Function::new(Some(1), Box::new(|arguments| {
/// Ok(arguments[0].clone()) /// Ok(arguments[0].clone())
/// }))).unwrap(); // Do proper error handling here /// }))).unwrap(); // Do proper error handling here
/// assert_eq!(eval_with_context("id(4)", &context), Ok(Value::from(4))); /// assert_eq!(eval_with_context("id(4)", &context), Ok(Value::from(4)));

View File

@ -282,7 +282,9 @@ pub use error::{EvalexprError, EvalexprResult};
pub use function::Function; pub use function::Function;
pub use interface::*; pub use interface::*;
pub use tree::Node; pub use tree::Node;
pub use value::{EmptyType, FloatType, IntType, TupleType, Value, value_type::ValueType}; pub use value::{
EMPTY_VALUE, EmptyType, FloatType, IntType, TupleType, Value, value_type::ValueType,
};
mod context; mod context;
pub mod error; pub mod error;

View File

@ -1,8 +1,9 @@
use EmptyContext; use EmptyContext;
use EmptyType;
use FloatType; use FloatType;
use IntType; use IntType;
use token::Token; use token::Token;
use value::TupleType; use value::{EMPTY_VALUE, TupleType};
use crate::{ use crate::{
context::Context, context::Context,
@ -145,6 +146,17 @@ impl Node {
} }
} }
/// Evaluates the operator tree rooted at this node into an empty value with an the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_empty_with_context(&self, context: &Context) -> EvalexprResult<EmptyType> {
match self.eval_with_context(context) {
Ok(Value::Empty) => Ok(EMPTY_VALUE),
Ok(value) => Err(EvalexprError::expected_empty(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a string with an the given mutable context. /// Evaluates the operator tree rooted at this node into a string with an the given mutable context.
/// ///
/// Fails, if one of the operators in the expression tree fails. /// Fails, if one of the operators in the expression tree fails.
@ -213,6 +225,17 @@ impl Node {
} }
} }
/// Evaluates the operator tree rooted at this node into an empty value with an the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_empty_with_context_mut(&self, context: &mut Context) -> EvalexprResult<EmptyType> {
match self.eval_with_context_mut(context) {
Ok(Value::Empty) => Ok(EMPTY_VALUE),
Ok(value) => Err(EvalexprError::expected_empty(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a string with an empty context. /// Evaluates the operator tree rooted at this node into a string with an empty context.
/// ///
/// Fails, if one of the operators in the expression tree fails. /// Fails, if one of the operators in the expression tree fails.
@ -256,6 +279,13 @@ impl Node {
self.eval_tuple_with_context(&EmptyContext) self.eval_tuple_with_context(&EmptyContext)
} }
/// Evaluates the operator tree rooted at this node into an empty value with an empty context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_empty(&self) -> EvalexprResult<EmptyType> {
self.eval_empty_with_context(&EmptyContext)
}
fn children(&self) -> &[Node] { fn children(&self) -> &[Node] {
&self.children &self.children
} }

View File

@ -15,6 +15,9 @@ pub type TupleType = Vec<Value>;
/// The type used to represent empty values in `Value::Empty`. /// The type used to represent empty values in `Value::Empty`.
pub type EmptyType = (); pub type EmptyType = ();
/// The value of the empty type to be used in rust.
pub const EMPTY_VALUE: () = ();
/// The value type used by the parser. /// The value type used by the parser.
/// Values can be of different subtypes that are the variants of this enum. /// Values can be of different subtypes that are the variants of this enum.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]

View File

@ -234,7 +234,17 @@ fn test_n_ary_functions() {
"count".into(), "count".into(),
Function::new( Function::new(
None, None,
Box::new(|arguments| Ok(Value::Int(arguments.len() as IntType))), Box::new(|arguments| {
if arguments.len() == 1 {
if arguments[0] == Value::Empty {
Ok(Value::Int(0))
} else {
Ok(Value::Int(1))
}
} else {
Ok(Value::Int(arguments.len() as IntType))
}
}),
), ),
) )
.unwrap(); .unwrap();
@ -259,13 +269,7 @@ fn test_n_ary_functions() {
eval_with_context("muladd(3, 6, -4)", &context), eval_with_context("muladd(3, 6, -4)", &context),
Ok(Value::Int(14)) Ok(Value::Int(14))
); );
assert_eq!( assert_eq!(eval_with_context("count()", &context), Ok(Value::Int(0)));
eval_with_context("count()", &context),
Err(EvalexprError::WrongOperatorArgumentAmount {
actual: 0,
expected: 1
})
);
assert_eq!( assert_eq!(
eval_with_context("count(3, 5.5, 2)", &context), eval_with_context("count(3, 5.5, 2)", &context),
Ok(Value::Int(3)) Ok(Value::Int(3))
@ -407,6 +411,12 @@ fn test_shortcut_functions() {
.eval_tuple_with_context(&context), .eval_tuple_with_context(&context),
Ok(vec![Value::Int(3), Value::Int(3)]) Ok(vec![Value::Int(3), Value::Int(3)])
); );
assert_eq!(
build_operator_tree("")
.unwrap()
.eval_empty_with_context(&context),
Ok(EMPTY_VALUE)
);
assert_eq!( assert_eq!(
eval_string_with_context_mut("string", &mut context), eval_string_with_context_mut("string", &mut context),
@ -458,9 +468,20 @@ fn test_shortcut_functions() {
assert_eq!( assert_eq!(
build_operator_tree("3,3") build_operator_tree("3,3")
.unwrap() .unwrap()
.eval_tuple_with_context(&mut context), .eval_tuple_with_context_mut(&mut context),
Ok(vec![Value::Int(3), Value::Int(3)]) Ok(vec![Value::Int(3), Value::Int(3)])
); );
assert_eq!(
build_operator_tree("")
.unwrap()
.eval_empty_with_context_mut(&mut context),
Ok(EMPTY_VALUE)
);
}
#[test]
fn test_whitespace() {
assert!(eval_boolean("2 < = 3").is_err());
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]