简体   繁体   English

如何在Rust过程宏中创建多个项目?

[英]How can I create multiple items in a Rust procedural macro?

I am trying to create a macro that, when used like this: 我正在尝试创建一个宏,当像这样使用时:

foo!()

expands to two items, a static item and a function. 扩展为两个项目,静态项目和功能。 Something like this: 像这样的东西:

static x: uint = 5;

fn bar() -> uint { x + 1 }

It has been pointed out to me that MacResult 's make_items method supports this, so I just need to create a type that implements it properly. 我已经向我指出, MacResultmake_items方法支持这一点,所以我只需要创建一个正确实现它的类型。 I have done so with this: 我这样做了:

struct MacItems {
    items: Vec<::std::gc::Gc<Item>>,
}

impl MacResult for MacItems {
    fn make_def(&self) -> Option<::syntax::ext::base::MacroDef> { None }
    fn make_expr(&self) -> Option<::std::gc::Gc<ast::Expr>> { None }
    fn make_pat(&self) -> Option<::std::gc::Gc<ast::Pat>> { None }
    fn make_stmt(&self) -> Option<::std::gc::Gc<ast::Stmt>> { None }

    fn make_items(&self) -> Option<::syntax::util::small_vector::SmallVector<::std::gc::Gc<Item>>> {
        Some(::syntax::util::small_vector::SmallVector::many(self.items.clone()))
    }
}

I have attempted to use the quote_item! 我试图使用quote_item! macro, but this macro apparently moves the ExtCtxt , making it not possible to use it twice in a row. 宏,但这个宏显然移动了ExtCtxt ,使得它不可能连续两次使用它。 Here's my code: 这是我的代码:

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("foo", expand);
}

fn expand(cx: &mut ExtCtxt, sp: codemap::Span, _: &[ast::TokenTree]) -> Box<MacResult> {
    let mut v = vec!();

    v.push( quote_item!(cx, static x: uint = 5;).unwrap() );
    v.push( quote_item!(cx, fn bar() -> uint { x + 1 }).unwrap() );

    box MacItems { items: v } as Box<MacResult>
}

And here's the error: 这是错误:

test.rs:37:13: 37:57 error: use of moved value: `cx`
test.rs:37     v.push( quote_item!(cx, fn bar() -> uint { x + 1 }).unwrap() );
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: in expansion of quote_item!
test.rs:37:13: 37:57 note: expansion site
test.rs:36:13: 36:50 note: `cx` moved here because it has type `&mut syntax::ext::base::ExtCtxt<'_>`, which is moved by default (use `ref` to override)
test.rs:36     v.push( quote_item!(cx, static x: uint = 5;).unwrap() );
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: in expansion of quote_item!
test.rs:36:13: 36:50 note: expansion site
error: aborting due to previous error

How can I achieve this? 我怎样才能做到这一点? I attempted to use AstBuilder::item_static to create the static item, but I cannot figure out which variant of Ty_ corresponds to uint here. 我试图使用AstBuilder::item_static来创建静态项目,但我无法确定Ty_哪个变体对应于uint (Also this is just a toy example, my real static declaration is &'static str , so I need to build that item instead). (这只是一个玩具示例,我真正的静态声明是&'static str ,所以我需要构建该项目)。

Am I doing this completely wrong? 我这样做完全错了吗? How can this be achieved? 怎么能实现这一目标?

You need to manually reborrow the cx to a temporary &mut ExtCtxt . 您需要手动将cx重新借用到临时&mut ExtCtxt Often the compiler can insert the reborrows automatically, but the quote_* macros do not expand to something ameniable to this. 编译器通常可以自动插入reborrows,但quote_*宏不会扩展为适合此的东西。

That is, 那是,

quote_item!(&mut *cx, ...)

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

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