parent
ace2da1f3e
commit
6f17e481aa
@ -221,7 +221,8 @@ See [LICENSE](LICENSE) for details.
|
||||
|
||||
## No Panicking
|
||||
|
||||
This makes extensive use of the `Result` pattern and is intended to never panic.
|
||||
This crate makes extensive use of the `Result` pattern and is intended to never panic.
|
||||
The *exception* are panics caused by *failed allocations*.
|
||||
But unfortunately, Rust does not provide any features to prove this behavior.
|
||||
The developer of this crate has not found a good solution to ensure no-panic behavior in any way.
|
||||
Please report a panic immediately if you found it as issue on [github](https://github.com/ISibboI/evalexpr/issues).
|
||||
|
@ -96,6 +96,52 @@ pub enum Error {
|
||||
/// The token that follows the unmatched partial token and that cannot be matched to the partial token, or `None`, if `first` is the last partial token in the stream.
|
||||
second: Option<PartialToken>,
|
||||
},
|
||||
|
||||
/// An addition operation performed by Rust failed.
|
||||
AdditionError {
|
||||
/// The first argument of the addition.
|
||||
augend: Value,
|
||||
/// The second argument of the addition.
|
||||
addend: Value,
|
||||
},
|
||||
|
||||
/// A subtraction operation performed by Rust failed.
|
||||
SubtractionError {
|
||||
/// The first argument of the subtraction.
|
||||
minuend: Value,
|
||||
/// The second argument of the subtraction.
|
||||
subtrahend: Value,
|
||||
},
|
||||
|
||||
/// A negation operation performed by Rust failed.
|
||||
NegationError {
|
||||
/// The argument of the negation.
|
||||
argument: Value,
|
||||
},
|
||||
|
||||
/// A multiplication operation performed by Rust failed.
|
||||
MultiplicationError {
|
||||
/// The first argument of the multiplication.
|
||||
multiplicand: Value,
|
||||
/// The second argument of the multiplication.
|
||||
multiplier: Value,
|
||||
},
|
||||
|
||||
/// A division operation performed by Rust failed.
|
||||
DivisionError {
|
||||
/// The first argument of the division.
|
||||
dividend: Value,
|
||||
/// The second argument of the division.
|
||||
divisor: Value,
|
||||
},
|
||||
|
||||
/// A modulation operation performed by Rust failed.
|
||||
ModulationError {
|
||||
/// The first argument of the modulation.
|
||||
dividend: Value,
|
||||
/// The second argument of the modulation.
|
||||
divisor: Value,
|
||||
},
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@ -109,7 +155,7 @@ impl Error {
|
||||
|
||||
/// Constructs `Error::TypeError{actual, expected}`.
|
||||
pub fn type_error(actual: Value, expected: Vec<Value>) -> Self {
|
||||
Error::TypeError {actual, expected}
|
||||
Error::TypeError { actual, expected }
|
||||
}
|
||||
|
||||
/// Constructs `Error::ExpectedInt(actual)`.
|
||||
@ -138,6 +184,36 @@ impl Error {
|
||||
) -> Self {
|
||||
Error::UnmatchedPartialToken { first, second }
|
||||
}
|
||||
|
||||
pub(crate) fn addition_error(augend: Value, addend: Value) -> Self {
|
||||
Error::AdditionError { augend, addend }
|
||||
}
|
||||
|
||||
pub(crate) fn subtraction_error(minuend: Value, subtrahend: Value) -> Self {
|
||||
Error::SubtractionError {
|
||||
minuend,
|
||||
subtrahend,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn negation_error(argument: Value) -> Self {
|
||||
Error::NegationError { argument }
|
||||
}
|
||||
|
||||
pub(crate) fn multiplication_error(multiplicand: Value, multiplier: Value) -> Self {
|
||||
Error::MultiplicationError {
|
||||
multiplicand,
|
||||
multiplier,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn division_error(dividend: Value, divisor: Value) -> Self {
|
||||
Error::DivisionError { dividend, divisor }
|
||||
}
|
||||
|
||||
pub(crate) fn modulation_error(dividend: Value, divisor: Value) -> Self {
|
||||
Error::ModulationError { dividend, divisor }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongOperatorArgumentAmount)` otherwise.
|
||||
|
33
src/lib.rs
33
src/lib.rs
@ -206,6 +206,8 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate core;
|
||||
|
||||
mod configuration;
|
||||
pub mod error;
|
||||
mod function;
|
||||
@ -593,4 +595,35 @@ mod test {
|
||||
);
|
||||
assert_eq!(eval("!(()true)"), Err(Error::AppendedToLeafNode));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_panic() {
|
||||
assert!(eval(&format!(
|
||||
"{} + {}",
|
||||
IntType::max_value(),
|
||||
IntType::max_value()
|
||||
))
|
||||
.is_err());
|
||||
assert!(eval(&format!(
|
||||
"-{} - {}",
|
||||
IntType::max_value(),
|
||||
IntType::max_value()
|
||||
))
|
||||
.is_err());
|
||||
assert!(eval(&format!("-(-{} - 1)", IntType::max_value())).is_err());
|
||||
assert!(eval(&format!(
|
||||
"{} * {}",
|
||||
IntType::max_value(),
|
||||
IntType::max_value()
|
||||
))
|
||||
.is_err());
|
||||
assert!(eval(&format!("{} / {}", IntType::max_value(), 0)).is_err());
|
||||
assert!(eval(&format!("{} % {}", IntType::max_value(), 0)).is_err());
|
||||
assert!(eval(&format!(
|
||||
"{} ^ {}",
|
||||
IntType::max_value(),
|
||||
IntType::max_value()
|
||||
))
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
|
@ -141,9 +141,18 @@ impl Operator for Add {
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
if arguments[0].is_int() && arguments[1].is_int() {
|
||||
Ok(Value::Int(
|
||||
arguments[0].as_int().unwrap() + arguments[1].as_int().unwrap(),
|
||||
let result = arguments[0]
|
||||
.as_int()
|
||||
.unwrap()
|
||||
.checked_add(arguments[1].as_int().unwrap());
|
||||
if let Some(result) = result {
|
||||
Ok(Value::Int(result))
|
||||
} else {
|
||||
Err(Error::addition_error(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(Value::Float(
|
||||
arguments[0].as_float().unwrap() + arguments[1].as_float().unwrap(),
|
||||
@ -171,9 +180,18 @@ impl Operator for Sub {
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
if arguments[0].is_int() && arguments[1].is_int() {
|
||||
Ok(Value::Int(
|
||||
arguments[0].as_int().unwrap() - arguments[1].as_int().unwrap(),
|
||||
let result = arguments[0]
|
||||
.as_int()
|
||||
.unwrap()
|
||||
.checked_sub(arguments[1].as_int().unwrap());
|
||||
if let Some(result) = result {
|
||||
Ok(Value::Int(result))
|
||||
} else {
|
||||
Err(Error::subtraction_error(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(Value::Float(
|
||||
arguments[0].as_float().unwrap() - arguments[1].as_float().unwrap(),
|
||||
@ -200,7 +218,12 @@ impl Operator for Neg {
|
||||
expect_number(&arguments[0])?;
|
||||
|
||||
if arguments[0].is_int() {
|
||||
Ok(Value::Int(-arguments[0].as_int().unwrap()))
|
||||
let result = arguments[0].as_int().unwrap().checked_neg();
|
||||
if let Some(result) = result {
|
||||
Ok(Value::Int(result))
|
||||
} else {
|
||||
Err(Error::negation_error(arguments[0].clone()))
|
||||
}
|
||||
} else {
|
||||
Ok(Value::Float(-arguments[0].as_float().unwrap()))
|
||||
}
|
||||
@ -226,9 +249,18 @@ impl Operator for Mul {
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
if arguments[0].is_int() && arguments[1].is_int() {
|
||||
Ok(Value::Int(
|
||||
arguments[0].as_int().unwrap() * arguments[1].as_int().unwrap(),
|
||||
let result = arguments[0]
|
||||
.as_int()
|
||||
.unwrap()
|
||||
.checked_mul(arguments[1].as_int().unwrap());
|
||||
if let Some(result) = result {
|
||||
Ok(Value::Int(result))
|
||||
} else {
|
||||
Err(Error::multiplication_error(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(Value::Float(
|
||||
arguments[0].as_float().unwrap() * arguments[1].as_float().unwrap(),
|
||||
@ -256,9 +288,18 @@ impl Operator for Div {
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
if arguments[0].is_int() && arguments[1].is_int() {
|
||||
Ok(Value::Int(
|
||||
arguments[0].as_int().unwrap() / arguments[1].as_int().unwrap(),
|
||||
let result = arguments[0]
|
||||
.as_int()
|
||||
.unwrap()
|
||||
.checked_div(arguments[1].as_int().unwrap());
|
||||
if let Some(result) = result {
|
||||
Ok(Value::Int(result))
|
||||
} else {
|
||||
Err(Error::division_error(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(Value::Float(
|
||||
arguments[0].as_float().unwrap() / arguments[1].as_float().unwrap(),
|
||||
@ -286,9 +327,18 @@ impl Operator for Mod {
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
if arguments[0].is_int() && arguments[1].is_int() {
|
||||
Ok(Value::Int(
|
||||
arguments[0].as_int().unwrap() % arguments[1].as_int().unwrap(),
|
||||
let result = arguments[0]
|
||||
.as_int()
|
||||
.unwrap()
|
||||
.checked_rem(arguments[1].as_int().unwrap());
|
||||
if let Some(result) = result {
|
||||
Ok(Value::Int(result))
|
||||
} else {
|
||||
Err(Error::modulation_error(
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(Value::Float(
|
||||
arguments[0].as_float().unwrap() % arguments[1].as_float().unwrap(),
|
||||
|
Loading…
Reference in New Issue
Block a user