Issues using macro rules macros and negative numbers

Ok so I stayed up all night trying to debug a macro_rules! macro I've been trying to make. I've come up with a MRE for my problem:

#[macro_export]
macro_rules! nums {
    () => {};

    ($x: expr $(,)?) => {
        dbg!($x)
    };
    
    ($x: expr, $($tail:tt),* $(,)?) => {
        dbg!($x);
        nums!( $($tail, )* );
    };
}

fn main() {
    nums!(-3.2, 2.5);
    nums!(6.2, -0.2, 2.3);
    nums!(6.2, 0.2, -2.3);
    nums!(-2.3, -2.4);
}

Compile error:

   Compiling playground v0.0.1 (/playground)
error: no rules expected the token `0.2`
  --> src/main.rs:17:17
   |
2  | macro_rules! nums {
   | ----------------- when calling this macro
...
17 |     nums!(6.2, -0.2, 2.3);
   |                 ^^^ no rules expected this token in macro call

error: no rules expected the token `2.3`
  --> src/main.rs:18:22
   |
2  | macro_rules! nums {
   | ----------------- when calling this macro
...
18 |     nums!(6.2, 0.2, -2.3);
   |                      ^^^ no rules expected this token in macro call

error: no rules expected the token `2.4`
  --> src/main.rs:19:18
   |
2  | macro_rules! nums {
   | ----------------- when calling this macro
...
19 |     nums!(-2.3, -2.4);
   |                  ^^^ no rules expected this token in macro call

error: could not compile `playground` due to 3 previous errors

The macro fails to compile if you use negative numbers, but it'll work if the only negative number is the first argument...?? I am going insane.

Help would be appreciated!! Thanks in advance!

In the third rule, change tt to expr. A "-" is parsed as a separate token (token tree), so the matcher will immediately expect a comma to follow it.

2 Likes

Alternatively, don't use comma-delimited repetition for your tail:

macro_rules! nums {
    () => {};

    ($x: expr $(,)?) => {
        dbg!($x)
    };
    
    ($x: expr, $($tail:tt)*) => {
        dbg!($x);
        nums!( $($tail)* );
    };
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.