Search code examples
rustrust-macros

"no rules expected the token" when using macro to implement methods


I previously used C/C++ and recently started using Rust. I'm experiencing difficulties on writing simple macro_rules! to automatically implement some helper methods.

Originally, I had Scanner struct, which scans data from stdio and converts them into a given type.

struct Scanner {
    buffer: Vec<String>
}

impl Scanner {
    fn next<T: std::str::FromStr>(&mut self) -> T { /* tldr */ }
}

After that, I tried to implement a helper macro to implement two methods which return T and Vec<T> respectively.

// It doesn't work 😢
macro_rules! scanner_shortcut {
    ($scan_type:ident, $single_scan_ident:ident, &multi_scan_ident:ident) => {
        impl Scanner {
            fn $single_scan_ident(&mut self) -> $scan_type {
                self.next()
            }
            fn $multi_scan_ident(&mut self, n: usize) -> Vec<$scan_type> {
                (0..n).map(|_| self.next()).collect()
            }
        }
    };
}

scanner_shortcut!(i32, scan_i32, scan_i32s);
scanner_shortcut!(i64, scan_i64, scan_i64s);

However, I got the following error message: no rules expected this token in macro call

error: no rules expected the token `scan_i32s`
  --> src/bin/playground.rs:36:34
   |
23 | macro_rules! scanner_shortcut {
   | ----------------------------- when calling this macro
...
36 | scanner_shortcut!(i32, scan_i32, scan_i32s);
   |                                  ^^^^^^^^^ no rules expected this token in macro call

error: no rules expected the token `scan_i64s`
  --> src/bin/playground.rs:37:34
   |
23 | macro_rules! scanner_shortcut {
   | ----------------------------- when calling this macro
...
37 | scanner_shortcut!(i64, scan_i64, scan_i64s);
   |                                  ^^^^^^^^^ no rules expected this token in macro call

I struggled to get rid of this problem, and I found that when I remove &multi_scan_ident:ident and the corresponding method declaration, it works well!

// It works well...  🧐
macro_rules! scanner_shortcut {
    ($scan_type:ident, $single_scan_ident:ident) => {
        impl Scanner {
            fn $single_scan_ident(&mut self) -> $scan_type {
                self.next()
            }
        }
    };
}

scanner_shortcut!(i32, scan_i32);
scanner_shortcut!(i64, scan_i64);

I guess the first code has some syntactic problems with the macro definition because the second version works well, but I couldn't figure out the exact reason. What makes this difference?

Any help will be appreciated!


Solution

  • You have a syntax error:

    &multi_scan_ident:ident
    

    This should be:

    $multi_scan_ident:ident