Support addition and comparison of strings.
This commit is contained in:
parent
725472ef96
commit
a9c45307dd
@ -24,6 +24,9 @@ impl fmt::Display for EvalexprError {
|
||||
ExpectedNumber { actual } => {
|
||||
write!(f, "Expected a Value::Number, but got {:?}.", actual)
|
||||
},
|
||||
ExpectedNumberOrString { actual } => {
|
||||
write!(f, "Expected a Value::Number or a Value::String, but got {:?}.", actual)
|
||||
},
|
||||
ExpectedBoolean { actual } => {
|
||||
write!(f, "Expected a Value::Boolean, but got {:?}.", actual)
|
||||
},
|
||||
|
@ -56,6 +56,13 @@ pub enum EvalexprError {
|
||||
actual: Value,
|
||||
},
|
||||
|
||||
/// A numeric or string value was expected.
|
||||
/// Numeric values are the variants `Value::Int` and `Value::Float`.
|
||||
ExpectedNumberOrString {
|
||||
/// The actual value.
|
||||
actual: Value,
|
||||
},
|
||||
|
||||
/// A boolean value was expected.
|
||||
ExpectedBoolean {
|
||||
/// The actual value.
|
||||
@ -204,6 +211,11 @@ impl EvalexprError {
|
||||
EvalexprError::ExpectedNumber { actual }
|
||||
}
|
||||
|
||||
/// Constructs `Error::ExpectedNumberOrString{actual}`.
|
||||
pub fn expected_number_or_string(actual: Value) -> Self {
|
||||
EvalexprError::ExpectedNumberOrString { actual }
|
||||
}
|
||||
|
||||
/// Constructs `Error::ExpectedBoolean{actual}`.
|
||||
pub fn expected_boolean(actual: Value) -> Self {
|
||||
EvalexprError::ExpectedBoolean { actual }
|
||||
@ -315,6 +327,14 @@ pub fn expect_number(actual: &Value) -> EvalexprResult<()> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns Ok(()) if the given value is a string or a numeric
|
||||
pub fn expect_number_or_string(actual: &Value) -> EvalexprResult<()> {
|
||||
match actual {
|
||||
Value::String(_) | Value::Float(_) | Value::Int(_) => Ok(()),
|
||||
_ => Err(EvalexprError::expected_number_or_string(actual.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Ok(bool)` if the given value is a `Value::Boolean`, or `Err(Error::ExpectedBoolean)` otherwise.
|
||||
pub fn expect_boolean(actual: &Value) -> EvalexprResult<bool> {
|
||||
match actual {
|
||||
|
@ -146,10 +146,15 @@ impl Operator for Add {
|
||||
|
||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
expect_number_or_string(&arguments[0])?;
|
||||
expect_number_or_string(&arguments[1])?;
|
||||
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
|
||||
let mut result = String::with_capacity(a.len() + b.len());
|
||||
result.push_str(&a);
|
||||
result.push_str(&b);
|
||||
Ok(Value::String(result))
|
||||
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
let result = a.checked_add(b);
|
||||
if let Some(result) = result {
|
||||
Ok(Value::Int(result))
|
||||
@ -395,10 +400,16 @@ impl Operator for Gt {
|
||||
|
||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
expect_number_or_string(&arguments[0])?;
|
||||
expect_number_or_string(&arguments[1])?;
|
||||
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
|
||||
if a > b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
Ok(Value::Boolean(false))
|
||||
}
|
||||
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if a > b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
@ -425,10 +436,16 @@ impl Operator for Lt {
|
||||
|
||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
expect_number_or_string(&arguments[0])?;
|
||||
expect_number_or_string(&arguments[1])?;
|
||||
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
|
||||
if a < b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
Ok(Value::Boolean(false))
|
||||
}
|
||||
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if a < b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
@ -455,10 +472,16 @@ impl Operator for Geq {
|
||||
|
||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
expect_number_or_string(&arguments[0])?;
|
||||
expect_number_or_string(&arguments[1])?;
|
||||
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
|
||||
if a >= b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
Ok(Value::Boolean(false))
|
||||
}
|
||||
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if a >= b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
@ -485,10 +508,16 @@ impl Operator for Leq {
|
||||
|
||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
expect_number_or_string(&arguments[0])?;
|
||||
expect_number_or_string(&arguments[1])?;
|
||||
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
|
||||
if a <= b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
Ok(Value::Boolean(false))
|
||||
}
|
||||
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
|
||||
if a <= b {
|
||||
Ok(Value::Boolean(true))
|
||||
} else {
|
||||
|
@ -551,6 +551,9 @@ fn test_strings() {
|
||||
eval_boolean_with_context("a == \"a string\"", &context),
|
||||
Ok(true)
|
||||
);
|
||||
assert_eq!(eval("\"a\" + \"b\""), Ok(Value::from("ab")));
|
||||
assert_eq!(eval("\"a\" > \"b\""), Ok(Value::from(false)));
|
||||
assert_eq!(eval("\"a\" < \"b\""), Ok(Value::from(true)));
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
|
Loading…
Reference in New Issue
Block a user