This commit is contained in:
Geoffroy Couprie 2020-10-24 15:19:14 +02:00
parent 4d7869b0e8
commit b52d460276
12 changed files with 138 additions and 116 deletions

View File

@ -21,7 +21,7 @@ use nom::branch::alt;
use nom::bytes::streaming::{is_not, take_while_m_n};
use nom::character::streaming::{char, multispace1};
use nom::combinator::{map, map_opt, map_res, value, verify};
use nom::error::{ParseError, FromExternalError};
use nom::error::{FromExternalError, ParseError};
use nom::multi::fold_many0;
use nom::sequence::{delimited, preceded};
use nom::IResult;
@ -33,8 +33,10 @@ use nom::IResult;
/// Parse a unicode sequence, of the form u{XXXX}, where XXXX is 1 to 6
/// hexadecimal numerals. We will combine this later with parse_escaped_char
/// to parse sequences like \u{00AC}.
fn parse_unicode<'a, E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>>(input: &'a str)
-> IResult<&'a str, char, E> {
fn parse_unicode<'a, E>(input: &'a str) -> IResult<&'a str, char, E>
where
E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
// `take_while_m_n` parses between `m` and `n` bytes (inclusive) that match
// a predicate. `parse_hex` here parses between 1 and 6 hexadecimal numerals.
let parse_hex = take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit());
@ -62,8 +64,10 @@ fn parse_unicode<'a, E: ParseError<&'a str> + FromExternalError<&'a str, std::nu
}
/// Parse an escaped character: \n, \t, \r, \u{00AC}, etc.
fn parse_escaped_char<'a, E: ParseError<&'a str>+ FromExternalError<&'a str, std::num::ParseIntError>>(input: &'a str)
-> IResult<&'a str, char, E> {
fn parse_escaped_char<'a, E>(input: &'a str) -> IResult<&'a str, char, E>
where
E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
preceded(
char('\\'),
// `alt` tries each parser in sequence, returning the result of
@ -119,9 +123,10 @@ enum StringFragment<'a> {
/// Combine parse_literal, parse_escaped_whitespace, and parse_escaped_char
/// into a StringFragment.
fn parse_fragment<'a, E: ParseError<&'a str>+ FromExternalError<&'a str, std::num::ParseIntError>>(
input: &'a str,
) -> IResult<&'a str, StringFragment<'a>, E> {
fn parse_fragment<'a, E>(input: &'a str) -> IResult<&'a str, StringFragment<'a>, E>
where
E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
alt((
// The `map` combinator runs a parser, then applies a function to the output
// of that parser.
@ -133,7 +138,10 @@ fn parse_fragment<'a, E: ParseError<&'a str>+ FromExternalError<&'a str, std::nu
/// Parse a string. Use a loop of parse_fragment and push all of the fragments
/// into an output string.
fn parse_string<'a, E: ParseError<&'a str>+ FromExternalError<&'a str, std::num::ParseIntError>>(input: &'a str) -> IResult<&'a str, String, E> {
fn parse_string<'a, E>(input: &'a str) -> IResult<&'a str, String, E>
where
E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
{
// fold_many0 is the equivalent of iterator::fold. It runs a parser in a loop,
// and for each output value, calls a folding function on each output value.
let build_string = fold_many0(

View File

@ -202,7 +202,9 @@ mod tests {
named!(
bits_bytes_bs,
bits!(bytes!(crate::combinator::rest::<_, crate::error::Error<&[u8]>>))
bits!(bytes!(
crate::combinator::rest::<_, crate::error::Error<&[u8]>>
))
);
#[test]
fn bits_bytes() {

View File

@ -305,11 +305,11 @@ where
))),
}
} else if len >= m && len <= n {
let res: IResult<_, _, Error> = Ok((input.slice(len..), input));
res
let res: IResult<_, _, Error> = Ok((input.slice(len..), input));
res
} else {
let e = ErrorKind::TakeWhileMN;
Err(Err::Error(Error::from_error_kind(input, e)))
let e = ErrorKind::TakeWhileMN;
Err(Err::Error(Error::from_error_kind(input, e)))
}
}
}

