Skip to content

Commit c418b14

Browse files
committed
Fixes #1384, by ensuring specials are properly parsed.
1 parent 3b872da commit c418b14

File tree

2 files changed

+382
-22
lines changed

2 files changed

+382
-22
lines changed

src/number/complete.rs

Lines changed: 192 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Parsers recognizing numbers, complete input version
22
3+
use core::{f32, f64};
34
use crate::branch::alt;
45
use crate::bytes::complete::tag;
56
use crate::character::complete::{char, digit1, sign};
@@ -1426,6 +1427,8 @@ where
14261427
)(input)
14271428
}
14281429

1430+
///
1431+
14291432
/// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data
14301433
///
14311434
/// *Complete version*: Can parse until the end of input.
@@ -1517,24 +1520,35 @@ where
15171520
Ok((i, (sign, integer, fraction, exp)))
15181521
}
15191522

1523+
/// Case-insensitive comparison of digits. Only works if `y` is only ASCII letters.
1524+
#[inline]
1525+
fn case_insensitive_cmp(x: &[u8], y: &[u8]) -> bool {
1526+
let d = (x.iter().zip(y.iter())).fold(0, |d, (xi, yi)| d | xi ^ yi);
1527+
// This uses the trick that 'a' - 'A' == 0x20, and this is true
1528+
// for all characters, so as long as `yi` is a valid ASCII letter,
1529+
// `xi ^ yi` can only be 0 or 0x20.
1530+
d == 0 || d == 32
1531+
}
1532+
15201533
/// Recognizes floating point number in text format and returns a f32.
15211534
///
1522-
/// *Complete version*: Can parse until the end of input.
1535+
/// *Complete version*: Can parse until the end of input. This only handles
1536+
/// finite (non-special floats).
15231537
/// ```rust
15241538
/// # use nom::{Err, error::ErrorKind, Needed};
15251539
/// # use nom::Needed::Size;
1526-
/// use nom::number::complete::float;
1540+
/// use nom::number::complete::float_finite;
15271541
///
15281542
/// let parser = |s| {
1529-
/// float(s)
1543+
/// float_finite(s)
15301544
/// };
15311545
///
15321546
/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
15331547
/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
15341548
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
15351549
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
15361550
/// ```
1537-
pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
1551+
pub fn float_finite<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
15381552
where
15391553
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
15401554
T: Clone + Offset,
@@ -1560,6 +1574,42 @@ where
15601574
Ok((i, float))
15611575
}
15621576

1577+
/// Recognizes floating point number in text format and returns a f32.
1578+
/// This only handles non-finite (special) values.
1579+
pub fn float_nonfinite<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
1580+
where
1581+
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
1582+
T: Clone + Offset,
1583+
T: InputIter + InputLength + InputTake,
1584+
<T as InputIter>::Item: AsChar + Copy,
1585+
<T as InputIter>::IterElem: Clone,
1586+
T: InputTakeAtPosition,
1587+
<T as InputTakeAtPosition>::Item: AsChar,
1588+
T: AsBytes,
1589+
T: for<'a> Compare<&'a [u8]>,
1590+
{
1591+
let (i, sign) = sign(input.clone())?;
1592+
let (mut float, count) = if i.input_len() >= 3 {
1593+
if case_insensitive_cmp(i.as_bytes(), b"nan") {
1594+
(f32::NAN, 3)
1595+
} else if i.input_len() >= 8 && case_insensitive_cmp(i.as_bytes(), b"infinity") {
1596+
(f32::INFINITY, 8)
1597+
} else if case_insensitive_cmp(i.as_bytes(), b"inf") {
1598+
(f32::INFINITY, 3)
1599+
} else {
1600+
return Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)));
1601+
}
1602+
} else {
1603+
return Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)));
1604+
};
1605+
1606+
if !sign {
1607+
float = -float;
1608+
}
1609+
1610+
Ok((i.slice(count..), float))
1611+
}
1612+
15631613
/// Recognizes floating point number in text format and returns a f32.
15641614
///
15651615
/// *Complete version*: Can parse until the end of input.
@@ -1577,7 +1627,44 @@ where
15771627
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
15781628
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
15791629
/// ```
1580-
pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
1630+
pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
1631+
where
1632+
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
1633+
T: Clone + Offset,
1634+
T: InputIter + InputLength + InputTake,
1635+
<T as InputIter>::Item: AsChar + Copy,
1636+
<T as InputIter>::IterElem: Clone,
1637+
T: InputTakeAtPosition,
1638+
<T as InputTakeAtPosition>::Item: AsChar,
1639+
T: AsBytes,
1640+
T: for<'a> Compare<&'a [u8]>,
1641+
{
1642+
if let Ok((i, float)) = float_finite::<T, E>(input.clone()) {
1643+
Ok((i, float))
1644+
} else {
1645+
float_nonfinite::<T, E>(input)
1646+
}
1647+
}
1648+
1649+
/// Recognizes floating point number in text format and returns a f64.
1650+
///
1651+
/// *Complete version*: Can parse until the end of input. This only handles
1652+
/// finite (non-special floats).
1653+
/// ```rust
1654+
/// # use nom::{Err, error::ErrorKind, Needed};
1655+
/// # use nom::Needed::Size;
1656+
/// use nom::number::complete::double_finite;
1657+
///
1658+
/// let parser = |s| {
1659+
/// double_finite(s)
1660+
/// };
1661+
///
1662+
/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
1663+
/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
1664+
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
1665+
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
1666+
/// ```
1667+
pub fn double_finite<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
15811668
where
15821669
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
15831670
T: Clone + Offset,
@@ -1603,6 +1690,78 @@ where
16031690
Ok((i, float))
16041691
}
16051692

