RangeIterator can also go down (#2913)

This commit is contained in:
Chris Gillespie 2021-01-12 11:27:54 -08:00 committed by GitHub
parent 3be198d2f5
commit dff85a7f70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 3 deletions

View File

@ -76,6 +76,7 @@ struct RangeIterator {
end: Primitive,
tag: Tag,
is_end_inclusive: bool,
moves_up: bool,
}
impl RangeIterator {
@ -85,9 +86,15 @@ impl RangeIterator {
x => x,
};
let end = match range.to.0.item {
Primitive::Nothing => Primitive::Int(u64::MAX.into()),
x => x,
};
RangeIterator {
moves_up: start <= end,
curr: start,
end: range.to.0.item,
end,
tag,
is_end_inclusive: matches!(range.to.1, RangeInclusion::Inclusive),
}
@ -121,7 +128,9 @@ impl Iterator for RangeIterator {
use std::cmp::Ordering;
if (ordering == Ordering::Less) || (self.is_end_inclusive && ordering == Ordering::Equal) {
if self.moves_up
&& (ordering == Ordering::Less || self.is_end_inclusive && ordering == Ordering::Equal)
{
let output = UntaggedValue::Primitive(self.curr.clone()).into_value(self.tag.clone());
let next_value = nu_data::value::compute_values(
@ -130,6 +139,35 @@ impl Iterator for RangeIterator {
&UntaggedValue::int(1),
);
self.curr = match next_value {
Ok(result) => match result {
UntaggedValue::Primitive(p) => p,
_ => {
return Some(Err(ShellError::unimplemented(
"Internal error: expected a primitive result from increment",
)));
}
},
Err((left_type, right_type)) => {
return Some(Err(ShellError::coerce_error(
left_type.spanned(self.tag.span),
right_type.spanned(self.tag.span),
)));
}
};
Some(ReturnSuccess::value(output))
} else if !self.moves_up
&& (ordering == Ordering::Greater
|| self.is_end_inclusive && ordering == Ordering::Equal)
{
let output = UntaggedValue::Primitive(self.curr.clone()).into_value(self.tag.clone());
let next_value = nu_data::value::compute_values(
Operator::Plus,
&UntaggedValue::Primitive(self.curr.clone()),
&UntaggedValue::int(-1),
);
self.curr = match next_value {
Ok(result) => match result {
UntaggedValue::Primitive(p) => p,
@ -148,7 +186,6 @@ impl Iterator for RangeIterator {
};
Some(ReturnSuccess::value(output))
} else {
// TODO: add inclusive/exclusive ranges
None
}
}

View File

@ -11,3 +11,51 @@ fn echo_range_is_lazy() {
assert_eq!(actual.out, "[1,2,3]");
}
#[test]
fn echo_range_handles_inclusive() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo 1..3 | to json
"#
));
assert_eq!(actual.out, "[1,2,3]");
}
#[test]
fn echo_range_handles_exclusive() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo 1..<3 | to json
"#
));
assert_eq!(actual.out, "[1,2]");
}
#[test]
fn echo_range_handles_inclusive_down() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo 3..1 | to json
"#
));
assert_eq!(actual.out, "[3,2,1]");
}
#[test]
fn echo_range_handles_exclusive_down() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo 3..<1 | to json
"#
));
assert_eq!(actual.out, "[3,2]");
}