我正在编写一个Rust编译器插件,它可以扩展代码。
choose! {
test_a
test_b
}
为了
#[cfg(feature = "a")]
mod test_a;
#[cfg(feature = "b")]
mod test_b;
现在几乎完成了,但是该模块在最终展开的代码中没有任何内容。我猜想原因是span标签未覆盖该模块文件。
use syntax::ast;
use syntax::ptr::P;
use syntax::codemap;
use syntax::parse::token;
use syntax::tokenstream::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;
use syntax_pos::Span;
use rustc_plugin::Registry;
use syntax::util::small_vector::SmallVector;
// Ideally, it will expand
//
// ```rust
// choose! {
// test_a
// test_b
// }
// ```
// to
// ```rust
// #[cfg(feature = "a")]
// mod test_a;
// #[cfg(feature = "b")]
// mod test_b;
// ```
//
// but the modules contain nothing in the expanded code at present
fn choose(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box<MacResult + 'static> {
let mut test_mods: SmallVector<P<ast::Item>> = SmallVector::many(vec![]);
for arg in args {
let mut attrs = vec![];
let text = match arg {
&TokenTree::Token(_, token::Ident(s)) => s.to_string(),
_ => {
return DummyResult::any(sp);
}
};
let cfg_str = token::InternedString::new("cfg");
let feat_str = token::InternedString::new("feature");
attrs.push(cx.attribute(sp,
cx.meta_list(sp,
cfg_str,
vec![cx.meta_name_value(sp,
feat_str,
ast::LitKind::Str(token::intern_and_get_ident(text.trim_left_matches("test_")), ast::StrStyle::Cooked))])));
test_mods.push(P(ast::Item {
ident: cx.ident_of(text.as_str()),
attrs: attrs,
id: ast::DUMMY_NODE_ID,
node: ast::ItemKind::Mod(
// === How to include the specified module file here? ===
ast::Mod {
inner: codemap::DUMMY_SP,
items: vec![],
}
),
vis: ast::Visibility::Inherited,
span: sp,
}))
}
MacEager::items(test_mods)
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("choose", choose);
}
(Gist)
foo.rs
或foo/mod.rs
中寻找模块foo
的内容(如果两个都存在,则会出错)。你可能也想这样做。 - Francis Gagné