mirror of
https://github.com/nushell/nushell
synced 2024-12-27 21:43:09 +00:00
Cleanup operator errors
This commit is contained in:
parent
916544a250
commit
183956eac1
7 changed files with 610 additions and 559 deletions
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue