m4rw3r / chomp

A fast monadic-style parser combinator designed to work on stable Rust.
Apache License 2.0
243 stars 19 forks source link

what type of argument to supply for i.err()? #29

Closed dckc closed 8 years ago

dckc commented 8 years ago

What do I give as the argument?

I can't figure out what to use in place of 0:

fn expr(i: Input<u8>) -> U8Result<ExprRef> {
    or(i,
       literal(i),
       // TODO: all the other sorts of Expr
       i.err(0))  // <- here
}

I can't understand the diagnostics:

cargo test
   Compiling monte-rs v0.1.0 (file:///home/connolly/projects/monte-rs)
src/mast.rs:24:5: 24:7 error: the trait `core::ops::FnOnce<(chomp::input::Input<'_, u8>,)>` is not implemented for the type `chomp::parse_result::ParseResult<'_, u8, Box<alloc::rc::Rc<kernel::Expr>>, chomp::parsers::Error<u8>>` [E0277]
src/mast.rs:24     or(i,
                   ^~
src/mast.rs:24:5: 24:7 help: run `rustc --explain E0277` to see a detailed explanation
src/mast.rs:24:5: 24:7 note: required by `chomp::combinators::or`
src/mast.rs:24:5: 24:7 error: the trait `core::ops::FnOnce<(chomp::input::Input<'_, u8>,)>` is not implemented for the type `chomp::parse_result::ParseResult<'_, u8, _, _>` [E0277]
src/mast.rs:24     or(i,
                   ^~
src/mast.rs:24:5: 24:7 help: run `rustc --explain E0277` to see a detailed explanation
src/mast.rs:24:5: 24:7 note: required by `chomp::combinators::or`
src/mast.rs:24:5: 24:7 error: the trait `core::ops::FnOnce<(chomp::input::Input<'_, u8>,)>` is not implemented for the type `chomp::parse_result::ParseResult<'_, u8, Box<alloc::rc::Rc<kernel::Expr>>, chomp::parsers::Error<u8>>` [E0277]
src/mast.rs:24     or(i,
                   ^~
src/mast.rs:24:5: 24:7 help: run `rustc --explain E0277` to see a detailed explanation
src/mast.rs:24:5: 24:7 note: required by `chomp::combinators::or`
src/mast.rs:24:5: 24:7 error: the trait `core::ops::FnOnce<(chomp::input::Input<'_, u8>,)>` is not implemented for the type `chomp::parse_result::ParseResult<'_, u8, _, _>` [E0277]
src/mast.rs:24     or(i,
                   ^~
src/mast.rs:24:5: 24:7 help: run `rustc --explain E0277` to see a detailed explanation
src/mast.rs:24:5: 24:7 note: required by `chomp::combinators::or`
error: aborting due to 2 previous errors
m4rw3r commented 8 years ago

U8Result is an alias for ParseResult<u8, T, Error<u8>>. The error type used by U8Result is parsers::Error, use Error::new to create an "unexpected error" to return.

If that is not good enough (ie. you need something more verbose), declare your own error type and implement From<Error> for it:

enum MyError {
    ParseError(chomp::Error<u8>),
    ExpectedExpression,
    // ...
}

impl From<chomp::Error<u8>> for MyError {
    fn from(e: chomp::Error<u8>) -> Self {
        MyError::ParseError(e)
    }
}

bind (and therefore also then and usages of the parse! macro) will automatically convert it for you if you chain anything. If it is just a plain or combinator which has been stacked, use map_err(From::from) on the parse error(s).

dckc commented 8 years ago

I tried to use Error:new, but I couldn't get it to work. I'd appreciate an example.

Likewise map_err; it's not clear to me how that would work.

dckc commented 8 years ago

I think I get it now.

m4rw3r commented 8 years ago

Just to make it clear for anyone else reading this, it would be one of these:

fn expr(i: Input<u8>) -> U8Result<ExprRef> {
    or(i,
       |i literal(i),
       // TODO: all the other sorts of Expr
       |i| i.err(Error::new()))  // <- here
}

This would yield an unexpected error at the start of the attempt to match an expr. Another alternative is to just skip the error part completely, letting the last error from the last attempted parser bubble up. The downside with this is that it can look a bit odd when an error occurs further in than it really is.

enum MyError {
    ParseError(chomp::Error<u8>),
    ExpectedExpression,
    // ...
}

impl From<chomp::Error<u8>> for MyError {
    fn from(e: chomp::Error<u8>) -> Self {
        MyError::ParseError(e)
    }
}

fn expr(i: Input<u8>) -> ParseResult<u8, ExprRef, MyError> {
    // We use two backtracks here to be able to use From::from once:
    or(i,
        |i| or(i, literal,
        |i| or(i, constant,
        |i| or(i, operator, ...)))
            .map_err(From::from),
        |i| i.err(MyError::ExpectedExpression))
}

The code above has the benefit of being very flexible when it comes to the errors, it can store plain parse errors as well as just indicating that an expression was expected (this could then be extended so that all of those errors are more verbose, exactly what part failed in parsing an expression).