如何在宏中匹配 Rust 的“if”表达式?

Posted

技术标签:

【中文标题】如何在宏中匹配 Rust 的“if”表达式?【英文标题】:How to match Rust's `if` expressions in a macro? 【发布时间】:2019-01-26 17:07:02 【问题描述】:

我正在尝试编写一个将重写某些 Rust 控制流的宏,但我在匹配 if 表达式时遇到了困难。问题是谓词是一个表达式,但expr 后面不允许跟block

我最好的方法是使用tt

macro_rules! branch 
    (
        if $pred:tt 
            $r1:block
        else
            $r2:block
    ) => 
        if $pred  
            $r1
         else 
            $r2
        
    ;

这适用于单令牌或分组谓词:

branch! 
    if (foo == bar) 
        1
     else 
        2
    

但如果谓词未分组则失败:

branch! 
    if foo == bar 
        1
     else 
        2
    

error: no rules expected the token `==`

我还尝试在谓词中使用tt 的重复模式:

macro_rules! branch 
    (
        if $($pred:tt)+
            $r1:block
        else
            $r2:block
    ) => 
        if $($pred)+  
            $r1
         else 
            $r2
        
    ;

但这会产生错误,因为现在不确定后续块是否也应匹配tt

error: local ambiguity: multiple parsing options: built-in NTs tt ('pred') or block ('r1').

有没有办法做到这一点,还是我坚持发明特殊语法以在宏中使用?

【问题讨论】:

我不想消极,但是宏太乱了……我也没有匹配到一些 Rust 构造。 @Boiethios 我记得。我只需要发明特殊的语法,类似于您可能对您的问题所做的事情。 【参考方案1】:

您可以使用TT muncher 来解析谓词:

macro_rules! branch 
    
        if $($rest:tt)*
     => 
        branch_parser! 
            predicate = ()
            rest = ($($rest)*)
        
    ;


macro_rules! branch_parser 
    
        predicate = ($($predicate:tt)*)
        rest = ( $($then:tt)*  else  $($else:tt)* )
     => 
        println!("predicate: ", stringify!($($predicate)*));
        println!("then: ", stringify!($($then)*));
        println!("else: ", stringify!($($else)*));
    ;

    
        predicate = ($($predicate:tt)*)
        rest = ($next:tt $($rest:tt)*)
     => 
        branch_parser! 
            predicate = ($($predicate)* $next)
            rest = ($($rest)*)
        
    ;


fn main() 
    branch! 
        if foo == bar 
            1
         else 
            2
        
    

输出:

predicate: foo == bar
then: 1
else: 2

【讨论】:

太棒了!请注意,它也可以在模式中没有 predicate =rest = 的情况下工作。后面的括号才是真正重要的。

以上是关于如何在宏中匹配 Rust 的“if”表达式?的主要内容,如果未能解决你的问题,请参考以下文章

如何从选定的 Excel 工作表单元格中在宏中添加时间戳

如何在宏中获取Scala-macro-annotated类或对象的扩展类路径?

在宏中使用 Objective C API 登录静态库

Symfony 3在宏中使用宏?

在宏中使用用户在表单中输入的信息

在宏中传递变量 args 时出现语法错误