繁体   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