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

Pet*_*all 7 macros rust rust-macros

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

我得到的最好的是使用tt:

macro_rules! branch {
    (
        if $pred:tt 
            $r1:block
        else
            $r2:block
    ) => {
        if $pred { 
            $r1
        } else {
            $r2
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

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

branch! {
    if (foo == bar) {
        1
    } else {
        2
    }
}
Run Code Online (Sandbox Code Playgroud)

但如果谓词没有分组,则会失败:

branch! {
    if foo == bar {
        1
    } else {
        2
    }
}
Run Code Online (Sandbox Code Playgroud)
error: no rules expected the token `==`
Run Code Online (Sandbox Code Playgroud)

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

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

但是这会产生一个错误,因为现在的后续块是否也应该匹配是不明确的tt:

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

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

dto*_*nay 6

您可以使用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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

predicate: foo == bar
then: 1
else: 2
Run Code Online (Sandbox Code Playgroud)