Marwes / combine

A parser combinator library for Rust
https://docs.rs/combine/*/combine/
MIT License
1.3k stars 94 forks source link

Help with reporting non-parsing errors. #319

Closed rneswold closed 3 years ago

rneswold commented 3 years ago

I've been having good, initial success using combine but I've reached a point where I need to report an error if an integer field is out of range. The function is

fn parse_u32<Input>() -> impl Parser<Input, Output = u32>
where
    Input: Stream<Token = char>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position>
{
    repeat::many1(char::digit()).and_then(|v: String| v.parse::<u32>())
}

This generates errors since ParseIntError can't be converted to a StreamError. I try some of the recommendations offered by the compiler but those also return errors. The project's Wiki page mentions ways of reporting errors, but it seems to be out-of-date since it mentions StreamErrorFor::<> which I couldn't find in the docs.

Am I trying too hard? Is there a straightforward way of reporting errors that I'm missing?

Can the Wiki be brought up to date?

rneswold commented 3 years ago

I found StreamErrorFor. Doing some investigating ...

rneswold commented 3 years ago

Sorry for the noise. The Wiki example makes the code compile.

gcoakes commented 2 years ago

For anyone who comes across this and doesn't quite understand StreamErrorFor (like I didn't)... It's essentially a type alias to help name an error which should satisfy some traits. It looks like you use it like this:

fn cc<I>() -> impl Parser<I, Output = PacketType>
where
    I: Stream<Token = char>,
    I::Error: ParseError<I::Token, I::Range, I::Position>,
    StreamErrorFor<I>: From<UnexpectedParse>,
{
    digit().and_then(|cc| PacketType::try_from(cc).map_err(|_| UnexpectedParse::Unexpected))
}

As opposed to what the compiler tells you to do:

fn cc<I>() -> impl Parser<I, Output = PacketType>
where
    I: Stream<Token = char>,
    I::Error: ParseError<I::Token, I::Range, I::Position>,
-   StreamErrorFor<I>: From<UnexpectedParse>,
+   <<I as StreamOnce>::Error as ParseError<
+       char,
+       <I as StreamOnce>::Range,
+       <I as StreamOnce>::Position,
+   >>::StreamError: From<UnexpectedParse>,
{
    digit().and_then(|cc| PacketType::try_from(cc).map_err(|_| UnexpectedParse::Unexpected))
}