mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 00:44:57 +02:00
Implement exclusive and inclusive ranges with ..< and .. (#2541)
* Implement exclusive and inclusive ranges with .. and ..= This commit adds right-exclusive ranges. The original a..b inclusive syntax was changed to reflect the Rust notation. New a..=b syntax was introduced to have the old behavior. Currently, both a.. and b..= is valid, and it is unclear whether it's valid to impose restrictions. The original issue suggests .. for inclusive and ..< for exclusive ranges, this can be implemented by making simple changes to this commit. * Fix collect tests by changing ranges to ..= * Fix clippy lints in exclusive range matching * Implement exclusive ranges using `..<`
This commit is contained in:
@ -5,7 +5,7 @@ use nu_errors::{ArgumentError, ParseError};
|
||||
use nu_protocol::hir::{
|
||||
self, Binary, Block, ClassifiedBlock, ClassifiedCommand, ClassifiedPipeline, Commands,
|
||||
Expression, ExternalRedirection, Flag, FlagKind, InternalCommand, Member, NamedArguments,
|
||||
Operator, SpannedExpression, Unit,
|
||||
Operator, RangeOperator, SpannedExpression, Unit,
|
||||
};
|
||||
use nu_protocol::{NamedType, PositionalType, Signature, SyntaxShape, UnspannedPathMember};
|
||||
use nu_source::{Span, Spanned, SpannedItem};
|
||||
@ -242,8 +242,18 @@ fn parse_range(
|
||||
) -> (SpannedExpression, Option<ParseError>) {
|
||||
let lite_arg_span_start = lite_arg.span.start();
|
||||
let lite_arg_len = lite_arg.item.len();
|
||||
let dotdot_pos = lite_arg.item.find("..");
|
||||
let numbers: Vec<_> = lite_arg.item.split("..").collect();
|
||||
let (dotdot_pos, operator_str, operator) = if let Some(pos) = lite_arg.item.find("..<") {
|
||||
(pos, "..<", RangeOperator::RightExclusive)
|
||||
} else if let Some(pos) = lite_arg.item.find("..") {
|
||||
(pos, "..", RangeOperator::Inclusive)
|
||||
} else {
|
||||
return (
|
||||
garbage(lite_arg.span),
|
||||
Some(ParseError::mismatch("range", lite_arg.clone())),
|
||||
);
|
||||
};
|
||||
|
||||
let numbers: Vec<_> = lite_arg.item.split(operator_str).collect();
|
||||
|
||||
if numbers.len() != 2 {
|
||||
return (
|
||||
@ -252,19 +262,19 @@ fn parse_range(
|
||||
);
|
||||
}
|
||||
|
||||
let dotdot_pos = dotdot_pos.expect("Internal error: range .. can't be found but should be");
|
||||
let right_number_offset = operator_str.len();
|
||||
|
||||
let lhs = numbers[0].to_string().spanned(Span::new(
|
||||
lite_arg_span_start,
|
||||
lite_arg_span_start + dotdot_pos,
|
||||
));
|
||||
let rhs = numbers[1].to_string().spanned(Span::new(
|
||||
lite_arg_span_start + dotdot_pos + 2,
|
||||
lite_arg_span_start + dotdot_pos + right_number_offset,
|
||||
lite_arg_span_start + lite_arg_len,
|
||||
));
|
||||
|
||||
let left_hand_open = dotdot_pos == 0;
|
||||
let right_hand_open = dotdot_pos == lite_arg_len - 2;
|
||||
let right_hand_open = dotdot_pos == lite_arg_len - right_number_offset;
|
||||
|
||||
let left = if left_hand_open {
|
||||
None
|
||||
@ -292,10 +302,10 @@ fn parse_range(
|
||||
SpannedExpression::new(
|
||||
Expression::range(
|
||||
left,
|
||||
Span::new(
|
||||
operator.spanned(Span::new(
|
||||
lite_arg_span_start + dotdot_pos,
|
||||
lite_arg_span_start + dotdot_pos + 2,
|
||||
),
|
||||
lite_arg_span_start + dotdot_pos + right_number_offset,
|
||||
)),
|
||||
right,
|
||||
),
|
||||
lite_arg.span,
|
||||
|
@ -68,7 +68,13 @@ pub fn expression_to_flat_shape(e: &SpannedExpression) -> Vec<Spanned<FlatShape>
|
||||
if let Some(left) = &range.left {
|
||||
output.append(&mut expression_to_flat_shape(left));
|
||||
}
|
||||
output.push(FlatShape::DotDot.spanned(range.dotdot));
|
||||
output.push(
|
||||
match &range.operator.item {
|
||||
RangeOperator::Inclusive => FlatShape::DotDot,
|
||||
RangeOperator::RightExclusive => FlatShape::DotDotLeftAngleBracket,
|
||||
}
|
||||
.spanned(&range.operator.span),
|
||||
);
|
||||
if let Some(right) = &range.right {
|
||||
output.append(&mut expression_to_flat_shape(right));
|
||||
}
|
||||
|
Reference in New Issue
Block a user