// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Used by `rustc` when loading a crate with exported macros. use creader::CrateReader; use cstore::CStore; use rustc::session::Session; use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::ext; use syntax_pos::Span; pub struct MacroLoader<'a> { sess: &'a Session, reader: CrateReader<'a>, } impl<'a> MacroLoader<'a> { pub fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> { MacroLoader { sess: sess, reader: CrateReader::new(sess, cstore, crate_name), } } } pub fn call_bad_macro_reexport(a: &Session, b: Span) { span_err!(a, b, E0467, "bad macro reexport"); } pub type MacroSelection = HashMap; impl<'a> ext::base::MacroLoader for MacroLoader<'a> { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { // Parse the attributes relating to macros. let mut import = Some(HashMap::new()); // None => load all let mut reexport = HashMap::new(); for attr in &extern_crate.attrs { let mut used = true; match &attr.name()[..] { "macro_use" => { let names = attr.meta_item_list(); if names.is_none() { // no names => load all import = None; } if let (Some(sel), Some(names)) = (import.as_mut(), names) { for attr in names { if attr.is_word() { sel.insert(attr.name().clone(), attr.span()); } else { span_err!(self.sess, attr.span(), E0466, "bad macro import"); } } } } "macro_reexport" => { let names = match attr.meta_item_list() { Some(names) => names, None => { call_bad_macro_reexport(self.sess, attr.span); continue; } }; for attr in names { if attr.is_word() { reexport.insert(attr.name().clone(), attr.span()); } else { call_bad_macro_reexport(self.sess, attr.span()); } } } _ => used = false, } if used { attr::mark_used(attr); } } self.load_macros(extern_crate, allows_macros, import, reexport) } } impl<'a> MacroLoader<'a> { fn load_macros<'b>(&mut self, vi: &ast::Item, allows_macros: bool, import: Option, reexport: MacroSelection) -> Vec { if let Some(sel) = import.as_ref() { if sel.is_empty() && reexport.is_empty() { return Vec::new(); } } if !allows_macros { span_err!(self.sess, vi.span, E0468, "an `extern crate` loading macros must be at the crate root"); return Vec::new(); } let mut macros = Vec::new(); let mut seen = HashSet::new(); for mut def in self.reader.read_exported_macros(vi) { let name = def.ident.name.as_str(); def.use_locally = match import.as_ref() { None => true, Some(sel) => sel.contains_key(&name), }; def.export = reexport.contains_key(&name); def.allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable"); debug!("load_macros: loaded: {:?}", def); macros.push(def); seen.insert(name); } if let Some(sel) = import.as_ref() { for (name, span) in sel { if !seen.contains(&name) { span_err!(self.sess, *span, E0469, "imported macro not found"); } } } for (name, span) in &reexport { if !seen.contains(&name) { span_err!(self.sess, *span, E0470, "reexported macro not found"); } } macros } }