2015-07-02 31 views
7

擺脫逗號我想編寫一個宏這使我轉變 (a, b, c, d)(a, a + b, a + b + c, a + b + c + d),等等。這是我到目前爲止有:宏輸出

macro_rules! pascal_next { 
    ($x: expr) => ($x); 
    ($x: expr, $y: expr) => (
     ($x, $x + $y) 
    ); 
    ($x: expr, $y: expr, $($rest: expr),+) => (
     ($x, pascal_next!(
       $x + $y, $($rest),+ 
      ) 
     ) 
    ); 
} 

然而,有一個問題,即它會實際輸出(a,(a + b,(a + b + c,a + b + c + d)))。原點是第二個匹配規則($x: expr, $y: expr) => (($x, $x + $y));,生成一個額外的括號,這樣就會有嵌套的括號。如果我不把支架外,我會得到錯誤錯誤:

unexpected token: ,

那麼,它可以輸出一個逗號,魯斯特宏?

回答

10

否;宏必須的結果是像表達式或項目一樣的完整語法結構。 絕對不能具有像逗號或右大括號這樣的語法隨機位。

你可以通過簡單地輸出任何東西來解決這個問題,直到你有完整的最終表達式。看哪!

#![feature(trace_macros)] 

macro_rules! pascal_impl { 
    /* 
    The input to this macro takes the following form: 

    ```ignore 
    (
     // The current output accumulator. 
     ($($out:tt)*); 

     // The current additive prefix. 
     $prefix:expr; 

     // The remaining, comma-terminated elements. 
     ... 
    ) 
    ``` 
    */ 

    /* 
    Termination condition: there is no input left. As 
    such, dump the output. 
    */ 
    (
     $out:expr; 
     $_prefix:expr; 
    ) => { 
     $out 
    }; 

    /* 
    Otherwise, we have more to scrape! 
    */ 
    (
     ($($out:tt)*); 
     $prefix:expr; 
     $e:expr, $($rest:tt)* 
    ) => { 
     pascal_impl!(
      ($($out)* $prefix+$e,); 
      $prefix+$e; 
      $($rest)* 
     ) 
    }; 
} 

macro_rules! pascal { 
    ($($es:expr),+) => { pascal_impl!((); 0; $($es),+,) }; 
} 

trace_macros!(true); 

fn main() { 
    println!("{:?}", pascal!(1, 2, 3, 4)); 
} 

注意:要在一個穩定的編譯器使用這個,你將需要刪除#![feature(trace_macros)]trace_macros!(true);線。其他一切都應該沒問題。

這樣做這是什麼遞歸munches遠在輸入,使所述部分(和潛在語義上無效)輸出作爲輸入遞歸的下一級。這讓我們建立了一個「開放清單」,這是我們無法做到的。

然後,一旦我們沒有輸入,我們只是將我們的部分輸出重新解釋爲一個完整的表達式,然後......完成。

我之所以包括跟蹤的東西,所以我可以告訴你它是什麼樣子,因爲它運行:

pascal! { 1 , 2 , 3 , 4 } 
pascal_impl! { () ; 0 ; 1 , 2 , 3 , 4 , } 
pascal_impl! { (0 + 1 ,) ; 0 + 1 ; 2 , 3 , 4 , } 
pascal_impl! { (0 + 1 , 0 + 1 + 2 ,) ; 0 + 1 + 2 ; 3 , 4 , } 
pascal_impl! { (0 + 1 , 0 + 1 + 2 , 0 + 1 + 2 + 3 ,) ; 0 + 1 + 2 + 3 ; 4 , } 
pascal_impl! { (0 + 1 , 0 + 1 + 2 , 0 + 1 + 2 + 3 , 0 + 1 + 2 + 3 + 4 ,) ; 0 + 1 + 2 + 3 + 4 ; } 

,輸出是:

(1, 3, 6, 10) 

有一點要注意的:大量未註釋的整數文字可能會導致編譯時間增加的顯着增加。如果發生這種情況,只需簡單地註釋全部即可解決問題(如1i32)。