1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00
expr now detects overflows and logs to stderr instead of overflowing the
input
https://github.com/uutils/coreutils/issues/1194
This commit is contained in:
bootandy 2018-06-26 23:30:07 +01:00
parent d5e6259b4c
commit 4756eb5c19
2 changed files with 33 additions and 9 deletions

View file

@ -85,18 +85,25 @@ impl ASTNode {
ASTNode::Node { ref op_type, .. } => match self.operand_values() { ASTNode::Node { ref op_type, .. } => match self.operand_values() {
Err(reason) => Err(reason), Err(reason) => Err(reason),
Ok(operand_values) => match op_type.as_ref() { Ok(operand_values) => match op_type.as_ref() {
"+" => infix_operator_two_ints(|a: i64, b: i64| Ok(a + b), &operand_values), "+" => infix_operator_two_ints(|a: i64, b: i64| {
"-" => infix_operator_two_ints(|a: i64, b: i64| Ok(a - b), &operand_values), checked_binop(|| a.checked_add(b), "+")
"*" => infix_operator_two_ints(|a: i64, b: i64| Ok(a * b), &operand_values), }, &operand_values
"/" => infix_operator_two_ints( ),
|a: i64, b: i64| { "-" => infix_operator_two_ints(|a: i64, b: i64| {
checked_binop(|| a.checked_sub(b), "-")
}, &operand_values
),
"*" => infix_operator_two_ints(|a: i64, b: i64| {
checked_binop(|| a.checked_mul(b), "*")
}, &operand_values
),
"/" => infix_operator_two_ints(|a: i64, b: i64| {
if b == 0 { if b == 0 {
Err("division by zero".to_owned()) Err("division by zero".to_owned())
} else { } else {
Ok(a / b) checked_binop(|| a.checked_div(b), "/")
} }
}, }, &operand_values
&operand_values,
), ),
"%" => infix_operator_two_ints( "%" => infix_operator_two_ints(
|a: i64, b: i64| { |a: i64, b: i64| {
@ -108,7 +115,6 @@ impl ASTNode {
}, },
&operand_values, &operand_values,
), ),
"=" => infix_operator_two_ints_or_two_strings( "=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok(bool_as_int(a == b)), |a: i64, b: i64| Ok(bool_as_int(a == b)),
|a: &String, b: &String| Ok(bool_as_string(a == b)), |a: &String, b: &String| Ok(bool_as_string(a == b)),
@ -384,6 +390,13 @@ fn move_till_match_paren(
} }
} }
fn checked_binop<F: Fn() -> Option<T>, T>(cb: F, op: &str) -> Result<T, String> {
match cb() {
Some(v) => Ok(v),
None => Err(format!("{}: Numerical result out of range", op)),
}
}
fn infix_operator_two_ints<F>(f: F, values: &Vec<String>) -> Result<String, String> fn infix_operator_two_ints<F>(f: F, values: &Vec<String>) -> Result<String, String>
where where
F: Fn(i64, i64) -> Result<i64, String>, F: Fn(i64, i64) -> Result<i64, String>,

View file

@ -12,6 +12,17 @@ fn test_simple_arithmetic() {
new_ucmd!().args(&["4", "/", "2"]).run().stdout_is("2\n"); new_ucmd!().args(&["4", "/", "2"]).run().stdout_is("2\n");
} }
#[test]
fn test_complex_arithmetic() {
let run = new_ucmd!().args(&["9223372036854775807", "+", "9223372036854775807"]).run();
run.stdout_is("");
run.stderr_is("expr: error: +: Numerical result out of range");
let run = new_ucmd!().args(&["9", "/", "0"]).run();
run.stdout_is("");
run.stderr_is("expr: error: division by zero");
}
#[test] #[test]
fn test_parenthesis() { fn test_parenthesis() {
new_ucmd!().args(&["(", "1", "+", "1", ")", "*", "2"]).run().stdout_is("4\n"); new_ucmd!().args(&["(", "1", "+", "1", ")", "*", "2"]).run().stdout_is("4\n");