Nested Iteration in Rust Macros

I play with macros in Rust and want to do a nested extension, i.e. combinatorics.

This is the code I wrote:

macro_rules! nested { ( $(arg $arg:ident;)* $(fun $fun:ident;)* ) => { $( $fun($($arg),*); )* } } fn show1(a: i32, b: i32, c: i32) { println!("show1: {} {} {}", a, b, c); } fn show2(a: i32, b: i32, c: i32) { println!("show2: {} {} {}", a, b, c); } fn main() { let a = 1; let b = 2; let c = 3; nested! { arg a; arg b; arg c; fun show1; fun show2; } } 

Playground

I want it to expand to

 fn main() { let a = 1; let b = 2; let c = 3; // iteration over $fun show1(/* iteration over $arg */a, b, c); show2(/* iteration over $arg */a, b, c); } 

However, it seems that Rust does not support this and instead complains:

 error: inconsistent lockstep iteration: 'fun' has 2 items, but 'arg' has 3 

Thus, it is obvious that it ignores the internal iteration.

However, if I remove one of the arguments to make it 2 elements for both, it still complains:

 <anon>:7:18: 7:25 error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth <anon>:7 $fun($($arg),*); 

Is there a way to do what I want?

+8
rust
source share
1 answer

It seems that such an extension is not possible. Here is a workaround:

 macro_rules! nested { ($(arg $arg:ident;)* $(fun $fun:ident;)*) => { // expand arg to a tuple that will be matched as tt // in @call_tuple an will be decomposed back to // a list of args in @call nested!(@call_tuple $($fun),* @ ($($arg),*)) }; (@call_tuple $($fun:ident),* @ $tuple:tt) => { $(nested!(@call $fun $tuple))* }; (@call $fun:ident ($($arg:expr),*)) => { $fun($($arg),*); }; } 

@id used only to save internal rules for macros.

+6
source share

All Articles