mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-09-14 19:16:17 +00:00
uucore: parser: num_parser: Ignore empty exponents
Numbers like 123.15e or 123.15e- should return PartialMatch. Numbers like `e`, `.e` are not valid. Fixes #7685.
This commit is contained in:
parent
e5eb004793
commit
8363274f75
1 changed files with 72 additions and 6 deletions
|
@ -458,7 +458,7 @@ pub(crate) fn parse<'a>(
|
||||||
let mut chars = rest.chars().enumerate().fuse().peekable();
|
let mut chars = rest.chars().enumerate().fuse().peekable();
|
||||||
let mut digits: Option<BigUint> = None;
|
let mut digits: Option<BigUint> = None;
|
||||||
let mut scale = 0u64;
|
let mut scale = 0u64;
|
||||||
let mut exponent = BigInt::zero();
|
let mut exponent: Option<BigInt> = None;
|
||||||
while let Some(d) = chars.peek().and_then(|&(_, c)| base.digit(c)) {
|
while let Some(d) = chars.peek().and_then(|&(_, c)| base.digit(c)) {
|
||||||
chars.next();
|
chars.next();
|
||||||
digits = Some(digits.unwrap_or_default() * base as u8 + d);
|
digits = Some(digits.unwrap_or_default() * base as u8 + d);
|
||||||
|
@ -487,6 +487,8 @@ pub(crate) fn parse<'a>(
|
||||||
.peek()
|
.peek()
|
||||||
.is_some_and(|&(_, c)| c.to_ascii_lowercase() == exp_char)
|
.is_some_and(|&(_, c)| c.to_ascii_lowercase() == exp_char)
|
||||||
{
|
{
|
||||||
|
// Save the iterator position in case we do not parse any exponent.
|
||||||
|
let save_chars = chars.clone();
|
||||||
chars.next();
|
chars.next();
|
||||||
let exp_negative = match chars.peek() {
|
let exp_negative = match chars.peek() {
|
||||||
Some((_, '-')) => {
|
Some((_, '-')) => {
|
||||||
|
@ -501,10 +503,15 @@ pub(crate) fn parse<'a>(
|
||||||
};
|
};
|
||||||
while let Some(d) = chars.peek().and_then(|&(_, c)| Base::Decimal.digit(c)) {
|
while let Some(d) = chars.peek().and_then(|&(_, c)| Base::Decimal.digit(c)) {
|
||||||
chars.next();
|
chars.next();
|
||||||
exponent = exponent * 10 + d as i64;
|
exponent = Some(exponent.unwrap_or_default() * 10 + d as i64);
|
||||||
}
|
}
|
||||||
if exp_negative {
|
if let Some(exp) = &exponent {
|
||||||
exponent = -exponent;
|
if exp_negative {
|
||||||
|
exponent = Some(-exp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No exponent actually parsed, reset iterator to return partial match.
|
||||||
|
chars = save_chars;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -532,7 +539,7 @@ pub(crate) fn parse<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let ebd_result =
|
let ebd_result =
|
||||||
construct_extended_big_decimal(digits, negative, base, scale, exponent);
|
construct_extended_big_decimal(digits, negative, base, scale, exponent.unwrap_or_default());
|
||||||
|
|
||||||
// Return what has been parsed so far. If there are extra characters, mark the
|
// Return what has been parsed so far. If there are extra characters, mark the
|
||||||
// parsing as a partial match.
|
// parsing as a partial match.
|
||||||
|
@ -671,6 +678,16 @@ mod tests {
|
||||||
Ok(0.15),
|
Ok(0.15),
|
||||||
f64::extended_parse(".150000000000000000000000000231313")
|
f64::extended_parse(".150000000000000000000000000231313")
|
||||||
);
|
);
|
||||||
|
assert!(matches!(f64::extended_parse("123.15e"),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "e")) if f == 123.15));
|
||||||
|
assert!(matches!(f64::extended_parse("123.15E"),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "E")) if f == 123.15));
|
||||||
|
assert!(matches!(f64::extended_parse("123.15e-"),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "e-")) if f == 123.15));
|
||||||
|
assert!(matches!(f64::extended_parse("123.15e+"),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "e+")) if f == 123.15));
|
||||||
|
assert!(matches!(f64::extended_parse("123.15e."),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "e.")) if f == 123.15));
|
||||||
assert!(matches!(f64::extended_parse("1.2.3"),
|
assert!(matches!(f64::extended_parse("1.2.3"),
|
||||||
Err(ExtendedParserError::PartialMatch(f, ".3")) if f == 1.2));
|
Err(ExtendedParserError::PartialMatch(f, ".3")) if f == 1.2));
|
||||||
assert!(matches!(f64::extended_parse("123.15p5"),
|
assert!(matches!(f64::extended_parse("123.15p5"),
|
||||||
|
@ -833,6 +850,38 @@ mod tests {
|
||||||
Err(ExtendedParserError::NotNumeric),
|
Err(ExtendedParserError::NotNumeric),
|
||||||
ExtendedBigDecimal::extended_parse(".")
|
ExtendedBigDecimal::extended_parse(".")
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("e")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse(".e")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("-e")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("+.e")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("e10")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("e-10")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("-e10")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("+e10")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -853,6 +902,15 @@ mod tests {
|
||||||
// but we can check that the number still gets parsed properly: 0x0.8e5 is 0x8e5 / 16**3
|
// but we can check that the number still gets parsed properly: 0x0.8e5 is 0x8e5 / 16**3
|
||||||
assert_eq!(Ok(0.555908203125), f64::extended_parse("0x0.8e5"));
|
assert_eq!(Ok(0.555908203125), f64::extended_parse("0x0.8e5"));
|
||||||
|
|
||||||
|
assert!(matches!(f64::extended_parse("0x0.1p"),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "p")) if f == 0.0625));
|
||||||
|
assert!(matches!(f64::extended_parse("0x0.1p-"),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "p-")) if f == 0.0625));
|
||||||
|
assert!(matches!(f64::extended_parse("0x.1p+"),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "p+")) if f == 0.0625));
|
||||||
|
assert!(matches!(f64::extended_parse("0x.1p."),
|
||||||
|
Err(ExtendedParserError::PartialMatch(f, "p.")) if f == 0.0625));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok(ExtendedBigDecimal::BigDecimal(
|
Ok(ExtendedBigDecimal::BigDecimal(
|
||||||
BigDecimal::from_str("0.0625").unwrap()
|
BigDecimal::from_str("0.0625").unwrap()
|
||||||
|
@ -910,7 +968,7 @@ mod tests {
|
||||||
))
|
))
|
||||||
));
|
));
|
||||||
|
|
||||||
// TODO: GNU coreutils treats these 2 as partial match.
|
// TODO: GNU coreutils treats these as partial matches.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(ExtendedParserError::NotNumeric),
|
Err(ExtendedParserError::NotNumeric),
|
||||||
ExtendedBigDecimal::extended_parse("0x")
|
ExtendedBigDecimal::extended_parse("0x")
|
||||||
|
@ -919,6 +977,14 @@ mod tests {
|
||||||
Err(ExtendedParserError::NotNumeric),
|
Err(ExtendedParserError::NotNumeric),
|
||||||
ExtendedBigDecimal::extended_parse("0x.")
|
ExtendedBigDecimal::extended_parse("0x.")
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("0xp")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("0xp-2")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue