diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 507f149d3..58b6a3d10 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -387,6 +387,7 @@ pub fn create_default_context() -> EngineState { MathPi, MathTau, MathEuler, + MathExp, MathLn, MathLog, }; diff --git a/crates/nu-command/src/math/exp.rs b/crates/nu-command/src/math/exp.rs new file mode 100644 index 000000000..d376e782e --- /dev/null +++ b/crates/nu-command/src/math/exp.rs @@ -0,0 +1,98 @@ +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "math exp" + } + + fn signature(&self) -> Signature { + Signature::build("math exp") + .input_output_types(vec![(Type::Number, Type::Float)]) + .vectorizes_over_list(true) + .category(Category::Math) + } + + fn usage(&self) -> &str { + "Returns e raised to the power of x." + } + + fn search_terms(&self) -> Vec<&str> { + vec!["exponential", "exponentiation", "euler"] + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + // This doesn't match explicit nulls + if matches!(input, PipelineData::Empty) { + return Err(ShellError::PipelineEmpty { dst_span: head }); + } + input.map( + move |value| operate(value, head), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Get e raised to the power of zero", + example: "0 | math exp", + result: Some(Value::test_float(1.0f64)), + }, + Example { + description: "Get e (same as 'math e')", + example: "1 | math exp", + result: Some(Value::test_float(1.0f64.exp())), + }, + ] + } +} + +fn operate(value: Value, head: Span) -> Value { + match value { + numeric @ (Value::Int { .. } | Value::Float { .. }) => { + let (val, span) = match numeric { + Value::Int { val, span } => (val as f64, span), + Value::Float { val, span } => (val, span), + _ => unreachable!(), + }; + + Value::Float { + val: val.exp(), + span, + } + } + Value::Error { .. } => value, + other => Value::Error { + error: Box::new(ShellError::OnlySupportsThisInputType { + exp_input_type: "numeric".into(), + wrong_type: other.get_type().to_string(), + dst_span: head, + src_span: other.expect_span(), + }), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/math/mod.rs b/crates/nu-command/src/math/mod.rs index 52a698208..87ab45704 100644 --- a/crates/nu-command/src/math/mod.rs +++ b/crates/nu-command/src/math/mod.rs @@ -10,6 +10,7 @@ mod ceil; mod cos; mod cosh; mod euler; +mod exp; mod floor; mod ln; mod log; @@ -68,4 +69,5 @@ pub use pi::SubCommand as MathPi; pub use tau::SubCommand as MathTau; pub use self::log::SubCommand as MathLog; +pub use exp::SubCommand as MathExp; pub use ln::SubCommand as MathLn;