forked from extern/nushell
Add basic in
operator support
This commit is contained in:
parent
563a0b92b5
commit
8783cf0138
@ -190,6 +190,7 @@ pub fn eval_expression(
|
|||||||
Operator::GreaterThanOrEqual => lhs.gte(op_span, &rhs),
|
Operator::GreaterThanOrEqual => lhs.gte(op_span, &rhs),
|
||||||
Operator::Equal => lhs.eq(op_span, &rhs),
|
Operator::Equal => lhs.eq(op_span, &rhs),
|
||||||
Operator::NotEqual => lhs.ne(op_span, &rhs),
|
Operator::NotEqual => lhs.ne(op_span, &rhs),
|
||||||
|
Operator::In => lhs.r#in(op_span, &rhs),
|
||||||
x => Err(ShellError::UnsupportedOperator(x, op_span)),
|
x => Err(ShellError::UnsupportedOperator(x, op_span)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,6 +273,27 @@ pub fn math_result_type(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
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),
|
||||||
|
|
||||||
|
(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(),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
*op = Expression::garbage(op.span);
|
*op = Expression::garbage(op.span);
|
||||||
|
@ -13,7 +13,7 @@ pub use unit::*;
|
|||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::ast::{CellPath, PathMember};
|
use crate::ast::{CellPath, PathMember, RangeInclusion};
|
||||||
use crate::{span, BlockId, Span, Type};
|
use crate::{span, BlockId, Span, Type};
|
||||||
|
|
||||||
use crate::ShellError;
|
use crate::ShellError;
|
||||||
@ -1014,6 +1014,44 @@ impl Value {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn r#in(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
|
||||||
|
let span = span(&[self.span(), rhs.span()]);
|
||||||
|
|
||||||
|
match (self, rhs) {
|
||||||
|
(lhs, Value::Range { val: rhs, .. }) => Ok(Value::Bool {
|
||||||
|
val: lhs
|
||||||
|
.gte(Span::unknown(), &rhs.from)
|
||||||
|
.map_or(false, |v| v.is_true())
|
||||||
|
&& match rhs.inclusion {
|
||||||
|
RangeInclusion::Inclusive => lhs
|
||||||
|
.lte(Span::unknown(), &rhs.to)
|
||||||
|
.map_or(false, |v| v.is_true()),
|
||||||
|
RangeInclusion::RightExclusive => lhs
|
||||||
|
.lt(Span::unknown(), &rhs.to)
|
||||||
|
.map_or(false, |v| v.is_true()),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::Bool {
|
||||||
|
val: rhs.contains(lhs),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
(lhs, Value::List { vals: rhs, .. }) => Ok(Value::Bool {
|
||||||
|
val: rhs
|
||||||
|
.iter()
|
||||||
|
.any(|x| lhs.eq(Span::unknown(), x).map_or(false, |v| v.is_true())),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
_ => Err(ShellError::OperatorMismatch {
|
||||||
|
op_span: op,
|
||||||
|
lhs_ty: self.get_type(),
|
||||||
|
lhs_span: self.span(),
|
||||||
|
rhs_ty: rhs.get_type(),
|
||||||
|
rhs_span: rhs.span(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format a duration in nanoseconds into a string
|
/// Format a duration in nanoseconds into a string
|
||||||
|
34
src/tests.rs
34
src/tests.rs
@ -569,3 +569,37 @@ fn split_column() -> TestResult {
|
|||||||
fn for_loops() -> TestResult {
|
fn for_loops() -> TestResult {
|
||||||
run_test(r#"(for x in [1, 2, 3] { $x + 10 }).1"#, "12")
|
run_test(r#"(for x in [1, 2, 3] { $x + 10 }).1"#, "12")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_in_list_of_this_type() -> TestResult {
|
||||||
|
run_test(r#"42 in [41 42 43]"#, "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn type_in_list_of_non_this_type() -> TestResult {
|
||||||
|
fail_test(r#"'hello' in [41 42 43]"#, "mismatched for operation")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_in_string() -> TestResult {
|
||||||
|
run_test(r#"'z' in 'abc'"#, "false")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_string_in_string() -> TestResult {
|
||||||
|
fail_test(r#"42 in 'abc'"#, "mismatched for operation")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn int_in_range() -> TestResult {
|
||||||
|
run_test(r#"1 in -4..9.42"#, "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn int_in_exclusive_range() -> TestResult {
|
||||||
|
run_test(r#"3 in 0..<3"#, "false")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_number_in_range() -> TestResult {
|
||||||
|
fail_test(r#"'a' in 1..3"#, "mismatched for operation")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user