0

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?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
lolad
  • 321
  • 6
  • 13

1 Answers1

5

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:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    Thanks, in that case is there a way to expand it before? I want to parse some of the elements of the array manually. – lolad Dec 08 '20 at 18:05
  • 1
    @lolad there's no "more eager" expansion, no. Perhaps reflowing your code such that `parse_rule` calls `foo` / `bar` would work, or baking that logic directly into `parse_rule`. Internal rules are quite common for this ([What does an @ symbol mean in a Rust declarative macro?](https://stackoverflow.com/q/54406388/155423)). – Shepmaster Dec 08 '20 at 18:12