2021-09-02 10:25:22 +02:00
|
|
|
use crate::ParseError;
|
2021-09-02 20:21:37 +02:00
|
|
|
use nu_protocol::{
|
|
|
|
ast::{Expr, Expression, Operator},
|
|
|
|
engine::StateWorkingSet,
|
|
|
|
Type,
|
|
|
|
};
|
2021-07-30 00:56:51 +02:00
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
pub fn type_compatible(lhs: &Type, rhs: &Type) -> bool {
|
|
|
|
match (lhs, rhs) {
|
|
|
|
(Type::List(c), Type::List(d)) => type_compatible(c, d),
|
2022-01-05 21:58:58 +01:00
|
|
|
(Type::Number, Type::Int) => true,
|
|
|
|
(Type::Number, Type::Float) => true,
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => true,
|
|
|
|
(_, Type::Unknown) => true,
|
|
|
|
(lhs, rhs) => lhs == rhs,
|
2021-08-17 01:00:00 +02:00
|
|
|
}
|
2021-09-02 10:25:22 +02:00
|
|
|
}
|
2021-08-17 01:00:00 +02:00
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
pub fn math_result_type(
|
2021-09-04 09:59:38 +02:00
|
|
|
_working_set: &StateWorkingSet,
|
2021-09-02 10:25:22 +02:00
|
|
|
lhs: &mut Expression,
|
|
|
|
op: &mut Expression,
|
|
|
|
rhs: &mut Expression,
|
|
|
|
) -> (Type, Option<ParseError>) {
|
2021-09-11 23:26:35 +02:00
|
|
|
//println!("checking: {:?} {:?} {:?}", lhs, op, rhs);
|
2021-09-02 10:25:22 +02:00
|
|
|
match &op.expr {
|
|
|
|
Expr::Operator(operator) => match operator {
|
|
|
|
Operator::Plus => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::Int, Type::Int) => (Type::Int, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Float, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Float, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Float, None),
|
|
|
|
(Type::String, Type::String) => (Type::String, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
(Type::Duration, Type::Duration) => (Type::Duration, None),
|
|
|
|
(Type::Filesize, Type::Filesize) => (Type::Filesize, None),
|
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Unknown, None),
|
|
|
|
(_, Type::Unknown) => (Type::Unknown, None),
|
|
|
|
(Type::Int, _) => {
|
2021-09-21 06:03:06 +02:00
|
|
|
let ty = rhs.ty.clone();
|
2021-09-02 10:25:22 +02:00
|
|
|
*rhs = Expression::garbage(rhs.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
2021-09-21 06:03:06 +02:00
|
|
|
ty,
|
2021-09-02 10:25:22 +02:00
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Operator::Minus => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::Int, Type::Int) => (Type::Int, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Float, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Float, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Float, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
(Type::Duration, Type::Duration) => (Type::Duration, None),
|
|
|
|
(Type::Filesize, Type::Filesize) => (Type::Filesize, None),
|
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Unknown, None),
|
|
|
|
(_, Type::Unknown) => (Type::Unknown, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2021-10-11 22:35:12 +02:00
|
|
|
Operator::Multiply | Operator::Pow => match (&lhs.ty, &rhs.ty) {
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Int, Type::Int) => (Type::Int, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Float, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Float, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Float, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Unknown, None),
|
|
|
|
(_, Type::Unknown) => (Type::Unknown, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2021-10-11 22:35:12 +02:00
|
|
|
Operator::Divide | Operator::Modulo => match (&lhs.ty, &rhs.ty) {
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Int, Type::Int) => (Type::Int, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Float, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Float, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Float, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Unknown, None),
|
|
|
|
(_, Type::Unknown) => (Type::Unknown, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2021-10-11 22:35:12 +02:00
|
|
|
Operator::And | Operator::Or => match (&lhs.ty, &rhs.ty) {
|
2021-12-14 06:19:16 +01:00
|
|
|
(Type::Bool, Type::Bool) => (Type::Bool, None),
|
2021-10-11 22:35:12 +02:00
|
|
|
|
|
|
|
(Type::Unknown, _) => (Type::Unknown, None),
|
|
|
|
(_, Type::Unknown) => (Type::Unknown, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2021-09-02 10:25:22 +02:00
|
|
|
Operator::LessThan => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::Int, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Bool, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
|
|
|
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
2021-07-30 00:56:51 +02:00
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
2021-08-17 01:00:00 +02:00
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
2021-07-30 00:56:51 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2021-09-02 10:25:22 +02:00
|
|
|
Operator::LessThanOrEqual => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::Int, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Bool, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
|
|
|
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Operator::GreaterThan => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::Int, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Bool, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
|
|
|
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Operator::GreaterThanOrEqual => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::Int, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Int) => (Type::Bool, None),
|
|
|
|
(Type::Int, Type::Float) => (Type::Bool, None),
|
|
|
|
(Type::Float, Type::Float) => (Type::Bool, None),
|
2021-10-05 04:27:39 +02:00
|
|
|
(Type::Duration, Type::Duration) => (Type::Bool, None),
|
|
|
|
(Type::Filesize, Type::Filesize) => (Type::Bool, None),
|
|
|
|
|
2021-09-02 10:25:22 +02:00
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2022-01-16 15:34:20 +01:00
|
|
|
Operator::Equal => (Type::Bool, None),
|
|
|
|
Operator::NotEqual => (Type::Bool, None),
|
2021-10-11 22:35:12 +02:00
|
|
|
Operator::Contains => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::String, Type::String) => (Type::Bool, None),
|
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Operator::NotContains => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(Type::String, Type::String) => (Type::Bool, None),
|
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2021-10-09 00:53:28 +02:00
|
|
|
Operator::In => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(t, Type::List(u)) if type_compatible(t, u) => (Type::Bool, None),
|
|
|
|
(Type::Int | Type::Float, Type::Range) => (Type::Bool, None),
|
|
|
|
(Type::String, Type::String) => (Type::Bool, None),
|
2021-11-19 05:30:27 +01:00
|
|
|
(Type::String, Type::Record(_)) => (Type::Bool, None),
|
2021-10-09 00:53:28 +02:00
|
|
|
|
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
2021-10-09 17:58:58 +02:00
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Operator::NotIn => match (&lhs.ty, &rhs.ty) {
|
|
|
|
(t, Type::List(u)) if type_compatible(t, u) => (Type::Bool, None),
|
|
|
|
(Type::Int | Type::Float, Type::Range) => (Type::Bool, None),
|
|
|
|
(Type::String, Type::String) => (Type::Bool, None),
|
2021-11-19 05:30:27 +01:00
|
|
|
(Type::String, Type::Record(_)) => (Type::Bool, None),
|
2021-10-09 17:58:58 +02:00
|
|
|
|
|
|
|
(Type::Unknown, _) => (Type::Bool, None),
|
|
|
|
(_, Type::Unknown) => (Type::Bool, None),
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
2021-09-02 10:25:22 +02:00
|
|
|
Some(ParseError::UnsupportedOperation(
|
|
|
|
op.span,
|
|
|
|
lhs.span,
|
|
|
|
lhs.ty.clone(),
|
|
|
|
rhs.span,
|
|
|
|
rhs.ty.clone(),
|
|
|
|
)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
*op = Expression::garbage(op.span);
|
|
|
|
|
|
|
|
(
|
|
|
|
Type::Unknown,
|
|
|
|
Some(ParseError::IncompleteMathExpression(op.span)),
|
|
|
|
)
|
2021-07-30 00:56:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|