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 } => {
|
ExpectedNumber { actual } => {
|
||||||
write!(f, "Expected a Value::Number, but got {:?}.", 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 } => {
|
ExpectedBoolean { actual } => {
|
||||||
write!(f, "Expected a Value::Boolean, but got {:?}.", actual)
|
write!(f, "Expected a Value::Boolean, but got {:?}.", actual)
|
||||||
},
|
},
|
||||||
|
@ -56,6 +56,13 @@ pub enum EvalexprError {
|
|||||||
actual: Value,
|
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.
|
/// A boolean value was expected.
|
||||||
ExpectedBoolean {
|
ExpectedBoolean {
|
||||||
/// The actual value.
|
/// The actual value.
|
||||||
@ -204,6 +211,11 @@ impl EvalexprError {
|
|||||||
EvalexprError::ExpectedNumber { actual }
|
EvalexprError::ExpectedNumber { actual }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs `Error::ExpectedNumberOrString{actual}`.
|
||||||
|
pub fn expected_number_or_string(actual: Value) -> Self {
|
||||||
|
EvalexprError::ExpectedNumberOrString { actual }
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs `Error::ExpectedBoolean{actual}`.
|
/// Constructs `Error::ExpectedBoolean{actual}`.
|
||||||
pub fn expected_boolean(actual: Value) -> Self {
|
pub fn expected_boolean(actual: Value) -> Self {
|
||||||
EvalexprError::ExpectedBoolean { actual }
|
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.
|
/// Returns `Ok(bool)` if the given value is a `Value::Boolean`, or `Err(Error::ExpectedBoolean)` otherwise.
|
||||||
pub fn expect_boolean(actual: &Value) -> EvalexprResult<bool> {
|
pub fn expect_boolean(actual: &Value) -> EvalexprResult<bool> {
|
||||||
match actual {
|
match actual {
|
||||||
|
@ -146,10 +146,15 @@ impl Operator for Add {
|
|||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
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);
|
let result = a.checked_add(b);
|
||||||
if let Some(result) = result {
|
if let Some(result) = result {
|
||||||
Ok(Value::Int(result))
|
Ok(Value::Int(result))
|
||||||
@ -395,10 +400,16 @@ impl Operator for Gt {
|
|||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
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 {
|
if a > b {
|
||||||
Ok(Value::Boolean(true))
|
Ok(Value::Boolean(true))
|
||||||
} else {
|
} else {
|
||||||
@ -425,10 +436,16 @@ impl Operator for Lt {
|
|||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
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 {
|
if a < b {
|
||||||
Ok(Value::Boolean(true))
|
Ok(Value::Boolean(true))
|
||||||
} else {
|
} else {
|
||||||
@ -455,10 +472,16 @@ impl Operator for Geq {
|
|||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
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 {
|
if a >= b {
|
||||||
Ok(Value::Boolean(true))
|
Ok(Value::Boolean(true))
|
||||||
} else {
|
} else {
|
||||||
@ -485,10 +508,16 @@ impl Operator for Leq {
|
|||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
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 {
|
if a <= b {
|
||||||
Ok(Value::Boolean(true))
|
Ok(Value::Boolean(true))
|
||||||
} else {
|
} else {
|
||||||
|
@ -551,6 +551,9 @@ fn test_strings() {
|
|||||||
eval_boolean_with_context("a == \"a string\"", &context),
|
eval_boolean_with_context("a == \"a string\"", &context),
|
||||||
Ok(true)
|
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")]
|
#[cfg(feature = "serde")]
|
||||||
|
Loading…
Reference in New Issue
Block a user