Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 67 additions & 3 deletions src/number/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,40 @@ where
)(input)
}

// workaround until issues with minimal-lexical are fixed
#[doc(hidden)]
pub fn recognize_float_or_exceptions<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
T: Clone + Offset,
T: InputIter + InputTake + Compare<&'static str>,
<T as InputIter>::Item: AsChar,
T: InputTakeAtPosition,
<T as InputTakeAtPosition>::Item: AsChar,
{
alt((
|i: T| {
recognize_float::<_, E>(i.clone()).map_err(|e| match e {
crate::Err::Error(_) => crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)),
crate::Err::Failure(_) => crate::Err::Failure(E::from_error_kind(i, ErrorKind::Float)),
crate::Err::Incomplete(needed) => crate::Err::Incomplete(needed),
})
},
|i: T| {
crate::bytes::complete::tag_no_case::<_, _, E>("nan")(i.clone())
.map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
|i: T| {
crate::bytes::complete::tag_no_case::<_, _, E>("inf")(i.clone())
.map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
|i: T| {
crate::bytes::complete::tag_no_case::<_, _, E>("infinity")(i.clone())
.map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
))(input)
}

/// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data
///
/// *Complete version*: Can parse until the end of input.
Expand Down Expand Up @@ -1517,6 +1551,8 @@ where
Ok((i, (sign, integer, fraction, exp)))
}

use crate::traits::ParseTo;

