6 个版本

0.2.1 2023年7月19日
0.2.0 2023年7月19日
0.1.2 2020年7月4日
0.1.1 2020年7月4日
0.1.0 2020年7月4日

#631 in Rust 模式

Download history 205/week @ 2024-03-13 150/week @ 2024-03-20 169/week @ 2024-03-27 139/week @ 2024-04-03 122/week @ 2024-04-10 203/week @ 2024-04-17 261/week @ 2024-04-24 313/week @ 2024-05-01 279/week @ 2024-05-08 111/week @ 2024-05-15 194/week @ 2024-05-22 181/week @ 2024-05-29 134/week @ 2024-06-05 254/week @ 2024-06-12 156/week @ 2024-06-19 134/week @ 2024-06-26

每月 702 次下载
用于 7 包 (直接使用 2 个)

使用 Zlib 或 MIT 或 Apache-2.0 许可

11KB

::defile

辅助过程宏,用于将捕获的宏元变量“取消分组”(因此可能会破坏它们的卫生,所以命名为“取消分组”)。

Repository Latest version Documentation MSRV unsafe forbidden License CI no_std

这在使用需要使用特殊规则(例如 :expr:path:pat)进行解析的辅助宏时非常有用,但这些宏随后还想进一步检查捕获的变量。

这不可能由 macro_rules! 本身完成,因为这些所谓的 元变量 被视为一个 不可见 的单个标记(捕获在元变量中的标记序列已经被 分组(≈ 括号内)但使用了不可见的括号)。

示例

macro_rules! check_expr {
    (
        42
    ) => ({
        println!("Got `42`!");
    });

    (
        $($tt:tt)*
    ) => ({
        println!("Did not get `42`. Instead, got the following tokens:\n[");
        $(
            println!("    `{}`,", stringify!($tt));
        )*
        println!("]");
    });
}

macro_rules! check_all_exprs {(
    $(
        $expr:expr // use :expr to be able to use `,` as a delimiter
    ),* $(,)?
) => (
    fn main () {
        $(
            println!("vvvvvvvvvvvvv");
            check_expr!($expr);
            println!("^^^^^^^^^^^^^\n");
        )*
    }
)}

check_all_exprs!(42, 1 + 1);

输出

vvvvvvvvvvvvv
Did not get `42`. Instead, got the following tokens:
[
    `42`,
]
^^^^^^^^^^^^^

vvvvvvvvvvvvv
Did not get `42`. Instead, got the following tokens:
[
    `1 + 1`,
]
^^^^^^^^^^^^^
  • 这就是

    • 标记 42 不匹配 42 的原因!

    • 话虽如此,表达式 1 + 1 也是一个不可分割的标记。

      实际上,这正是这种行为的要点:如果我们执行 2 * $expr,其中 $expr 捕获 1 + 1,我们期望结果为 2 * (1 + 1),而不是 2 * 1 + 1

但是通过执行

macro_rules! check_all_exprs {(
    $(
        $expr:expr // use :expr to be able to use `,` as a delimiter
    ),* $(,)?
) => (::defile::defile! { // 👈
    fn main () {
        $(
            println!("vvvvvvvvvvvvv");
            check_expr!(@$expr);
//                      👆
            println!("^^^^^^^^^^^^^\n");
        )*
    }
})}

我们确实得到了

vvvvvvvvvvvvv
Got `42`!
^^^^^^^^^^^^^

vvvvvvvvvvvvv
Did not get `42`. Instead, got the following tokens:
[
    `1`,
    `+`,
    `1`,
]
^^^^^^^^^^^^^
  • 42 匹配了字面量 42,但请注意,这也导致了 1 + 1 被分割。所以,如果你要使用 defile 表达式如 2 * @$expr,你可能不会得到预期的结果!请谨慎使用。

注意事项

目前(1.45.0),存在一些关于 macro_rules! 宏和过程宏之间交互的bug,可能会导致 defile! 和任何其他辅助过程宏将非 @-前缀的组分割。

希望这些bug已经解决,使得 defile! 的实际实现变得有意义。

依赖项