I use the alt
function of nom
to build a parser for bot commands, namely parse_command
in the example.
# src/main.rs
use nom::{
IResult,
bytes::complete::{tag},
branch::alt,
combinator::map,
};
#[derive(Debug, PartialEq)]
pub enum Command {
Foo(),
Bar(),
}
pub fn parse_command(input: &str) -> IResult<&str, Command> {
alt((
parse_foo,
parse_bar,
))(input)
}
fn parse_foo(input: &str) -> IResult<&str, Command> {
map(tag("!bar"), |_| Command::Bar())(input)
}
fn parse_bar(input: &str) -> IResult<&str, Command> {
map(tag("!foo"), |_| Command::Foo())(input)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_bar() {
let s = "!bar";
let (_, result) = parse_command(s).unwrap();
assert_eq!(result, Command::Bar());
}
#[test]
fn test_parse_foo() {
let s = "!foo";
let (_, result) = parse_command(s).unwrap();
assert_eq!(result, Command::Foo());
}
}
This works fine. However, reading examples, I was under the impression that I could update the signature of the parse_bar
and parse_foo
functions like so:
use nom::{
Parser,
error::Error,
};
fn parse_foo<'a>() -> impl Parser<&'a str, Command, Error<&'a str>> {
map(tag("!bar"), |_| Command::Bar())
}
fn parse_bar<'a>() -> impl Parser<&'a str, Command, Error<&'a str>> {
map(tag("!foo"), |_| Command::Foo())
}
But then, the compiler screams at me:
error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
--> src/main.rs:18:9
|
17 | alt((
| --- required by a bound introduced by this call
18 | parse_foo,
| ^^^^^^^^^ expected function that takes 1 argument
...
24 | fn parse_foo<'a>() -> impl Parser<&'a str, Command, Error<&'a str>> {
| ------------------------------------------------------------------- takes 0 arguments
|
= note: required for `fn() -> impl Parser<&str, Command, nom::error::Error<&str>> {parse_foo::<'_>}` to implement `Parser<_, _, _>`
= note: required for `(fn() -> impl Parser<&str, Command, nom::error::Error<&str>> {parse_foo::<'_>}, fn() -> impl Parser<&str, Command, nom::error::Error<&str>> {parse_bar::<'_>})` to implement `nom::branch::Alt<_, _, _>`
note: required by a bound in `alt`
--> /home/pamplemousse/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nom-7.1.3/src/branch/mod.rs:47:49
|
47 | pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>(
| ^^^^^^^^^^^^ required by this bound in `alt`
[... and same error for `parse_bar`...]
Are my expectations about using the Parser
trait to implement such functions wrong? If not, what am I missing/misunderstanding so that my updated code works?
Your second example, where it fails, doesn't show the call to parse_command
. If it is exactly the same as the first call which works, then the problem is that you are not calling the functions to return the actual Parser
implementations, and instead you are passing fn
's where it expects Parser
impls.
So the fix should be:
pub fn parse_command(input: &str) -> IResult<&str, Command> {
alt((
parse_foo(),
parse_bar(),
))(input)
}
To be clear, the difference is parse_foo()
vs parse_foo
, similarly for parse_bar
.