How to select a parser and reuse it later in nom?

I am using nom to parse hour/minute/second time formats such as 16:45:38. I want to be able to parse various different formats, for example: 16 should be recognized as 16:00:00, 16:45 as 16:45:00 and I also want to support 16 45 38 to be recognized.
This is the nom parser I use to achieve this:

    named!(parse(&'a str) -> Self,
    map!(
        tuple!(
            Units::parse,
            opt!(
                complete!(
                    alt!(
                        tuple!(
                            preceded!(
                                tag!(":"),
                                Units::parse
                            ),
                            opt!(
                                complete!(
                                    preceded!(
                                        tag!(":"),
                                        Units::parse
                                    )
                                )
                            )
                        ) // tuple!
                        |
                        tuple!(
                            preceded!(
                                space1,
                                Units::parse
                            ),
                            opt!(
                                complete!(
                                    preceded!(
                                        space1,
                                        Units::parse
                                    )
                                )
                            )
                        ) // tuple!
                    ) // alt!
                ) // complete!
            ) // opt!
        ), // tuple!
        |(h, tail)| {
            let (m, s) =
                tail
                .map(|(minutes, osec)| (minutes, osec.unwrap_or(0)))
                .unwrap_or((0, 0));
            NaiveTime::from_hms(h as u32, m as u32, s as u32)
        }) // map!
    );

However I have a lot of code duplication because I have to alternate between the space1 and tag!(":") parsers, but can't just alternate at each separator, because that would cause 16:45 38 or 16 45:38 to be accepted aswell, which I don't want.

I need something like a variable for a parser that I can set once, or a function that takes a parser as an argument. How would you solve this with nom?

You could write your own macro that takes as input either space1 or tag!(":") and outputs the tuple!(…) with the inserted input at the 2 places.

I had already thought it would be useful to have a separated_tuple macro, which would allow to set a separator for a fixed number of elements. There is separate_list, but this will accept any number of elements.

But when looking at the definitions of tuple and separated_pair I just get confused...

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.