Jeremy Meadows
Jeremy Meadows

Reputation: 2561

repeat a group of tokens in a macro

I'm trying to create a macro-based finite state machine, and I'm having issues figuring out how to get my repeating pattern to capture multiple lines of tokens. I've tried moving the repetition block around and changing the delimiters between lines, but that didn't seem to get me closer. I couldn't find examples of using multiple tokens in a single repeat pattern, so I'm guessing I am breaking some sort of rule there which I couldn't find...

macro_rules! build_machine {
    ($($state_a:tt : $activity:tt -> $state_b:tt),* $(,)*) => {
        #[derive(Debug)]
        enum State { $( $state_a, $state_b )* }

        #[derive(Debug)]
        enum Activity { $( $activity )* }
    }
}

build_machine!(
    Locked : TurnKey -> Unlocked,
    //Stopped : Push -> Moving,
);

fn main() {
    println!(
        "{:?} + {:?} -> {:?}",
        State::Locked,
        Activity::TurnKey,
        State::Unlocked,
    );
    // println!(
    //     "{:?} + {:?} -> {:?}",
    //     State::Stopped,
    //     Activity::Push,
    //     State::Moving,
    // );
}

It works as expected like this, but adding in the commented lines gives a weird error complaining about the missing comma at the comma:

error: expected one of `(`, `,`, `=`, `{`, or `}`, found `Stopped`
  --> src/main.rs:13:5
   |
12 |     Locked : TurnKey -> Unlocked,
   |                                 -
   |                                 |
   |                                 expected one of `(`, `,`, `=`, `{`, or `}`
   |                                 help: missing `,`
13 |     Stopped : Push -> Moving,
   |     ^^^^^^^ unexpected token

I'm new to macros, but I think using a macro_rules is a better fit than using a proc_macro. However, I'm fine switching if that's not the case.

Upvotes: 0

Views: 2536

Answers (1)

Dogbert
Dogbert

Reputation: 222168

You're missing commas in the generated code:

#[derive(Debug)]
enum State { $( $state_a, $state_b, )* }
//                                ^ this

#[derive(Debug)]
enum Activity { $( $activity, )* }
//                          ^ and this

Without those your macro is generating invalid code if the outer macro has more than one repetition.

Playground

Upvotes: 1

Related Questions