mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-31 13:07:46 +00:00
uucore: parser: num_parser: Return error if no digit has been parsed
This is mostly important when parsing digits like `.` and `0x.` where we should return an error. Fixes #7684.
This commit is contained in:
parent
8a5a2eed2a
commit
e5eb004793
1 changed files with 52 additions and 6 deletions
|
@ -456,12 +456,12 @@ pub(crate) fn parse<'a>(
|
||||||
|
|
||||||
// Parse the integral part of the number
|
// Parse the integral part of the number
|
||||||
let mut chars = rest.chars().enumerate().fuse().peekable();
|
let mut chars = rest.chars().enumerate().fuse().peekable();
|
||||||
let mut digits = BigUint::zero();
|
let mut digits: Option<BigUint> = None;
|
||||||
let mut scale = 0u64;
|
let mut scale = 0u64;
|
||||||
let mut exponent = BigInt::zero();
|
let mut exponent = BigInt::zero();
|
||||||
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 = digits * base as u8 + d;
|
digits = Some(digits.unwrap_or_default() * base as u8 + d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse fractional/exponent part of the number for supported bases.
|
// Parse fractional/exponent part of the number for supported bases.
|
||||||
|
@ -472,7 +472,7 @@ pub(crate) fn parse<'a>(
|
||||||
chars.next();
|
chars.next();
|
||||||
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, scale) = (digits * base as u8 + d, scale + 1);
|
(digits, scale) = (Some(digits.unwrap_or_default() * base as u8 + d), scale + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,8 +509,8 @@ pub(crate) fn parse<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If nothing has been parsed, check if this is a special value, or declare the parsing unsuccessful
|
// If no digit has been parsed, check if this is a special value, or declare the parsing unsuccessful
|
||||||
if let Some((0, _)) = chars.peek() {
|
if digits.is_none() {
|
||||||
return if target == ParseTarget::Integral {
|
return if target == ParseTarget::Integral {
|
||||||
Err(ExtendedParserError::NotNumeric)
|
Err(ExtendedParserError::NotNumeric)
|
||||||
} else {
|
} else {
|
||||||
|
@ -518,6 +518,8 @@ pub(crate) fn parse<'a>(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut digits = digits.unwrap();
|
||||||
|
|
||||||
if let Some((_, ch)) = chars.peek() {
|
if let Some((_, ch)) = chars.peek() {
|
||||||
if let Some(times) = allowed_suffixes
|
if let Some(times) = allowed_suffixes
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -529,7 +531,8 @@ pub(crate) fn parse<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ebd_result = construct_extended_big_decimal(digits, negative, base, scale, exponent);
|
let ebd_result =
|
||||||
|
construct_extended_big_decimal(digits, negative, base, scale, exponent);
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -625,6 +628,15 @@ mod tests {
|
||||||
i64::extended_parse(&format!("{}", i64::MIN as i128 - 1)),
|
i64::extended_parse(&format!("{}", i64::MIN as i128 - 1)),
|
||||||
Err(ExtendedParserError::Overflow(i64::MIN))
|
Err(ExtendedParserError::Overflow(i64::MIN))
|
||||||
));
|
));
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
i64::extended_parse(""),
|
||||||
|
Err(ExtendedParserError::NotNumeric)
|
||||||
|
));
|
||||||
|
assert!(matches!(
|
||||||
|
i64::extended_parse("."),
|
||||||
|
Err(ExtendedParserError::NotNumeric)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -811,6 +823,16 @@ mod tests {
|
||||||
ExtendedBigDecimal::extended_parse(&format!("-0e{}", i64::MIN + 2)),
|
ExtendedBigDecimal::extended_parse(&format!("-0e{}", i64::MIN + 2)),
|
||||||
Ok(ExtendedBigDecimal::MinusZero)
|
Ok(ExtendedBigDecimal::MinusZero)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Invalid numbers */
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse(".")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -887,6 +909,16 @@ mod tests {
|
||||||
ExtendedBigDecimal::MinusZero
|
ExtendedBigDecimal::MinusZero
|
||||||
))
|
))
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// TODO: GNU coreutils treats these 2 as partial match.
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("0x")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
ExtendedBigDecimal::extended_parse("0x.")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -935,6 +967,20 @@ mod tests {
|
||||||
ebd == ExtendedBigDecimal::zero(),
|
ebd == ExtendedBigDecimal::zero(),
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
assert!(match ExtendedBigDecimal::extended_parse("0b") {
|
||||||
|
Err(ExtendedParserError::PartialMatch(ebd, "b")) => ebd == ExtendedBigDecimal::zero(),
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
assert!(match ExtendedBigDecimal::extended_parse("0b.") {
|
||||||
|
Err(ExtendedParserError::PartialMatch(ebd, "b.")) => ebd == ExtendedBigDecimal::zero(),
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
// TODO: GNU coreutils treats this as partial match.
|
||||||
|
assert_eq!(
|
||||||
|
Err(ExtendedParserError::NotNumeric),
|
||||||
|
u64::extended_parse("0b")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue