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

11

我试图编写一个宏,以重写特定的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').

有没有什么方法可以做到这一点,还是我必须发明一些特殊的语法来在宏中使用?


3
我不想过于负面,但宏实在太凌乱了...我也无法匹配一些 Rust 的结构。 - Boiethios
@Boiethios 我记得。我只需要发明一种特殊的语法,类似于您可能在解决问题时所做的。 - Peter Hall
1个回答

5
你可以使用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 =,它也可以正常工作。之后的括号才是真正重要的。 - cambunctious

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接