As an example I want to parse a string that can either be 2 dot-separated words or a single word. Each "word" is a combination of alphanumeric and underscore characters, so I write the word-parser as a closure. In either case I want the parser-function to return a pair of words with one of them potentially being an empty string. There might be a better solution for this specific problem, but I simply want to motivate my problem here.
Writing my parser with nom
I stumble upon the following problem: I cannot write my sub-parsers as closures (in order to re-use them), because the closures are moved if I use them multiple times in an alt
statement:
fn parse_dot_sep_words_or_word(i: &str) -> IResult<&str, (&str, &str)> {
let word = recognize(many0(alt((alphanumeric1, tag("_")))));
let dot_sep_word = separated_pair(word, tag("."), word);
alt((
map(word, |single_word| ("", single_word)),
map(dot_sep_word, |(a,b)| (a,b))
))
(i)
}
This does not work as word
gets moved once it is used inside dot_sep_word
. Following the instructions of the compiler ("use &mut word") doesn't help either.
The only solution I can use is to write out what word
is defined as everytime word
is used. But this seems counterintuitive to the advantages nom offers.
What did I miss here? Is there a simple way this can be solved?
One option is to simply make word
a function instead of a closure.
fn word(i: &str) -> IResult<&str, &str> {
recognize(many0(alt((alphanumeric1, tag("_")))))(i)
}
fn parse_dot_sep_words_or_word(i: &str) -> IResult<&str, (&str, &str)> {
let dot_sep_word = separated_pair(word, tag("."), word);
alt((
map(word, |single_word| ("", single_word)),
map(dot_sep_word, |(a, b)| (a, b)),
))(i)
}