/// Recognizes floating point number in text format and returns a f32.
///
/// *Complete version*: Can parse until the end of input.
Expand All @@ -1537,7 +1573,7 @@ where
pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
T: Clone + Offset,
T: Clone + Offset + ParseTo<f32> + Compare<&'static str>,
T: InputIter + InputLength + InputTake,
<T as InputIter>::Item: AsChar + Copy,
<T as InputIter>::IterElem: Clone,
Expand All @@ -1546,6 +1582,7 @@ where
T: AsBytes,
T: for<'a> Compare<&'a [u8]>,
{
/*
let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;

let mut float: f32 = minimal_lexical::parse_float(
Expand All @@ -1558,6 +1595,15 @@ where
}

Ok((i, float))
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
Some(f) => (Ok((i, f))),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
))),
}
}

/// Recognizes floating point number in text format and returns a f64.
Expand All @@ -1580,7 +1626,7 @@ where
pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
T: Clone + Offset,
T: Clone + Offset + ParseTo<f64> + Compare<&'static str>,
T: InputIter + InputLength + InputTake,
<T as InputIter>::Item: AsChar + Copy,
<T as InputIter>::IterElem: Clone,
Expand All @@ -1589,6 +1635,7 @@ where
T: AsBytes,
T: for<'a> Compare<&'a [u8]>,
{
/*
let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;

let mut float: f64 = minimal_lexical::parse_float(
Expand All @@ -1601,6 +1648,15 @@ where
}

Ok((i, float))
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
Some(f) => (Ok((i, f))),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
))),
}
}

#[cfg(test)]
Expand Down Expand Up @@ -1941,6 +1997,7 @@ mod tests {
"12.34",
"-1.234E-12",
"-1.234e-12",
"0.00000000000000000087",
];

for test in test_cases.drain(..) {
Expand All @@ -1964,6 +2021,14 @@ mod tests {
recognize_float(remaining_exponent),
Err(Err::Failure(("", ErrorKind::Digit)))
);

let (_i, nan) = float::<_, ()>("NaN").unwrap();
assert!(nan.is_nan());

let (_i, inf) = float::<_, ()>("inf").unwrap();
assert!(inf.is_infinite());
let (_i, inf) = float::<_, ()>("infinite").unwrap();
assert!(inf.is_infinite());
}

#[test]
Expand Down Expand Up @@ -2051,7 +2116,6 @@ mod tests {

#[cfg(feature = "std")]
fn parse_f64(i: &str) -> IResult<&str, f64, ()> {
use crate::traits::ParseTo;
match recognize_float(i) {
Err(e) => Err(e),
Ok((i, s)) => {
Expand Down
67 changes: 65 additions & 2 deletions src/number/streaming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,40 @@ where
)(input)
}

// workaround until issues with minimal-lexical are fixed
#[doc(hidden)]
pub fn recognize_float_or_exceptions<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
T: Clone + Offset,
T: InputIter + InputTake + InputLength + Compare<&'static str>,
<T as InputIter>::Item: AsChar,
T: InputTakeAtPosition,
<T as InputTakeAtPosition>::Item: AsChar,
{
alt((
|i: T| {
recognize_float::<_, E>(i.clone()).map_err(|e| match e {
crate::Err::Error(_) => crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)),
crate::Err::Failure(_) => crate::Err::Failure(E::from_error_kind(i, ErrorKind::Float)),
crate::Err::Incomplete(needed) => crate::Err::Incomplete(needed),
})
},
|i: T| {
crate::bytes::streaming::tag_no_case::<_, _, E>("nan")(i.clone())
.map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
|i: T| {
crate::bytes::streaming::tag_no_case::<_, _, E>("inf")(i.clone())
.map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
|i: T| {
crate::bytes::streaming::tag_no_case::<_, _, E>("infinity")(i.clone())
.map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
))(input)
}

/// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data
///
/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there is not enough data.
Expand Down Expand Up @@ -1512,14 +1546,15 @@ pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
T: Clone + Offset,
T: InputIter + InputLength + InputTake + crate::traits::ParseTo<i32>,
T: InputIter + InputLength + InputTake + crate::traits::ParseTo<f32> + Compare<&'static str>,
<T as InputIter>::Item: AsChar,
<T as InputIter>::IterElem: Clone,
T: InputTakeAtPosition,
<T as InputTakeAtPosition>::Item: AsChar,
T: AsBytes,
T: for<'a> Compare<&'a [u8]>,
{
/*
let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;

let mut float: f32 = minimal_lexical::parse_float(
Expand All @@ -1532,6 +1567,15 @@ where
}

Ok((i, float))
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
Some(f) => (Ok((i, f))),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
))),
}
}

/// Recognizes floating point number in text format and returns a f64.
Expand All @@ -1556,14 +1600,15 @@ pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
T: Clone + Offset,
T: InputIter + InputLength + InputTake + crate::traits::ParseTo<i32>,
T: InputIter + InputLength + InputTake + crate::traits::ParseTo<f64> + Compare<&'static str>,
<T as InputIter>::Item: AsChar,
<T as InputIter>::IterElem: Clone,
T: InputTakeAtPosition,
<T as InputTakeAtPosition>::Item: AsChar,
T: AsBytes,
T: for<'a> Compare<&'a [u8]>,
{
/*
let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;

let mut float: f64 = minimal_lexical::parse_float(
Expand All @@ -1576,6 +1621,15 @@ where
}

Ok((i, float))
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
Some(f) => (Ok((i, f))),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
))),
}
}

#[cfg(test)]
Expand Down Expand Up @@ -2022,6 +2076,7 @@ mod tests {
"12.34",
"-1.234E-12",
"-1.234e-12",
"0.00000000000000000087",
];

for test in test_cases.drain(..) {
Expand All @@ -2045,6 +2100,14 @@ mod tests {
recognize_float(remaining_exponent),
Err(Err::Incomplete(Needed::new(1)))
);

let (_i, nan) = float::<_, ()>("NaN").unwrap();
assert!(nan.is_nan());

let (_i, inf) = float::<_, ()>("inf").unwrap();
assert!(inf.is_infinite());
let (_i, inf) = float::<_, ()>("infinite").unwrap();
assert!(inf.is_infinite());
Comment on lines +2109 to +2110
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this test should fail cause it's only eat 'inf' and not 'infinite' https://github.com/Geal/nom/pull/1391/files# parse infinity before inf cause of this

}

#[test]
Expand Down