2016-06-10 3 views
8

Sto giocando con i macro in Rust e voglio fare l'espansione nidificata, cioè combinatoria.iterazione annidata in macro Rust

Questo è il codice che ho scritto:

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

Voglio che questo per espandere a

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); 
} 

Tuttavia, sembra che la ruggine non supporta questo e si lamenta invece:

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

Quindi apparentemente ignora l'iterazione interna.

Tuttavia, se tolgo uno dei args, per renderlo 2 elementi per entrambi, si lamenta ancora:

<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),*); 

C'è un modo per fare quello che voglio?

risposta

6

Sembra che non sia possibile eseguire questo tipo di espansione. Ecco una soluzione:

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),*); 
    }; 
} 

Il @id viene utilizzato solo per mantenere le regole internal alla macro.