mirror of
https://github.com/nushell/nushell.git
synced 2025-04-23 04:38:21 +02:00
Attempts to add //
math operator (#5759)
* attempts to add `div` math operator * allows `//` to be used too * fmt: * clippy issue * returns appropriate type * returns appropriate type 2 * fmt * ensure consistency; rename to `fdiv` * Update parser.rs
This commit is contained in:
parent
43a218240c
commit
caafd26deb
@ -112,6 +112,7 @@ impl CustomValue for ExprDb {
|
|||||||
Operator::Multiply => Ok(BinaryOperator::Multiply),
|
Operator::Multiply => Ok(BinaryOperator::Multiply),
|
||||||
Operator::Divide => Ok(BinaryOperator::Divide),
|
Operator::Divide => Ok(BinaryOperator::Divide),
|
||||||
Operator::Modulo => Ok(BinaryOperator::Modulo),
|
Operator::Modulo => Ok(BinaryOperator::Modulo),
|
||||||
|
Operator::FloorDivision => Ok(BinaryOperator::Divide),
|
||||||
Operator::And => Ok(BinaryOperator::And),
|
Operator::And => Ok(BinaryOperator::And),
|
||||||
Operator::Or => Ok(BinaryOperator::Or),
|
Operator::Or => Ok(BinaryOperator::Or),
|
||||||
Operator::In
|
Operator::In
|
||||||
|
@ -100,6 +100,7 @@ fn with_operator(
|
|||||||
Operator::Multiply => apply_arithmetic(left, right, lhs_span, Mul::mul),
|
Operator::Multiply => apply_arithmetic(left, right, lhs_span, Mul::mul),
|
||||||
Operator::Divide => apply_arithmetic(left, right, lhs_span, Div::div),
|
Operator::Divide => apply_arithmetic(left, right, lhs_span, Div::div),
|
||||||
Operator::Modulo => apply_arithmetic(left, right, lhs_span, Rem::rem),
|
Operator::Modulo => apply_arithmetic(left, right, lhs_span, Rem::rem),
|
||||||
|
Operator::FloorDivision => apply_arithmetic(left, right, lhs_span, Div::div),
|
||||||
Operator::Equal => Ok(left
|
Operator::Equal => Ok(left
|
||||||
.clone()
|
.clone()
|
||||||
.apply_with_expr(right.clone(), Expr::eq)
|
.apply_with_expr(right.clone(), Expr::eq)
|
||||||
|
@ -163,6 +163,89 @@ fn error_zero_division_decimal_decimal() {
|
|||||||
assert!(actual.err.contains("division by zero"));
|
assert!(actual.err.contains("division by zero"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn floor_division_of_ints() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
5 // 2
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "2");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn floor_division_of_ints2() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
-3 // 2
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "-2");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn floor_division_of_floats() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
-3.0 // 2.0
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "-2");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_zero_floor_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_floor_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_floor_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_floor_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!(
|
||||||
|
@ -422,6 +422,10 @@ pub fn eval_expression(
|
|||||||
let rhs = eval_expression(engine_state, stack, rhs)?;
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
||||||
lhs.modulo(op_span, &rhs, expr.span)
|
lhs.modulo(op_span, &rhs, expr.span)
|
||||||
}
|
}
|
||||||
|
Operator::FloorDivision => {
|
||||||
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
||||||
|
lhs.floor_div(op_span, &rhs, expr.span)
|
||||||
|
}
|
||||||
Operator::Pow => {
|
Operator::Pow => {
|
||||||
let rhs = eval_expression(engine_state, stack, rhs)?;
|
let rhs = eval_expression(engine_state, stack, rhs)?;
|
||||||
lhs.pow(op_span, &rhs, expr.span)
|
lhs.pow(op_span, &rhs, expr.span)
|
||||||
|
@ -4086,6 +4086,7 @@ pub fn parse_operator(
|
|||||||
b"-" => Operator::Minus,
|
b"-" => Operator::Minus,
|
||||||
b"*" => Operator::Multiply,
|
b"*" => Operator::Multiply,
|
||||||
b"/" => Operator::Divide,
|
b"/" => Operator::Divide,
|
||||||
|
b"//" => Operator::FloorDivision,
|
||||||
b"in" => Operator::In,
|
b"in" => Operator::In,
|
||||||
b"not-in" => Operator::NotIn,
|
b"not-in" => Operator::NotIn,
|
||||||
b"mod" => Operator::Modulo,
|
b"mod" => Operator::Modulo,
|
||||||
|
@ -181,6 +181,33 @@ pub fn math_result_type(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Operator::FloorDivision => match (&lhs.ty, &rhs.ty) {
|
||||||
|
(Type::Int, Type::Int) => (Type::Int, None),
|
||||||
|
(Type::Float, Type::Int) => (Type::Int, None),
|
||||||
|
(Type::Int, Type::Float) => (Type::Int, None),
|
||||||
|
(Type::Float, Type::Float) => (Type::Int, None),
|
||||||
|
(Type::Filesize, Type::Filesize) => (Type::Int, None),
|
||||||
|
(Type::Duration, Type::Duration) => (Type::Int, None),
|
||||||
|
|
||||||
|
(Type::Filesize, Type::Int) => (Type::Filesize, None),
|
||||||
|
(Type::Duration, Type::Int) => (Type::Duration, None),
|
||||||
|
|
||||||
|
(Type::Any, _) => (Type::Any, None),
|
||||||
|
(_, Type::Any) => (Type::Any, None),
|
||||||
|
_ => {
|
||||||
|
*op = Expression::garbage(op.span);
|
||||||
|
(
|
||||||
|
Type::Any,
|
||||||
|
Some(ParseError::UnsupportedOperation(
|
||||||
|
op.span,
|
||||||
|
lhs.span,
|
||||||
|
lhs.ty.clone(),
|
||||||
|
rhs.span,
|
||||||
|
rhs.ty.clone(),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
Operator::And | Operator::Or => match (&lhs.ty, &rhs.ty) {
|
Operator::And | Operator::Or => match (&lhs.ty, &rhs.ty) {
|
||||||
(Type::Bool, Type::Bool) => (Type::Bool, None),
|
(Type::Bool, Type::Bool) => (Type::Bool, None),
|
||||||
|
|
||||||
|
@ -30,7 +30,10 @@ impl Expression {
|
|||||||
|
|
||||||
match operator {
|
match operator {
|
||||||
Operator::Pow => 100,
|
Operator::Pow => 100,
|
||||||
Operator::Multiply | Operator::Divide | Operator::Modulo => 95,
|
Operator::Multiply
|
||||||
|
| Operator::Divide
|
||||||
|
| Operator::Modulo
|
||||||
|
| Operator::FloorDivision => 95,
|
||||||
Operator::Plus | Operator::Minus => 90,
|
Operator::Plus | Operator::Minus => 90,
|
||||||
Operator::NotRegexMatch
|
Operator::NotRegexMatch
|
||||||
| Operator::RegexMatch
|
| Operator::RegexMatch
|
||||||
|
@ -20,6 +20,7 @@ pub enum Operator {
|
|||||||
In,
|
In,
|
||||||
NotIn,
|
NotIn,
|
||||||
Modulo,
|
Modulo,
|
||||||
|
FloorDivision,
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
Pow,
|
Pow,
|
||||||
@ -43,6 +44,7 @@ impl Display for Operator {
|
|||||||
Operator::In => write!(f, "in"),
|
Operator::In => write!(f, "in"),
|
||||||
Operator::NotIn => write!(f, "not-in"),
|
Operator::NotIn => write!(f, "not-in"),
|
||||||
Operator::Modulo => write!(f, "mod"),
|
Operator::Modulo => write!(f, "mod"),
|
||||||
|
Operator::FloorDivision => write!(f, "fdiv"),
|
||||||
Operator::And => write!(f, "&&"),
|
Operator::And => write!(f, "&&"),
|
||||||
Operator::Or => write!(f, "||"),
|
Operator::Or => write!(f, "||"),
|
||||||
Operator::Pow => write!(f, "**"),
|
Operator::Pow => write!(f, "**"),
|
||||||
|
@ -1769,6 +1769,119 @@ impl Value {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn floor_div(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
||||||
|
match (self, rhs) {
|
||||||
|
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: (*lhs as f64 / *rhs as f64)
|
||||||
|
.max(std::i64::MIN as f64)
|
||||||
|
.min(std::i64::MAX as f64)
|
||||||
|
.floor() as i64,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0.0 {
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: (*lhs as f64 / *rhs)
|
||||||
|
.max(std::i64::MIN as f64)
|
||||||
|
.min(std::i64::MAX as f64)
|
||||||
|
.floor() as i64,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: (*lhs / *rhs as f64)
|
||||||
|
.max(std::i64::MIN as f64)
|
||||||
|
.min(std::i64::MAX as f64)
|
||||||
|
.floor() as i64,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0.0 {
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: (lhs / rhs)
|
||||||
|
.max(std::i64::MIN as f64)
|
||||||
|
.min(std::i64::MAX as f64)
|
||||||
|
.floor() as i64,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Filesize { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: (*lhs as f64 / *rhs as f64)
|
||||||
|
.max(std::i64::MIN as f64)
|
||||||
|
.min(std::i64::MAX as f64)
|
||||||
|
.floor() as i64,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Int {
|
||||||
|
val: (*lhs as f64 / *rhs as f64)
|
||||||
|
.max(std::i64::MIN as f64)
|
||||||
|
.min(std::i64::MAX as f64)
|
||||||
|
.floor() as i64,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Filesize {
|
||||||
|
val: lhs / rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
if *rhs != 0 {
|
||||||
|
Ok(Value::Duration {
|
||||||
|
val: lhs / rhs,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ShellError::DivisionByZero(op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::CustomValue { val: lhs, span }, rhs) => {
|
||||||
|
lhs.operation(*span, Operator::Divide, op, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Err(ShellError::OperatorMismatch {
|
||||||
|
op_span: op,
|
||||||
|
lhs_ty: self.get_type(),
|
||||||
|
lhs_span: self.span()?,
|
||||||
|
rhs_ty: rhs.get_type(),
|
||||||
|
rhs_span: rhs.span()?,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn lt(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
pub fn lt(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
||||||
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
|
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
|
||||||
return lhs.operation(*span, Operator::LessThan, op, rhs);
|
return lhs.operation(*span, Operator::LessThan, op, rhs);
|
||||||
|
Loading…
Reference in New Issue
Block a user