diff --git a/crates/nu-parser/src/type_check.rs b/crates/nu-parser/src/type_check.rs index b026c5b821..a639fbcaa8 100644 --- a/crates/nu-parser/src/type_check.rs +++ b/crates/nu-parser/src/type_check.rs @@ -1,15 +1,12 @@ use nu_protocol::{ - ast::{ - Assignment, Bits, Block, Boolean, Comparison, Expr, Expression, Math, Operator, Pipeline, - Range, - }, + ast::{Block, Comparison, Expr, Expression, Math, Operator, Pipeline, Range}, engine::StateWorkingSet, - ParseError, Type, + ParseError, Span, Type, }; fn type_error( - name: &'static str, - op: &Expression, + op: Operator, + op_span: Span, lhs: &Expression, rhs: &Expression, is_supported: fn(&Type) -> bool, @@ -17,25 +14,25 @@ fn type_error( let is_supported = |ty| is_supported(ty) || matches!(ty, Type::Any | Type::Custom(_)); let err = match (is_supported(&lhs.ty), is_supported(&rhs.ty)) { (true, true) => ParseError::OperatorIncompatibleTypes { - op: name, + op: op.as_str(), lhs: lhs.ty.clone(), rhs: rhs.ty.clone(), - op_span: op.span, + op_span, lhs_span: lhs.span, rhs_span: rhs.span, help: None, }, (true, false) => ParseError::OperatorUnsupportedType { - op: name, + op: op.as_str(), unsupported: rhs.ty.clone(), - op_span: op.span, + op_span, unsupported_span: rhs.span, help: None, }, (false, _) => ParseError::OperatorUnsupportedType { - op: name, + op: op.as_str(), unsupported: lhs.ty.clone(), - op_span: op.span, + op_span, unsupported_span: lhs.span, help: None, }, @@ -141,7 +138,7 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("addition", op, lhs, rhs, |ty| { + type_error(Operator::Math(Math::Add), op.span, lhs, rhs, |ty| { matches!( ty, Type::Int @@ -175,7 +172,7 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("subtraction", op, lhs, rhs, |ty| { + type_error(Operator::Math(Math::Subtract), op.span, lhs, rhs, |ty| { matches!( ty, Type::Int @@ -212,7 +209,7 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("multiplication", op, lhs, rhs, |ty| { + type_error(Operator::Math(Math::Multiply), op.span, lhs, rhs, |ty| { matches!( ty, Type::Int | Type::Float | Type::Number | Type::Duration | Type::Filesize, @@ -242,7 +239,7 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("division", op, lhs, rhs, |ty| { + type_error(Operator::Math(Math::Divide), op.span, lhs, rhs, |ty| { matches!( ty, Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration @@ -272,7 +269,7 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("floor division", op, lhs, rhs, |ty| { + type_error(Operator::Math(Math::FloorDivide), op.span, lhs, rhs, |ty| { matches!( ty, Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration @@ -302,7 +299,7 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("modulo", op, lhs, rhs, |ty| { + type_error(Operator::Math(Math::Modulo), op.span, lhs, rhs, |ty| { matches!( ty, Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration @@ -326,7 +323,7 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("exponentiation", op, lhs, rhs, |ty| { + type_error(Operator::Math(Math::Pow), op.span, lhs, rhs, |ty| { matches!(ty, Type::Int | Type::Float | Type::Number) }) } @@ -382,7 +379,7 @@ pub fn math_result_type( }; let err = match (is_supported(&lhs.ty), is_supported(&rhs.ty)) { (true, true) => ParseError::OperatorIncompatibleTypes { - op: "concatentation", + op: Operator::Math(Math::Concatenate).as_str(), lhs: lhs.ty.clone(), rhs: rhs.ty.clone(), op_span: op.span, @@ -391,14 +388,14 @@ pub fn math_result_type( help, }, (true, false) => ParseError::OperatorUnsupportedType { - op: "concatentation", + op: Operator::Math(Math::Concatenate).as_str(), unsupported: rhs.ty.clone(), op_span: op.span, unsupported_span: rhs.span, help, }, (false, _) => ParseError::OperatorUnsupportedType { - op: "concatentation", + op: Operator::Math(Math::Concatenate).as_str(), unsupported: lhs.ty.clone(), op_span: op.span, unsupported_span: lhs.span, @@ -416,12 +413,9 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - let name = match operator { - Boolean::Or => "boolean or", - Boolean::Xor => "boolean xor", - Boolean::And => "boolean and", - }; - type_error(name, op, lhs, rhs, |ty| matches!(ty, Type::Bool)) + type_error(Operator::Boolean(operator), op.span, lhs, rhs, |ty| { + matches!(ty, Type::Bool) + }) } }, Operator::Comparison(Comparison::LessThan) => match (&lhs.ty, &rhs.ty) { @@ -454,20 +448,26 @@ pub fn math_result_type( (_, Type::Any) => (Type::Bool, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("less than comparison", op, lhs, rhs, |ty| { - matches!( - ty, - Type::Int - | Type::Float - | Type::Number - | Type::String - | Type::Filesize - | Type::Duration - | Type::Date - | Type::Bool - | Type::Nothing - ) - }) + type_error( + Operator::Comparison(Comparison::LessThan), + op.span, + lhs, + rhs, + |ty| { + matches!( + ty, + Type::Int + | Type::Float + | Type::Number + | Type::String + | Type::Filesize + | Type::Duration + | Type::Date + | Type::Bool + | Type::Nothing + ) + }, + ) } }, Operator::Comparison(Comparison::LessThanOrEqual) => match (&lhs.ty, &rhs.ty) { @@ -500,20 +500,26 @@ pub fn math_result_type( (_, Type::Any) => (Type::Bool, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("less than or equal to comparison", op, lhs, rhs, |ty| { - matches!( - ty, - Type::Int - | Type::Float - | Type::Number - | Type::String - | Type::Filesize - | Type::Duration - | Type::Date - | Type::Bool - | Type::Nothing - ) - }) + type_error( + Operator::Comparison(Comparison::LessThanOrEqual), + op.span, + lhs, + rhs, + |ty| { + matches!( + ty, + Type::Int + | Type::Float + | Type::Number + | Type::String + | Type::Filesize + | Type::Duration + | Type::Date + | Type::Bool + | Type::Nothing + ) + }, + ) } }, Operator::Comparison(Comparison::GreaterThan) => match (&lhs.ty, &rhs.ty) { @@ -546,20 +552,26 @@ pub fn math_result_type( (_, Type::Any) => (Type::Bool, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("greater than comparison", op, lhs, rhs, |ty| { - matches!( - ty, - Type::Int - | Type::Float - | Type::Number - | Type::String - | Type::Filesize - | Type::Duration - | Type::Date - | Type::Bool - | Type::Nothing - ) - }) + type_error( + Operator::Comparison(Comparison::GreaterThan), + op.span, + lhs, + rhs, + |ty| { + matches!( + ty, + Type::Int + | Type::Float + | Type::Number + | Type::String + | Type::Filesize + | Type::Duration + | Type::Date + | Type::Bool + | Type::Nothing + ) + }, + ) } }, Operator::Comparison(Comparison::GreaterThanOrEqual) => match (&lhs.ty, &rhs.ty) { @@ -592,20 +604,26 @@ pub fn math_result_type( (_, Type::Any) => (Type::Bool, None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("greater than or equal to comparison", op, lhs, rhs, |ty| { - matches!( - ty, - Type::Int - | Type::Float - | Type::Number - | Type::String - | Type::Filesize - | Type::Duration - | Type::Date - | Type::Bool - | Type::Nothing - ) - }) + type_error( + Operator::Comparison(Comparison::GreaterThanOrEqual), + op.span, + lhs, + rhs, + |ty| { + matches!( + ty, + Type::Int + | Type::Float + | Type::Number + | Type::String + | Type::Filesize + | Type::Duration + | Type::Date + | Type::Bool + | Type::Nothing + ) + }, + ) } }, Operator::Comparison(Comparison::Equal) => match (&lhs.ty, &rhs.ty) { @@ -625,7 +643,13 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("regex match", op, lhs, rhs, |ty| matches!(ty, Type::String)) + type_error( + Operator::Comparison(Comparison::RegexMatch), + op.span, + lhs, + rhs, + |ty| matches!(ty, Type::String), + ) } }, Operator::Comparison(Comparison::NotRegexMatch) => match (&lhs.ty, &rhs.ty) { @@ -635,9 +659,13 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("negative regex match", op, lhs, rhs, |ty| { - matches!(ty, Type::String) - }) + type_error( + Operator::Comparison(Comparison::NotRegexMatch), + op.span, + lhs, + rhs, + |ty| matches!(ty, Type::String), + ) } }, Operator::Comparison(Comparison::StartsWith) => match (&lhs.ty, &rhs.ty) { @@ -647,9 +675,13 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("starts-with comparison", op, lhs, rhs, |ty| { - matches!(ty, Type::String) - }) + type_error( + Operator::Comparison(Comparison::StartsWith), + op.span, + lhs, + rhs, + |ty| matches!(ty, Type::String), + ) } }, Operator::Comparison(Comparison::EndsWith) => match (&lhs.ty, &rhs.ty) { @@ -659,9 +691,13 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), _ => { *op = Expression::garbage(working_set, op.span); - type_error("ends-with comparison", op, lhs, rhs, |ty| { - matches!(ty, Type::String) - }) + type_error( + Operator::Comparison(Comparison::LessThan), + op.span, + lhs, + rhs, + |ty| matches!(ty, Type::String), + ) } }, Operator::Comparison(Comparison::In) => match (&lhs.ty, &rhs.ty) { @@ -685,7 +721,7 @@ pub fn math_result_type( | Type::Any ) { ParseError::OperatorIncompatibleTypes { - op: "'in' comparison", + op: Operator::Comparison(Comparison::In).as_str(), lhs: lhs.ty.clone(), rhs: rhs.ty.clone(), op_span: op.span, @@ -695,7 +731,7 @@ pub fn math_result_type( } } else { ParseError::OperatorUnsupportedType { - op: "'in' comparison", + op: Operator::Comparison(Comparison::In).as_str(), unsupported: rhs.ty.clone(), op_span: op.span, unsupported_span: rhs.span, @@ -726,7 +762,7 @@ pub fn math_result_type( | Type::Any ) { ParseError::OperatorIncompatibleTypes { - op: "'not-in' comparison", + op: Operator::Comparison(Comparison::NotIn).as_str(), lhs: lhs.ty.clone(), rhs: rhs.ty.clone(), op_span: op.span, @@ -736,7 +772,7 @@ pub fn math_result_type( } } else { ParseError::OperatorUnsupportedType { - op: "'not-in' comparison", + op: Operator::Comparison(Comparison::NotIn).as_str(), unsupported: rhs.ty.clone(), op_span: op.span, unsupported_span: rhs.span, @@ -752,14 +788,9 @@ pub fn math_result_type( (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(working_set, op.span); - let name = match operator { - Bits::BitOr => "bitwise or", - Bits::BitXor => "bitwise xor", - Bits::BitAnd => "bitwise and", - Bits::ShiftLeft => "bit left shift", - Bits::ShiftRight => "bit right shift", - }; - type_error(name, op, lhs, rhs, |ty| matches!(ty, Type::Int)) + type_error(Operator::Bits(operator), op.span, lhs, rhs, |ty| { + matches!(ty, Type::Int) + }) } }, // TODO: fix this @@ -771,16 +802,8 @@ pub fn math_result_type( (Type::Nothing, None) } _ => { - let name = match operator { - Assignment::Assign => "variable assignment", - Assignment::AddAssign => "addition assignment", - Assignment::SubtractAssign => "subtraction assignment", - Assignment::MultiplyAssign => "multiplication assignment", - Assignment::DivideAssign => "division assignment", - Assignment::ConcatenateAssign => "concatenation assignment", - }; let err = ParseError::OperatorIncompatibleTypes { - op: name, + op: Operator::Assignment(operator).as_str(), lhs: lhs.ty.clone(), rhs: rhs.ty.clone(), op_span: op.span, diff --git a/crates/nu-protocol/src/errors/parse_error.rs b/crates/nu-protocol/src/errors/parse_error.rs index 8ff4cff8eb..c90133a294 100644 --- a/crates/nu-protocol/src/errors/parse_error.rs +++ b/crates/nu-protocol/src/errors/parse_error.rs @@ -1,11 +1,10 @@ +use crate::{ast::RedirectionSource, did_you_mean, Span, Type}; +use miette::Diagnostic; +use serde::{Deserialize, Serialize}; use std::{ fmt::Display, str::{from_utf8, Utf8Error}, }; - -use crate::{ast::RedirectionSource, did_you_mean, Span, Type}; -use miette::Diagnostic; -use serde::{Deserialize, Serialize}; use thiserror::Error; #[derive(Clone, Debug, Error, Diagnostic, Serialize, Deserialize)] @@ -112,12 +111,12 @@ pub enum ParseError { }, /// One or more of the values have types not supported by the operator. - #[error("{op} is not supported on values of type {unsupported}.")] - #[diagnostic(code(nu::parser::operator_unsupported_type))] + #[error("The '{op}' operator does not work on values of type '{unsupported}'.")] + #[diagnostic(code(nu::shell::operator_unsupported_type))] OperatorUnsupportedType { op: &'static str, unsupported: Type, - #[label = "does support this type"] + #[label = "does not support '{unsupported}'"] op_span: Span, #[label("{unsupported}")] unsupported_span: Span, @@ -126,13 +125,13 @@ pub enum ParseError { }, /// The operator supports the types of both values, but not the specific combination of their types. - #[error("{op} is not supported between types {lhs} and {rhs}.")] - #[diagnostic(code(nu::parser::operator_incompatible_types))] + #[error("Types '{lhs}' and '{rhs}' are not compatiable for the '{op}' operator.")] + #[diagnostic(code(nu::shell::operator_incompatible_types))] OperatorIncompatibleTypes { op: &'static str, lhs: Type, rhs: Type, - #[label = "does not operate between these two types"] + #[label = "does not operate between '{lhs}' and '{rhs}'"] op_span: Span, #[label("{lhs}")] lhs_span: Span, diff --git a/crates/nu-protocol/src/errors/shell_error.rs b/crates/nu-protocol/src/errors/shell_error.rs index 6932c51333..6514028003 100644 --- a/crates/nu-protocol/src/errors/shell_error.rs +++ b/crates/nu-protocol/src/errors/shell_error.rs @@ -12,33 +12,13 @@ use thiserror::Error; /// and pass it into an error viewer to display to the user. #[derive(Debug, Clone, Error, Diagnostic, PartialEq)] pub enum ShellError { - /// An operator received two arguments of incompatible types. - /// - /// ## Resolution - /// - /// Check each argument's type and convert one or both as needed. - /// - #[deprecated = "use `OperatorUnsupportedType` or `OperatorTypeMismatch` instead"] - #[error("Type mismatch during operation.")] - #[diagnostic(code(nu::shell::type_mismatch))] - OperatorMismatch { - #[label = "type mismatch for operator"] - op_span: Span, - lhs_ty: String, - #[label("{lhs_ty}")] - lhs_span: Span, - rhs_ty: String, - #[label("{rhs_ty}")] - rhs_span: Span, - }, - /// One or more of the values have types not supported by the operator. - #[error("{op} is not supported on values of type {unsupported}.")] + #[error("The '{op}' operator does not work on values of type '{unsupported}'.")] #[diagnostic(code(nu::shell::operator_unsupported_type))] OperatorUnsupportedType { - op: &'static str, + op: Operator, unsupported: Type, - #[label = "does support this type"] + #[label = "does not support '{unsupported}'"] op_span: Span, #[label("{unsupported}")] unsupported_span: Span, @@ -47,13 +27,13 @@ pub enum ShellError { }, /// The operator supports the types of both values, but not the specific combination of their types. - #[error("{op} is not supported between types {lhs} and {rhs}.")] + #[error("Types '{lhs}' and '{rhs}' are not compatiable for the '{op}' operator.")] #[diagnostic(code(nu::shell::operator_incompatible_types))] OperatorIncompatibleTypes { - op: &'static str, + op: Operator, lhs: Type, rhs: Type, - #[label = "does not operate between these two types"] + #[label = "does not operate between '{lhs}' and '{rhs}'"] op_span: Span, #[label("{lhs}")] lhs_span: Span, diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 6b89fc3695..75066ce065 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -2490,17 +2490,23 @@ impl Value { (Value::Custom { val: lhs, .. }, rhs) => { lhs.operation(self.span(), Operator::Math(Math::Add), op, rhs) } - _ => Err(operator_type_error("addition", op, self, rhs, |val| { - matches!( - val, - Value::Int { .. } - | Value::Float { .. } - | Value::String { .. } - | Value::Date { .. } - | Value::Duration { .. } - | Value::Filesize { .. }, - ) - })), + _ => Err(operator_type_error( + Operator::Math(Math::Add), + op, + self, + rhs, + |val| { + matches!( + val, + Value::Int { .. } + | Value::Float { .. } + | Value::String { .. } + | Value::Date { .. } + | Value::Duration { .. } + | Value::Filesize { .. }, + ) + }, + )), } } @@ -2573,16 +2579,22 @@ impl Value { (Value::Custom { val: lhs, .. }, rhs) => { lhs.operation(self.span(), Operator::Math(Math::Subtract), op, rhs) } - _ => Err(operator_type_error("subtraction", op, self, rhs, |val| { - matches!( - val, - Value::Int { .. } - | Value::Float { .. } - | Value::Date { .. } - | Value::Duration { .. } - | Value::Filesize { .. }, - ) - })), + _ => Err(operator_type_error( + Operator::Math(Math::Subtract), + op, + self, + rhs, + |val| { + matches!( + val, + Value::Int { .. } + | Value::Float { .. } + | Value::Date { .. } + | Value::Duration { .. } + | Value::Filesize { .. }, + ) + }, + )), } } @@ -2636,7 +2648,7 @@ impl Value { lhs.operation(self.span(), Operator::Math(Math::Multiply), op, rhs) } _ => Err(operator_type_error( - "multiplication", + Operator::Math(Math::Multiply), op, self, rhs, @@ -2758,173 +2770,21 @@ impl Value { (Value::Custom { val: lhs, .. }, rhs) => { lhs.operation(self.span(), Operator::Math(Math::Divide), op, rhs) } - _ => Err(operator_type_error("division", op, self, rhs, |val| { - matches!( - val, - Value::Int { .. } - | Value::Float { .. } - | Value::Duration { .. } - | Value::Filesize { .. }, - ) - })), - } - } - - pub fn modulo(&self, op: Span, rhs: &Value, span: Span) -> Result { - // Based off the unstable `div_floor` function in the std library. - fn checked_mod_i64(dividend: i64, divisor: i64) -> Option { - let remainder = dividend.checked_rem(divisor)?; - if (remainder > 0 && divisor < 0) || (remainder < 0 && divisor > 0) { - // Note that `remainder + divisor` cannot overflow, because `remainder` and - // `divisor` have opposite signs. - Some(remainder + divisor) - } else { - Some(remainder) - } - } - - fn checked_mod_f64(dividend: f64, divisor: f64) -> Option { - if divisor == 0.0 { - None - } else { - let remainder = dividend % divisor; - if (remainder > 0.0 && divisor < 0.0) || (remainder < 0.0 && divisor > 0.0) { - Some(remainder + divisor) - } else { - Some(remainder) - } - } - } - - match (self, rhs) { - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - if let Some(val) = checked_mod_i64(*lhs, *rhs) { - Ok(Value::int(val, span)) - } else if *rhs == 0 { - Err(ShellError::DivisionByZero { span: op }) - } else { - Err(ShellError::OperatorOverflow { - msg: "modulo operation overflowed".into(), - span, - help: None, - }) - } - } - (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => { - if let Some(val) = checked_mod_f64(*lhs as f64, *rhs) { - Ok(Value::float(val, span)) - } else { - Err(ShellError::DivisionByZero { span: op }) - } - } - (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - if let Some(val) = checked_mod_f64(*lhs, *rhs as f64) { - Ok(Value::float(val, span)) - } else { - Err(ShellError::DivisionByZero { span: op }) - } - } - (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => { - if let Some(val) = checked_mod_f64(*lhs, *rhs) { - Ok(Value::float(val, span)) - } else { - Err(ShellError::DivisionByZero { span: op }) - } - } - (Value::Filesize { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => { - if let Some(val) = checked_mod_i64(*lhs, *rhs) { - Ok(Value::filesize(val, span)) - } else if *rhs == 0 { - Err(ShellError::DivisionByZero { span: op }) - } else { - Err(ShellError::OperatorOverflow { - msg: "modulo operation overflowed".into(), - span, - help: None, - }) - } - } - (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - if let Some(val) = checked_mod_i64(*lhs, *rhs) { - Ok(Value::filesize(val, span)) - } else if *rhs == 0 { - Err(ShellError::DivisionByZero { span: op }) - } else { - Err(ShellError::OperatorOverflow { - msg: "modulo operation overflowed".into(), - span, - help: None, - }) - } - } - (Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => { - if let Some(val) = checked_mod_f64(*lhs as f64, *rhs) { - if i64::MIN as f64 <= val && val <= i64::MAX as f64 { - Ok(Value::filesize(val as i64, span)) - } else { - Err(ShellError::OperatorOverflow { - msg: "modulo operation overflowed".into(), - span, - help: None, - }) - } - } else { - Err(ShellError::DivisionByZero { span: op }) - } - } - (Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { - if let Some(val) = checked_mod_i64(*lhs, *rhs) { - Ok(Value::duration(val, span)) - } else if *rhs == 0 { - Err(ShellError::DivisionByZero { span: op }) - } else { - Err(ShellError::OperatorOverflow { - msg: "division operation overflowed".into(), - span, - help: None, - }) - } - } - (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - if let Some(val) = checked_mod_i64(*lhs, *rhs) { - Ok(Value::duration(val, span)) - } else if *rhs == 0 { - Err(ShellError::DivisionByZero { span: op }) - } else { - Err(ShellError::OperatorOverflow { - msg: "division operation overflowed".into(), - span, - help: None, - }) - } - } - (Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => { - if let Some(val) = checked_mod_f64(*lhs as f64, *rhs) { - if i64::MIN as f64 <= val && val <= i64::MAX as f64 { - Ok(Value::duration(val as i64, span)) - } else { - Err(ShellError::OperatorOverflow { - msg: "division operation overflowed".into(), - span, - help: None, - }) - } - } else { - Err(ShellError::DivisionByZero { span: op }) - } - } - (Value::Custom { val: lhs, .. }, rhs) => { - lhs.operation(span, Operator::Math(Math::Modulo), op, rhs) - } - _ => Err(operator_type_error("modulo", op, self, rhs, |val| { - matches!( - val, - Value::Int { .. } - | Value::Float { .. } - | Value::Duration { .. } - | Value::Filesize { .. }, - ) - })), + _ => Err(operator_type_error( + Operator::Math(Math::Divide), + op, + self, + rhs, + |val| { + matches!( + val, + Value::Int { .. } + | Value::Float { .. } + | Value::Duration { .. } + | Value::Filesize { .. }, + ) + }, + )), } } @@ -3074,7 +2934,7 @@ impl Value { lhs.operation(self.span(), Operator::Math(Math::Divide), op, rhs) } _ => Err(operator_type_error( - "floor division", + Operator::Math(Math::FloorDivide), op, self, rhs, @@ -3091,6 +2951,205 @@ impl Value { } } + pub fn modulo(&self, op: Span, rhs: &Value, span: Span) -> Result { + // Based off the unstable `div_floor` function in the std library. + fn checked_mod_i64(dividend: i64, divisor: i64) -> Option { + let remainder = dividend.checked_rem(divisor)?; + if (remainder > 0 && divisor < 0) || (remainder < 0 && divisor > 0) { + // Note that `remainder + divisor` cannot overflow, because `remainder` and + // `divisor` have opposite signs. + Some(remainder + divisor) + } else { + Some(remainder) + } + } + + fn checked_mod_f64(dividend: f64, divisor: f64) -> Option { + if divisor == 0.0 { + None + } else { + let remainder = dividend % divisor; + if (remainder > 0.0 && divisor < 0.0) || (remainder < 0.0 && divisor > 0.0) { + Some(remainder + divisor) + } else { + Some(remainder) + } + } + } + + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if let Some(val) = checked_mod_i64(*lhs, *rhs) { + Ok(Value::int(val, span)) + } else if *rhs == 0 { + Err(ShellError::DivisionByZero { span: op }) + } else { + Err(ShellError::OperatorOverflow { + msg: "modulo operation overflowed".into(), + span, + help: None, + }) + } + } + (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if let Some(val) = checked_mod_f64(*lhs as f64, *rhs) { + Ok(Value::float(val, span)) + } else { + Err(ShellError::DivisionByZero { span: op }) + } + } + (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if let Some(val) = checked_mod_f64(*lhs, *rhs as f64) { + Ok(Value::float(val, span)) + } else { + Err(ShellError::DivisionByZero { span: op }) + } + } + (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if let Some(val) = checked_mod_f64(*lhs, *rhs) { + Ok(Value::float(val, span)) + } else { + Err(ShellError::DivisionByZero { span: op }) + } + } + (Value::Filesize { val: lhs, .. }, Value::Filesize { val: rhs, .. }) => { + if let Some(val) = checked_mod_i64(*lhs, *rhs) { + Ok(Value::filesize(val, span)) + } else if *rhs == 0 { + Err(ShellError::DivisionByZero { span: op }) + } else { + Err(ShellError::OperatorOverflow { + msg: "modulo operation overflowed".into(), + span, + help: None, + }) + } + } + (Value::Filesize { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if let Some(val) = checked_mod_i64(*lhs, *rhs) { + Ok(Value::filesize(val, span)) + } else if *rhs == 0 { + Err(ShellError::DivisionByZero { span: op }) + } else { + Err(ShellError::OperatorOverflow { + msg: "modulo operation overflowed".into(), + span, + help: None, + }) + } + } + (Value::Filesize { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if let Some(val) = checked_mod_f64(*lhs as f64, *rhs) { + if i64::MIN as f64 <= val && val <= i64::MAX as f64 { + Ok(Value::filesize(val as i64, span)) + } else { + Err(ShellError::OperatorOverflow { + msg: "modulo operation overflowed".into(), + span, + help: None, + }) + } + } else { + Err(ShellError::DivisionByZero { span: op }) + } + } + (Value::Duration { val: lhs, .. }, Value::Duration { val: rhs, .. }) => { + if let Some(val) = checked_mod_i64(*lhs, *rhs) { + Ok(Value::duration(val, span)) + } else if *rhs == 0 { + Err(ShellError::DivisionByZero { span: op }) + } else { + Err(ShellError::OperatorOverflow { + msg: "division operation overflowed".into(), + span, + help: None, + }) + } + } + (Value::Duration { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if let Some(val) = checked_mod_i64(*lhs, *rhs) { + Ok(Value::duration(val, span)) + } else if *rhs == 0 { + Err(ShellError::DivisionByZero { span: op }) + } else { + Err(ShellError::OperatorOverflow { + msg: "division operation overflowed".into(), + span, + help: None, + }) + } + } + (Value::Duration { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + if let Some(val) = checked_mod_f64(*lhs as f64, *rhs) { + if i64::MIN as f64 <= val && val <= i64::MAX as f64 { + Ok(Value::duration(val as i64, span)) + } else { + Err(ShellError::OperatorOverflow { + msg: "division operation overflowed".into(), + span, + help: None, + }) + } + } else { + Err(ShellError::DivisionByZero { span: op }) + } + } + (Value::Custom { val: lhs, .. }, rhs) => { + lhs.operation(span, Operator::Math(Math::Modulo), op, rhs) + } + _ => Err(operator_type_error( + Operator::Math(Math::Modulo), + op, + self, + rhs, + |val| { + matches!( + val, + Value::Int { .. } + | Value::Float { .. } + | Value::Duration { .. } + | Value::Filesize { .. }, + ) + }, + )), + } + } + + pub fn pow(&self, op: Span, rhs: &Value, span: Span) -> Result { + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + if let Some(val) = lhs.checked_pow(*rhs as u32) { + Ok(Value::int(val, span)) + } else { + Err(ShellError::OperatorOverflow { + msg: "pow operation overflowed".into(), + span, + help: Some("Consider using floating point values for increased range by promoting operand with 'into float'. Note: float has reduced precision!".into()), + }) + } + } + (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + Ok(Value::float((*lhs as f64).powf(*rhs), span)) + } + (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + Ok(Value::float(lhs.powf(*rhs as f64), span)) + } + (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => { + Ok(Value::float(lhs.powf(*rhs), span)) + } + (Value::Custom { val: lhs, .. }, rhs) => { + lhs.operation(span, Operator::Math(Math::Pow), op, rhs) + } + _ => Err(operator_type_error( + Operator::Math(Math::Pow), + op, + self, + rhs, + |val| matches!(val, Value::Int { .. } | Value::Float { .. }), + )), + } + } + pub fn concat(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::List { vals: lhs, .. }, Value::List { vals: rhs, .. }) => { @@ -3107,7 +3166,7 @@ impl Value { lhs.operation(self.span(), Operator::Math(Math::Concatenate), op, rhs) } _ => Err(operator_type_error( - "concatentation", + Operator::Math(Math::Concatenate), op, self, rhs, @@ -3137,7 +3196,7 @@ impl Value { if !type_compatible(self.get_type(), rhs.get_type()) { return Err(operator_type_error( - "less than comparison", + Operator::Comparison(Comparison::LessThan), op, self, rhs, @@ -3179,7 +3238,7 @@ impl Value { if !type_compatible(self.get_type(), rhs.get_type()) { return Err(operator_type_error( - "less than or equal to comparison", + Operator::Comparison(Comparison::LessThanOrEqual), op, self, rhs, @@ -3224,7 +3283,7 @@ impl Value { if !type_compatible(self.get_type(), rhs.get_type()) { return Err(operator_type_error( - "greater than comparison", + Operator::Comparison(Comparison::GreaterThan), op, self, rhs, @@ -3266,7 +3325,7 @@ impl Value { if !type_compatible(self.get_type(), rhs.get_type()) { return Err(operator_type_error( - "greater than or equal to comparison", + Operator::Comparison(Comparison::GreaterThanOrEqual), op, self, rhs, @@ -3375,7 +3434,7 @@ impl Value { | Value::Custom { .. } ) { ShellError::OperatorIncompatibleTypes { - op: "'in' comparison", + op: Operator::Comparison(Comparison::In), lhs: lhs.get_type(), rhs: rhs.get_type(), op_span: op, @@ -3385,7 +3444,7 @@ impl Value { } } else { ShellError::OperatorUnsupportedType { - op: "'in' comparison", + op: Operator::Comparison(Comparison::In), unsupported: rhs.get_type(), op_span: op, unsupported_span: rhs.span(), @@ -3447,7 +3506,7 @@ impl Value { | Value::Custom { .. } ) { ShellError::OperatorIncompatibleTypes { - op: "'not-in' comparison", + op: Operator::Comparison(Comparison::NotIn), lhs: lhs.get_type(), rhs: rhs.get_type(), op_span: op, @@ -3457,7 +3516,7 @@ impl Value { } } else { ShellError::OperatorUnsupportedType { - op: "'not-in' comparison", + op: Operator::Comparison(Comparison::NotIn), unsupported: rhs.get_type(), op_span: op, unsupported_span: rhs.span(), @@ -3526,9 +3585,17 @@ impl Value { op, rhs, ), - _ => Err(operator_type_error("regex match", op, self, rhs, |val| { - matches!(val, Value::String { .. }) - })), + _ => Err(operator_type_error( + if invert { + Operator::Comparison(Comparison::NotRegexMatch) + } else { + Operator::Comparison(Comparison::RegexMatch) + }, + op, + self, + rhs, + |val| matches!(val, Value::String { .. }), + )), } } @@ -3544,7 +3611,7 @@ impl Value { rhs, ), _ => Err(operator_type_error( - "starts-with comparison", + Operator::Comparison(Comparison::StartsWith), op, self, rhs, @@ -3565,7 +3632,7 @@ impl Value { rhs, ), _ => Err(operator_type_error( - "ends-with comparison", + Operator::Comparison(Comparison::EndsWith), op, self, rhs, @@ -3574,6 +3641,60 @@ impl Value { } } + pub fn bit_or(&self, op: Span, rhs: &Value, span: Span) -> Result { + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + Ok(Value::int(*lhs | rhs, span)) + } + (Value::Custom { val: lhs, .. }, rhs) => { + lhs.operation(span, Operator::Bits(Bits::BitOr), op, rhs) + } + _ => Err(operator_type_error( + Operator::Bits(Bits::BitOr), + op, + self, + rhs, + |val| matches!(val, Value::Int { .. }), + )), + } + } + + pub fn bit_xor(&self, op: Span, rhs: &Value, span: Span) -> Result { + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + Ok(Value::int(*lhs ^ rhs, span)) + } + (Value::Custom { val: lhs, .. }, rhs) => { + lhs.operation(span, Operator::Bits(Bits::BitXor), op, rhs) + } + _ => Err(operator_type_error( + Operator::Bits(Bits::BitXor), + op, + self, + rhs, + |val| matches!(val, Value::Int { .. }), + )), + } + } + + pub fn bit_and(&self, op: Span, rhs: &Value, span: Span) -> Result { + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + Ok(Value::int(*lhs & rhs, span)) + } + (Value::Custom { val: lhs, .. }, rhs) => { + lhs.operation(span, Operator::Bits(Bits::BitAnd), op, rhs) + } + _ => Err(operator_type_error( + Operator::Bits(Bits::BitAnd), + op, + self, + rhs, + |val| matches!(val, Value::Int { .. }), + )), + } + } + pub fn bit_shl(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { @@ -3594,7 +3715,7 @@ impl Value { lhs.operation(span, Operator::Bits(Bits::ShiftLeft), op, rhs) } _ => Err(operator_type_error( - "bit left shift", + Operator::Bits(Bits::ShiftLeft), op, self, rhs, @@ -3623,7 +3744,7 @@ impl Value { lhs.operation(span, Operator::Bits(Bits::ShiftRight), op, rhs) } _ => Err(operator_type_error( - "bit right shift", + Operator::Bits(Bits::ShiftRight), op, self, rhs, @@ -3632,62 +3753,6 @@ impl Value { } } - pub fn bit_and(&self, op: Span, rhs: &Value, span: Span) -> Result { - match (self, rhs) { - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - Ok(Value::int(*lhs & rhs, span)) - } - (Value::Custom { val: lhs, .. }, rhs) => { - lhs.operation(span, Operator::Bits(Bits::BitAnd), op, rhs) - } - _ => Err(operator_type_error("bitwise and", op, self, rhs, |val| { - matches!(val, Value::Int { .. }) - })), - } - } - - pub fn bit_or(&self, op: Span, rhs: &Value, span: Span) -> Result { - match (self, rhs) { - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - Ok(Value::int(*lhs | rhs, span)) - } - (Value::Custom { val: lhs, .. }, rhs) => { - lhs.operation(span, Operator::Bits(Bits::BitOr), op, rhs) - } - _ => Err(operator_type_error("bitwise or", op, self, rhs, |val| { - matches!(val, Value::Int { .. }) - })), - } - } - - pub fn bit_xor(&self, op: Span, rhs: &Value, span: Span) -> Result { - match (self, rhs) { - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - Ok(Value::int(*lhs ^ rhs, span)) - } - (Value::Custom { val: lhs, .. }, rhs) => { - lhs.operation(span, Operator::Bits(Bits::BitXor), op, rhs) - } - _ => Err(operator_type_error("bitwise xor", op, self, rhs, |val| { - matches!(val, Value::Int { .. }) - })), - } - } - - pub fn and(&self, op: Span, rhs: &Value, span: Span) -> Result { - match (self, rhs) { - (Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => { - Ok(Value::bool(*lhs && *rhs, span)) - } - (Value::Custom { val: lhs, .. }, rhs) => { - lhs.operation(span, Operator::Boolean(Boolean::And), op, rhs) - } - _ => Err(operator_type_error("boolean and", op, self, rhs, |val| { - matches!(val, Value::Bool { .. }) - })), - } - } - pub fn or(&self, op: Span, rhs: &Value, span: Span) -> Result { match (self, rhs) { (Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => { @@ -3696,9 +3761,13 @@ impl Value { (Value::Custom { val: lhs, .. }, rhs) => { lhs.operation(span, Operator::Boolean(Boolean::Or), op, rhs) } - _ => Err(operator_type_error("boolean or", op, self, rhs, |val| { - matches!(val, Value::Bool { .. }) - })), + _ => Err(operator_type_error( + Operator::Boolean(Boolean::Or), + op, + self, + rhs, + |val| matches!(val, Value::Bool { .. }), + )), } } @@ -3710,43 +3779,30 @@ impl Value { (Value::Custom { val: lhs, .. }, rhs) => { lhs.operation(span, Operator::Boolean(Boolean::Xor), op, rhs) } - _ => Err(operator_type_error("boolean xor", op, self, rhs, |val| { - matches!(val, Value::Bool { .. }) - })), - } - } - - pub fn pow(&self, op: Span, rhs: &Value, span: Span) -> Result { - match (self, rhs) { - (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - if let Some(val) = lhs.checked_pow(*rhs as u32) { - Ok(Value::int(val, span)) - } else { - Err(ShellError::OperatorOverflow { - msg: "pow operation overflowed".into(), - span, - help: Some("Consider using floating point values for increased range by promoting operand with 'into float'. Note: float has reduced precision!".into()), - }) - } - } - (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => { - Ok(Value::float((*lhs as f64).powf(*rhs), span)) - } - (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => { - Ok(Value::float(lhs.powf(*rhs as f64), span)) - } - (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => { - Ok(Value::float(lhs.powf(*rhs), span)) - } - (Value::Custom { val: lhs, .. }, rhs) => { - lhs.operation(span, Operator::Math(Math::Pow), op, rhs) - } _ => Err(operator_type_error( - "exponentiation", + Operator::Boolean(Boolean::Xor), op, self, rhs, - |val| matches!(val, Value::Int { .. } | Value::Float { .. }), + |val| matches!(val, Value::Bool { .. }), + )), + } + } + + pub fn and(&self, op: Span, rhs: &Value, span: Span) -> Result { + match (self, rhs) { + (Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => { + Ok(Value::bool(*lhs && *rhs, span)) + } + (Value::Custom { val: lhs, .. }, rhs) => { + lhs.operation(span, Operator::Boolean(Boolean::And), op, rhs) + } + _ => Err(operator_type_error( + Operator::Boolean(Boolean::And), + op, + self, + rhs, + |val| matches!(val, Value::Bool { .. }), )), } } @@ -3763,7 +3819,7 @@ fn type_compatible(a: Type, b: Type) -> bool { } fn operator_type_error( - op_name: &'static str, + op: Operator, op_span: Span, lhs: &Value, rhs: &Value, @@ -3772,7 +3828,7 @@ fn operator_type_error( let is_supported = |val| is_supported(val) || matches!(val, Value::Custom { .. }); match (is_supported(lhs), is_supported(rhs)) { (true, true) => ShellError::OperatorIncompatibleTypes { - op: op_name, + op, lhs: lhs.get_type(), rhs: rhs.get_type(), op_span, @@ -3781,14 +3837,14 @@ fn operator_type_error( help: None, }, (true, false) => ShellError::OperatorUnsupportedType { - op: op_name, + op, unsupported: rhs.get_type(), op_span, unsupported_span: rhs.span(), help: None, }, (false, _) => ShellError::OperatorUnsupportedType { - op: op_name, + op, unsupported: lhs.get_type(), op_span, unsupported_span: lhs.span(), diff --git a/crates/nu_plugin_custom_values/src/cool_custom_value.rs b/crates/nu_plugin_custom_values/src/cool_custom_value.rs index b4ed6c65ff..f29f63ef49 100644 --- a/crates/nu_plugin_custom_values/src/cool_custom_value.rs +++ b/crates/nu_plugin_custom_values/src/cool_custom_value.rs @@ -1,4 +1,7 @@ -use nu_protocol::{ast, CustomValue, ShellError, Span, Value}; +use nu_protocol::{ + ast::{self, Math, Operator}, + CustomValue, ShellError, Span, Value, +}; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; @@ -112,7 +115,7 @@ impl CustomValue for CoolCustomValue { ) -> Result { match operator { // Append the string inside `cool` - ast::Operator::Math(ast::Math::Concatenate) => { + Operator::Math(Math::Concatenate) => { if let Some(right) = right .as_custom_value() .ok() @@ -126,7 +129,7 @@ impl CustomValue for CoolCustomValue { )) } else { Err(ShellError::OperatorUnsupportedType { - op: "concatenation", + op: Operator::Math(Math::Concatenate), unsupported: right.get_type(), op_span, unsupported_span: right.span(), diff --git a/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs b/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs index 61acfde14e..00780fde63 100644 --- a/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs +++ b/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/between_values.rs @@ -21,12 +21,12 @@ pub(super) fn between_dataframes( Operator::Math(Math::Add) => { lhs.append_df(rhs, Axis::Row, Span::merge(left.span(), right.span())) } - _ => Err(ShellError::OperatorMismatch { + op => Err(ShellError::OperatorUnsupportedType { + op, + unsupported: left.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: left.span(), + help: None, }), } } @@ -181,12 +181,12 @@ pub(super) fn compute_between_series( span: operation_span, }), }, - _ => Err(ShellError::OperatorMismatch { + op => Err(ShellError::OperatorUnsupportedType { + op, + unsupported: left.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: left.span(), + help: None, }), } } @@ -222,12 +222,12 @@ pub(super) fn compute_series_single_value( right: &Value, ) -> Result { if !lhs.is_series() { - return Err(ShellError::OperatorMismatch { + return Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: left.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: left.span(), + help: None, }); } @@ -243,12 +243,12 @@ pub(super) fn compute_series_single_value( compute_series_float(&lhs, *val, >::add, lhs_span) } Value::String { val, .. } => add_string_to_series(&lhs, val, lhs_span), - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Math(Math::Subtract) => match &right { @@ -258,12 +258,12 @@ pub(super) fn compute_series_single_value( Value::Float { val, .. } => { compute_series_float(&lhs, *val, >::sub, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Math(Math::Multiply) => match &right { @@ -273,12 +273,12 @@ pub(super) fn compute_series_single_value( Value::Float { val, .. } => { compute_series_float(&lhs, *val, >::mul, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Math(Math::Divide) => { @@ -298,12 +298,12 @@ pub(super) fn compute_series_single_value( compute_series_float(&lhs, *val, >::div, lhs_span) } } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), } } @@ -319,12 +319,12 @@ pub(super) fn compute_series_single_value( Value::Date { val, .. } => { compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::equal, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Comparison(Comparison::NotEqual) => match &right { @@ -344,12 +344,12 @@ pub(super) fn compute_series_single_value( ChunkedArray::not_equal, lhs_span, ), - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Comparison(Comparison::LessThan) => match &right { @@ -360,12 +360,12 @@ pub(super) fn compute_series_single_value( Value::Date { val, .. } => { compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Comparison(Comparison::LessThanOrEqual) => match &right { @@ -376,12 +376,12 @@ pub(super) fn compute_series_single_value( Value::Date { val, .. } => { compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt_eq, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Comparison(Comparison::GreaterThan) => match &right { @@ -392,12 +392,12 @@ pub(super) fn compute_series_single_value( Value::Date { val, .. } => { compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Comparison(Comparison::GreaterThanOrEqual) => match &right { @@ -408,23 +408,23 @@ pub(super) fn compute_series_single_value( Value::Date { val, .. } => { compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt_eq, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, // TODO: update this to do a regex match instead of a simple contains? Operator::Comparison(Comparison::RegexMatch) => match &right { Value::String { val, .. } => contains_series_pat(&lhs, val, lhs_span), - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Comparison(Comparison::StartsWith) => match &right { @@ -432,12 +432,12 @@ pub(super) fn compute_series_single_value( let starts_with_pattern = format!("^{}", fancy_regex::escape(val)); contains_series_pat(&lhs, &starts_with_pattern, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, Operator::Comparison(Comparison::EndsWith) => match &right { @@ -445,20 +445,20 @@ pub(super) fn compute_series_single_value( let ends_with_pattern = format!("{}$", fancy_regex::escape(val)); contains_series_pat(&lhs, &ends_with_pattern, lhs_span) } - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: right.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: right.span(), + help: None, }), }, - _ => Err(ShellError::OperatorMismatch { + _ => Err(ShellError::OperatorUnsupportedType { + op: operator.item, + unsupported: left.get_type(), op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), + unsupported_span: left.span(), + help: None, }), } } diff --git a/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs b/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs index 26d8714e18..e0da3012c5 100644 --- a/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs +++ b/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs @@ -133,23 +133,13 @@ fn with_operator( .apply_with_expr(right.clone(), Expr::lt_eq) .cache(plugin, engine, lhs_span)? .into_value(lhs_span)), - _ => - // Err(ShellError::OperatorMismatch { - // op_span, - // lhs_ty: Type::Custom(TYPE_NAME.into()).to_string(), - // lhs_span, - // rhs_ty: Type::Custom(TYPE_NAME.into()).to_string(), - // rhs_span, - // }), - { - Err(ShellError::OperatorUnsupportedType { - op: "TODO", - unsupported: Type::Custom(TYPE_NAME.into()), - op_span, - unsupported_span: lhs_span, - help: None, - }) - } + op => Err(ShellError::OperatorUnsupportedType { + op, + unsupported: Type::Custom(TYPE_NAME.into()), + op_span, + unsupported_span: lhs_span, + help: None, + }), } }