forked from extern/nushell
* error for division by zero with = * cargo fmt * add helper zero_division_error * tests for zero division error * fix test names (zero div error)
This commit is contained in:
parent
e3e1e6f81b
commit
7532618bdc
@ -8,6 +8,7 @@ use nu_protocol::ShellTypeName;
|
|||||||
use nu_protocol::{Primitive, Type, UntaggedValue};
|
use nu_protocol::{Primitive, Type, UntaggedValue};
|
||||||
use nu_source::{DebugDocBuilder, PrettyDebug, Tagged};
|
use nu_source::{DebugDocBuilder, PrettyDebug, Tagged};
|
||||||
use nu_table::TextStyle;
|
use nu_table::TextStyle;
|
||||||
|
use num_traits::Zero;
|
||||||
|
|
||||||
pub fn date_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
|
pub fn date_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
|
||||||
let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| {
|
let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| {
|
||||||
@ -35,6 +36,10 @@ pub fn merge_values(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn zero_division_error() -> UntaggedValue {
|
||||||
|
UntaggedValue::Error(ShellError::untagged_runtime_error("division by zero"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compute_values(
|
pub fn compute_values(
|
||||||
operator: Operator,
|
operator: Operator,
|
||||||
left: &UntaggedValue,
|
left: &UntaggedValue,
|
||||||
@ -55,7 +60,9 @@ pub fn compute_values(
|
|||||||
Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))),
|
Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))),
|
||||||
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))),
|
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))),
|
||||||
Operator::Divide => {
|
Operator::Divide => {
|
||||||
if x - (y * (x / y)) == num_bigint::BigInt::from(0) {
|
if y.is_zero() {
|
||||||
|
Ok(zero_division_error())
|
||||||
|
} else if x - (y * (x / y)) == num_bigint::BigInt::from(0) {
|
||||||
Ok(UntaggedValue::Primitive(Primitive::Int(x / y)))
|
Ok(UntaggedValue::Primitive(Primitive::Int(x / y)))
|
||||||
} else {
|
} else {
|
||||||
Ok(UntaggedValue::Primitive(Primitive::Decimal(
|
Ok(UntaggedValue::Primitive(Primitive::Decimal(
|
||||||
@ -71,7 +78,12 @@ pub fn compute_values(
|
|||||||
Operator::Plus => Ok(x + bigdecimal::BigDecimal::from(y.clone())),
|
Operator::Plus => Ok(x + bigdecimal::BigDecimal::from(y.clone())),
|
||||||
Operator::Minus => Ok(x - bigdecimal::BigDecimal::from(y.clone())),
|
Operator::Minus => Ok(x - bigdecimal::BigDecimal::from(y.clone())),
|
||||||
Operator::Multiply => Ok(x * bigdecimal::BigDecimal::from(y.clone())),
|
Operator::Multiply => Ok(x * bigdecimal::BigDecimal::from(y.clone())),
|
||||||
Operator::Divide => Ok(x / bigdecimal::BigDecimal::from(y.clone())),
|
Operator::Divide => {
|
||||||
|
if y.is_zero() {
|
||||||
|
return Ok(zero_division_error());
|
||||||
|
}
|
||||||
|
Ok(x / bigdecimal::BigDecimal::from(y.clone()))
|
||||||
|
}
|
||||||
_ => Err((left.type_name(), right.type_name())),
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
}?;
|
}?;
|
||||||
Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
|
Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
|
||||||
@ -81,7 +93,12 @@ pub fn compute_values(
|
|||||||
Operator::Plus => Ok(bigdecimal::BigDecimal::from(x.clone()) + y),
|
Operator::Plus => Ok(bigdecimal::BigDecimal::from(x.clone()) + y),
|
||||||
Operator::Minus => Ok(bigdecimal::BigDecimal::from(x.clone()) - y),
|
Operator::Minus => Ok(bigdecimal::BigDecimal::from(x.clone()) - y),
|
||||||
Operator::Multiply => Ok(bigdecimal::BigDecimal::from(x.clone()) * y),
|
Operator::Multiply => Ok(bigdecimal::BigDecimal::from(x.clone()) * y),
|
||||||
Operator::Divide => Ok(bigdecimal::BigDecimal::from(x.clone()) / y),
|
Operator::Divide => {
|
||||||
|
if y.is_zero() {
|
||||||
|
return Ok(zero_division_error());
|
||||||
|
}
|
||||||
|
Ok(bigdecimal::BigDecimal::from(x.clone()) / y)
|
||||||
|
}
|
||||||
_ => Err((left.type_name(), right.type_name())),
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
}?;
|
}?;
|
||||||
Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
|
Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
|
||||||
@ -91,7 +108,12 @@ pub fn compute_values(
|
|||||||
Operator::Plus => Ok(x + y),
|
Operator::Plus => Ok(x + y),
|
||||||
Operator::Minus => Ok(x - y),
|
Operator::Minus => Ok(x - y),
|
||||||
Operator::Multiply => Ok(x * y),
|
Operator::Multiply => Ok(x * y),
|
||||||
Operator::Divide => Ok(x / y),
|
Operator::Divide => {
|
||||||
|
if y.is_zero() {
|
||||||
|
return Ok(zero_division_error());
|
||||||
|
}
|
||||||
|
Ok(x / y)
|
||||||
|
}
|
||||||
_ => Err((left.type_name(), right.type_name())),
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
}?;
|
}?;
|
||||||
Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
|
Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
|
||||||
|
@ -47,7 +47,10 @@ pub(crate) async fn evaluate_baseline_expr(
|
|||||||
match binary.op.expr {
|
match binary.op.expr {
|
||||||
Expression::Literal(hir::Literal::Operator(op)) => {
|
Expression::Literal(hir::Literal::Operator(op)) => {
|
||||||
match apply_operator(op, &left, &right) {
|
match apply_operator(op, &left, &right) {
|
||||||
Ok(result) => Ok(result.into_value(tag)),
|
Ok(result) => match result {
|
||||||
|
UntaggedValue::Error(shell_err) => Err(shell_err),
|
||||||
|
_ => Ok(result.into_value(tag)),
|
||||||
|
},
|
||||||
Err((left_type, right_type)) => Err(ShellError::coerce_error(
|
Err((left_type, right_type)) => Err(ShellError::coerce_error(
|
||||||
left_type.spanned(binary.left.span),
|
left_type.spanned(binary.left.span),
|
||||||
right_type.spanned(binary.right.span),
|
right_type.spanned(binary.right.span),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::data::value;
|
use crate::data::value;
|
||||||
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::hir::Operator;
|
use nu_protocol::hir::Operator;
|
||||||
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
@ -24,7 +25,14 @@ pub fn apply_operator(
|
|||||||
Operator::Plus => value::compute_values(op, left, right),
|
Operator::Plus => value::compute_values(op, left, right),
|
||||||
Operator::Minus => value::compute_values(op, left, right),
|
Operator::Minus => value::compute_values(op, left, right),
|
||||||
Operator::Multiply => value::compute_values(op, left, right),
|
Operator::Multiply => value::compute_values(op, left, right),
|
||||||
Operator::Divide => value::compute_values(op, left, right),
|
Operator::Divide => value::compute_values(op, left, right).map(|res| match res {
|
||||||
|
UntaggedValue::Error(_) => UntaggedValue::Error(ShellError::labeled_error(
|
||||||
|
"Evaluation error",
|
||||||
|
"division by zero",
|
||||||
|
&right.tag.span,
|
||||||
|
)),
|
||||||
|
_ => res,
|
||||||
|
}),
|
||||||
Operator::In => table_contains(left, right).map(UntaggedValue::boolean),
|
Operator::In => table_contains(left, right).map(UntaggedValue::boolean),
|
||||||
Operator::NotIn => table_contains(left, right).map(|x| UntaggedValue::boolean(!x)),
|
Operator::NotIn => table_contains(left, right).map(|x| UntaggedValue::boolean(!x)),
|
||||||
Operator::And => match (left.as_bool(), right.as_bool()) {
|
Operator::And => match (left.as_bool(), right.as_bool()) {
|
||||||
|
@ -87,6 +87,54 @@ fn division_of_ints2() {
|
|||||||
assert_eq!(actual.out, "0.25");
|
assert_eq!(actual.out, "0.25");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_zero_division_int_int() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
= 1 / 0
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert!(actual.err.contains("division by zero"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_zero_division_decimal_int() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
= 1.0 / 0
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert!(actual.err.contains("division by zero"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_zero_division_int_decimal() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
= 1 / 0.0
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert!(actual.err.contains("division by zero"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_zero_division_decimal_decimal() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
= 1.0 / 0.0
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert!(actual.err.contains("division by zero"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn proper_precedence_history() {
|
fn proper_precedence_history() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
|
Loading…
Reference in New Issue
Block a user