lolad
lolad

Reputation: 321

Why does a macro call inside another macro not expand, but instead I get "no rules expected the token `!`"?

I'm calling a macro within a macro, i.e

macro_rules! foo {
    (yes) => {
        true
    };
    () => {
        false
    };
}

macro_rules! baz {
    () => {
        [(); 0]
    };
    ($args: tt) => {
        $args
    };
}

macro_rules! parse_rule {
    ($rule: tt, $args: tt, $newline: expr) => {
        println!("The rule is {}, with args {:?}", $rule, $args);
        if $newline {
            println!()
        }
    };
}

macro_rules! bar {
    ($($rule: tt  $([$($args: tt),*])? $($flag: ident)?);+) => {
        $(parse_rule!($rule, baz!($([$($args),*])?), foo!($($flag)?)));+
    }
}

fn main() {
    bar!("hi" yes; "there" ["are", "some", "args"]; "no" yes);
}

The compiler complains about me calling baz within the parse_rule invocation:

error: no rules expected the token `!`
  --> src/main.rs:30:33
   |
19 | macro_rules! parse_rule {
   | ----------------------- when calling this macro
...
30 |         $(parse_rule!($rule, baz!($([$($args),*])?), foo!($($flag)?)));+
   |                                 ^ no rules expected this token in macro call
...
35 |     bar!("hi" yes; "there" ["are", "some", "args"]; "no" yes);
   |     ---------------------------------------------------------- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

Why does it not expand?

Upvotes: 0

Views: 1722

Answers (1)

Shepmaster
Shepmaster

Reputation: 430524

Macros are are invoked with their unexpanded arguments. macro_call!(arg) is three token trees, not one:

macro_rules! example {
    ($($x:tt)+) => {
        $(eprintln!(">{}<", stringify!($x));)*
    }
}

fn main() {
    example!(macro_call!(arg));
}
>macro_call<
>!<
>(arg)<

Your macro only allows for a single token tree ($args: tt). That matches the macro's name, leaving the !. That isn't matched by anything, so you get your error.

You probably want $args: expr.

is there a way to expand it before? I want to parse some of the elements of the array manually

There's no "more eager" expansion, that I know of. It has been suggested in various RFCs (e.g. Eager Macro Expansion — 2320).

I'd suggest reflowing your code such that parse_rule calls foo / bar itself, or baking the logic of foo / bar directly into parse_rule. Internal rules are quite common for this.

See also:

Upvotes: 5

Related Questions