Skip to content

Commit 4846497

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

File tree

2 files changed

+380
-22
lines changed

2 files changed

+380
-22
lines changed

src/number/complete.rs

Lines changed: 191 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,6 +1426,8 @@ where
14261426
)(input)
14271427
}
14281428

1429+
///
1430+
14291431
/// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data
14301432
///
14311433
/// *Complete version*: Can parse until the end of input.
@@ -1517,24 +1519,35 @@ where
15171519
Ok((i, (sign, integer, fraction, exp)))
15181520
}
15191521

1522+
/// Case-insensitive comparison of digits. Only works if `y` is only ASCII letters.
1523+
#[inline]
1524+
fn case_insensitive_cmp(x: &[u8], y: &[u8]) -> bool {
1525+
let d = (x.iter().zip(y.iter())).fold(0, |d, (xi, yi)| d | xi ^ yi);
1526+
// This uses the trick that 'a' - 'A' == 0x20, and this is true
1527+
// for all characters, so as long as `yi` is a valid ASCII letter,
1528+
// `xi ^ yi` can only be 0 or 0x20.
1529+
d == 0 || d == 32
1530+
}
1531+
15201532
/// Recognizes floating point number in text format and returns a f32.
15211533
///
1522-
/// *Complete version*: Can parse until the end of input.
1534+
/// *Complete version*: Can parse until the end of input. This only handles
1535+
/// finite (non-special floats).
15231536
/// ```rust
15241537
/// # use nom::{Err, error::ErrorKind, Needed};
15251538
/// # use nom::Needed::Size;
1526-
/// use nom::number::complete::float;
1539+
/// use nom::number::complete::float_finite;
15271540
///
15281541
/// let parser = |s| {
1529-
/// float(s)
1542+
/// float_finite(s)
15301543
/// };
15311544
///
15321545
/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
15331546
/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
15341547
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
15351548
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
15361549
/// ```
1537-
pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
1550+
pub fn float_finite<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
15381551
where
15391552
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
15401553
T: Clone + Offset,
@@ -1560,6 +1573,42 @@ where
15601573
Ok((i, float))
15611574
}
15621575

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

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

1779+
// Need more complex logic, since NaN != NaN.
1780+
macro_rules! assert_float_eq {
1781+
($left: expr, $right: expr) => {
1782+
let left: $crate::IResult<_, _, (_, ErrorKind)> = $left;
1783+
let right: $crate::IResult<_, _, (_, ErrorKind)> = $right;
1784+
if let Ok((_, float)) = right {
1785+
if float.is_nan() {
1786+
assert!(left.unwrap().1.is_nan());
1787+
} else {
1788+
assert_eq!(left, right);
1789+
}
1790+
}else {
1791+
assert_eq!(left, right);
1792+
}
1793+
};
1794+
}
1795+
16211796
#[test]
16221797
fn i8_tests() {
16231798
assert_parse!(i8(&[0x00][..]), Ok((&b""[..], 0)));
@@ -1942,6 +2117,8 @@ mod tests {
19422117
"12.34",
19432118
"-1.234E-12",
19442119
"-1.234e-12",
2120+
"NaN",
2121+
"inf",
19452122
];
19462123

19472124
for test in test_cases.drain(..) {
@@ -1951,13 +2128,15 @@ mod tests {
19512128
println!("now parsing: {} -> {}", test, expected32);
19522129

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

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

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

19632142
let remaining_exponent = "-1.234E-";
@@ -2051,8 +2230,8 @@ mod tests {
20512230
}
20522231

20532232
fn parse_f64(i: &str) -> IResult<&str, f64, ()> {
2054-
match recognize_float(i) {
2055-
Err(e) => Err(e),
2233+
match recognize_float::<_, ()>(i) {
2234+
Err(_) => Err(Err::Error(())),
20562235
Ok((i, s)) => {
20572236
if s.is_empty() {
20582237
return Err(Err::Error(()));

0 commit comments

Comments
 (0)