//! 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 { let rustc_builtin_macro = Attribute { id: attr::mk_attr_id(), style: AttrStyle::Outer, path: Path::from_ident(Ident::new(sym::rustc_builtin_macro, span)), tokens: TokenStream::empty(), is_sugared_doc: false, 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, 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); } }