2014-07-12 23 views
8

生鏽是否有可能編寫一個創建其他宏的宏。例如,假設我定義了以下兩個宏:高階宏指令

macro_rules! myprint(
    ($a:expr) => (print!("{}", $a)) 
) 

macro_rules! myprintln(
    ($a:expr) => (println!("{}", $a)) 
) 

由於兩個宏重複大量的代碼,我可能要編寫一個宏來產生宏。

我試圖產生這樣的meta macro

#![feature(macro_rules)] 

macro_rules! metamacro(
    ($i:ident) => (
     macro_rules! $i (
      ($a:expr) => ({println!("hello {}", $a)}) 
     ) 
    ); 
) 

metamacro!(foo) 

fn main() { 
    foo!(1i); 
} 

,但得到以下錯誤:

<anon>:6:13: 6:14 error: unknown macro variable `a` 
<anon>:6    ($a:expr) => ({println!("hello {}", $a)}) 
        ^
playpen: application terminated with error code 101 
Program ended. 

編輯:與宏多一些玩耍後,我發現,如果返回的宏不按預期高階宏的工作方式接收任何參數。例如,下面的code

#![feature(macro_rules)] 

macro_rules! metamacro(
    ($i:ident) => (
     macro_rules! $i (
      () => ({println!("hello")}) 
     ) 
    ); 
) 

metamacro!(foo) 

fn main() { 
    foo!(); 
} 

打印hello

+1

爲什麼不試試自己嗎? –

+2

我試過了,沒有找到有效的東西。我在這裏問過,如果有一個我還沒有嘗試過的隱藏或較少已知的鏽蝕機制。我將這個添加到我的問題中,使其更清楚一點。 – mwhittaker

+0

你沒有顯示你嘗試過什麼或錯誤是什麼。這些細節對於給出任何答案都是絕對必要的。 –

回答

10

#34925這是最近成爲可能。下面的答案指Rust的舊版本。


這是#6795#6994,並不能直接的時刻。例如。一個想嘗試的第一件事是

#![feature(macro_rules)] 

macro_rules! define { 
    ($name: ident, $other: ident) => { 
     macro_rules! $name { 
      ($e: expr) => { 
       $other!("{}", $e) 
      } 
     } 
    } 
} 

define!{myprintln, println} 
define!{myprint, print} 

fn main() {} 

但這種失敗

so8.rs:6:13: 6:14 error: unknown macro variable `e` 
so8.rs:6    ($e: expr) => { 
        ^

(提起#15640關於在(代替$e插入符號指向。)

的原因是宏擴展是「愚蠢的」:它天真地解釋並替換所有的標記,即使在嵌套的宏調用中也是如此(並且macro_rules!是一個宏調用)。因此,它不能說明內部macro_rules!內的$e實際上應該保留爲$e:它只是在擴展define時試圖替換它們。

#![feature(macro_rules)] 

macro_rules! define { 
    ($name: ident, $other: ident, $($interior: tt)*) => { 
     macro_rules! $name { 
      ($($interior)*: expr) => { 
       $other!("{}", $($interior)*) 
      } 
     } 
    } 
} 

define!{myprintln, println, $e} 
define!{myprint, print, $e} 

fn main() {} 

也就是說,我說:

一個可以嘗試的額外參數被傳遞到define在內部定義的地方,這樣$e不直接嵌套調用出現的第二件事$interior: tt允許捕獲$ett代表令牌樹,它是非定界符原始令牌(例如$some_ident)或由匹配定界符(例如(foo + bar fn "baz"))包圍的令牌序列。不幸的是,它似乎擴展足以渴望被過於擴大$e擴展:

so8.rs:8:13: 8:14 error: unknown macro variable `e` 
so8.rs:8    ($($interior)*: expr) => { 
        ^

它工作正常時,嵌套宏沒有參數本身,因爲沒有嵌套$...非終端等擴張階段並沒有遇到上述定義問題。


最後,你可以得到的代碼共享一些外表,因爲你可以通過名字擴展到宏調用:

#![feature(macro_rules)] 

macro_rules! my { 
    ($name: ident, $e: expr) => { 
     $name!("{}", $e) 
    } 
} 

fn main() { 
    my!(print, 1i); 
    my!(println, 2i); 
} 

它打印12

+0

嗯,我想說,也許我們要麼使它工作得很好,要麼不允許嵌套宏一起... – errordeveloper

+0

哇,太棒了!你會不會知道在未來的某個時間是否會計劃將更高階的宏包含在語言中? – mwhittaker

+0

@mwhittaker,目前沒有現在的計劃,但它肯定是一個煩惱,這將是很好的修復。 – huon

0

下面是一個例子這樣的作品,也許是一個起點你:

#![feature(macro_rules)] 

macro_rules! metamacro(
    ($i:ident) => (
     macro_rules! $i (
      () => ({println!("hello!")}) 
     ) 
    ); 
) 

metamacro!(hello) 

fn main() { 
    hello!(); 
}