blob: a725f5e46ad1c813a5cb11b9c05a85ae80f029de [file] [log] [blame]
//! Each macro must have a definition, so `#[plugin]` attributes
//! inject a dummy `macro_rules` item for each macro they define.
use syntax::ast::*;
use syntax::attr;
use syntax::edition::Edition;
use syntax::ext::base::{Resolver, NamedSyntaxExtension};
use syntax::parse::token;
use syntax::ptr::P;
use syntax::source_map::respan;
use syntax::symbol::sym;
use syntax::tokenstream::*;
use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::hygiene::{ExpnId, ExpnInfo, ExpnKind, MacroKind};
use std::mem;
fn plugin_macro_def(name: Name, span: Span) -> P<Item> {
let rustc_builtin_macro = attr::mk_attr_outer(
attr::mk_word_item(Ident::new(sym::rustc_builtin_macro, span)));
let parens: TreeAndJoint = TokenTree::Delimited(
DelimSpan::from_single(span), token::Paren, TokenStream::empty()
).into();
let trees = vec![parens.clone(), TokenTree::token(token::FatArrow, span).into(), parens];
P(Item {
ident: Ident::new(name, span),
attrs: vec![rustc_builtin_macro],
id: DUMMY_NODE_ID,
node: ItemKind::MacroDef(MacroDef { tokens: TokenStream::new(trees), legacy: true }),
vis: respan(span, VisibilityKind::Inherited),
span: span,
tokens: None,
})
}
pub fn inject(
krate: &mut Crate,
resolver: &mut dyn Resolver,
named_exts: Vec<NamedSyntaxExtension>,
edition: Edition,
) {
if !named_exts.is_empty() {
let mut extra_items = Vec::new();
let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
ExpnKind::Macro(MacroKind::Attr, sym::plugin), DUMMY_SP, edition,
[sym::rustc_attrs][..].into(),
));
for (name, ext) in named_exts {
resolver.register_builtin_macro(Ident::with_empty_ctxt(name), ext);
extra_items.push(plugin_macro_def(name, span));
}
// The `macro_rules` items must be inserted before any other items.
mem::swap(&mut extra_items, &mut krate.module.items);
krate.module.items.append(&mut extra_items);
}
}