否;宏必須的結果是像表達式或項目一樣的完整語法結構。 絕對不能具有像逗號或右大括號這樣的語法隨機位。
你可以通過簡單地輸出任何東西來解決這個問題,直到你有完整的最終表達式。看哪!
#![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
)。