How to match entries of a vector with nom?

My question is quite simliar to where I want to parse some text that could be one of many options (possibly only known at runtime). Usually I could just use the alt combinator (for the ones known at compile time) but that does not have a 'dynamic' length option. In the question , I linked above contains an answer (but for nom 4 , I am using nom 7.1.3 ) , which goes like

/// Dynamic version of `alt` that takes a slice of strings
fn alternative<T>(input: T, alternatives: &[&'static str]) -> IResult<T, T>
where
    T: InputTake,
    T: Compare<&'static str>,
    T: InputLength,
    T: AtEof,
    T: Clone,
{
    let mut last_err = None;
    for alternative in alternatives {
        let inp = input.clone();
        match tag!(inp, &**alternative) {
            done @ Ok(..) => return done,
            err @ Err(..) => last_err = Some(err), // continue
        }
    }
    last_err.unwrap()
}

/// Usage
named!(test<Span, Span>,
    call!(alternative, &["a", "b", "c"])
);

However I am not really sure on how to convert this macro nom into the functional nom that I know. Any help is appreactiated !

I guess the macros are a red herring? They just show one way to run the parser. Your example code can be modified slightly so that it compiles under nom 7.x. I believe the resulting function is already a Parser in itself and I'm certain you don't have to call it using macros: Playground

use nom::{IResult, InputTake, InputLength, Compare, error::{Error, ErrorKind}};

fn alternative<T>(input: T, alternatives: &[&'static str]) -> IResult<T, T>
where
    T: Copy + InputLength + InputTake + Compare<&'static str>,
{
    let mut last_err = None;

    for &alt in alternatives {
        match nom::bytes::complete::tag(alt)(input) {
            Ok(result) => return Ok(result),
            Err(error) => {
                last_err = Some(error);
            }
        }
    }

    Err(last_err.unwrap_or(nom::Err::Error(Error { input, code: ErrorKind::NonEmpty })))
}

fn main() {
    assert_eq!(alternative("bar lol", ["foo", "bar", "qux"].as_slice()), Ok((" lol", "bar")));
}

Oh :sweat_smile: , thanks and yes the macros were the herring. I was sure macros were some black magic in that version of nom :joy:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.