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

Recursively defining nom 5 combinators #1044

Closed
zakcutner opened this issue Oct 10, 2019 · 2 comments
Closed

Recursively defining nom 5 combinators #1044

zakcutner opened this issue Oct 10, 2019 · 2 comments

Comments

@zakcutner
Copy link

Hello! I am trying to create a nom 5 style combinator in order to parse an arbitrary number of brackets from a string (e.g. "(((abc)))" => "abc"). I have a working implementation like so...

pub fn brackets<I, O, E, F>(f: F) -> impl Fn(I) -> IResult<I, O, E>
where
    I: Slice<RangeFrom<usize>> + InputIter + Clone + PartialEq,
    <I as InputIter>::Item: AsChar,
    E: ParseError<I>,
    F: Fn(I) -> IResult<I, O, E>,
{
    move |input: I| {
        let (input, brackets) = many1_count(char('('))(input)?;
        let (input, output) = f(input)?;
        let (input, _) = count(char(')'), brackets)(input)?;
        Ok((input, output))
    }
}

...however when I attempt to use the terminated() combinator within my generated closure like so...

pub fn brackets<I, O, E, F>(f: F) -> impl Fn(I) -> IResult<I, O, E>
where
    I: Slice<RangeFrom<usize>> + InputIter + Clone + PartialEq,
    <I as InputIter>::Item: AsChar,
    E: ParseError<I>,
    F: Fn(I) -> IResult<I, O, E>,
{
    move |input: I| {
        let (input, brackets) = many1_count(char('('))(input)?;
        terminated(f, count(char(')'), brackets))(input)
    }
}

...the compiler won't allow it because it cannot move out of 'f', a captured variable in an 'Fn' closure. Essentially, for this to work the Fns would have to be replaced with FnOnces (which is not what nom uses), see this question.

The first method works and is acceptable but this has got me thinking about whether it is possible to use existing combinators within new ones like this? I assume this would have worked quite differently with the nom 4 macro-based approach but nonetheless seems like an important feature.

Sorry if I am being stupid, any pointers in the right direction would be much appreciated!

@zakcutner zakcutner changed the title Creating nom 5 brackets combinator Recursively defining nom 5 combinators Oct 11, 2019
@zakcutner
Copy link
Author

So I figured out a possible solution to this issue; the bounds on F can be changed to make it implement the Copy trait like this...

F: Fn(I) -> IResult<I, O, E> + Copy

However, I am unsure whether this will result in inefficiencies (compared to my original solution) due to unnecessary copying at runtime. Perhaps someone would be able to help clarify this for me?

@omerbenamram
Copy link

@zakcutner The bound is on F being Copy, which means you are only copying the closure, which isn't costly (in comparison to having I being Copy).

Read about it here:
rust-lang/rust#44490

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