parent
ace2da1f3e
commit
6f17e481aa
@ -221,7 +221,8 @@ See [LICENSE](LICENSE) for details.
|
|||||||
|
|
||||||
## No Panicking
|
## 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.
|
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.
|
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).
|
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.
|
/// 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>,
|
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 {
|
impl Error {
|
||||||
@ -109,7 +155,7 @@ impl Error {
|
|||||||
|
|
||||||
/// Constructs `Error::TypeError{actual, expected}`.
|
/// Constructs `Error::TypeError{actual, expected}`.
|
||||||
pub fn type_error(actual: Value, expected: Vec<Value>) -> Self {
|
pub fn type_error(actual: Value, expected: Vec<Value>) -> Self {
|
||||||
Error::TypeError {actual, expected}
|
Error::TypeError { actual, expected }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs `Error::ExpectedInt(actual)`.
|
/// Constructs `Error::ExpectedInt(actual)`.
|
||||||
@ -138,6 +184,36 @@ impl Error {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Error::UnmatchedPartialToken { first, second }
|
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.
|
/// 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)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
mod configuration;
|
mod configuration;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod function;
|
mod function;
|
||||||
@ -593,4 +595,35 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert_eq!(eval("!(()true)"), Err(Error::AppendedToLeafNode));
|
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])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
if arguments[0].is_int() && arguments[1].is_int() {
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
Ok(Value::Int(
|
let result = arguments[0]
|
||||||
arguments[0].as_int().unwrap() + arguments[1].as_int().unwrap(),
|
.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 {
|
} else {
|
||||||
Ok(Value::Float(
|
Ok(Value::Float(
|
||||||
arguments[0].as_float().unwrap() + arguments[1].as_float().unwrap(),
|
arguments[0].as_float().unwrap() + arguments[1].as_float().unwrap(),
|
||||||
@ -171,9 +180,18 @@ impl Operator for Sub {
|
|||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
if arguments[0].is_int() && arguments[1].is_int() {
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
Ok(Value::Int(
|
let result = arguments[0]
|
||||||
arguments[0].as_int().unwrap() - arguments[1].as_int().unwrap(),
|
.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 {
|
} else {
|
||||||
Ok(Value::Float(
|
Ok(Value::Float(
|
||||||
arguments[0].as_float().unwrap() - arguments[1].as_float().unwrap(),
|
arguments[0].as_float().unwrap() - arguments[1].as_float().unwrap(),
|
||||||
@ -200,7 +218,12 @@ impl Operator for Neg {
|
|||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
|
|
||||||
if arguments[0].is_int() {
|
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 {
|
} else {
|
||||||
Ok(Value::Float(-arguments[0].as_float().unwrap()))
|
Ok(Value::Float(-arguments[0].as_float().unwrap()))
|
||||||
}
|
}
|
||||||
@ -226,9 +249,18 @@ impl Operator for Mul {
|
|||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
if arguments[0].is_int() && arguments[1].is_int() {
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
Ok(Value::Int(
|
let result = arguments[0]
|
||||||
arguments[0].as_int().unwrap() * arguments[1].as_int().unwrap(),
|
.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 {
|
} else {
|
||||||
Ok(Value::Float(
|
Ok(Value::Float(
|
||||||
arguments[0].as_float().unwrap() * arguments[1].as_float().unwrap(),
|
arguments[0].as_float().unwrap() * arguments[1].as_float().unwrap(),
|
||||||
@ -256,9 +288,18 @@ impl Operator for Div {
|
|||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
if arguments[0].is_int() && arguments[1].is_int() {
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
Ok(Value::Int(
|
let result = arguments[0]
|
||||||
arguments[0].as_int().unwrap() / arguments[1].as_int().unwrap(),
|
.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 {
|
} else {
|
||||||
Ok(Value::Float(
|
Ok(Value::Float(
|
||||||
arguments[0].as_float().unwrap() / arguments[1].as_float().unwrap(),
|
arguments[0].as_float().unwrap() / arguments[1].as_float().unwrap(),
|
||||||
@ -286,9 +327,18 @@ impl Operator for Mod {
|
|||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
if arguments[0].is_int() && arguments[1].is_int() {
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
Ok(Value::Int(
|
let result = arguments[0]
|
||||||
arguments[0].as_int().unwrap() % arguments[1].as_int().unwrap(),
|
.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 {
|
} else {
|
||||||
Ok(Value::Float(
|
Ok(Value::Float(
|
||||||
arguments[0].as_float().unwrap() % arguments[1].as_float().unwrap(),
|
arguments[0].as_float().unwrap() % arguments[1].as_float().unwrap(),
|
||||||
|
Loading…
Reference in New Issue
Block a user