1

I've been trying to use Rust macros but I'm hitting a stumbling block with token trees, I'm given to understand a token tree will accept any valid sequence of tokens, grouping them into a hierarchy based on paired (), [], {}.

When I try to pass in any sequence of tokens, I get parse errors that reject the 2nd token in the sequence.

#![feature(trace_macros)]
#![allow(dead_code)]

macro_rules! repro {
    ($foo:tt) => {
        stringify!($foo);
    };
}

fn main() {
    trace_macros!(true);
    // println!("{}", repro!(bar)); works

    //these break, but succeed for meta type expr
    println!("{}", repro!(bar: fizz));
    println!("{}", repro!(1 + 2));
    trace_macros!(false);
}

In the above code, the ':' and '+' tokens trigger failures:

error: no rules expected the token `:`
  --> src/main.rs:15:30
   |
4  | macro_rules! repro {
   | ------------------ when calling this macro
...
15 |     println!("{}", repro!(bar: fizz));
   |                              ^ no rules expected this token in macro call

note: trace_macro
  --> src/main.rs:15:5
   |
15 |     println!("{}", repro!(bar: fizz));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: expanding `println! { "{}" , repro ! (bar : fizz) }`
   = note: to `{ $crate :: io :: _print (format_args_nl ! ("{}" , repro ! (bar : fizz))) ; }`

note: trace_macro
  --> src/main.rs:15:20
   |
15 |     println!("{}", repro!(bar: fizz));
   |                    ^^^^^^^^^^^^^^^^^
   |
   = note: expanding `repro! { bar : fizz }`

error: no rules expected the token `+`
  --> src/main.rs:16:29
   |
4  | macro_rules! repro {
   | ------------------ when calling this macro
...
16 |     println!("{}", repro!(1 + 2));
   |                             ^ no rules expected this token in macro call

note: trace_macro
  --> src/main.rs:16:20
   |
16 |     println!("{}", repro!(1 + 2));
   |                    ^^^^^^^^^^^^^
   |
   = note: expanding `repro! { 1 + 2 }`

note: trace_macro
  --> src/main.rs:16:5
   |
16 |     println!("{}", repro!(1 + 2));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: expanding `println! { "{}" , repro ! (1 + 2) }`
   = note: to `{ $crate :: io :: _print (format_args_nl ! ("{}" , repro ! (1 + 2))) ; }`

I would expect that bar: fizz maps to ['bar', ':', 'fizz'] and 1 + 2 maps to ['1', '+', '2']

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
mamidon
  • 895
  • 1
  • 10
  • 25
  • [The duplicate applied to your question](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=f6e0a66f3403266610cc6156d60c1fdb). – Shepmaster Aug 13 '19 at 16:18
  • Yes, I've found that before -- it doesn't answer my question! – mamidon Aug 13 '19 at 16:37
  • That particular answer claims that token trees match 'anything', which jives with the documentation that I've read. But what I'm feeding in seems like it should match -- it's a stream of tokens, yet that isn't the case here. – mamidon Aug 13 '19 at 16:38
  • Marking my question as a duplicate isn't helpful! – mamidon Aug 13 '19 at 16:38
  • 1
    The answer was recently rephrased to more clearly address your specific problem. With my emphasis added: *`tt` will match **any single token** or any pair of parenthesis/brackets/braces and their content*. Also, at the end of the answer, you can see *`$($arg:tt)*` means “all the rest”*; you need the repetition operator to capture your sequential `tt`s. – Shepmaster Aug 13 '19 at 16:39

0 Answers0