View File

@ -5,7 +5,7 @@
#[cfg(feature = "alloc")]
use crate::lib::std::boxed::Box;
use crate::error::{ErrorKind, ParseError, FromExternalError};
use crate::error::{ErrorKind, FromExternalError, ParseError};
use crate::internal::*;
use crate::lib::std::borrow::Borrow;
#[cfg(feature = "std")]
@ -702,32 +702,30 @@ pub fn consumed<I, O, F, E>(mut parser: F) -> impl FnMut(I) -> IResult<I, (I, O)
where
I: Clone + Offset + Slice<RangeTo<usize>>,
E: ParseError<I>,
F: Parser<I, O, E>
F: Parser<I, O, E>,
{
move |input: I| {
let i = input.clone();
match parser.parse(i) {
Ok((remaining, result )) => {
Ok((remaining, result)) => {
let index = input.offset(&remaining);
let consumed = input.slice(..index);
Ok((remaining, (consumed, result)))
},
Err(e) => Err(e)
}
Err(e) => Err(e),
}
}
}
#[doc(hidden)]
pub fn consumedc<I, O, E: ParseError<I>, F>(
input: I,
parser: F
) -> IResult<I, (I, O), E>
pub fn consumedc<I, O, E: ParseError<I>, F>(input: I, parser: F) -> IResult<I, (I, O), E>
where
I: Clone + Offset + Slice<RangeTo<usize>>,
E: ParseError<E>,
F: Fn(I) -> IResult<I, O, E>
{ consumed(parser)(input) }
F: Fn(I) -> IResult<I, O, E>,
{
consumed(parser)(input)
}
/// transforms an error to failure
///
@ -934,7 +932,10 @@ mod tests {
let is_over: &[u8] = &b""[..];
let res_not_over = eof(not_over);
assert_parse!(res_not_over, Err(Err::Error(error_position!(not_over, ErrorKind::Eof))));
assert_parse!(
res_not_over,
Err(Err::Error(error_position!(not_over, ErrorKind::Eof)))
);
let res_over = eof(is_over);
assert_parse!(res_over, Ok((is_over, is_over)));
@ -946,7 +947,10 @@ mod tests {
let is_over: &str = "";
let res_not_over = eof(not_over);
assert_parse!(res_not_over, Err(Err::Error(error_position!(not_over, ErrorKind::Eof))));
assert_parse!(
res_not_over,
Err(Err::Error(error_position!(not_over, ErrorKind::Eof)))
);
let res_over = eof(is_over);
assert_parse!(res_over, Ok((is_over, is_over)));

View File

@ -54,19 +54,19 @@ pub trait FromExternalError<I, E> {
}
/// default error type, only contains the error' location and code
#[derive(Debug,PartialEq)]
#[derive(Debug, PartialEq)]
pub struct Error<I> {
/// position of the error in the input data
pub input: I,
/// nom error code
pub code: ErrorKind,
/// position of the error in the input data
pub input: I,
/// nom error code
pub code: ErrorKind,
}
impl<I> Error<I> {
/// creates a new basic error
pub fn new(input: I, code: ErrorKind) -> Error<I> {
Error { input, code }
}
/// creates a new basic error
pub fn new(input: I, code: ErrorKind) -> Error<I> {
Error { input, code }
}
}
impl<I> ParseError<I> for Error<I> {
@ -90,13 +90,13 @@ impl<I, E> FromExternalError<I, E> for Error<I> {
/// The Display implementation allows the std::error::Error implementation
impl<I: fmt::Display> fmt::Display for Error<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "error {:?} at: {}", self.code, self.input)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "error {:?} at: {}", self.code, self.input)
}
}
#[cfg(feature = "std")]
impl<I: fmt::Debug+fmt::Display> std::error::Error for Error<I> { }
impl<I: fmt::Debug + fmt::Display> std::error::Error for Error<I> {}
// for backward compatibility, keep those trait implementations
// for the previously used error type
@ -208,18 +208,18 @@ impl<I, E> FromExternalError<I, E> for VerboseError<I> {
#[cfg(feature = "alloc")]
impl<I: fmt::Display> fmt::Display for VerboseError<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Parse error:")?;
for (input, error) in &self.errors {
match error {
VerboseErrorKind::Nom(e) => writeln!(f, "{:?} at: {}", e, input)?,
VerboseErrorKind::Char(c) => writeln!(f, "expected '{}' at: {}", c, input)?,
VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?,
}
}
Ok(())
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Parse error:")?;
for (input, error) in &self.errors {
match error {
VerboseErrorKind::Nom(e) => writeln!(f, "{:?} at: {}", e, input)?,
VerboseErrorKind::Char(c) => writeln!(f, "expected '{}' at: {}", c, input)?,
VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?,
}
}
Ok(())
}
}
use crate::internal::{Err, IResult};
@ -245,8 +245,10 @@ where
/// Transforms a `VerboseError` into a trace with input position information
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn convert_error<I: core::ops::Deref<Target = str>>(input: I, e: VerboseError<I>)
-> crate::lib::std::string::String {
pub fn convert_error<I: core::ops::Deref<Target = str>>(
input: I,
e: VerboseError<I>,
) -> crate::lib::std::string::String {
use crate::lib::std::fmt::Write;
use crate::traits::Offset;

View File

@ -17,30 +17,30 @@ use core::num::NonZeroUsize;
pub type IResult<I, O, E = error::Error<I>> = Result<(I, O), Err<E>>;
/// Helper trait to convert a parser's result to a more manageable type
pub trait Finish<I,O,E> {
/// converts the parser's result to a type that is more consumable by error
/// management libraries. It keeps the same `Ok` branch, and merges `Err::Error`
/// and `Err::Failure` into the `Err` side.
///
/// *warning*: if the result is `Err(Err::Incomplete(_))`, this method will panic.
/// - "complete" parsers: It will not be an issue, `Incomplete` is never used
/// - "streaming" parsers: `Incomplete` will be returned if there's not enough data
/// for the parser to decide, and you should gather more data before parsing again.
/// Once the parser returns either `Ok(_)`, `Err(Err::Error(_))` or `Err(Err::Failure(_))`,
/// you can get out of the parsing loop and call `finish()` on the parser's result
fn finish(self) -> Result<(I, O), E>;
pub trait Finish<I, O, E> {
/// converts the parser's result to a type that is more consumable by error
/// management libraries. It keeps the same `Ok` branch, and merges `Err::Error`
/// and `Err::Failure` into the `Err` side.
///
/// *warning*: if the result is `Err(Err::Incomplete(_))`, this method will panic.
/// - "complete" parsers: It will not be an issue, `Incomplete` is never used
/// - "streaming" parsers: `Incomplete` will be returned if there's not enough data
/// for the parser to decide, and you should gather more data before parsing again.
/// Once the parser returns either `Ok(_)`, `Err(Err::Error(_))` or `Err(Err::Failure(_))`,
/// you can get out of the parsing loop and call `finish()` on the parser's result
fn finish(self) -> Result<(I, O), E>;
}
impl<I,O,E> Finish<I,O,E> for IResult<I,O,E> {
fn finish(self) -> Result<(I, O), E> {
match self {
impl<I, O, E> Finish<I, O, E> for IResult<I, O, E> {
fn finish(self) -> Result<(I, O), E> {
match self {
Ok(res) => Ok(res),
Err(Err::Error(e)) | Err(Err::Failure(e)) => Err(e),
Err(Err::Incomplete(_)) => {
panic!("Cannot call `finish()` on `Err(Err::Incomplete(_))`: this result means that the parser does not have enough data to decide, you should gather more data and try to reapply the parser instead")
}
}
}
}
}
/// Contains information on needed data if a parser returned `Incomplete`
@ -148,7 +148,7 @@ impl<T> Err<(T, ErrorKind)> {
}
#[cfg(feature = "alloc")]
use crate::lib::std::{vec::Vec, string::String, borrow::ToOwned};
use crate::lib::std::{borrow::ToOwned, string::String, vec::Vec};
#[cfg(feature = "alloc")]
impl Err<(&[u8], ErrorKind)> {
/// Obtaining ownership

View File

@ -512,6 +512,6 @@ mod str;
#[macro_use]
pub mod number;
#[cfg(feature="docsrs")]
#[cfg(feature = "docsrs")]
#[cfg_attr(docsrs, doc(include = "../doc/nom_recipes.md"))]
pub mod recipes{}
pub mod recipes {}

View File

@ -108,27 +108,25 @@ where
F: Parser<I, O, E>,
E: ParseError<I>,
{
move |mut i: I| {
match f.parse(i.clone()) {
Err(Err::Error(err)) => Err(Err::Error(E::append(i, ErrorKind::Many1, err))),
Err(e) => Err(e),
Ok((i1, o)) => {
let mut acc = crate::lib::std::vec::Vec::with_capacity(4);
acc.push(o);
i = i1;
move |mut i: I| match f.parse(i.clone()) {
Err(Err::Error(err)) => Err(Err::Error(E::append(i, ErrorKind::Many1, err))),
Err(e) => Err(e),
Ok((i1, o)) => {
let mut acc = crate::lib::std::vec::Vec::with_capacity(4);
acc.push(o);
i = i1;
loop {
match f.parse(i.clone()) {
Err(Err::Error(_)) => return Ok((i, acc)),
Err(e) => return Err(e),
Ok((i1, o)) => {
if i1 == i {
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1)));
}
i = i1;
acc.push(o);
loop {
match f.parse(i.clone()) {
Err(Err::Error(_)) => return Ok((i, acc)),
Err(e) => return Err(e),
Ok((i1, o)) => {
if i1 == i {
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1)));
}
i = i1;
acc.push(o);
}
}
}
@ -1007,7 +1005,10 @@ where
let length: usize = length.to_usize();
if let Some(needed) = length.checked_sub(i.input_len()).and_then(NonZeroUsize::new) {
if let Some(needed) = length
.checked_sub(i.input_len())
.and_then(NonZeroUsize::new)
{
Err(Err::Incomplete(Needed::Size(needed)))
} else {
Ok(i.take_split(length))
@ -1050,7 +1051,10 @@ where
let length: usize = length.to_usize();
if let Some(needed) = length.checked_sub(i.input_len()).and_then(NonZeroUsize::new) {
if let Some(needed) = length
.checked_sub(i.input_len())
.and_then(NonZeroUsize::new)
{
Err(Err::Incomplete(Needed::Size(needed)))
} else {
let (rest, i) = i.take_split(length);

View File

@ -6,10 +6,10 @@ mod macros;
pub mod str {
use crate::error::{ErrorKind, ParseError};
use crate::lib::regex::Regex;
use crate::traits::{InputLength, Slice};
use crate::{Err, IResult};
#[cfg(feature = "alloc")]
use crate::lib::std::vec::Vec;
use crate::traits::{InputLength, Slice};
use crate::{Err, IResult};
/// Compares the input with a regular expression and returns the
/// whole input if a match is found.
@ -58,7 +58,7 @@ pub mod str {
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpMatches))));
/// # }
/// ```
#[cfg(all(feature = "regexp", feature="alloc"))]
#[cfg(all(feature = "regexp", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "regexp", feature = "alloc"))))]
pub fn re_matches<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, Vec<&'a str>, E>
where
@ -129,7 +129,7 @@ pub mod str {
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpCapture))));
/// # }
/// ```
#[cfg(all(feature = "regexp", feature="alloc"))]
#[cfg(all(feature = "regexp", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "regexp", feature = "alloc"))))]
pub fn re_capture<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, Vec<&'a str>, E>
where
@ -170,7 +170,7 @@ pub mod str {
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpCapture))));
/// # }
/// ```
#[cfg(all(feature = "regexp", feature="alloc"))]
#[cfg(all(feature = "regexp", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "regexp", feature = "alloc"))))]
pub fn re_captures<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, Vec<Vec<&'a str>>, E>
where
@ -309,10 +309,10 @@ pub mod str {
pub mod bytes {
use crate::error::{ErrorKind, ParseError};
use crate::lib::regex::bytes::Regex;
use crate::traits::{InputLength, Slice};
use crate::{Err, IResult};
#[cfg(feature = "alloc")]
use crate::lib::std::vec::Vec;
use crate::traits::{InputLength, Slice};
use crate::{Err, IResult};
/// Compares the input with a regular expression and returns the
/// whole input if a match is found.
@ -360,7 +360,7 @@ pub mod bytes {
/// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpMatches))));
/// # }
/// ```
#[cfg(all(feature = "regexp", feature="alloc"))]
#[cfg(all(feature = "regexp", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "regexp", feature = "alloc"))))]
pub fn re_matches<'a, E>(re: Regex) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<&'a [u8]>, E>
where
@ -430,7 +430,7 @@ pub mod bytes {
/// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpCapture))));
/// # }
/// ```
#[cfg(all(feature = "regexp", feature="alloc"))]
#[cfg(all(feature = "regexp", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "regexp", feature = "alloc"))))]
pub fn re_capture<'a, E>(re: Regex) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<&'a [u8]>, E>
where
@ -471,7 +471,7 @@ pub mod bytes {
/// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpCapture))));
/// # }
/// ```
#[cfg(all(feature = "regexp", feature="alloc"))]
#[cfg(all(feature = "regexp", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "regexp", feature = "alloc"))))]
pub fn re_captures<'a, E>(
re: Regex,

View File

@ -1592,13 +1592,19 @@ impl<I> ErrorConvert<((I, usize), ErrorKind)> for (I, ErrorKind) {
use crate::error;
impl<I> ErrorConvert<error::Error<I>> for error::Error<(I, usize)> {
fn convert(self) -> error::Error<I> {
error::Error { input: self.input.0, code: self.code }
error::Error {
input: self.input.0,
code: self.code,
}
}
}
impl<I> ErrorConvert<error::Error<(I, usize)>> for error::Error<I> {
fn convert(self) -> error::Error<(I, usize)> {
error::Error { input: (self.input, 0), code: self.code }
error::Error {
input: (self.input, 0),
code: self.code,
}
}
}

View File

@ -299,8 +299,10 @@ fn issue_848_overflow_incomplete_bits_to_bytes() {
#[test]
fn issue_942() {
use nom::error::{ParseError, ContextError};
pub fn parser<'a, E: ParseError<&'a str>+ContextError<&'a str>>(i: &'a str) -> IResult<&'a str, usize, E> {
use nom::error::{ContextError, ParseError};
pub fn parser<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
i: &'a str,
) -> IResult<&'a str, usize, E> {
use nom::{character::complete::char, error::context, multi::many0_count};
many0_count(context("char_a", char('a')))(i)
}

View File

@ -226,14 +226,8 @@ fn json_whitespace() {
.collect()
)
),
(
"empty_array".to_string(),
Array(vec![]),
),
(
"empty_object".to_string(),
Object(HashMap::new()),
),
("empty_array".to_string(), Array(vec![]),),
("empty_object".to_string(), Object(HashMap::new()),),
]
.into_iter()
.collect()