mirror of
https://github.com/nushell/nushell
synced 2024-12-29 06:23:11 +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::{
|
use nu_protocol::{
|
||||||
ast::{
|
ast::{Block, Comparison, Expr, Expression, Math, Operator, Pipeline, Range},
|
||||||
Assignment, Bits, Block, Boolean, Comparison, Expr, Expression, Math, Operator, Pipeline,
|
|
||||||
Range,
|
|
||||||
},
|
|
||||||
engine::StateWorkingSet,
|
engine::StateWorkingSet,
|
||||||
ParseError, Type,
|
ParseError, Span, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn type_error(
|
fn type_error(
|
||||||
name: &'static str,
|
op: Operator,
|
||||||
op: &Expression,
|
op_span: Span,
|
||||||
lhs: &Expression,
|
lhs: &Expression,
|
||||||
rhs: &Expression,
|
rhs: &Expression,
|
||||||
is_supported: fn(&Type) -> bool,
|
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 is_supported = |ty| is_supported(ty) || matches!(ty, Type::Any | Type::Custom(_));
|
||||||
let err = match (is_supported(&lhs.ty), is_supported(&rhs.ty)) {
|
let err = match (is_supported(&lhs.ty), is_supported(&rhs.ty)) {
|
||||||
(true, true) => ParseError::OperatorIncompatibleTypes {
|
(true, true) => ParseError::OperatorIncompatibleTypes {
|
||||||
op: name,
|
op: op.as_str(),
|
||||||
lhs: lhs.ty.clone(),
|
lhs: lhs.ty.clone(),
|
||||||
rhs: rhs.ty.clone(),
|
rhs: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span,
|
||||||
lhs_span: lhs.span,
|
lhs_span: lhs.span,
|
||||||
rhs_span: rhs.span,
|
rhs_span: rhs.span,
|
||||||
help: None,
|
help: None,
|
||||||
},
|
},
|
||||||
(true, false) => ParseError::OperatorUnsupportedType {
|
(true, false) => ParseError::OperatorUnsupportedType {
|
||||||
op: name,
|
op: op.as_str(),
|
||||||
unsupported: rhs.ty.clone(),
|
unsupported: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span,
|
||||||
unsupported_span: rhs.span,
|
unsupported_span: rhs.span,
|
||||||
help: None,
|
help: None,
|
||||||
},
|
},
|
||||||
(false, _) => ParseError::OperatorUnsupportedType {
|
(false, _) => ParseError::OperatorUnsupportedType {
|
||||||
op: name,
|
op: op.as_str(),
|
||||||
unsupported: lhs.ty.clone(),
|
unsupported: lhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span,
|
||||||
unsupported_span: lhs.span,
|
unsupported_span: lhs.span,
|
||||||
help: None,
|
help: None,
|
||||||
},
|
},
|
||||||
|
@ -141,7 +138,7 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int
|
Type::Int
|
||||||
|
@ -175,7 +172,7 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int
|
Type::Int
|
||||||
|
@ -212,7 +209,7 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int | Type::Float | Type::Number | Type::Duration | Type::Filesize,
|
Type::Int | Type::Float | Type::Number | Type::Duration | Type::Filesize,
|
||||||
|
@ -242,7 +239,7 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration
|
Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration
|
||||||
|
@ -272,7 +269,7 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration
|
Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration
|
||||||
|
@ -302,7 +299,7 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration
|
Type::Int | Type::Float | Type::Number | Type::Filesize | Type::Duration
|
||||||
|
@ -326,7 +323,7 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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)
|
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)) {
|
let err = match (is_supported(&lhs.ty), is_supported(&rhs.ty)) {
|
||||||
(true, true) => ParseError::OperatorIncompatibleTypes {
|
(true, true) => ParseError::OperatorIncompatibleTypes {
|
||||||
op: "concatentation",
|
op: Operator::Math(Math::Concatenate).as_str(),
|
||||||
lhs: lhs.ty.clone(),
|
lhs: lhs.ty.clone(),
|
||||||
rhs: rhs.ty.clone(),
|
rhs: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span: op.span,
|
||||||
|
@ -391,14 +388,14 @@ pub fn math_result_type(
|
||||||
help,
|
help,
|
||||||
},
|
},
|
||||||
(true, false) => ParseError::OperatorUnsupportedType {
|
(true, false) => ParseError::OperatorUnsupportedType {
|
||||||
op: "concatentation",
|
op: Operator::Math(Math::Concatenate).as_str(),
|
||||||
unsupported: rhs.ty.clone(),
|
unsupported: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span: op.span,
|
||||||
unsupported_span: rhs.span,
|
unsupported_span: rhs.span,
|
||||||
help,
|
help,
|
||||||
},
|
},
|
||||||
(false, _) => ParseError::OperatorUnsupportedType {
|
(false, _) => ParseError::OperatorUnsupportedType {
|
||||||
op: "concatentation",
|
op: Operator::Math(Math::Concatenate).as_str(),
|
||||||
unsupported: lhs.ty.clone(),
|
unsupported: lhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span: op.span,
|
||||||
unsupported_span: lhs.span,
|
unsupported_span: lhs.span,
|
||||||
|
@ -416,12 +413,9 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
let name = match operator {
|
type_error(Operator::Boolean(operator), op.span, lhs, rhs, |ty| {
|
||||||
Boolean::Or => "boolean or",
|
matches!(ty, Type::Bool)
|
||||||
Boolean::Xor => "boolean xor",
|
})
|
||||||
Boolean::And => "boolean and",
|
|
||||||
};
|
|
||||||
type_error(name, op, lhs, rhs, |ty| matches!(ty, Type::Bool))
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::LessThan) => match (&lhs.ty, &rhs.ty) {
|
Operator::Comparison(Comparison::LessThan) => match (&lhs.ty, &rhs.ty) {
|
||||||
|
@ -454,7 +448,12 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Bool, None),
|
(_, Type::Any) => (Type::Bool, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
type_error("less than comparison", op, lhs, rhs, |ty| {
|
type_error(
|
||||||
|
Operator::Comparison(Comparison::LessThan),
|
||||||
|
op.span,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
|ty| {
|
||||||
matches!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int
|
Type::Int
|
||||||
|
@ -467,7 +466,8 @@ pub fn math_result_type(
|
||||||
| Type::Bool
|
| Type::Bool
|
||||||
| Type::Nothing
|
| Type::Nothing
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::LessThanOrEqual) => match (&lhs.ty, &rhs.ty) {
|
Operator::Comparison(Comparison::LessThanOrEqual) => match (&lhs.ty, &rhs.ty) {
|
||||||
|
@ -500,7 +500,12 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Bool, None),
|
(_, Type::Any) => (Type::Bool, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
type_error("less than or equal to comparison", op, lhs, rhs, |ty| {
|
type_error(
|
||||||
|
Operator::Comparison(Comparison::LessThanOrEqual),
|
||||||
|
op.span,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
|ty| {
|
||||||
matches!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int
|
Type::Int
|
||||||
|
@ -513,7 +518,8 @@ pub fn math_result_type(
|
||||||
| Type::Bool
|
| Type::Bool
|
||||||
| Type::Nothing
|
| Type::Nothing
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::GreaterThan) => match (&lhs.ty, &rhs.ty) {
|
Operator::Comparison(Comparison::GreaterThan) => match (&lhs.ty, &rhs.ty) {
|
||||||
|
@ -546,7 +552,12 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Bool, None),
|
(_, Type::Any) => (Type::Bool, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
type_error("greater than comparison", op, lhs, rhs, |ty| {
|
type_error(
|
||||||
|
Operator::Comparison(Comparison::GreaterThan),
|
||||||
|
op.span,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
|ty| {
|
||||||
matches!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int
|
Type::Int
|
||||||
|
@ -559,7 +570,8 @@ pub fn math_result_type(
|
||||||
| Type::Bool
|
| Type::Bool
|
||||||
| Type::Nothing
|
| Type::Nothing
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::GreaterThanOrEqual) => match (&lhs.ty, &rhs.ty) {
|
Operator::Comparison(Comparison::GreaterThanOrEqual) => match (&lhs.ty, &rhs.ty) {
|
||||||
|
@ -592,7 +604,12 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Bool, None),
|
(_, Type::Any) => (Type::Bool, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
type_error("greater than or equal to comparison", op, lhs, rhs, |ty| {
|
type_error(
|
||||||
|
Operator::Comparison(Comparison::GreaterThanOrEqual),
|
||||||
|
op.span,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
|ty| {
|
||||||
matches!(
|
matches!(
|
||||||
ty,
|
ty,
|
||||||
Type::Int
|
Type::Int
|
||||||
|
@ -605,7 +622,8 @@ pub fn math_result_type(
|
||||||
| Type::Bool
|
| Type::Bool
|
||||||
| Type::Nothing
|
| Type::Nothing
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::Equal) => match (&lhs.ty, &rhs.ty) {
|
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),
|
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*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) {
|
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),
|
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
type_error("negative regex match", op, lhs, rhs, |ty| {
|
type_error(
|
||||||
matches!(ty, Type::String)
|
Operator::Comparison(Comparison::NotRegexMatch),
|
||||||
})
|
op.span,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
|ty| matches!(ty, Type::String),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::StartsWith) => match (&lhs.ty, &rhs.ty) {
|
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),
|
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
type_error("starts-with comparison", op, lhs, rhs, |ty| {
|
type_error(
|
||||||
matches!(ty, Type::String)
|
Operator::Comparison(Comparison::StartsWith),
|
||||||
})
|
op.span,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
|ty| matches!(ty, Type::String),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::EndsWith) => match (&lhs.ty, &rhs.ty) {
|
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),
|
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
type_error("ends-with comparison", op, lhs, rhs, |ty| {
|
type_error(
|
||||||
matches!(ty, Type::String)
|
Operator::Comparison(Comparison::LessThan),
|
||||||
})
|
op.span,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
|ty| matches!(ty, Type::String),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::In) => match (&lhs.ty, &rhs.ty) {
|
Operator::Comparison(Comparison::In) => match (&lhs.ty, &rhs.ty) {
|
||||||
|
@ -685,7 +721,7 @@ pub fn math_result_type(
|
||||||
| Type::Any
|
| Type::Any
|
||||||
) {
|
) {
|
||||||
ParseError::OperatorIncompatibleTypes {
|
ParseError::OperatorIncompatibleTypes {
|
||||||
op: "'in' comparison",
|
op: Operator::Comparison(Comparison::In).as_str(),
|
||||||
lhs: lhs.ty.clone(),
|
lhs: lhs.ty.clone(),
|
||||||
rhs: rhs.ty.clone(),
|
rhs: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span: op.span,
|
||||||
|
@ -695,7 +731,7 @@ pub fn math_result_type(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ParseError::OperatorUnsupportedType {
|
ParseError::OperatorUnsupportedType {
|
||||||
op: "'in' comparison",
|
op: Operator::Comparison(Comparison::In).as_str(),
|
||||||
unsupported: rhs.ty.clone(),
|
unsupported: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span: op.span,
|
||||||
unsupported_span: rhs.span,
|
unsupported_span: rhs.span,
|
||||||
|
@ -726,7 +762,7 @@ pub fn math_result_type(
|
||||||
| Type::Any
|
| Type::Any
|
||||||
) {
|
) {
|
||||||
ParseError::OperatorIncompatibleTypes {
|
ParseError::OperatorIncompatibleTypes {
|
||||||
op: "'not-in' comparison",
|
op: Operator::Comparison(Comparison::NotIn).as_str(),
|
||||||
lhs: lhs.ty.clone(),
|
lhs: lhs.ty.clone(),
|
||||||
rhs: rhs.ty.clone(),
|
rhs: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span: op.span,
|
||||||
|
@ -736,7 +772,7 @@ pub fn math_result_type(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ParseError::OperatorUnsupportedType {
|
ParseError::OperatorUnsupportedType {
|
||||||
op: "'not-in' comparison",
|
op: Operator::Comparison(Comparison::NotIn).as_str(),
|
||||||
unsupported: rhs.ty.clone(),
|
unsupported: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
op_span: op.span,
|
||||||
unsupported_span: rhs.span,
|
unsupported_span: rhs.span,
|
||||||
|
@ -752,14 +788,9 @@ pub fn math_result_type(
|
||||||
(_, Type::Any) => (Type::Any, None),
|
(_, Type::Any) => (Type::Any, None),
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(working_set, op.span);
|
*op = Expression::garbage(working_set, op.span);
|
||||||
let name = match operator {
|
type_error(Operator::Bits(operator), op.span, lhs, rhs, |ty| {
|
||||||
Bits::BitOr => "bitwise or",
|
matches!(ty, Type::Int)
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO: fix this
|
// TODO: fix this
|
||||||
|
@ -771,16 +802,8 @@ pub fn math_result_type(
|
||||||
(Type::Nothing, None)
|
(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 {
|
let err = ParseError::OperatorIncompatibleTypes {
|
||||||
op: name,
|
op: Operator::Assignment(operator).as_str(),
|
||||||
lhs: lhs.ty.clone(),
|
lhs: lhs.ty.clone(),
|
||||||
rhs: rhs.ty.clone(),
|
rhs: rhs.ty.clone(),
|
||||||
op_span: op.span,
|
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::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
str::{from_utf8, Utf8Error},
|
str::{from_utf8, Utf8Error},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{ast::RedirectionSource, did_you_mean, Span, Type};
|
|
||||||
use miette::Diagnostic;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Error, Diagnostic, Serialize, Deserialize)]
|
#[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.
|
/// 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::parser::operator_unsupported_type))]
|
#[diagnostic(code(nu::shell::operator_unsupported_type))]
|
||||||
OperatorUnsupportedType {
|
OperatorUnsupportedType {
|
||||||
op: &'static str,
|
op: &'static str,
|
||||||
unsupported: Type,
|
unsupported: Type,
|
||||||
#[label = "does support this type"]
|
#[label = "does not support '{unsupported}'"]
|
||||||
op_span: Span,
|
op_span: Span,
|
||||||
#[label("{unsupported}")]
|
#[label("{unsupported}")]
|
||||||
unsupported_span: Span,
|
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.
|
/// 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::parser::operator_incompatible_types))]
|
#[diagnostic(code(nu::shell::operator_incompatible_types))]
|
||||||
OperatorIncompatibleTypes {
|
OperatorIncompatibleTypes {
|
||||||
op: &'static str,
|
op: &'static str,
|
||||||
lhs: Type,
|
lhs: Type,
|
||||||
rhs: Type,
|
rhs: Type,
|
||||||
#[label = "does not operate between these two types"]
|
#[label = "does not operate between '{lhs}' and '{rhs}'"]
|
||||||
op_span: Span,
|
op_span: Span,
|
||||||
#[label("{lhs}")]
|
#[label("{lhs}")]
|
||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
|
|
|
@ -12,33 +12,13 @@ use thiserror::Error;
|
||||||
/// and pass it into an error viewer to display to the user.
|
/// and pass it into an error viewer to display to the user.
|
||||||
#[derive(Debug, Clone, Error, Diagnostic, PartialEq)]
|
#[derive(Debug, Clone, Error, Diagnostic, PartialEq)]
|
||||||
pub enum ShellError {
|
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.
|
/// 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))]
|
#[diagnostic(code(nu::shell::operator_unsupported_type))]
|
||||||
OperatorUnsupportedType {
|
OperatorUnsupportedType {
|
||||||
op: &'static str,
|
op: Operator,
|
||||||
unsupported: Type,
|
unsupported: Type,
|
||||||
#[label = "does support this type"]
|
#[label = "does not support '{unsupported}'"]
|
||||||
op_span: Span,
|
op_span: Span,
|
||||||
#[label("{unsupported}")]
|
#[label("{unsupported}")]
|
||||||
unsupported_span: Span,
|
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.
|
/// 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))]
|
#[diagnostic(code(nu::shell::operator_incompatible_types))]
|
||||||
OperatorIncompatibleTypes {
|
OperatorIncompatibleTypes {
|
||||||
op: &'static str,
|
op: Operator,
|
||||||
lhs: Type,
|
lhs: Type,
|
||||||
rhs: Type,
|
rhs: Type,
|
||||||
#[label = "does not operate between these two types"]
|
#[label = "does not operate between '{lhs}' and '{rhs}'"]
|
||||||
op_span: Span,
|
op_span: Span,
|
||||||
#[label("{lhs}")]
|
#[label("{lhs}")]
|
||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
|
|
|
@ -2490,7 +2490,12 @@ impl Value {
|
||||||
(Value::Custom { val: lhs, .. }, rhs) => {
|
(Value::Custom { val: lhs, .. }, rhs) => {
|
||||||
lhs.operation(self.span(), Operator::Math(Math::Add), op, rhs)
|
lhs.operation(self.span(), Operator::Math(Math::Add), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error("addition", op, self, rhs, |val| {
|
_ => Err(operator_type_error(
|
||||||
|
Operator::Math(Math::Add),
|
||||||
|
op,
|
||||||
|
self,
|
||||||
|
rhs,
|
||||||
|
|val| {
|
||||||
matches!(
|
matches!(
|
||||||
val,
|
val,
|
||||||
Value::Int { .. }
|
Value::Int { .. }
|
||||||
|
@ -2500,7 +2505,8 @@ impl Value {
|
||||||
| Value::Duration { .. }
|
| Value::Duration { .. }
|
||||||
| Value::Filesize { .. },
|
| Value::Filesize { .. },
|
||||||
)
|
)
|
||||||
})),
|
},
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2573,7 +2579,12 @@ impl Value {
|
||||||
(Value::Custom { val: lhs, .. }, rhs) => {
|
(Value::Custom { val: lhs, .. }, rhs) => {
|
||||||
lhs.operation(self.span(), Operator::Math(Math::Subtract), op, rhs)
|
lhs.operation(self.span(), Operator::Math(Math::Subtract), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error("subtraction", op, self, rhs, |val| {
|
_ => Err(operator_type_error(
|
||||||
|
Operator::Math(Math::Subtract),
|
||||||
|
op,
|
||||||
|
self,
|
||||||
|
rhs,
|
||||||
|
|val| {
|
||||||
matches!(
|
matches!(
|
||||||
val,
|
val,
|
||||||
Value::Int { .. }
|
Value::Int { .. }
|
||||||
|
@ -2582,7 +2593,8 @@ impl Value {
|
||||||
| Value::Duration { .. }
|
| Value::Duration { .. }
|
||||||
| Value::Filesize { .. },
|
| Value::Filesize { .. },
|
||||||
)
|
)
|
||||||
})),
|
},
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2636,7 +2648,7 @@ impl Value {
|
||||||
lhs.operation(self.span(), Operator::Math(Math::Multiply), op, rhs)
|
lhs.operation(self.span(), Operator::Math(Math::Multiply), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error(
|
_ => Err(operator_type_error(
|
||||||
"multiplication",
|
Operator::Math(Math::Multiply),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -2758,7 +2770,12 @@ impl Value {
|
||||||
(Value::Custom { val: lhs, .. }, rhs) => {
|
(Value::Custom { val: lhs, .. }, rhs) => {
|
||||||
lhs.operation(self.span(), Operator::Math(Math::Divide), op, rhs)
|
lhs.operation(self.span(), Operator::Math(Math::Divide), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error("division", op, self, rhs, |val| {
|
_ => Err(operator_type_error(
|
||||||
|
Operator::Math(Math::Divide),
|
||||||
|
op,
|
||||||
|
self,
|
||||||
|
rhs,
|
||||||
|
|val| {
|
||||||
matches!(
|
matches!(
|
||||||
val,
|
val,
|
||||||
Value::Int { .. }
|
Value::Int { .. }
|
||||||
|
@ -2766,165 +2783,8 @@ impl Value {
|
||||||
| Value::Duration { .. }
|
| Value::Duration { .. }
|
||||||
| Value::Filesize { .. },
|
| 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 { .. },
|
|
||||||
)
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3074,7 +2934,7 @@ impl Value {
|
||||||
lhs.operation(self.span(), Operator::Math(Math::Divide), op, rhs)
|
lhs.operation(self.span(), Operator::Math(Math::Divide), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error(
|
_ => Err(operator_type_error(
|
||||||
"floor division",
|
Operator::Math(Math::FloorDivide),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
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> {
|
pub fn concat(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::List { vals: lhs, .. }, Value::List { vals: 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)
|
lhs.operation(self.span(), Operator::Math(Math::Concatenate), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error(
|
_ => Err(operator_type_error(
|
||||||
"concatentation",
|
Operator::Math(Math::Concatenate),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -3137,7 +3196,7 @@ impl Value {
|
||||||
|
|
||||||
if !type_compatible(self.get_type(), rhs.get_type()) {
|
if !type_compatible(self.get_type(), rhs.get_type()) {
|
||||||
return Err(operator_type_error(
|
return Err(operator_type_error(
|
||||||
"less than comparison",
|
Operator::Comparison(Comparison::LessThan),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -3179,7 +3238,7 @@ impl Value {
|
||||||
|
|
||||||
if !type_compatible(self.get_type(), rhs.get_type()) {
|
if !type_compatible(self.get_type(), rhs.get_type()) {
|
||||||
return Err(operator_type_error(
|
return Err(operator_type_error(
|
||||||
"less than or equal to comparison",
|
Operator::Comparison(Comparison::LessThanOrEqual),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -3224,7 +3283,7 @@ impl Value {
|
||||||
|
|
||||||
if !type_compatible(self.get_type(), rhs.get_type()) {
|
if !type_compatible(self.get_type(), rhs.get_type()) {
|
||||||
return Err(operator_type_error(
|
return Err(operator_type_error(
|
||||||
"greater than comparison",
|
Operator::Comparison(Comparison::GreaterThan),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -3266,7 +3325,7 @@ impl Value {
|
||||||
|
|
||||||
if !type_compatible(self.get_type(), rhs.get_type()) {
|
if !type_compatible(self.get_type(), rhs.get_type()) {
|
||||||
return Err(operator_type_error(
|
return Err(operator_type_error(
|
||||||
"greater than or equal to comparison",
|
Operator::Comparison(Comparison::GreaterThanOrEqual),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -3375,7 +3434,7 @@ impl Value {
|
||||||
| Value::Custom { .. }
|
| Value::Custom { .. }
|
||||||
) {
|
) {
|
||||||
ShellError::OperatorIncompatibleTypes {
|
ShellError::OperatorIncompatibleTypes {
|
||||||
op: "'in' comparison",
|
op: Operator::Comparison(Comparison::In),
|
||||||
lhs: lhs.get_type(),
|
lhs: lhs.get_type(),
|
||||||
rhs: rhs.get_type(),
|
rhs: rhs.get_type(),
|
||||||
op_span: op,
|
op_span: op,
|
||||||
|
@ -3385,7 +3444,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ShellError::OperatorUnsupportedType {
|
ShellError::OperatorUnsupportedType {
|
||||||
op: "'in' comparison",
|
op: Operator::Comparison(Comparison::In),
|
||||||
unsupported: rhs.get_type(),
|
unsupported: rhs.get_type(),
|
||||||
op_span: op,
|
op_span: op,
|
||||||
unsupported_span: rhs.span(),
|
unsupported_span: rhs.span(),
|
||||||
|
@ -3447,7 +3506,7 @@ impl Value {
|
||||||
| Value::Custom { .. }
|
| Value::Custom { .. }
|
||||||
) {
|
) {
|
||||||
ShellError::OperatorIncompatibleTypes {
|
ShellError::OperatorIncompatibleTypes {
|
||||||
op: "'not-in' comparison",
|
op: Operator::Comparison(Comparison::NotIn),
|
||||||
lhs: lhs.get_type(),
|
lhs: lhs.get_type(),
|
||||||
rhs: rhs.get_type(),
|
rhs: rhs.get_type(),
|
||||||
op_span: op,
|
op_span: op,
|
||||||
|
@ -3457,7 +3516,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ShellError::OperatorUnsupportedType {
|
ShellError::OperatorUnsupportedType {
|
||||||
op: "'not-in' comparison",
|
op: Operator::Comparison(Comparison::NotIn),
|
||||||
unsupported: rhs.get_type(),
|
unsupported: rhs.get_type(),
|
||||||
op_span: op,
|
op_span: op,
|
||||||
unsupported_span: rhs.span(),
|
unsupported_span: rhs.span(),
|
||||||
|
@ -3526,9 +3585,17 @@ impl Value {
|
||||||
op,
|
op,
|
||||||
rhs,
|
rhs,
|
||||||
),
|
),
|
||||||
_ => Err(operator_type_error("regex match", op, self, rhs, |val| {
|
_ => Err(operator_type_error(
|
||||||
matches!(val, Value::String { .. })
|
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,
|
rhs,
|
||||||
),
|
),
|
||||||
_ => Err(operator_type_error(
|
_ => Err(operator_type_error(
|
||||||
"starts-with comparison",
|
Operator::Comparison(Comparison::StartsWith),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -3565,7 +3632,7 @@ impl Value {
|
||||||
rhs,
|
rhs,
|
||||||
),
|
),
|
||||||
_ => Err(operator_type_error(
|
_ => Err(operator_type_error(
|
||||||
"ends-with comparison",
|
Operator::Comparison(Comparison::EndsWith),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
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> {
|
pub fn bit_shl(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||||
|
@ -3594,7 +3715,7 @@ impl Value {
|
||||||
lhs.operation(span, Operator::Bits(Bits::ShiftLeft), op, rhs)
|
lhs.operation(span, Operator::Bits(Bits::ShiftLeft), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error(
|
_ => Err(operator_type_error(
|
||||||
"bit left shift",
|
Operator::Bits(Bits::ShiftLeft),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
rhs,
|
||||||
|
@ -3623,7 +3744,7 @@ impl Value {
|
||||||
lhs.operation(span, Operator::Bits(Bits::ShiftRight), op, rhs)
|
lhs.operation(span, Operator::Bits(Bits::ShiftRight), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error(
|
_ => Err(operator_type_error(
|
||||||
"bit right shift",
|
Operator::Bits(Bits::ShiftRight),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
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> {
|
pub fn or(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => {
|
(Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => {
|
||||||
|
@ -3696,9 +3761,13 @@ impl Value {
|
||||||
(Value::Custom { val: lhs, .. }, rhs) => {
|
(Value::Custom { val: lhs, .. }, rhs) => {
|
||||||
lhs.operation(span, Operator::Boolean(Boolean::Or), op, rhs)
|
lhs.operation(span, Operator::Boolean(Boolean::Or), op, rhs)
|
||||||
}
|
}
|
||||||
_ => Err(operator_type_error("boolean or", op, self, rhs, |val| {
|
_ => Err(operator_type_error(
|
||||||
matches!(val, Value::Bool { .. })
|
Operator::Boolean(Boolean::Or),
|
||||||
})),
|
op,
|
||||||
|
self,
|
||||||
|
rhs,
|
||||||
|
|val| matches!(val, Value::Bool { .. }),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3710,43 +3779,30 @@ impl Value {
|
||||||
(Value::Custom { val: lhs, .. }, rhs) => {
|
(Value::Custom { val: lhs, .. }, rhs) => {
|
||||||
lhs.operation(span, Operator::Boolean(Boolean::Xor), op, 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(
|
_ => Err(operator_type_error(
|
||||||
"exponentiation",
|
Operator::Boolean(Boolean::Xor),
|
||||||
op,
|
op,
|
||||||
self,
|
self,
|
||||||
rhs,
|
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(
|
fn operator_type_error(
|
||||||
op_name: &'static str,
|
op: Operator,
|
||||||
op_span: Span,
|
op_span: Span,
|
||||||
lhs: &Value,
|
lhs: &Value,
|
||||||
rhs: &Value,
|
rhs: &Value,
|
||||||
|
@ -3772,7 +3828,7 @@ fn operator_type_error(
|
||||||
let is_supported = |val| is_supported(val) || matches!(val, Value::Custom { .. });
|
let is_supported = |val| is_supported(val) || matches!(val, Value::Custom { .. });
|
||||||
match (is_supported(lhs), is_supported(rhs)) {
|
match (is_supported(lhs), is_supported(rhs)) {
|
||||||
(true, true) => ShellError::OperatorIncompatibleTypes {
|
(true, true) => ShellError::OperatorIncompatibleTypes {
|
||||||
op: op_name,
|
op,
|
||||||
lhs: lhs.get_type(),
|
lhs: lhs.get_type(),
|
||||||
rhs: rhs.get_type(),
|
rhs: rhs.get_type(),
|
||||||
op_span,
|
op_span,
|
||||||
|
@ -3781,14 +3837,14 @@ fn operator_type_error(
|
||||||
help: None,
|
help: None,
|
||||||
},
|
},
|
||||||
(true, false) => ShellError::OperatorUnsupportedType {
|
(true, false) => ShellError::OperatorUnsupportedType {
|
||||||
op: op_name,
|
op,
|
||||||
unsupported: rhs.get_type(),
|
unsupported: rhs.get_type(),
|
||||||
op_span,
|
op_span,
|
||||||
unsupported_span: rhs.span(),
|
unsupported_span: rhs.span(),
|
||||||
help: None,
|
help: None,
|
||||||
},
|
},
|
||||||
(false, _) => ShellError::OperatorUnsupportedType {
|
(false, _) => ShellError::OperatorUnsupportedType {
|
||||||
op: op_name,
|
op,
|
||||||
unsupported: lhs.get_type(),
|
unsupported: lhs.get_type(),
|
||||||
op_span,
|
op_span,
|
||||||
unsupported_span: lhs.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 serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
@ -112,7 +115,7 @@ impl CustomValue for CoolCustomValue {
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
match operator {
|
match operator {
|
||||||
// Append the string inside `cool`
|
// Append the string inside `cool`
|
||||||
ast::Operator::Math(ast::Math::Concatenate) => {
|
Operator::Math(Math::Concatenate) => {
|
||||||
if let Some(right) = right
|
if let Some(right) = right
|
||||||
.as_custom_value()
|
.as_custom_value()
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -126,7 +129,7 @@ impl CustomValue for CoolCustomValue {
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::OperatorUnsupportedType {
|
Err(ShellError::OperatorUnsupportedType {
|
||||||
op: "concatenation",
|
op: Operator::Math(Math::Concatenate),
|
||||||
unsupported: right.get_type(),
|
unsupported: right.get_type(),
|
||||||
op_span,
|
op_span,
|
||||||
unsupported_span: right.span(),
|
unsupported_span: right.span(),
|
||||||
|
|
|
@ -21,12 +21,12 @@ pub(super) fn between_dataframes(
|
||||||
Operator::Math(Math::Add) => {
|
Operator::Math(Math::Add) => {
|
||||||
lhs.append_df(rhs, Axis::Row, Span::merge(left.span(), right.span()))
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: left.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,12 +181,12 @@ pub(super) fn compute_between_series(
|
||||||
span: operation_span,
|
span: operation_span,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
op => Err(ShellError::OperatorUnsupportedType {
|
||||||
|
op,
|
||||||
|
unsupported: left.get_type(),
|
||||||
op_span: operator.span,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: left.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,12 +222,12 @@ pub(super) fn compute_series_single_value(
|
||||||
right: &Value,
|
right: &Value,
|
||||||
) -> Result<NuDataFrame, ShellError> {
|
) -> Result<NuDataFrame, ShellError> {
|
||||||
if !lhs.is_series() {
|
if !lhs.is_series() {
|
||||||
return Err(ShellError::OperatorMismatch {
|
return Err(ShellError::OperatorUnsupportedType {
|
||||||
|
op: operator.item,
|
||||||
|
unsupported: left.get_type(),
|
||||||
op_span: operator.span,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: left.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,12 +243,12 @@ pub(super) fn compute_series_single_value(
|
||||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::add, lhs_span)
|
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::add, lhs_span)
|
||||||
}
|
}
|
||||||
Value::String { val, .. } => add_string_to_series(&lhs, val, 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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Math(Math::Subtract) => match &right {
|
Operator::Math(Math::Subtract) => match &right {
|
||||||
|
@ -258,12 +258,12 @@ pub(super) fn compute_series_single_value(
|
||||||
Value::Float { val, .. } => {
|
Value::Float { val, .. } => {
|
||||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::sub, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Math(Math::Multiply) => match &right {
|
Operator::Math(Math::Multiply) => match &right {
|
||||||
|
@ -273,12 +273,12 @@ pub(super) fn compute_series_single_value(
|
||||||
Value::Float { val, .. } => {
|
Value::Float { val, .. } => {
|
||||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::mul, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Math(Math::Divide) => {
|
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)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,12 +319,12 @@ pub(super) fn compute_series_single_value(
|
||||||
Value::Date { val, .. } => {
|
Value::Date { val, .. } => {
|
||||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::equal, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::NotEqual) => match &right {
|
Operator::Comparison(Comparison::NotEqual) => match &right {
|
||||||
|
@ -344,12 +344,12 @@ pub(super) fn compute_series_single_value(
|
||||||
ChunkedArray::not_equal,
|
ChunkedArray::not_equal,
|
||||||
lhs_span,
|
lhs_span,
|
||||||
),
|
),
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
_ => Err(ShellError::OperatorUnsupportedType {
|
||||||
|
op: operator.item,
|
||||||
|
unsupported: right.get_type(),
|
||||||
op_span: operator.span,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::LessThan) => match &right {
|
Operator::Comparison(Comparison::LessThan) => match &right {
|
||||||
|
@ -360,12 +360,12 @@ pub(super) fn compute_series_single_value(
|
||||||
Value::Date { val, .. } => {
|
Value::Date { val, .. } => {
|
||||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::LessThanOrEqual) => match &right {
|
Operator::Comparison(Comparison::LessThanOrEqual) => match &right {
|
||||||
|
@ -376,12 +376,12 @@ pub(super) fn compute_series_single_value(
|
||||||
Value::Date { val, .. } => {
|
Value::Date { val, .. } => {
|
||||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt_eq, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::GreaterThan) => match &right {
|
Operator::Comparison(Comparison::GreaterThan) => match &right {
|
||||||
|
@ -392,12 +392,12 @@ pub(super) fn compute_series_single_value(
|
||||||
Value::Date { val, .. } => {
|
Value::Date { val, .. } => {
|
||||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::GreaterThanOrEqual) => match &right {
|
Operator::Comparison(Comparison::GreaterThanOrEqual) => match &right {
|
||||||
|
@ -408,23 +408,23 @@ pub(super) fn compute_series_single_value(
|
||||||
Value::Date { val, .. } => {
|
Value::Date { val, .. } => {
|
||||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt_eq, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
// TODO: update this to do a regex match instead of a simple contains?
|
// TODO: update this to do a regex match instead of a simple contains?
|
||||||
Operator::Comparison(Comparison::RegexMatch) => match &right {
|
Operator::Comparison(Comparison::RegexMatch) => match &right {
|
||||||
Value::String { val, .. } => contains_series_pat(&lhs, val, lhs_span),
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::StartsWith) => match &right {
|
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));
|
let starts_with_pattern = format!("^{}", fancy_regex::escape(val));
|
||||||
contains_series_pat(&lhs, &starts_with_pattern, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Operator::Comparison(Comparison::EndsWith) => match &right {
|
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));
|
let ends_with_pattern = format!("{}$", fancy_regex::escape(val));
|
||||||
contains_series_pat(&lhs, &ends_with_pattern, lhs_span)
|
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,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: right.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
_ => Err(ShellError::OperatorUnsupportedType {
|
||||||
|
op: operator.item,
|
||||||
|
unsupported: left.get_type(),
|
||||||
op_span: operator.span,
|
op_span: operator.span,
|
||||||
lhs_ty: left.get_type().to_string(),
|
unsupported_span: left.span(),
|
||||||
lhs_span: left.span(),
|
help: None,
|
||||||
rhs_ty: right.get_type().to_string(),
|
|
||||||
rhs_span: right.span(),
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,23 +133,13 @@ fn with_operator(
|
||||||
.apply_with_expr(right.clone(), Expr::lt_eq)
|
.apply_with_expr(right.clone(), Expr::lt_eq)
|
||||||
.cache(plugin, engine, lhs_span)?
|
.cache(plugin, engine, lhs_span)?
|
||||||
.into_value(lhs_span)),
|
.into_value(lhs_span)),
|
||||||
_ =>
|
op => Err(ShellError::OperatorUnsupportedType {
|
||||||
// Err(ShellError::OperatorMismatch {
|
op,
|
||||||
// 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()),
|
unsupported: Type::Custom(TYPE_NAME.into()),
|
||||||
op_span,
|
op_span,
|
||||||
unsupported_span: lhs_span,
|
unsupported_span: lhs_span,
|
||||||
help: None,
|
help: None,
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue