admin管理员组

文章数量:1353453

I'd like to write a nom parser combinator that takes a generic parser inner, builds two different variants of it using combinators that already exist in nom, and then tries them in say an alt combinator. Conceptually, I'd like to do

alt((some_existing_combinator(inner), some_other_existing_combinator(inner)))

Of course, this doesn't work, because inner isn't in general of a type that is Copy (or even Clone). From my understanding, no parser built from nom combinators is Copy or Clone. Thus, I'm clearly barking up the wrong tree here. How does one typically approach this kind of problem?

I'd like to write a nom parser combinator that takes a generic parser inner, builds two different variants of it using combinators that already exist in nom, and then tries them in say an alt combinator. Conceptually, I'd like to do

alt((some_existing_combinator(inner), some_other_existing_combinator(inner)))

Of course, this doesn't work, because inner isn't in general of a type that is Copy (or even Clone). From my understanding, no parser built from nom combinators is Copy or Clone. Thus, I'm clearly barking up the wrong tree here. How does one typically approach this kind of problem?

Share Improve this question edited Apr 1 at 9:30 cafce25 27.9k5 gold badges45 silver badges58 bronze badges asked Apr 1 at 9:28 gsprgspr 11.2k4 gold badges44 silver badges80 bronze badges 2
  • Most combinators are Clone if their arguments are, or are even Copy if they're a plain old function (because all functions are Copy). Why isn't your inner: Clone? – BallpointBen Commented Apr 1 at 10:57
  • @BallpointBen: I'm struggling a bit to resolve what traits a combinator's return value implements, since it's not an nameable type. If my inner is delimited(multispace0, parser, multispace0), and parser is in turn made up from tuple, map, tag and some number parsers included with nom, then the compiler complains that inner is not Clone. But again, with functions not quite being first class types, I'm having a bit of an issue resolving that types I actually have. Do you have any hints for me? – gspr Commented Apr 1 at 11:06
Add a comment  | 

1 Answer 1

Reset to default 1

You basically have two options: wrap the whole delimited thing in its own parsing function, which is Copy; or create a zero-arg closure (or function) that creates one-off delimited parsers each time you need one. The toy example below compiles.

use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{digit1, multispace0},
    combinator::map_res,
    multi::{many0, many1},
    sequence::delimited,
    IResult, Parser,
};

fn parser(s: &str) -> IResult<&str, i32> {
    map_res((tag("num="), digit1), |(_, n): (_, &str)| n.parse::<i32>())
        .parse(s)
}

// a fn, therefore Copy
fn my_delimited(s: &str) -> IResult<&str, i32> {
    delimited(multispace0, parser, multispace0).parse(s)
}

fn main() {
    // makes a fresh parser each time it's called
    let make_inner = || delimited(multispace0, parser, multispace0);

    let parser_1 = alt((many0(my_delimited), many1(my_delimited)));
    let parser_2 = alt((many0(make_inner()), many1(make_inner())));
}

本文标签: