简体   繁体   English

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

[英]How to match Rust's `if` expressions in a macro?

I'm trying to write a macro that will rewrite certain Rust control flow, but I'm having difficulty matching an if expression. 我正在尝试编写一个将重写某些Rust控制流的宏,但是我很难匹配if表达式。 The problem is that the predicate is an expression, but an expr is not permitted to be followed by a block or { . 问题是谓词是一个表达式,但是不允许expr后跟一个block{

The best I've got is to use tt : 我得到的最好的是使用tt

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

Which works fine with single-token or grouped predicates: 哪个适用于单令牌或分组谓词:

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

But fails if the predicate was not grouped: 但如果谓词没有分组,则会失败:

branch! {
    if foo == bar {
        1
    } else {
        2
    }
}
error: no rules expected the token `==`

I also tried to use a repeating pattern of tt in the predicate: 我还尝试在谓词中使用tt的重复模式:

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

But this produces an error because it's now ambiguous whether subsequent block should match the tt too: 但是这会产生错误,因为现在后续块是否应该匹配tt现在还不明确:

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

Is there a way to do this, or am I stuck with inventing special syntax to use in the macro? 有没有办法做到这一点,还是我坚持发明特殊语法在宏中使用?

You could use a TT muncher to parse the predicate: 您可以使用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
        }
    }
}

Output: 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM