rustmacros

How to separate last expression in repeated expressions in a Rust macro?


I'd like to have this macro:

macro_rules! macro1 {
    ($f1:expr, $($f2:expr),+, $f3:expr) => {
        $f1(|a| {
            $(
                $f2(a, |b| {
                    $f3(a, b);
                });
            )*
        });
    }
}

This, however, errors with local ambiguity when calling macro macro1: multiple parsing options: built-in NTs expr ('f3') or expr ('f2').. I can resolve this error if I replace the last , in the macro rule with a ; instead so it clearly separates the repeated f2 and the last f3, but I'd like to keep the comma if possible to resemble a function. I can also swap f2 and f3, but in my code f2 tends to be very short and f3 will be quite long, so I'd like to also keep this order if possible.

Is there another way to write this macro to achieve this effect?


Solution

  • Only with the very powerful but hard to understand TT munching:

    macro_rules! macro1 {
        ($f1:expr, $($f2_and_3:expr),+) => {
            macro1! { @transpose $f1, [ ] $($f2_and_3),+ }
        };
        (@transpose $f1:expr, [ $($f2_parsed:expr,)* ] $f2:expr, $($f2_rest_and_3:expr),+ ) => {
            macro1! { @transpose $f1, [ $($f2_parsed,)* $f2, ] $($f2_rest_and_3),+ }
        };
        (@transpose $f1:expr, [ $($f2:expr,)+ ] $f3:expr ) => {
            $f1(|a| {
                $(
                    $f2(a, |b| {
                        $f3(a, b);
                    });
                )*
            });
        }
    }