mirror of
https://github.com/nushell/nushell.git
synced 2025-01-09 15:58:17 +01:00
Allow underscores in integers and floats (#7759)
# Description This PR makes changes that allow underscores in numbers. Example: ```nu # allows underscores to be placed arbitrarily to enhance readability. let pi = 3.1415_9265_3589_793 # works with integers let num = 1_000_000_000_000 let fav_color = 0x68_9d_6a ```
This commit is contained in:
parent
7221eb7f39
commit
56a9eab7eb
@ -1329,12 +1329,19 @@ fn decode_with_base(s: &str, base: u32, digits_per_byte: usize) -> Result<Vec<u8
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn strip_underscores(token: &[u8]) -> String {
|
||||
String::from_utf8_lossy(token)
|
||||
.chars()
|
||||
.filter(|c| *c != '_')
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn parse_int(token: &[u8], span: Span) -> (Expression, Option<ParseError>) {
|
||||
if let Some(token) = token.strip_prefix(b"0x") {
|
||||
if let Ok(v) = i64::from_str_radix(&String::from_utf8_lossy(token), 16) {
|
||||
fn extract_int(token: &str, span: Span, radix: u32) -> (Expression, Option<ParseError>) {
|
||||
if let Ok(num) = i64::from_str_radix(token, radix) {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::Int(v),
|
||||
expr: Expr::Int(num),
|
||||
span,
|
||||
ty: Type::Int,
|
||||
custom_completion: None,
|
||||
@ -1351,52 +1358,20 @@ pub fn parse_int(token: &[u8], span: Span) -> (Expression, Option<ParseError>) {
|
||||
)),
|
||||
)
|
||||
}
|
||||
} else if let Some(token) = token.strip_prefix(b"0b") {
|
||||
if let Ok(v) = i64::from_str_radix(&String::from_utf8_lossy(token), 2) {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::Int(v),
|
||||
span,
|
||||
ty: Type::Int,
|
||||
custom_completion: None,
|
||||
},
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Mismatch(
|
||||
"int".into(),
|
||||
"incompatible int".into(),
|
||||
span,
|
||||
)),
|
||||
)
|
||||
}
|
||||
} else if let Some(token) = token.strip_prefix(b"0o") {
|
||||
if let Ok(v) = i64::from_str_radix(&String::from_utf8_lossy(token), 8) {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::Int(v),
|
||||
span,
|
||||
ty: Type::Int,
|
||||
custom_completion: None,
|
||||
},
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
garbage(span),
|
||||
Some(ParseError::Mismatch(
|
||||
"int".into(),
|
||||
"incompatible int".into(),
|
||||
span,
|
||||
)),
|
||||
)
|
||||
}
|
||||
} else if let Ok(x) = String::from_utf8_lossy(token).parse::<i64>() {
|
||||
}
|
||||
|
||||
let token = strip_underscores(token);
|
||||
|
||||
if let Some(num) = token.strip_prefix("0b") {
|
||||
extract_int(num, span, 2)
|
||||
} else if let Some(num) = token.strip_prefix("0o") {
|
||||
extract_int(num, span, 8)
|
||||
} else if let Some(num) = token.strip_prefix("0x") {
|
||||
extract_int(num, span, 16)
|
||||
} else if let Ok(num) = token.parse::<i64>() {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::Int(x),
|
||||
expr: Expr::Int(num),
|
||||
span,
|
||||
ty: Type::Int,
|
||||
custom_completion: None,
|
||||
@ -1412,7 +1387,9 @@ pub fn parse_int(token: &[u8], span: Span) -> (Expression, Option<ParseError>) {
|
||||
}
|
||||
|
||||
pub fn parse_float(token: &[u8], span: Span) -> (Expression, Option<ParseError>) {
|
||||
if let Ok(x) = String::from_utf8_lossy(token).parse::<f64>() {
|
||||
let token = strip_underscores(token);
|
||||
|
||||
if let Ok(x) = token.parse::<f64>() {
|
||||
(
|
||||
Expression {
|
||||
expr: Expr::Float(x),
|
||||
|
@ -64,6 +64,29 @@ pub fn parse_int() {
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn parse_int_with_underscores() {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
|
||||
let (block, err) = parse(&mut working_set, None, b"420_69_2023", true, &[]);
|
||||
|
||||
assert!(err.is_none());
|
||||
assert_eq!(block.len(), 1);
|
||||
let expressions = &block[0];
|
||||
assert_eq!(expressions.len(), 1);
|
||||
assert!(matches!(
|
||||
expressions[0],
|
||||
PipelineElement::Expression(
|
||||
_,
|
||||
Expression {
|
||||
expr: Expr::Int(420692023),
|
||||
..
|
||||
}
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn parse_binary_with_hex_format() {
|
||||
let engine_state = EngineState::new();
|
||||
|
@ -18,6 +18,31 @@ fn alias_1() -> TestResult {
|
||||
run_test("def foo [$x] { $x + 10 }; alias f = foo; f 100", "110")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ints_with_underscores() -> TestResult {
|
||||
run_test("1_0000_0000_0000 + 10", "1000000000010")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floats_with_underscores() -> TestResult {
|
||||
run_test("3.1415_9265_3589_793 * 2", "6.283185307179586")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bin_ints_with_underscores() -> TestResult {
|
||||
run_test("0b_10100_11101_10010", "21426")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oct_ints_with_underscores() -> TestResult {
|
||||
run_test("0o2443_6442_7652_0044", "90422533333028")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hex_ints_with_underscores() -> TestResult {
|
||||
run_test("0x68__9d__6a", "6856042")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alias_2() -> TestResult {
|
||||
run_test(
|
||||
|
Loading…
Reference in New Issue
Block a user