diff --git a/crates/nu-command/src/math/abs.rs b/crates/nu-command/src/math/abs.rs index 4fae0633c8..5ebae80e2f 100644 --- a/crates/nu-command/src/math/abs.rs +++ b/crates/nu-command/src/math/abs.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathAbs; @@ -21,6 +23,7 @@ impl Command for MathAbs { Type::List(Box::new(Type::Duration)), Type::List(Box::new(Type::Duration)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -46,6 +49,19 @@ impl Command for MathAbs { input: PipelineData, ) -> Result { let head = call.head; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| abs_helper(value, head), engine_state.signals()) } @@ -56,6 +72,19 @@ impl Command for MathAbs { input: PipelineData, ) -> Result { let head = call.head; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| abs_helper(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/ceil.rs b/crates/nu-command/src/math/ceil.rs index 5867f21bca..585b12aa62 100644 --- a/crates/nu-command/src/math/ceil.rs +++ b/crates/nu-command/src/math/ceil.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathCeil; @@ -16,6 +18,7 @@ impl Command for MathCeil { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Int)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -45,6 +48,19 @@ impl Command for MathCeil { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| operate(value, head), engine_state.signals()) } @@ -59,6 +75,19 @@ impl Command for MathCeil { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/floor.rs b/crates/nu-command/src/math/floor.rs index 2bc705f926..73760a390a 100644 --- a/crates/nu-command/src/math/floor.rs +++ b/crates/nu-command/src/math/floor.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathFloor; @@ -16,6 +18,7 @@ impl Command for MathFloor { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Int)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -45,6 +48,19 @@ impl Command for MathFloor { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| operate(value, head), engine_state.signals()) } @@ -59,6 +75,19 @@ impl Command for MathFloor { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/log.rs b/crates/nu-command/src/math/log.rs index 79eed71640..eff8c583df 100644 --- a/crates/nu-command/src/math/log.rs +++ b/crates/nu-command/src/math/log.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; use nu_protocol::Signals; #[derive(Clone)] @@ -22,6 +24,7 @@ impl Command for MathLog { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Float)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -46,7 +49,21 @@ impl Command for MathLog { call: &Call, input: PipelineData, ) -> Result { + let head = call.head; let base: Spanned = call.req(engine_state, stack, 0)?; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } log(base, call.head, input, engine_state.signals()) } @@ -56,7 +73,21 @@ impl Command for MathLog { call: &Call, input: PipelineData, ) -> Result { + let head = call.head; let base: Spanned = call.req_const(working_set, 0)?; + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } log(base, call.head, input, working_set.permanent().signals()) } diff --git a/crates/nu-command/src/math/mode.rs b/crates/nu-command/src/math/mode.rs index 5183a855a9..e9e827ad83 100644 --- a/crates/nu-command/src/math/mode.rs +++ b/crates/nu-command/src/math/mode.rs @@ -110,7 +110,7 @@ impl Command for MathMode { } } -pub fn mode(values: &[Value], _span: Span, head: Span) -> Result { +pub fn mode(values: &[Value], span: Span, head: Span) -> Result { //In e-q, Value doesn't implement Hash or Eq, so we have to get the values inside // But f64 doesn't implement Hash, so we get the binary representation to use as // key in the HashMap @@ -130,11 +130,11 @@ pub fn mode(values: &[Value], _span: Span, head: Span) -> Result Err(*error.clone()), - other => Err(ShellError::UnsupportedInput { + _ => Err(ShellError::UnsupportedInput { msg: "Unable to give a result with this input".to_string(), input: "value originates from here".into(), msg_span: head, - input_span: other.span(), + input_span: span, }), }) .collect::, ShellError>>()?; diff --git a/crates/nu-command/src/math/round.rs b/crates/nu-command/src/math/round.rs index 558715e675..aa04839e32 100644 --- a/crates/nu-command/src/math/round.rs +++ b/crates/nu-command/src/math/round.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathRound; @@ -16,6 +18,7 @@ impl Command for MathRound { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Number)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .named( @@ -52,6 +55,19 @@ impl Command for MathRound { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head, precision_param), engine_state.signals(), @@ -70,6 +86,19 @@ impl Command for MathRound { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head, precision_param), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/sqrt.rs b/crates/nu-command/src/math/sqrt.rs index 38b2a4d800..7bb5ccc78e 100644 --- a/crates/nu-command/src/math/sqrt.rs +++ b/crates/nu-command/src/math/sqrt.rs @@ -1,4 +1,6 @@ +use crate::math::utils::ensure_bounded; use nu_engine::command_prelude::*; +use nu_protocol::Range; #[derive(Clone)] pub struct MathSqrt; @@ -16,6 +18,7 @@ impl Command for MathSqrt { Type::List(Box::new(Type::Number)), Type::List(Box::new(Type::Float)), ), + (Type::Range, Type::List(Box::new(Type::Number))), ]) .allow_variants_without_examples(true) .category(Category::Math) @@ -45,6 +48,19 @@ impl Command for MathSqrt { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map(move |value| operate(value, head), engine_state.signals()) } @@ -59,6 +75,19 @@ impl Command for MathSqrt { if matches!(input, PipelineData::Empty) { return Err(ShellError::PipelineEmpty { dst_span: head }); } + if let PipelineData::Value( + Value::Range { + ref val, + internal_span, + }, + .., + ) = input + { + match &**val { + Range::IntRange(range) => ensure_bounded(range.end(), internal_span, head)?, + Range::FloatRange(range) => ensure_bounded(range.end(), internal_span, head)?, + } + } input.map( move |value| operate(value, head), working_set.permanent().signals(), diff --git a/crates/nu-command/src/math/stddev.rs b/crates/nu-command/src/math/stddev.rs index 051f7d02d7..2987949e05 100644 --- a/crates/nu-command/src/math/stddev.rs +++ b/crates/nu-command/src/math/stddev.rs @@ -14,6 +14,7 @@ impl Command for MathStddev { Signature::build("math stddev") .input_output_types(vec![ (Type::List(Box::new(Type::Number)), Type::Number), + (Type::Range, Type::Number), (Type::table(), Type::record()), (Type::record(), Type::record()), ]) @@ -53,6 +54,18 @@ impl Command for MathStddev { input: PipelineData, ) -> Result { let sample = call.has_flag(engine_state, stack, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_stddev(sample)) } @@ -63,6 +76,18 @@ impl Command for MathStddev { input: PipelineData, ) -> Result { let sample = call.has_flag_const(working_set, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_stddev(sample)) } diff --git a/crates/nu-command/src/math/variance.rs b/crates/nu-command/src/math/variance.rs index b221d92746..92712872f5 100644 --- a/crates/nu-command/src/math/variance.rs +++ b/crates/nu-command/src/math/variance.rs @@ -13,6 +13,7 @@ impl Command for MathVariance { Signature::build("math variance") .input_output_types(vec![ (Type::List(Box::new(Type::Number)), Type::Number), + (Type::Range, Type::Number), (Type::table(), Type::record()), (Type::record(), Type::record()), ]) @@ -45,6 +46,18 @@ impl Command for MathVariance { input: PipelineData, ) -> Result { let sample = call.has_flag(engine_state, stack, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_variance(sample)) } @@ -55,6 +68,18 @@ impl Command for MathVariance { input: PipelineData, ) -> Result { let sample = call.has_flag_const(working_set, "sample")?; + let name = call.head; + let span = input.span().unwrap_or(name); + let input: PipelineData = match input.try_expand_range() { + Err(_) => { + return Err(ShellError::IncorrectValue { + msg: "Range must be bounded".to_string(), + val_span: span, + call_span: name, + }); + } + Ok(val) => val, + }; run_with_function(call, input, compute_variance(sample)) } diff --git a/crates/nu-command/tests/commands/math/abs.rs b/crates/nu-command/tests/commands/math/abs.rs index de5c7551aa..4ddafd5bb0 100644 --- a/crates/nu-command/tests/commands/math/abs.rs +++ b/crates/nu-command/tests/commands/math/abs.rs @@ -7,8 +7,16 @@ fn const_abs() { } #[test] -fn cannot_abs_range() { - let actual = nu!("0..5 | math abs"); +fn can_abs_range_into_list() { + let actual = nu!("-1.5..-10.5 | math abs"); + let expected = nu!("1.5..10.5"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_abs_infinite_range() { + let actual = nu!("0.. | math abs"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/ceil.rs b/crates/nu-command/tests/commands/math/ceil.rs index f9c753d1dd..e7377efec4 100644 --- a/crates/nu-command/tests/commands/math/ceil.rs +++ b/crates/nu-command/tests/commands/math/ceil.rs @@ -7,8 +7,16 @@ fn const_ceil() { } #[test] -fn cannot_ceil_range() { - let actual = nu!("0..5 | math ceil"); +fn can_ceil_range_into_list() { + let actual = nu!("(1.8)..(3.8) | math ceil"); + let expected = nu!("[2 3 4]"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_ceil_infinite_range() { + let actual = nu!("0.. | math ceil"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/floor.rs b/crates/nu-command/tests/commands/math/floor.rs index 5517233caa..0cf2a47946 100644 --- a/crates/nu-command/tests/commands/math/floor.rs +++ b/crates/nu-command/tests/commands/math/floor.rs @@ -7,8 +7,16 @@ fn const_floor() { } #[test] -fn cannot_floor_range() { +fn can_floor_range_into_list() { + let actual = nu!("(1.8)..(3.8) | math floor"); + let expected = nu!("[1 2 3]"); + + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_floor_infinite_range() { let actual = nu!("0.. | math floor"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/log.rs b/crates/nu-command/tests/commands/math/log.rs index db69378e41..23d6abd7cb 100644 --- a/crates/nu-command/tests/commands/math/log.rs +++ b/crates/nu-command/tests/commands/math/log.rs @@ -7,8 +7,16 @@ fn const_log() { } #[test] -fn cannot_log_range() { - let actual = nu!("0.. | math log 2"); +fn can_log_range_into_list() { + let actual = nu!("1..5 | math log 2"); + let expected = nu!("[1 2 3 4 5] | math log 2"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_log_infinite_range() { + let actual = nu!("1.. | math log 2"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/round.rs b/crates/nu-command/tests/commands/math/round.rs index 2c3badad5e..70b7567354 100644 --- a/crates/nu-command/tests/commands/math/round.rs +++ b/crates/nu-command/tests/commands/math/round.rs @@ -42,8 +42,16 @@ fn const_round() { } #[test] -fn cannot_round_infinite_range() { - let actual = nu!("0..5 | math round"); +fn can_round_range_into_list() { + let actual = nu!("(1.0)..(1.2)..(2.0) | math round"); + let expected = nu!("[1 1 1 2 2 2]"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_round_infinite_range() { + let actual = nu!("0.. | math round"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/sqrt.rs b/crates/nu-command/tests/commands/math/sqrt.rs index 9f5cc55f88..3da12fab7c 100644 --- a/crates/nu-command/tests/commands/math/sqrt.rs +++ b/crates/nu-command/tests/commands/math/sqrt.rs @@ -28,8 +28,16 @@ fn const_sqrt() { } #[test] -fn cannot_sqrt_range() { +fn can_sqrt_range() { let actual = nu!("0..5 | math sqrt"); + let expected = nu!("[0 1 2 3 4 5] | math sqrt"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_sqrt_infinite_range() { + let actual = nu!("0.. | math sqrt"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/stddev.rs b/crates/nu-command/tests/commands/math/stddev.rs index f1688c2d7a..c8398d5637 100644 --- a/crates/nu-command/tests/commands/math/stddev.rs +++ b/crates/nu-command/tests/commands/math/stddev.rs @@ -7,8 +7,16 @@ fn const_avg() { } #[test] -fn cannot_stddev_range() { +fn can_stddev_range() { let actual = nu!("0..5 | math stddev"); + let expected = nu!("[0 1 2 3 4 5] | math stddev"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_stddev_infinite_range() { + let actual = nu!("0.. | math stddev"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/crates/nu-command/tests/commands/math/variance.rs b/crates/nu-command/tests/commands/math/variance.rs index 1573a131bb..b31d75e148 100644 --- a/crates/nu-command/tests/commands/math/variance.rs +++ b/crates/nu-command/tests/commands/math/variance.rs @@ -7,8 +7,16 @@ fn const_variance() { } #[test] -fn cannot_variance_range() { +fn can_variance_range() { let actual = nu!("0..5 | math variance"); + let expected = nu!("[0 1 2 3 4 5] | math variance"); - assert!(actual.err.contains("nu::parser::input_type_mismatch")); + assert_eq!(actual.out, expected.out); +} + +#[test] +fn cannot_variance_infinite_range() { + let actual = nu!("0.. | math variance"); + + assert!(actual.err.contains("nu::shell::incorrect_value")); } diff --git a/devdocs/README.md b/devdocs/README.md index fe558d5e65..08a6a29dc5 100644 --- a/devdocs/README.md +++ b/devdocs/README.md @@ -9,4 +9,4 @@ A complementary (currently stale) resource has been the [Nushell contributor boo - [Developer FAQ](FAQ.md) - [How to/SOPs](HOWTOS.md) - [Platform support policy](PLATFORM_SUPPORT.md) -- [Our Rust style](devdocs/rust_style.md) +- [Our Rust style](rust_style.md)