Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of higher order parser generating functions. #66

Closed
nejucomo opened this issue Aug 30, 2016 · 4 comments
Closed

Example of higher order parser generating functions. #66

nejucomo opened this issue Aug 30, 2016 · 4 comments

Comments

@nejucomo
Copy link

nejucomo commented Aug 30, 2016

I'm having trouble implementing higher order functions that create parsers. My latest attempt looks like this:

pub fn keyword(kw: &'static str) -> Box<Fn(&str) -> ParseResult<(), &str>>
{
    use combine::{ParserExt, string, value};

    assert!(KEYWORDS.contains(&kw));

    Box::new(|input| {
        string(kw)
            .with(value(()))
            .parse_state(input)
    })
}

Later I want to compose keyword in different ways. Here's an attempted use in a unit test:

parser(keyword("let")).skip(eof()).parse(test_case)

Variations on the types I've tried include:

  • dropping Box<…> from the return value of keyword - Sized is not satisfied.
  • dereferencing the result of keyword("let") - Sized is not satisfied.

How can I make this work?

Note: if there's a better way to implement keyword itself, that's of secondary interest. My primary interest is to learn how to create higher order parser generators.

@nejucomo
Copy link
Author

Ah, I used to be generic over the stream type, but elsewhere I followed an example for the then docs that had this snippet:

// Force input to be a &str
let _: &str = input;

This is with 2.0.0-beta.

@Marwes
Copy link
Owner

Marwes commented Aug 30, 2016

It appears that Parser is only implemented for FnMut not Fn which I believe is why that does not just work. That being said it is not really needed (at least in this case), an easier way of writing that would be.

// Fn -> Parser
pub fn keyword(kw: &'static str) -> Box<Parser<Input = &str, Output = ()>
{
    use combine::{ParserExt, string, value};

    assert!(KEYWORDS.contains(&kw));

// Remove the closure
    Box::new(string(kw)
            .with(value(())))
}

Just be aware that boxing incurs a runtime cost (allocation + indirection) so if you want the best performance you should avoid it as much as possible (once rust-lang/rust#35091 becomes stable creating higher order parsers should be much more convenient as well!).

@nejucomo
Copy link
Author

Thanks, this indeed fixes all type errors. This is my first use of a trait object.

@Marwes
Copy link
Owner

Marwes commented Aug 30, 2016

Happy to be of help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants