Macros “固定”;不应使用令牌“的任何规则”;宏错误

Macros “固定”;不应使用令牌“的任何规则”;宏错误,macros,rust,Macros,Rust,我正在尝试编写一个宏,用于分解BSON数据,如下所示: let bson: Document = ...; let (id, hash, name, path, modification_time, size, metadata, commit_data) = bson_destructure! { get id = from (bson), optional, name ("_id"), as ObjectId; get hash = from (bson), as Strin

我正在尝试编写一个宏,用于分解BSON数据,如下所示:

let bson: Document = ...;
let (id, hash, name, path, modification_time, size, metadata, commit_data) = bson_destructure! {
    get id = from (bson), optional, name ("_id"), as ObjectId;
    get hash = from (bson), as String, through (|s| ContentHash::from_str(&s));
    get name = from (bson), as String;
    get path = from (bson), as Bson, through (PathBuf::from_bson);
    get modification_time = from (bson), as UtcDatetime, through (FileTime);
    get size = from (bson), as I64, through (|n| n as u64);
    get metadata = from (bson), as Document, through (Metadata::from_bson);
    get commit_data = from (bson), optional, as Document, through (CommitData::from_bson);
    ret (id, hash, name, path, modification_time, size, metadata, commit_data)
};
我为它编写了以下宏(相当大):

但是,上面的第一个示例会导致以下编译错误:

src/db/data.rs:345:22: 345:25 error: no rules expected the token `opt`
src/db/data.rs:345             @collect opt,
                                        ^~~
我有点惊讶,它没有像往常一样显示错误位置(也就是说,没有显示扩展发生的位置),但是,当我注释使用宏的代码段时,错误消失了

我不明白为什么它说没有规则需要这个令牌,因为有这样一个规则,但也许我不明白什么

我很确定这是可能的,因为这大概就是quick_error crate所做的,但我似乎仍然缺乏宏编写技能

我应该如何修复宏,使其按预期工作

为完整起见,以下是
bsondstructureerror
的定义:

#[derive(Debug, Clone)]
pub enum BsonDestructureError {
    InvalidType {
        field_name: &'static str,
        expected: &'static str,
        actual: Bson
    },
    InvalidArrayItemType {
        index: usize,
        expected: &'static str,
        actual: Bson
    },
    MissingField {
        field_name: &'static str,
        expected: &'static str
    }
}

我还使用了从
ejb
crater重新导出的
bson
crater。是一个最小的示例,可以在稳定的Rust上运行。

两个
货物脚本
,一个递归muncher,以及我最喜欢的内部规则语法;我怎么能不呢

首先,可以通过运行
c--Z跟踪宏来确定确切的问题。这将在扩展时输出每个规则,为我们提供一个“回溯”,经过一些手动重新格式化后,结果如下所示:

bson\u解构!{
get id=from(bson),可选,名称(“_id”),作为ObjectId;
获取hash=from(bson),作为字符串;
获取name=from(bson),作为字符串;
获取路径=从(bson),作为bson;
获取修改时间=从(bson),作为UtcDatetime;
获取大小=从(bson),作为I64,到(| n | n作为u64);
获取元数据=来自(bson),作为文档;
获取commit_data=from(bson),可选,作为文档;
ret(id、哈希、名称、路径、修改时间、大小、元数据、提交数据)
}
B去破坏结构!{
@收集选项,
[id,bson,stringify!(id),bson,Ok],
[名称(“_id”),作为ObjectId];
获取hash=from(bson),作为字符串;
获取name=from(bson),作为字符串;
获取路径=从(bson),作为bson;
获取修改时间=从(bson),作为UtcDatetime;
获取大小=从(bson),作为I64,到(| n | n作为u64);
获取元数据=来自(bson),作为文档;
获取commit_data=from(bson),可选,作为文档;
ret(id、哈希、名称、路径、修改时间、大小、元数据、提交数据)
}
B去破坏结构!{
@收集选项,
[id,bson,“_id”,bson,Ok],[as ObjectId];
获取hash=from(bson),作为字符串;
获取name=from(bson),作为字符串;
获取路径=从(bson),作为bson;
获取修改时间=从(bson),作为UtcDatetime;
获取大小=从(bson),作为I64,到(| n | n作为u64);
获取元数据=来自(bson),作为文档;
获取commit_data=from(bson),可选,作为文档;
ret(id、哈希、名称、路径、修改时间、大小、元数据、提交数据)
}
仔细阅读
bson\u destructure中的规则显示问题:没有与第三个扩展匹配的规则<代码>宏规则在报告合理的错误位置方面是垃圾;它指向
opt
标记与此无关。真正的问题是它找不到匹配规则

特别是,违反的规则是:

// change variant name
(
    @collect $k:tt,
    [$target:ident, $source:expr, $field:expr, $variant:ident, $f:expr],
    [as $nv:ident, $($word:ident $arg:tt),*];
    $($rest:tt)*
) => {
    ...
};
注意,
$nv:ident
后面紧接着的逗号。还要注意,输入中没有这样的逗号。这可以通过在重复中移动逗号来解决,如下所示:

// change field name
(
    @collect $k:tt,
    [$target:ident, $source:expr, $field:expr, $variant:ident, $f:expr],
    [name ($nn:expr) $(, $word:ident $arg:tt)*];
    $($rest:tt)*
) => {
    ...
};
另一种选择(我通常会选择)是在第一次遇到输入时简单地对其进行变异,以确保始终有一个尾随逗号


由于本机依赖关系,代码实际上不会在我的机器上编译,但我确实验证了进行此更改(包括此处的更改以及对具有类似问题的其他规则的更改)是否允许它完成宏扩展。您可以使用
c--Z不稳定选项--pretty=expanded

检查输出是否正确哇,我希望我以前知道
-Z跟踪宏
。我总是想逗号之类的东西,但现在忘了><非常感谢!使用rustc版本1.31时,使用-Z时出现错误。选项“Z”仅在夜间编译器上被接受
// change field name
(
    @collect $k:tt,
    [$target:ident, $source:expr, $field:expr, $variant:ident, $f:expr],
    [name ($nn:expr) $(, $word:ident $arg:tt)*];
    $($rest:tt)*
) => {
    ...
};