0

I am trying to match user-provided lists in a macro, but the repeat-pattern does not match the same branches depending on whether I call the macro on single items directly, or whether I call it from a repeat block.

Input code (playground link):

macro_rules! foo {
    ($a:ident) => { println!("Printing ident"); };
    ($b:literal) => { println!("Printing literal"); };
    ([ $($something:expr),+ $(,)? ]) => {
            println!("Printing repeat");
            $(
                foo!($something);
            )*
    };
    ($catch_all:expr) => { println!("Printing expr"); };
}


fn main() {
    foo!(baz);
    foo!([1, "asd"]);
    foo!([baz]);
}

Output:

Printing ident
Printing repeat
Printing literal
Printing literal
Printing repeat
Printing expr

The first line prints the "ident" line, the last one prints the "expr" line (the other one is just to show that what I want to do works, with literals, at least).

My problem with this behavior is that I also expect expr from the user, and now I cannot distinguish raw ident from expr.

To be more specific, I would like to be able to write foo!(["a literal", some_ident, complex_stuff!()]), where all three parameters are treated differently.

cafce25
  • 15,907
  • 4
  • 25
  • 31
lesurp
  • 343
  • 4
  • 19
  • BTW: the problem I have here can be avoided simply by using a [TT muncher](https://danielkeep.github.io/tlborm/book/pat-incremental-tt-munchers.html), and basically matching a concrete ident / literal / expr with a bunch of trailing tt, which we process recursively. This avoids the whole "casting" of the tokens, but forces me to copy-paste some of the code, as well create a recursion where a simple repeat pattern could suffice. – lesurp Mar 06 '23 at 15:30
  • Unless these are single tokens (in which case you can use `tt` as @cafce25 suggested), TT munching is your only option (except creating a proc macro). – Chayim Friedman Mar 07 '23 at 09:39

1 Answers1

0

To avoid forcing the type of a token you can match with the type tt:

macro_rules! foo {
    ($a:ident) => { println!("Printing ident"); };

    ($b:literal) => { println!("Printing literal"); };

    ([ $($something:tt),+ $(,)? ]) => {
            println!("Printing repeat");
            $(
                foo!($something);
            )*
    };

    ($catch_all:expr) => { println!("Printing expr"); };
}

Results in the following with your main.

Printing ident
Printing repeat
Printing literal
Printing literal
Printing repeat
Printing ident
cafce25
  • 15,907
  • 4
  • 25
  • 31