簡體   English   中英

如何在不重復規則的情況下為宏編寫包裝器?

[英]How do I write a wrapper for a macro without repeating the rules?

我正在嘗試為宏制作一個包裝器。 問題是我不想在兩個宏中重復相同的規則。 有沒有辦法做到這一點?

這是我嘗試過的:

macro_rules! inner {
    ($test:ident) => { stringify!($test) };
    ($test:ident.run()) => { format!("{}.run()", stringify!($test)) };
}

macro_rules! outer {
    ($expression:expr) => {
        println!("{}", inner!($expression));
    }
}

fn main() {
    println!("{}", inner!(test));
    println!("{}", inner!(test.run()));
    outer!(test);
    outer!(test.run());
}

但我收到以下錯誤:

src/main.rs:8:31: 8:42 error: expected ident, found test
src/main.rs:8         println!("{}", inner!($expression));
                                            ^~~~~~~~~~~

如果我為此更改outer宏,代碼編譯:

macro_rules! outer {
    ($expression:expr) => {
        println!("{}", stringify!($expression));
    }
}

我究竟做錯了什么?

macro_rules! 比你可能意識到的更聰明笨拙

最初,對宏的所有輸入都以無差別的令牌湯開始。 這里是一個IdentStrLit 等等。但是,當你匹配並捕獲一些輸入時,通常輸入將在一個抽象語法樹節點中解析; 這是expr的情況。

“聰明”位是當你替換這個捕獲(例如, $expression )時,你不只是替換最初匹配的標記:你將整個AST節點替換為單個標記 所以現在輸出中的這個奇怪的非真正的標記就是整個語法元素。

“愚蠢”的一點是,這個過程基本上是不可逆轉的,而且大多是完全不可見的 讓我們舉個例子:

outer!(test);

我們通過一個擴展級別運行它,它變為:

println!("{}", inner!(test));

除此之外,這不是它的樣子。 為了使事情更清楚,我將發明一些非標准語法

println!("{}", inner!( $(test):expr ));

假設$(test):expr是一個單一的標記:它是一個表達式,可以用標記序列test來表示。 不僅是該令牌序列test 這很重要,因為當宏解釋器擴展inner! 宏,它檢查第一條規則:

    ($test:ident) => { stringify!($test) };

問題是$(test):expr是一個表達式, 而不是標識符 是的,它包含一個標識符,但宏解釋器看起來並不那么深。 它看到了一個表達,只是放棄了

由於同樣的原因,它無法匹配第二條規則。

所以你會怎么做? ......嗯,這取決於。 outer! 不對其輸入進行任何處理,您可以使用tt匹配器代替:

macro_rules! outer {
    ($($tts:tt)*) => {
        println!("{}", inner!($($tts)*));
    }
}

tt將匹配任何令牌樹(請參閱Rust Book宏章章節 )。 $($tts:tt)*將匹配任何序列的標記,而不更改它們。 這是將一堆令牌安全地轉發到另一個宏的方法。

如果你需要對輸入進行處理並將其轉發到inner! 宏......你可能不得不重復這些規則。

我在$($stuff: expr),+語法上取得了一些成功。

macro_rules! println {
    ( $($stuff: expr),+) => {
    avr_device::interrupt::free(|cs| {
    uwriteln!(unsafe { &SERIAL_STATIC}.borrow(cs).borrow_mut().as_mut().unwrap(),
    $($stuff),+)
    })
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM