mirror of
https://github.com/nushell/nushell.git
synced 2025-08-14 18:59:06 +02: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:
@ -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();
|
||||
|
Reference in New Issue
Block a user