mirror of
https://github.com/nushell/nushell.git
synced 2025-02-08 22:51:42 +01:00
range operator accepts bot..=top as well as bot..top (#8382)
# Description A compromise fix for #8162. Nushell range operator now accepts `..=` to mean the range includes the top value, so you can use your Rust habits. But the unadorned `..` range operator also includes the value, so you can also use your Nushell habits. _(Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience.)_ ```nushell 〉1..5 ╭───┬───╮ │ 0 │ 1 │ │ 1 │ 2 │ │ 2 │ 3 │ │ 3 │ 4 │ │ 4 │ 5 │ ╰───┴───╯ -------------------------------------------- /home/bobhy/src/rust/nushell -------------------------------------------- 〉1..=5 ╭───┬───╮ │ 0 │ 1 │ │ 1 │ 2 │ │ 2 │ 3 │ │ 3 │ 4 │ │ 4 │ 5 │ ╰───┴───╯ -------------------------------------------- /home/bobhy/src/rust/nushell -------------------------------------------- 〉1..<5 ╭───┬───╮ │ 0 │ 1 │ │ 1 │ 2 │ │ 2 │ 3 │ │ 3 │ 4 │ ╰───┴───╯ ``` # User-Facing Changes Existing scripts with range operator will continue to operate as heretofore. _(List of all changes that impact the user experience here. This helps us keep track of breaking changes.)_ # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - [x] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - [x] `cargo test --workspace` to check that all tests pass # After Submitting Will update the book to include new syntax.
This commit is contained in:
parent
aded2c1937
commit
771e24913d
33
Cargo.lock
generated
33
Cargo.lock
generated
@ -2708,7 +2708,7 @@ dependencies = [
|
|||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"rayon",
|
"rayon",
|
||||||
"reedline",
|
"reedline",
|
||||||
"rstest",
|
"rstest 0.17.0",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
@ -2751,7 +2751,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"reedline",
|
"reedline",
|
||||||
"rstest",
|
"rstest 0.17.0",
|
||||||
"sysinfo 0.28.2",
|
"sysinfo 0.28.2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
@ -2863,7 +2863,7 @@ dependencies = [
|
|||||||
"reedline",
|
"reedline",
|
||||||
"regex",
|
"regex",
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
"rstest",
|
"rstest 0.17.0",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"same-file",
|
"same-file",
|
||||||
@ -2954,6 +2954,7 @@ dependencies = [
|
|||||||
"nu-path",
|
"nu-path",
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
|
"rstest 0.16.0",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
@ -4348,16 +4349,40 @@ dependencies = [
|
|||||||
"xmlparser",
|
"xmlparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rstest"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b07f2d176c472198ec1e6551dc7da28f1c089652f66a7b722676c2238ebc0edf"
|
||||||
|
dependencies = [
|
||||||
|
"rstest_macros 0.16.0",
|
||||||
|
"rustc_version",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rstest"
|
name = "rstest"
|
||||||
version = "0.17.0"
|
version = "0.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962"
|
checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rstest_macros",
|
"rstest_macros 0.17.0",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rstest_macros"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"syn 1.0.109",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rstest_macros"
|
name = "rstest_macros"
|
||||||
version = "0.17.0"
|
version = "0.17.0"
|
||||||
|
@ -23,5 +23,8 @@ nu-plugin = { path = "../nu-plugin", optional = true, version = "0.78.1" }
|
|||||||
nu-engine = { path = "../nu-engine", version = "0.78.1" }
|
nu-engine = { path = "../nu-engine", version = "0.78.1" }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rstest = { version = "0.16.0", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugin = ["nu-plugin"]
|
plugin = ["nu-plugin"]
|
||||||
|
@ -1500,7 +1500,7 @@ pub fn parse_range(
|
|||||||
|
|
||||||
// Range follows the following syntax: [<from>][<next_operator><next>]<range_operator>[<to>]
|
// Range follows the following syntax: [<from>][<next_operator><next>]<range_operator>[<to>]
|
||||||
// where <next_operator> is ".."
|
// where <next_operator> is ".."
|
||||||
// and <range_operator> is ".." or "..<"
|
// and <range_operator> is "..", "..=" or "..<"
|
||||||
// and one of the <from> or <to> bounds must be present (just '..' is not allowed since it
|
// and one of the <from> or <to> bounds must be present (just '..' is not allowed since it
|
||||||
// looks like parent directory)
|
// looks like parent directory)
|
||||||
//bugbug range cannot be [..] because that looks like parent directory
|
//bugbug range cannot be [..] because that looks like parent directory
|
||||||
@ -1553,12 +1553,12 @@ pub fn parse_range(
|
|||||||
return garbage(span);
|
return garbage(span);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let op_str = "..";
|
let op_str = if token.contains("..=") { "..=" } else { ".." };
|
||||||
let op_span = Span::new(
|
let op_span = Span::new(
|
||||||
span.start + range_op_pos,
|
span.start + range_op_pos,
|
||||||
span.start + range_op_pos + op_str.len(),
|
span.start + range_op_pos + op_str.len(),
|
||||||
);
|
);
|
||||||
(RangeInclusion::Inclusive, "..", op_span)
|
(RangeInclusion::Inclusive, op_str, op_span)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Now, based on the operator positions, figure out where the bounds & next are located and
|
// Now, based on the operator positions, figure out where the bounds & next are located and
|
||||||
@ -5178,7 +5178,12 @@ pub fn parse_expression(
|
|||||||
|
|
||||||
let split = name.splitn(2, |x| *x == b'=');
|
let split = name.splitn(2, |x| *x == b'=');
|
||||||
let split: Vec<_> = split.collect();
|
let split: Vec<_> = split.collect();
|
||||||
if !name.starts_with(b"^") && split.len() == 2 && !split[0].is_empty() {
|
if !name.starts_with(b"^")
|
||||||
|
&& split.len() == 2
|
||||||
|
&& !split[0].is_empty()
|
||||||
|
&& !split[0].ends_with(b"..")
|
||||||
|
// was range op ..=
|
||||||
|
{
|
||||||
let point = split[0].len() + 1;
|
let point = split[0].len() + 1;
|
||||||
|
|
||||||
let starting_error_count = working_set.parse_errors.len();
|
let starting_error_count = working_set.parse_errors.len();
|
||||||
|
@ -6,6 +6,7 @@ use nu_protocol::{
|
|||||||
engine::{Command, EngineState, Stack, StateWorkingSet},
|
engine::{Command, EngineState, Stack, StateWorkingSet},
|
||||||
ParseError, PipelineData, ShellError, Signature, SyntaxShape,
|
ParseError, PipelineData, ShellError, Signature, SyntaxShape,
|
||||||
};
|
};
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -974,334 +975,267 @@ mod range {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use nu_protocol::ast::{RangeInclusion, RangeOperator};
|
use nu_protocol::ast::{RangeInclusion, RangeOperator};
|
||||||
|
|
||||||
#[test]
|
#[rstest]
|
||||||
fn parse_inclusive_range() {
|
#[case(b"0..10", RangeInclusion::Inclusive, "inclusive")]
|
||||||
|
#[case(b"0..=10", RangeInclusion::Inclusive, "=inclusive")]
|
||||||
|
#[case(b"0..<10", RangeInclusion::RightExclusive, "exclusive")]
|
||||||
|
#[case(b"10..0", RangeInclusion::Inclusive, "reverse inclusive")]
|
||||||
|
#[case(b"10..=0", RangeInclusion::Inclusive, "reverse =inclusive")]
|
||||||
|
#[case(
|
||||||
|
b"(3 - 3)..<(8 + 2)",
|
||||||
|
RangeInclusion::RightExclusive,
|
||||||
|
"subexpression exclusive"
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
b"(3 - 3)..(8 + 2)",
|
||||||
|
RangeInclusion::Inclusive,
|
||||||
|
"subexpression inclusive"
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
b"(3 - 3)..=(8 + 2)",
|
||||||
|
RangeInclusion::Inclusive,
|
||||||
|
"subexpression =inclusive"
|
||||||
|
)]
|
||||||
|
#[case(b"-10..-3", RangeInclusion::Inclusive, "negative inclusive")]
|
||||||
|
#[case(b"-10..=-3", RangeInclusion::Inclusive, "negative =inclusive")]
|
||||||
|
#[case(b"-10..<-3", RangeInclusion::RightExclusive, "negative exclusive")]
|
||||||
|
|
||||||
|
fn parse_bounded_range(
|
||||||
|
#[case] phrase: &[u8],
|
||||||
|
#[case] inclusion: RangeInclusion,
|
||||||
|
#[case] tag: &str,
|
||||||
|
) {
|
||||||
let engine_state = EngineState::new();
|
let engine_state = EngineState::new();
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"0..10", true, &[]);
|
let block = parse(&mut working_set, None, phrase, true, &[]);
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
assert!(working_set.parse_errors.is_empty());
|
||||||
assert_eq!(block.len(), 1);
|
assert_eq!(block.len(), 1, "{tag}: block length");
|
||||||
|
|
||||||
let expressions = &block[0];
|
let expressions = &block[0];
|
||||||
assert_eq!(expressions.len(), 1);
|
assert_eq!(expressions.len(), 1, "{tag}: expression length");
|
||||||
assert!(matches!(
|
if let PipelineElement::Expression(
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
_,
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Range(
|
expr:
|
||||||
|
Expr::Range(
|
||||||
Some(_),
|
Some(_),
|
||||||
None,
|
None,
|
||||||
Some(_),
|
Some(_),
|
||||||
RangeOperator {
|
RangeOperator {
|
||||||
inclusion: RangeInclusion::Inclusive,
|
inclusion: the_inclusion,
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
)
|
) = expressions[0]
|
||||||
))
|
{
|
||||||
}
|
assert_eq!(
|
||||||
|
the_inclusion, inclusion,
|
||||||
#[test]
|
"{tag}: wrong RangeInclusion {the_inclusion:?}"
|
||||||
fn parse_exclusive_range() {
|
|
||||||
let engine_state = EngineState::new();
|
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"0..<10", true, &[]);
|
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
|
||||||
assert_eq!(block.len(), 1);
|
|
||||||
|
|
||||||
let expressions = &block[0];
|
|
||||||
assert_eq!(expressions.len(), 1);
|
|
||||||
assert!(matches!(
|
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
|
||||||
Expression {
|
|
||||||
expr: Expr::Range(
|
|
||||||
Some(_),
|
|
||||||
None,
|
|
||||||
Some(_),
|
|
||||||
RangeOperator {
|
|
||||||
inclusion: RangeInclusion::RightExclusive,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
),
|
|
||||||
..
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_reverse_range() {
|
|
||||||
let engine_state = EngineState::new();
|
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"10..0", true, &[]);
|
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
|
||||||
assert_eq!(block.len(), 1);
|
|
||||||
|
|
||||||
let expressions = &block[0];
|
|
||||||
assert_eq!(expressions.len(), 1);
|
|
||||||
assert!(matches!(
|
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
|
||||||
Expression {
|
|
||||||
expr: Expr::Range(
|
|
||||||
Some(_),
|
|
||||||
None,
|
|
||||||
Some(_),
|
|
||||||
RangeOperator {
|
|
||||||
inclusion: RangeInclusion::Inclusive,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
),
|
|
||||||
..
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_subexpression_range() {
|
|
||||||
let engine_state = EngineState::new();
|
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"(3 - 3)..<(8 + 2)", true, &[]);
|
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
|
||||||
assert_eq!(block.len(), 1);
|
|
||||||
|
|
||||||
let expressions = &block[0];
|
|
||||||
assert_eq!(expressions.len(), 1);
|
|
||||||
assert!(matches!(
|
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
|
||||||
Expression {
|
|
||||||
expr: Expr::Range(
|
|
||||||
Some(_),
|
|
||||||
None,
|
|
||||||
Some(_),
|
|
||||||
RangeOperator {
|
|
||||||
inclusion: RangeInclusion::RightExclusive,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
),
|
|
||||||
..
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_variable_range() {
|
|
||||||
let engine_state = EngineState::new();
|
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
||||||
|
|
||||||
working_set.add_decl(Box::new(Let));
|
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"let a = 2; $a..10", true, &[]);
|
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
|
||||||
assert_eq!(block.len(), 2);
|
|
||||||
|
|
||||||
let expressions = &block[1];
|
|
||||||
assert_eq!(expressions.len(), 1);
|
|
||||||
assert!(matches!(
|
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
|
||||||
Expression {
|
|
||||||
expr: Expr::Range(
|
|
||||||
Some(_),
|
|
||||||
None,
|
|
||||||
Some(_),
|
|
||||||
RangeOperator {
|
|
||||||
inclusion: RangeInclusion::Inclusive,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
),
|
|
||||||
..
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_subexpression_variable_range() {
|
|
||||||
let engine_state = EngineState::new();
|
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
||||||
|
|
||||||
working_set.add_decl(Box::new(Let));
|
|
||||||
|
|
||||||
let block = parse(
|
|
||||||
&mut working_set,
|
|
||||||
None,
|
|
||||||
b"let a = 2; $a..<($a + 10)",
|
|
||||||
true,
|
|
||||||
&[],
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
panic!("{tag}: expression mismatch.")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(
|
||||||
|
b"let a = 2; $a..10",
|
||||||
|
RangeInclusion::Inclusive,
|
||||||
|
"variable start inclusive"
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
b"let a = 2; $a..=10",
|
||||||
|
RangeInclusion::Inclusive,
|
||||||
|
"variable start =inclusive"
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
b"let a = 2; $a..<($a + 10)",
|
||||||
|
RangeInclusion::RightExclusive,
|
||||||
|
"subexpression variable exclusive"
|
||||||
|
)]
|
||||||
|
fn parse_variable_range(
|
||||||
|
#[case] phrase: &[u8],
|
||||||
|
#[case] inclusion: RangeInclusion,
|
||||||
|
#[case] tag: &str,
|
||||||
|
) {
|
||||||
|
let engine_state = EngineState::new();
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
|
working_set.add_decl(Box::new(Let));
|
||||||
|
|
||||||
|
let block = parse(&mut working_set, None, phrase, true, &[]);
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
assert!(working_set.parse_errors.is_empty());
|
||||||
assert_eq!(block.len(), 2);
|
assert_eq!(block.len(), 2, "{tag} block len 2");
|
||||||
|
|
||||||
let expressions = &block[1];
|
let expressions = &block[1];
|
||||||
assert_eq!(expressions.len(), 1);
|
assert_eq!(expressions.len(), 1, "{tag}: expression length 1");
|
||||||
assert!(matches!(
|
if let PipelineElement::Expression(
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
_,
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Range(
|
expr:
|
||||||
|
Expr::Range(
|
||||||
Some(_),
|
Some(_),
|
||||||
None,
|
None,
|
||||||
Some(_),
|
Some(_),
|
||||||
RangeOperator {
|
RangeOperator {
|
||||||
inclusion: RangeInclusion::RightExclusive,
|
inclusion: the_inclusion,
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
)
|
) = expressions[0]
|
||||||
))
|
{
|
||||||
|
assert_eq!(
|
||||||
|
the_inclusion, inclusion,
|
||||||
|
"{tag}: wrong RangeInclusion {the_inclusion:?}"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("{tag}: expression mismatch.")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[rstest]
|
||||||
fn parse_right_unbounded_range() {
|
#[case(b"0..", RangeInclusion::Inclusive, "right unbounded")]
|
||||||
|
#[case(b"0..=", RangeInclusion::Inclusive, "right unbounded =inclusive")]
|
||||||
|
#[case(b"0..<", RangeInclusion::RightExclusive, "right unbounded")]
|
||||||
|
|
||||||
|
fn parse_right_unbounded_range(
|
||||||
|
#[case] phrase: &[u8],
|
||||||
|
#[case] inclusion: RangeInclusion,
|
||||||
|
#[case] tag: &str,
|
||||||
|
) {
|
||||||
let engine_state = EngineState::new();
|
let engine_state = EngineState::new();
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"0..", true, &[]);
|
let block = parse(&mut working_set, None, phrase, true, &[]);
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
assert!(working_set.parse_errors.is_empty());
|
||||||
assert_eq!(block.len(), 1);
|
assert_eq!(block.len(), 1, "{tag}: block len 1");
|
||||||
|
|
||||||
let expressions = &block[0];
|
let expressions = &block[0];
|
||||||
assert_eq!(expressions.len(), 1);
|
assert_eq!(expressions.len(), 1, "{tag}: expression length 1");
|
||||||
assert!(matches!(
|
if let PipelineElement::Expression(
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
_,
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Range(
|
expr:
|
||||||
|
Expr::Range(
|
||||||
Some(_),
|
Some(_),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
RangeOperator {
|
RangeOperator {
|
||||||
inclusion: RangeInclusion::Inclusive,
|
inclusion: the_inclusion,
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
)
|
) = expressions[0]
|
||||||
))
|
{
|
||||||
|
assert_eq!(
|
||||||
|
the_inclusion, inclusion,
|
||||||
|
"{tag}: wrong RangeInclusion {the_inclusion:?}"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("{tag}: expression mismatch.")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[rstest]
|
||||||
fn parse_left_unbounded_range() {
|
#[case(b"..10", RangeInclusion::Inclusive, "left unbounded inclusive")]
|
||||||
|
#[case(b"..=10", RangeInclusion::Inclusive, "left unbounded =inclusive")]
|
||||||
|
#[case(b"..<10", RangeInclusion::RightExclusive, "left unbounded exclusive")]
|
||||||
|
|
||||||
|
fn parse_left_unbounded_range(
|
||||||
|
#[case] phrase: &[u8],
|
||||||
|
#[case] inclusion: RangeInclusion,
|
||||||
|
#[case] tag: &str,
|
||||||
|
) {
|
||||||
let engine_state = EngineState::new();
|
let engine_state = EngineState::new();
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"..10", true, &[]);
|
let block = parse(&mut working_set, None, phrase, true, &[]);
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
assert!(working_set.parse_errors.is_empty());
|
||||||
assert_eq!(block.len(), 1);
|
assert_eq!(block.len(), 1, "{tag}: block len 1");
|
||||||
|
|
||||||
let expressions = &block[0];
|
let expressions = &block[0];
|
||||||
assert_eq!(expressions.len(), 1);
|
assert_eq!(expressions.len(), 1, "{tag}: expression length 1");
|
||||||
assert!(matches!(
|
if let PipelineElement::Expression(
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
_,
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Range(
|
expr:
|
||||||
|
Expr::Range(
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(_),
|
Some(_),
|
||||||
RangeOperator {
|
RangeOperator {
|
||||||
inclusion: RangeInclusion::Inclusive,
|
inclusion: the_inclusion,
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
)
|
) = expressions[0]
|
||||||
))
|
{
|
||||||
|
assert_eq!(
|
||||||
|
the_inclusion, inclusion,
|
||||||
|
"{tag}: wrong RangeInclusion {the_inclusion:?}"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("{tag}: expression mismatch.")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[rstest]
|
||||||
fn parse_negative_range() {
|
#[case(b"2.0..4.0..10.0", RangeInclusion::Inclusive, "float inclusive")]
|
||||||
|
#[case(b"2.0..4.0..=10.0", RangeInclusion::Inclusive, "float =inclusive")]
|
||||||
|
#[case(b"2.0..4.0..<10.0", RangeInclusion::RightExclusive, "float exclusive")]
|
||||||
|
|
||||||
|
fn parse_float_range(
|
||||||
|
#[case] phrase: &[u8],
|
||||||
|
#[case] inclusion: RangeInclusion,
|
||||||
|
#[case] tag: &str,
|
||||||
|
) {
|
||||||
let engine_state = EngineState::new();
|
let engine_state = EngineState::new();
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"-10..-3", true, &[]);
|
let block = parse(&mut working_set, None, phrase, true, &[]);
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
assert!(working_set.parse_errors.is_empty());
|
||||||
assert_eq!(block.len(), 1);
|
assert_eq!(block.len(), 1, "{tag}: block length 1");
|
||||||
|
|
||||||
let expressions = &block[0];
|
let expressions = &block[0];
|
||||||
assert_eq!(expressions.len(), 1);
|
assert_eq!(expressions.len(), 1, "{tag}: expression length 1");
|
||||||
assert!(matches!(
|
if let PipelineElement::Expression(
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
_,
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Range(
|
expr:
|
||||||
Some(_),
|
Expr::Range(
|
||||||
None,
|
|
||||||
Some(_),
|
|
||||||
RangeOperator {
|
|
||||||
inclusion: RangeInclusion::Inclusive,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
),
|
|
||||||
..
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_float_range() {
|
|
||||||
let engine_state = EngineState::new();
|
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
||||||
|
|
||||||
let block = parse(&mut working_set, None, b"2.0..4.0..10.0", true, &[]);
|
|
||||||
|
|
||||||
assert!(working_set.parse_errors.is_empty());
|
|
||||||
assert_eq!(block.len(), 1);
|
|
||||||
|
|
||||||
let expressions = &block[0];
|
|
||||||
assert_eq!(expressions.len(), 1);
|
|
||||||
assert!(matches!(
|
|
||||||
expressions[0],
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
|
||||||
Expression {
|
|
||||||
expr: Expr::Range(
|
|
||||||
Some(_),
|
Some(_),
|
||||||
Some(_),
|
Some(_),
|
||||||
Some(_),
|
Some(_),
|
||||||
RangeOperator {
|
RangeOperator {
|
||||||
inclusion: RangeInclusion::Inclusive,
|
inclusion: the_inclusion,
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
..
|
..
|
||||||
}
|
},
|
||||||
)
|
) = expressions[0]
|
||||||
))
|
{
|
||||||
|
assert_eq!(
|
||||||
|
the_inclusion, inclusion,
|
||||||
|
"{tag}: wrong RangeInclusion {the_inclusion:?}"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("{tag}: expression mismatch.")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1309,7 +1243,7 @@ mod range {
|
|||||||
let engine_state = EngineState::new();
|
let engine_state = EngineState::new();
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
parse(&mut working_set, None, b"(0)..\"a\"", true, &[]);
|
let _ = parse(&mut working_set, None, b"(0)..\"a\"", true, &[]);
|
||||||
|
|
||||||
assert!(!working_set.parse_errors.is_empty());
|
assert!(!working_set.parse_errors.is_empty());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user