From b052d524da3ed5cbc85d955c60a4694a0fb8f55d Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Fri, 29 Jan 2021 07:44:02 -0600 Subject: [PATCH] added pow operator, and filesize math (#2976) * added pow operator, and filesize math * removed + and - arms, removed some pow, pow higher precedence * Update value.rs Co-authored-by: Jonathan Turner --- crates/nu-cli/src/types/deduction.rs | 3 +- crates/nu-data/src/value.rs | 41 +++++++++++++++++++++-- crates/nu-engine/src/evaluate/operator.rs | 1 + crates/nu-parser/src/parse.rs | 1 + crates/nu-protocol/src/hir.rs | 4 ++- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/crates/nu-cli/src/types/deduction.rs b/crates/nu-cli/src/types/deduction.rs index 88d99f0f8a..4928591100 100644 --- a/crates/nu-cli/src/types/deduction.rs +++ b/crates/nu-cli/src/types/deduction.rs @@ -257,6 +257,7 @@ fn get_result_shape_of( } } Operator::Modulo => SyntaxShape::Number, + Operator::Pow => SyntaxShape::Number, }) } @@ -860,7 +861,7 @@ impl VarSyntaxShapeDeductor { } } } - Operator::Multiply | Operator::Divide => { + Operator::Multiply | Operator::Divide | Operator::Pow => { if let Some(shape) = self.get_shape_of_binary_arg_or_insert_dependency( (var, expr), bin_spanned, diff --git a/crates/nu-data/src/value.rs b/crates/nu-data/src/value.rs index ea49a4c2d7..7294e2e9bc 100644 --- a/crates/nu-data/src/value.rs +++ b/crates/nu-data/src/value.rs @@ -8,7 +8,7 @@ use nu_protocol::ShellTypeName; use nu_protocol::{Primitive, Type, UntaggedValue}; use nu_source::{DebugDocBuilder, PrettyDebug, Span, Tagged}; use nu_table::TextStyle; -use num_traits::Zero; +use num_traits::{ToPrimitive, Zero}; use std::collections::HashMap; pub struct Date; @@ -119,6 +119,11 @@ pub fn compute_values( }?; Ok(UntaggedValue::Primitive(Primitive::Filesize(result))) } + (Primitive::Filesize(x), Primitive::Int(y)) => match operator { + Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))), + Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Int(x / y))), + _ => Err((left.type_name(), right.type_name())), + }, (Primitive::Int(x), Primitive::Int(y)) => match operator { Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Int(x + y))), Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))), @@ -142,6 +147,13 @@ pub fn compute_values( Ok(UntaggedValue::Primitive(Primitive::Int(x % y))) } } + Operator::Pow => { + let prim_u32 = ToPrimitive::to_u32(y); + match prim_u32 { + Some(num) => Ok(UntaggedValue::Primitive(Primitive::Int(x.pow(num)))), + _ => Err((left.type_name(), right.type_name())), + } + } _ => Err((left.type_name(), right.type_name())), }, (Primitive::Decimal(x), Primitive::Int(y)) => { @@ -161,6 +173,16 @@ pub fn compute_values( } Ok(x % bigdecimal::BigDecimal::from(y.clone())) } + // leaving this here for the hope that bigdecimal will one day support pow/powf/fpow + // Operator::Pow => { + // let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0); + // let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0); + // let pow = bigdecimal::FromPrimitive::from_f64(xp.powf(yp)); + // match pow { + // Some(p) => Ok(p), + // None => Err((left.type_name(), right.type_name())), + // } + // } _ => Err((left.type_name(), right.type_name())), }?; Ok(UntaggedValue::Primitive(Primitive::Decimal(result))) @@ -182,7 +204,11 @@ pub fn compute_values( } Ok(bigdecimal::BigDecimal::from(x.clone()) % y) } - + // big decimal doesn't support pow yet + // Operator::Pow => { + // let yp = bigdecimal::ToPrimitive::to_u32(y).unwrap_or(0); + // Ok(bigdecimal::BigDecimal::from(x.pow(yp))) + // } _ => Err((left.type_name(), right.type_name())), }?; Ok(UntaggedValue::Primitive(Primitive::Decimal(result))) @@ -204,7 +230,16 @@ pub fn compute_values( } Ok(x % y) } - + // big decimal doesn't support pow yet + // Operator::Pow => { + // let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0); + // let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0); + // let pow = bigdecimal::FromPrimitive::from_f64(xp.powf(yp)); + // match pow { + // Some(p) => Ok(p), + // None => Err((left.type_name(), right.type_name())), + // } + // } _ => Err((left.type_name(), right.type_name())), }?; Ok(UntaggedValue::Primitive(Primitive::Decimal(result))) diff --git a/crates/nu-engine/src/evaluate/operator.rs b/crates/nu-engine/src/evaluate/operator.rs index dd05700ecd..06efe19114 100644 --- a/crates/nu-engine/src/evaluate/operator.rs +++ b/crates/nu-engine/src/evaluate/operator.rs @@ -25,6 +25,7 @@ pub fn apply_operator( Operator::Plus => value::compute_values(op, left, right), Operator::Minus => value::compute_values(op, left, right), Operator::Multiply => value::compute_values(op, left, right), + Operator::Pow => 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", diff --git a/crates/nu-parser/src/parse.rs b/crates/nu-parser/src/parse.rs index 7de1f4bbb8..57411fcb64 100644 --- a/crates/nu-parser/src/parse.rs +++ b/crates/nu-parser/src/parse.rs @@ -307,6 +307,7 @@ fn parse_operator(lite_arg: &Spanned) -> (SpannedExpression, Option Operator::Modulo, "&&" => Operator::And, "||" => Operator::Or, + "**" => Operator::Pow, _ => { return ( garbage(lite_arg.span), diff --git a/crates/nu-protocol/src/hir.rs b/crates/nu-protocol/src/hir.rs index 3d1db9bbaa..d27a750d8d 100644 --- a/crates/nu-protocol/src/hir.rs +++ b/crates/nu-protocol/src/hir.rs @@ -656,7 +656,8 @@ impl SpannedExpression { // Higher precedence binds tighter match operator { - Operator::Multiply | Operator::Divide | Operator::Modulo => 100, + Operator::Pow => 100, + Operator::Multiply | Operator::Divide | Operator::Modulo => 95, Operator::Plus | Operator::Minus => 90, Operator::NotContains | Operator::Contains @@ -848,6 +849,7 @@ pub enum Operator { Modulo, And, Or, + Pow, } #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, Deserialize, Serialize, new)]