Cleanup operator errors

This commit is contained in:
Ian Manske 2024-11-23 22:11:18 -08:00
parent 916544a250
commit 183956eac1
7 changed files with 610 additions and 559 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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<Value, ShellError> {
// Based off the unstable `div_floor` function in the std library.
fn checked_mod_i64(dividend: i64, divisor: i64) -> Option<i64> {
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<f64> {
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<Value, ShellError> {
// Based off the unstable `div_floor` function in the std library.
fn checked_mod_i64(dividend: i64, divisor: i64) -> Option<i64> {
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<f64> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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<Value, ShellError> {
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(),

View file

@ -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<Value, ShellError> {
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(),

View file

@ -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<NuDataFrame, ShellError> {
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, <ChunkedArray<Float64Type>>::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, <ChunkedArray<Float64Type>>::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, <ChunkedArray<Float64Type>>::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, <ChunkedArray<Float64Type>>::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,
}),
}
}

View file

@ -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,
}),
}
}