use crate::commands::PerItemCommand; use crate::prelude::*; use nu_errors::ShellError; use nu_protocol::{CallInfo, Primitive, ReturnSuccess, UntaggedValue, Value}; pub struct Calc; impl PerItemCommand for Calc { fn name(&self) -> &str { "calc" } fn usage(&self) -> &str { "Parse a math expression into a number" } fn run( &self, _call_info: &CallInfo, _registry: &CommandRegistry, raw_args: &RawCommandArgs, input: Value, ) -> Result { calc(input, raw_args) } } fn calc(input: Value, args: &RawCommandArgs) -> Result { let name_span = &args.call_info.name_tag.span; let output = if let Ok(string) = input.as_string() { match parse(&string, &input.tag) { Ok(value) => ReturnSuccess::value(value), Err(err) => Err(ShellError::labeled_error( "Calculation error", err, &input.tag.span, )), } } else { Err(ShellError::labeled_error( "Expected a string from pipeline", "requires string input", name_span, )) }; Ok(vec![output].into()) } pub fn parse(math_expression: &str, tag: impl Into) -> Result { use std::f64; let num = meval::eval_str(math_expression); match num { Ok(num) => { if num == f64::INFINITY || num == f64::NEG_INFINITY { return Err(String::from("cannot represent result")); } Ok(UntaggedValue::from(Primitive::from(num)).into_value(tag)) } Err(error) => Err(error.to_string()), } }