1693+
/// Recognizes floating point number in text format and returns a f64.
1694+
/// This only handles non-finite (special) values.
1695+
pub fn double_nonfinite<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
1696+
where
1697+
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
1698+
T: Clone + Offset,
1699+
T: InputIter + InputLength + InputTake,
1700+
<T as InputIter>::Item: AsChar + Copy,
1701+
<T as InputIter>::IterElem: Clone,
1702+
T: InputTakeAtPosition,
1703+
<T as InputTakeAtPosition>::Item: AsChar,
1704+
T: AsBytes,
1705+
T: for<'a> Compare<&'a [u8]>,
1706+
{
1707+
let (i, sign) = sign(input.clone())?;
1708+
let (mut double, count) = if i.input_len() >= 3 {
1709+
if case_insensitive_cmp(i.as_bytes(), b"nan") {
1710+
(f64::NAN, 3)
1711+
} else if i.input_len() >= 8 && case_insensitive_cmp(i.as_bytes(), b"infinity") {
1712+
(f64::INFINITY, 8)
1713+
} else if case_insensitive_cmp(i.as_bytes(), b"inf") {
1714+
(f64::INFINITY, 3)
1715+
} else {
1716+
return Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)));
1717+
}
1718+
} else {
1719+
return Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)));
1720+
};
1721+
1722+
if !sign {
1723+
double = -double;
1724+
}
1725+
1726+
Ok((i.slice(count..), double))
1727+
}
1728+
1729+
/// Recognizes floating point number in text format and returns a f64.
1730+
///
1731+
/// *Complete version*: Can parse until the end of input.
1732+
/// ```rust
1733+
/// # use nom::{Err, error::ErrorKind, Needed};
1734+
/// # use nom::Needed::Size;
1735+
/// use nom::number::complete::double;
1736+
///
1737+
/// let parser = |s| {
1738+
/// double(s)
1739+
/// };
1740+
///
1741+
/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
1742+
/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
1743+
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
1744+
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
1745+
/// ```
1746+
pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
1747+
where
1748+
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
1749+
T: Clone + Offset,
1750+
T: InputIter + InputLength + InputTake,
1751+
<T as InputIter>::Item: AsChar + Copy,
1752+
<T as InputIter>::IterElem: Clone,
1753+
T: InputTakeAtPosition,
1754+
<T as InputTakeAtPosition>::Item: AsChar,
1755+
T: AsBytes,
1756+
T: for<'a> Compare<&'a [u8]>,
1757+
{
1758+
match double_finite::<T, E>(input.clone()) {
1759+
Ok((i, double)) => Ok((i, double)),
1760+
Err(Err::Incomplete(e)) => Err(Err::Incomplete(e)),
1761+
_ => double_nonfinite::<T, E>(input),
1762+
}
1763+
}
1764+
16061765
#[cfg(test)]
16071766
mod tests {
16081767
use super::*;
@@ -1618,6 +1777,23 @@ mod tests {
16181777
};
16191778
);
16201779

1780+
// Need more complex logic, since NaN != NaN.
1781+
macro_rules! assert_float_eq {
1782+
($left: expr, $right: expr) => {
1783+
let left: $crate::IResult<_, _, (_, ErrorKind)> = $left;
1784+
let right: $crate::IResult<_, _, (_, ErrorKind)> = $right;
1785+
if let Ok((_, float)) = right {
1786+
if float.is_nan() {
1787+
assert!(left.unwrap().1.is_nan());
1788+
} else {
1789+
assert_eq!(left, right);
1790+
}
1791+
}else {
1792+
assert_eq!(left, right);
1793+
}
1794+
};
1795+
}
1796+
16211797
#[test]
16221798
fn i8_tests() {
16231799
assert_parse!(i8(&[0x00][..]), Ok((&b""[..], 0)));
@@ -1942,6 +2118,8 @@ mod tests {
19422118
"12.34",
19432119
"-1.234E-12",
19442120
"-1.234e-12",
2121+
"NaN",
2122+
"inf",
19452123
];
19462124

19472125
for test in test_cases.drain(..) {
@@ -1951,13 +2129,15 @@ mod tests {
19512129
println!("now parsing: {} -> {}", test, expected32);
19522130

19532131
let larger = format!("{}", test);
1954-
assert_parse!(recognize_float(&larger[..]), Ok(("", test)));
2132+
if expected32.is_finite() {
2133+
assert_parse!(recognize_float(&larger[..]), Ok(("", test)));
2134+
}
19552135

1956-
assert_parse!(float(larger.as_bytes()), Ok((&b""[..], expected32)));
1957-
assert_parse!(float(&larger[..]), Ok(("", expected32)));
2136+
assert_float_eq!(float(larger.as_bytes()), Ok((&b""[..], expected32)));
2137+
assert_float_eq!(float(&larger[..]), Ok(("", expected32)));
19582138

1959-
assert_parse!(double(larger.as_bytes()), Ok((&b""[..], expected64)));
1960-
assert_parse!(double(&larger[..]), Ok(("", expected64)));
2139+
assert_float_eq!(double(larger.as_bytes()), Ok((&b""[..], expected64)));
2140+
assert_float_eq!(double(&larger[..]), Ok(("", expected64)));
19612141
}
19622142

19632143
let remaining_exponent = "-1.234E-";
@@ -2051,8 +2231,8 @@ mod tests {
20512231
}
20522232

20532233
fn parse_f64(i: &str) -> IResult<&str, f64, ()> {
2054-
match recognize_float(i) {
2055-
Err(e) => Err(e),
2234+
match recognize_float::<_, ()>(i) {
2235+
Err(_) => Err(Err::Error(())),
20562236
Ok((i, s)) => {
20572237
if s.is_empty() {
20582238
return Err(Err::Error(()));

0 commit comments

Comments
 (0)