Move macro resolution into librustc_resolve
.
This commit is contained in:
parent
20b43b2323
commit
72a636975f
11 changed files with 438 additions and 405 deletions
|
@ -21,7 +21,7 @@ use util::nodemap::{NodeMap, FnvHashMap};
|
||||||
use util::common::duration_to_secs_str;
|
use util::common::duration_to_secs_str;
|
||||||
use mir::transform as mir_pass;
|
use mir::transform as mir_pass;
|
||||||
|
|
||||||
use syntax::ast::{NodeId, Name};
|
use syntax::ast::NodeId;
|
||||||
use errors::{self, DiagnosticBuilder};
|
use errors::{self, DiagnosticBuilder};
|
||||||
use errors::emitter::{Emitter, EmitterWriter};
|
use errors::emitter::{Emitter, EmitterWriter};
|
||||||
use syntax::json::JsonEmitter;
|
use syntax::json::JsonEmitter;
|
||||||
|
@ -39,7 +39,7 @@ use llvm;
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::cell::{self, Cell, RefCell};
|
use std::cell::{self, Cell, RefCell};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -96,10 +96,6 @@ pub struct Session {
|
||||||
pub injected_allocator: Cell<Option<ast::CrateNum>>,
|
pub injected_allocator: Cell<Option<ast::CrateNum>>,
|
||||||
pub injected_panic_runtime: Cell<Option<ast::CrateNum>>,
|
pub injected_panic_runtime: Cell<Option<ast::CrateNum>>,
|
||||||
|
|
||||||
/// Names of all bang-style macros and syntax extensions
|
|
||||||
/// available in this crate
|
|
||||||
pub available_macros: RefCell<HashSet<Name>>,
|
|
||||||
|
|
||||||
/// Map from imported macro spans (which consist of
|
/// Map from imported macro spans (which consist of
|
||||||
/// the localized span for the macro body) to the
|
/// the localized span for the macro body) to the
|
||||||
/// macro name and defintion span in the source crate.
|
/// macro name and defintion span in the source crate.
|
||||||
|
@ -552,7 +548,6 @@ pub fn build_session_(sopts: config::Options,
|
||||||
next_node_id: Cell::new(1),
|
next_node_id: Cell::new(1),
|
||||||
injected_allocator: Cell::new(None),
|
injected_allocator: Cell::new(None),
|
||||||
injected_panic_runtime: Cell::new(None),
|
injected_panic_runtime: Cell::new(None),
|
||||||
available_macros: RefCell::new(HashSet::new()),
|
|
||||||
imported_macro_spans: RefCell::new(HashMap::new()),
|
imported_macro_spans: RefCell::new(HashMap::new()),
|
||||||
incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
|
incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
|
||||||
perf_stats: PerfStats {
|
perf_stats: PerfStats {
|
||||||
|
|
|
@ -50,6 +50,7 @@ use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use syntax::{ast, diagnostics, visit};
|
use syntax::{ast, diagnostics, visit};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
use syntax::ext::base::ExtCtxt;
|
||||||
use syntax::parse::{self, PResult, token};
|
use syntax::parse::{self, PResult, token};
|
||||||
use syntax::util::node_count::NodeCounter;
|
use syntax::util::node_count::NodeCounter;
|
||||||
use syntax;
|
use syntax;
|
||||||
|
@ -643,6 +644,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|
||||||
|
|
||||||
let resolver_arenas = Resolver::arenas();
|
let resolver_arenas = Resolver::arenas();
|
||||||
let mut resolver = Resolver::new(sess, make_glob_map, &mut macro_loader, &resolver_arenas);
|
let mut resolver = Resolver::new(sess, make_glob_map, &mut macro_loader, &resolver_arenas);
|
||||||
|
syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote);
|
||||||
|
|
||||||
krate = time(time_passes, "expansion", || {
|
krate = time(time_passes, "expansion", || {
|
||||||
// Windows dlls do not have rpaths, so they don't know how to find their
|
// Windows dlls do not have rpaths, so they don't know how to find their
|
||||||
|
@ -678,16 +680,11 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
|
||||||
trace_mac: sess.opts.debugging_opts.trace_macros,
|
trace_mac: sess.opts.debugging_opts.trace_macros,
|
||||||
should_test: sess.opts.test,
|
should_test: sess.opts.test,
|
||||||
};
|
};
|
||||||
let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess,
|
let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver);
|
||||||
krate.config.clone(),
|
|
||||||
cfg,
|
|
||||||
&mut resolver);
|
|
||||||
syntax_ext::register_builtins(&mut ecx.syntax_env);
|
|
||||||
let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
|
let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
env::set_var("PATH", &old_path);
|
env::set_var("PATH", &old_path);
|
||||||
}
|
}
|
||||||
*sess.available_macros.borrow_mut() = ecx.syntax_env.names;
|
|
||||||
ret
|
ret
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,6 @@ use rustc::ty;
|
||||||
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
|
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
|
||||||
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
|
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
|
||||||
|
|
||||||
use syntax::ext;
|
|
||||||
use syntax::ext::base::LoadedMacro;
|
|
||||||
use syntax::ext::hygiene::Mark;
|
use syntax::ext::hygiene::Mark;
|
||||||
use syntax::ast::{self, FloatTy};
|
use syntax::ast::{self, FloatTy};
|
||||||
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
|
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
|
||||||
|
@ -82,6 +80,7 @@ use resolve_imports::{ImportDirective, NameResolution};
|
||||||
// registered before they are used.
|
// registered before they are used.
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
|
|
||||||
|
mod macros;
|
||||||
mod check_unused;
|
mod check_unused;
|
||||||
mod build_reduced_graph;
|
mod build_reduced_graph;
|
||||||
mod resolve_imports;
|
mod resolve_imports;
|
||||||
|
@ -1073,6 +1072,10 @@ pub struct Resolver<'a> {
|
||||||
new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
|
new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
|
||||||
|
|
||||||
macro_loader: &'a mut MacroLoader,
|
macro_loader: &'a mut MacroLoader,
|
||||||
|
macro_names: FnvHashSet<Name>,
|
||||||
|
|
||||||
|
// Maps the `Mark` of an expansion to its containing module or block.
|
||||||
|
expansion_data: Vec<macros::ExpansionData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ResolverArenas<'a> {
|
pub struct ResolverArenas<'a> {
|
||||||
|
@ -1154,12 +1157,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ext::base::Resolver for Resolver<'a> {
|
|
||||||
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> {
|
|
||||||
self.macro_loader.load_crate(extern_crate, allows_macros)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Named {
|
trait Named {
|
||||||
fn name(&self) -> Name;
|
fn name(&self) -> Name;
|
||||||
}
|
}
|
||||||
|
@ -1243,6 +1240,8 @@ impl<'a> Resolver<'a> {
|
||||||
new_import_semantics: session.features.borrow().item_like_imports,
|
new_import_semantics: session.features.borrow().item_like_imports,
|
||||||
|
|
||||||
macro_loader: macro_loader,
|
macro_loader: macro_loader,
|
||||||
|
macro_names: FnvHashSet(),
|
||||||
|
expansion_data: vec![macros::ExpansionData::default()],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2784,8 +2783,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_best_match(&mut self, name: &str) -> SuggestionType {
|
fn find_best_match(&mut self, name: &str) -> SuggestionType {
|
||||||
if let Some(macro_name) = self.session.available_macros
|
if let Some(macro_name) = self.macro_names.iter().find(|n| n.as_str() == name) {
|
||||||
.borrow().iter().find(|n| n.as_str() == name) {
|
|
||||||
return SuggestionType::Macro(format!("{}!", macro_name));
|
return SuggestionType::Macro(format!("{}!", macro_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
213
src/librustc_resolve/macros.rs
Normal file
213
src/librustc_resolve/macros.rs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
// Copyright 2016 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use Resolver;
|
||||||
|
use rustc::util::nodemap::FnvHashMap;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use syntax::ast::{self, Name};
|
||||||
|
use syntax::errors::DiagnosticBuilder;
|
||||||
|
use syntax::ext::base::{self, LoadedMacro, MultiModifier, MultiDecorator};
|
||||||
|
use syntax::ext::base::{NormalTT, SyntaxExtension};
|
||||||
|
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
|
||||||
|
use syntax::ext::hygiene::Mark;
|
||||||
|
use syntax::parse::token::intern;
|
||||||
|
use syntax::util::lev_distance::find_best_match_for_name;
|
||||||
|
use syntax::visit::{self, Visitor};
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct ExpansionData {
|
||||||
|
module: Rc<ModuleData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(jseyfried): merge with `::ModuleS`.
|
||||||
|
#[derive(Default)]
|
||||||
|
struct ModuleData {
|
||||||
|
parent: Option<Rc<ModuleData>>,
|
||||||
|
macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
|
||||||
|
macros_escape: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> base::Resolver for Resolver<'a> {
|
||||||
|
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> {
|
||||||
|
self.macro_loader.load_crate(extern_crate, allows_macros)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
|
||||||
|
expansion.visit_with(&mut ExpansionVisitor {
|
||||||
|
current_module: self.expansion_data[mark.as_u32() as usize].module.clone(),
|
||||||
|
resolver: self,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
|
||||||
|
if let NormalTT(..) = *ext {
|
||||||
|
self.macro_names.insert(ident.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut module = self.expansion_data[scope.as_u32() as usize].module.clone();
|
||||||
|
while module.macros_escape {
|
||||||
|
module = module.parent.clone().unwrap();
|
||||||
|
}
|
||||||
|
module.macros.borrow_mut().insert(ident.name, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
|
||||||
|
self.macros_at_scope.insert(id, macros);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
|
||||||
|
for i in 0..attrs.len() {
|
||||||
|
let name = intern(&attrs[i].name());
|
||||||
|
match self.expansion_data[0].module.macros.borrow().get(&name) {
|
||||||
|
Some(ext) => match **ext {
|
||||||
|
MultiModifier(..) | MultiDecorator(..) => return Some(attrs.remove(i)),
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_invoc(&mut self, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
|
||||||
|
let (name, span) = match invoc.kind {
|
||||||
|
InvocationKind::Bang { ref mac, .. } => {
|
||||||
|
let path = &mac.node.path;
|
||||||
|
if path.segments.len() > 1 || path.global ||
|
||||||
|
!path.segments[0].parameters.is_empty() {
|
||||||
|
self.session.span_err(path.span,
|
||||||
|
"expected macro name without module separators");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
(path.segments[0].identifier.name, path.span)
|
||||||
|
}
|
||||||
|
InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut module = self.expansion_data[invoc.mark().as_u32() as usize].module.clone();
|
||||||
|
loop {
|
||||||
|
if let Some(ext) = module.macros.borrow().get(&name) {
|
||||||
|
return Some(ext.clone());
|
||||||
|
}
|
||||||
|
match module.parent.clone() {
|
||||||
|
Some(parent) => module = parent,
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut err =
|
||||||
|
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
|
||||||
|
self.suggest_macro_name(&name.as_str(), &mut err);
|
||||||
|
err.emit();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Resolver<'a> {
|
||||||
|
fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
|
||||||
|
if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
|
||||||
|
if suggestion != name {
|
||||||
|
err.help(&format!("did you mean `{}!`?", suggestion));
|
||||||
|
} else {
|
||||||
|
err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ExpansionVisitor<'b, 'a: 'b> {
|
||||||
|
resolver: &'b mut Resolver<'a>,
|
||||||
|
current_module: Rc<ModuleData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> ExpansionVisitor<'a, 'b> {
|
||||||
|
fn visit_invoc(&mut self, id: ast::NodeId) {
|
||||||
|
assert_eq!(id, self.resolver.expansion_data.len() as u32);
|
||||||
|
self.resolver.expansion_data.push(ExpansionData {
|
||||||
|
module: self.current_module.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// does this attribute list contain "macro_use"?
|
||||||
|
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||||
|
for attr in attrs {
|
||||||
|
if attr.check_name("macro_escape") {
|
||||||
|
let msg = "macro_escape is a deprecated synonym for macro_use";
|
||||||
|
let mut err = self.resolver.session.struct_span_warn(attr.span, msg);
|
||||||
|
if let ast::AttrStyle::Inner = attr.node.style {
|
||||||
|
err.help("consider an outer attribute, #[macro_use] mod ...").emit();
|
||||||
|
} else {
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
} else if !attr.check_name("macro_use") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !attr.is_word() {
|
||||||
|
self.resolver.session.span_err(attr.span,
|
||||||
|
"arguments to macro_use are not allowed here");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! method {
|
||||||
|
($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
|
||||||
|
fn $visit(&mut self, node: &$ty) {
|
||||||
|
match node.node {
|
||||||
|
$invoc(..) => self.visit_invoc(node.id),
|
||||||
|
_ => visit::$walk(self, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b> {
|
||||||
|
method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item);
|
||||||
|
method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
|
||||||
|
method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt);
|
||||||
|
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
|
||||||
|
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
|
||||||
|
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
|
||||||
|
|
||||||
|
fn visit_item(&mut self, item: &ast::Item) {
|
||||||
|
match item.node {
|
||||||
|
ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder
|
||||||
|
ast::ItemKind::Mac(..) => self.visit_invoc(item.id),
|
||||||
|
ast::ItemKind::Mod(..) => {
|
||||||
|
let module_data = ModuleData {
|
||||||
|
parent: Some(self.current_module.clone()),
|
||||||
|
macros: RefCell::new(FnvHashMap()),
|
||||||
|
macros_escape: self.contains_macro_use(&item.attrs),
|
||||||
|
};
|
||||||
|
let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
|
||||||
|
visit::walk_item(self, item);
|
||||||
|
self.current_module = orig_module;
|
||||||
|
}
|
||||||
|
_ => visit::walk_item(self, item),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_block(&mut self, block: &ast::Block) {
|
||||||
|
let module_data = ModuleData {
|
||||||
|
parent: Some(self.current_module.clone()),
|
||||||
|
macros: RefCell::new(FnvHashMap()),
|
||||||
|
macros_escape: false,
|
||||||
|
};
|
||||||
|
let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
|
||||||
|
visit::walk_block(self, block);
|
||||||
|
self.current_module = orig_module;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,27 +10,25 @@
|
||||||
|
|
||||||
pub use self::SyntaxExtension::*;
|
pub use self::SyntaxExtension::*;
|
||||||
|
|
||||||
use ast;
|
use ast::{self, Attribute, Name, PatKind};
|
||||||
use ast::{Name, PatKind};
|
|
||||||
use attr::HasAttrs;
|
use attr::HasAttrs;
|
||||||
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
|
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
|
||||||
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
|
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
|
||||||
use errors::DiagnosticBuilder;
|
use errors::DiagnosticBuilder;
|
||||||
use ext;
|
use ext::expand::{self, Invocation, Expansion};
|
||||||
use ext::expand;
|
use ext::hygiene::Mark;
|
||||||
use ext::tt::macro_rules;
|
use ext::tt::macro_rules;
|
||||||
use parse;
|
use parse;
|
||||||
use parse::parser;
|
use parse::parser;
|
||||||
use parse::token;
|
use parse::token;
|
||||||
use parse::token::{InternedString, intern, str_to_ident};
|
use parse::token::{InternedString, str_to_ident};
|
||||||
use ptr::P;
|
use ptr::P;
|
||||||
use std_inject;
|
use std_inject;
|
||||||
use util::small_vector::SmallVector;
|
use util::small_vector::SmallVector;
|
||||||
use util::lev_distance::find_best_match_for_name;
|
|
||||||
use fold::Folder;
|
use fold::Folder;
|
||||||
use feature_gate;
|
use feature_gate;
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use tokenstream;
|
use tokenstream;
|
||||||
|
@ -44,7 +42,7 @@ pub enum Annotatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasAttrs for Annotatable {
|
impl HasAttrs for Annotatable {
|
||||||
fn attrs(&self) -> &[ast::Attribute] {
|
fn attrs(&self) -> &[Attribute] {
|
||||||
match *self {
|
match *self {
|
||||||
Annotatable::Item(ref item) => &item.attrs,
|
Annotatable::Item(ref item) => &item.attrs,
|
||||||
Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
|
Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
|
||||||
|
@ -52,7 +50,7 @@ impl HasAttrs for Annotatable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
|
fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
|
Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
|
||||||
Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
|
Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
|
||||||
|
@ -464,91 +462,15 @@ pub enum SyntaxExtension {
|
||||||
|
|
||||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||||
|
|
||||||
/// The base map of methods for expanding syntax extension
|
|
||||||
/// AST nodes into full ASTs
|
|
||||||
fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
|
|
||||||
-> SyntaxEnv {
|
|
||||||
// utility function to simplify creating NormalTT syntax extensions
|
|
||||||
fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
|
|
||||||
NormalTT(Box::new(f), None, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut syntax_expanders = SyntaxEnv::new();
|
|
||||||
syntax_expanders.insert(intern("macro_rules"), MacroRulesTT);
|
|
||||||
|
|
||||||
if ecfg.enable_quotes() {
|
|
||||||
// Quasi-quoting expanders
|
|
||||||
syntax_expanders.insert(intern("quote_tokens"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_tokens));
|
|
||||||
syntax_expanders.insert(intern("quote_expr"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_expr));
|
|
||||||
syntax_expanders.insert(intern("quote_ty"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_ty));
|
|
||||||
syntax_expanders.insert(intern("quote_item"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_item));
|
|
||||||
syntax_expanders.insert(intern("quote_pat"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_pat));
|
|
||||||
syntax_expanders.insert(intern("quote_arm"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_arm));
|
|
||||||
syntax_expanders.insert(intern("quote_stmt"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_stmt));
|
|
||||||
syntax_expanders.insert(intern("quote_matcher"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_matcher));
|
|
||||||
syntax_expanders.insert(intern("quote_attr"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_attr));
|
|
||||||
syntax_expanders.insert(intern("quote_arg"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_arg));
|
|
||||||
syntax_expanders.insert(intern("quote_block"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_block));
|
|
||||||
syntax_expanders.insert(intern("quote_meta_item"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_meta_item));
|
|
||||||
syntax_expanders.insert(intern("quote_path"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::quote::expand_quote_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
syntax_expanders.insert(intern("line"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_line));
|
|
||||||
syntax_expanders.insert(intern("column"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_column));
|
|
||||||
syntax_expanders.insert(intern("file"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_file));
|
|
||||||
syntax_expanders.insert(intern("stringify"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_stringify));
|
|
||||||
syntax_expanders.insert(intern("include"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_include));
|
|
||||||
syntax_expanders.insert(intern("include_str"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_include_str));
|
|
||||||
syntax_expanders.insert(intern("include_bytes"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_include_bytes));
|
|
||||||
syntax_expanders.insert(intern("module_path"),
|
|
||||||
builtin_normal_expander(
|
|
||||||
ext::source_util::expand_mod));
|
|
||||||
syntax_expanders
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Resolver {
|
pub trait Resolver {
|
||||||
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool)
|
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
|
||||||
-> Vec<LoadedMacro>;
|
|
||||||
|
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
|
||||||
|
fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>);
|
||||||
|
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
|
||||||
|
|
||||||
|
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
|
||||||
|
fn resolve_invoc(&mut self, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LoadedMacro {
|
pub enum LoadedMacro {
|
||||||
|
@ -558,9 +480,31 @@ pub enum LoadedMacro {
|
||||||
|
|
||||||
pub struct DummyResolver;
|
pub struct DummyResolver;
|
||||||
impl Resolver for DummyResolver {
|
impl Resolver for DummyResolver {
|
||||||
fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<LoadedMacro> {
|
fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec<LoadedMacro> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
|
||||||
|
fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
|
||||||
|
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
|
||||||
|
|
||||||
|
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
|
||||||
|
fn resolve_invoc(&mut self, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ModuleData {
|
||||||
|
pub mod_path: Vec<ast::Ident>,
|
||||||
|
pub directory: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ExpansionData {
|
||||||
|
pub mark: Mark,
|
||||||
|
pub depth: usize,
|
||||||
|
pub backtrace: ExpnId,
|
||||||
|
pub module: Rc<ModuleData>,
|
||||||
|
pub in_block: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One of these is made during expansion and incrementally updated as we go;
|
/// One of these is made during expansion and incrementally updated as we go;
|
||||||
|
@ -569,16 +513,12 @@ impl Resolver for DummyResolver {
|
||||||
pub struct ExtCtxt<'a> {
|
pub struct ExtCtxt<'a> {
|
||||||
pub parse_sess: &'a parse::ParseSess,
|
pub parse_sess: &'a parse::ParseSess,
|
||||||
pub cfg: ast::CrateConfig,
|
pub cfg: ast::CrateConfig,
|
||||||
pub backtrace: ExpnId,
|
|
||||||
pub ecfg: expand::ExpansionConfig<'a>,
|
pub ecfg: expand::ExpansionConfig<'a>,
|
||||||
pub crate_root: Option<&'static str>,
|
pub crate_root: Option<&'static str>,
|
||||||
pub resolver: &'a mut Resolver,
|
pub resolver: &'a mut Resolver,
|
||||||
|
|
||||||
pub exported_macros: Vec<ast::MacroDef>,
|
pub exported_macros: Vec<ast::MacroDef>,
|
||||||
|
|
||||||
pub syntax_env: SyntaxEnv,
|
|
||||||
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
|
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
|
||||||
pub recursion_count: usize,
|
pub current_expansion: ExpansionData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExtCtxt<'a> {
|
impl<'a> ExtCtxt<'a> {
|
||||||
|
@ -587,16 +527,20 @@ impl<'a> ExtCtxt<'a> {
|
||||||
resolver: &'a mut Resolver)
|
resolver: &'a mut Resolver)
|
||||||
-> ExtCtxt<'a> {
|
-> ExtCtxt<'a> {
|
||||||
ExtCtxt {
|
ExtCtxt {
|
||||||
syntax_env: initial_syntax_expander_table(&ecfg),
|
|
||||||
parse_sess: parse_sess,
|
parse_sess: parse_sess,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
backtrace: NO_EXPANSION,
|
|
||||||
ecfg: ecfg,
|
ecfg: ecfg,
|
||||||
crate_root: None,
|
crate_root: None,
|
||||||
exported_macros: Vec::new(),
|
exported_macros: Vec::new(),
|
||||||
resolver: resolver,
|
resolver: resolver,
|
||||||
derive_modes: HashMap::new(),
|
derive_modes: HashMap::new(),
|
||||||
recursion_count: 0,
|
current_expansion: ExpansionData {
|
||||||
|
mark: Mark::root(),
|
||||||
|
depth: 0,
|
||||||
|
backtrace: NO_EXPANSION,
|
||||||
|
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
|
||||||
|
in_block: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,23 +553,22 @@ impl<'a> ExtCtxt<'a> {
|
||||||
-> parser::Parser<'a> {
|
-> parser::Parser<'a> {
|
||||||
parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg())
|
parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
|
pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
|
||||||
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
|
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
|
||||||
pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
|
pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
|
||||||
pub fn call_site(&self) -> Span {
|
pub fn call_site(&self) -> Span {
|
||||||
self.codemap().with_expn_info(self.backtrace, |ei| match ei {
|
self.codemap().with_expn_info(self.backtrace(), |ei| match ei {
|
||||||
Some(expn_info) => expn_info.call_site,
|
Some(expn_info) => expn_info.call_site,
|
||||||
None => self.bug("missing top span")
|
None => self.bug("missing top span")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn backtrace(&self) -> ExpnId { self.backtrace }
|
pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace }
|
||||||
|
|
||||||
/// Returns span for the macro which originally caused the current expansion to happen.
|
/// Returns span for the macro which originally caused the current expansion to happen.
|
||||||
///
|
///
|
||||||
/// Stops backtracing at include! boundary.
|
/// Stops backtracing at include! boundary.
|
||||||
pub fn expansion_cause(&self) -> Span {
|
pub fn expansion_cause(&self) -> Span {
|
||||||
let mut expn_id = self.backtrace;
|
let mut expn_id = self.backtrace();
|
||||||
let mut last_macro = None;
|
let mut last_macro = None;
|
||||||
loop {
|
loop {
|
||||||
if self.codemap().with_expn_info(expn_id, |info| {
|
if self.codemap().with_expn_info(expn_id, |info| {
|
||||||
|
@ -646,15 +589,15 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bt_push(&mut self, ei: ExpnInfo) {
|
pub fn bt_push(&mut self, ei: ExpnInfo) {
|
||||||
if self.recursion_count > self.ecfg.recursion_limit {
|
if self.current_expansion.depth > self.ecfg.recursion_limit {
|
||||||
self.span_fatal(ei.call_site,
|
self.span_fatal(ei.call_site,
|
||||||
&format!("recursion limit reached while expanding the macro `{}`",
|
&format!("recursion limit reached while expanding the macro `{}`",
|
||||||
ei.callee.name()));
|
ei.callee.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut call_site = ei.call_site;
|
let mut call_site = ei.call_site;
|
||||||
call_site.expn_id = self.backtrace;
|
call_site.expn_id = self.backtrace();
|
||||||
self.backtrace = self.codemap().record_expansion(ExpnInfo {
|
self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo {
|
||||||
call_site: call_site,
|
call_site: call_site,
|
||||||
callee: ei.callee
|
callee: ei.callee
|
||||||
});
|
});
|
||||||
|
@ -667,14 +610,11 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
if def.use_locally {
|
if def.use_locally {
|
||||||
let ext = macro_rules::compile(self, &def);
|
let ext = macro_rules::compile(self, &def);
|
||||||
self.syntax_env.insert(def.ident.name, ext);
|
self.resolver.add_macro(self.current_expansion.mark, def.ident, Rc::new(ext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_custom_derive(&mut self,
|
pub fn insert_custom_derive(&mut self, name: &str, ext: Box<MultiItemModifier>, sp: Span) {
|
||||||
name: &str,
|
|
||||||
ext: Box<MultiItemModifier>,
|
|
||||||
sp: Span) {
|
|
||||||
if !self.ecfg.enable_rustc_macro() {
|
if !self.ecfg.enable_rustc_macro() {
|
||||||
feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
|
feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
|
||||||
"rustc_macro",
|
"rustc_macro",
|
||||||
|
@ -685,8 +625,7 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
let name = token::intern_and_get_ident(name);
|
let name = token::intern_and_get_ident(name);
|
||||||
if self.derive_modes.insert(name.clone(), ext).is_some() {
|
if self.derive_modes.insert(name.clone(), ext).is_some() {
|
||||||
self.span_err(sp, &format!("cannot shadow existing derive mode `{}`",
|
self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
|
||||||
name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,20 +704,6 @@ impl<'a> ExtCtxt<'a> {
|
||||||
token::intern(st)
|
token::intern(st)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn suggest_macro_name(&mut self,
|
|
||||||
name: &str,
|
|
||||||
err: &mut DiagnosticBuilder<'a>) {
|
|
||||||
let names = &self.syntax_env.names;
|
|
||||||
if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) {
|
|
||||||
if suggestion != name {
|
|
||||||
err.help(&format!("did you mean `{}!`?", suggestion));
|
|
||||||
} else {
|
|
||||||
err.help(&format!("have you added the `#[macro_use]` on the \
|
|
||||||
module/import?"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
|
pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
|
||||||
if std_inject::no_core(&krate) {
|
if std_inject::no_core(&krate) {
|
||||||
self.crate_root = None;
|
self.crate_root = None;
|
||||||
|
@ -789,16 +714,16 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, extension) in user_exts {
|
for (name, extension) in user_exts {
|
||||||
self.syntax_env.insert(name, extension);
|
let ident = ast::Ident::with_empty_ctxt(name);
|
||||||
|
self.resolver.add_macro(Mark::root(), ident, Rc::new(extension));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.syntax_env.current_module = Module(0);
|
let mut module = ModuleData {
|
||||||
let mut paths = ModulePaths {
|
|
||||||
mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
|
mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
|
||||||
directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
|
directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
|
||||||
};
|
};
|
||||||
paths.directory.pop();
|
module.directory.pop();
|
||||||
self.syntax_env.module_data[0].paths = Rc::new(paths);
|
self.current_expansion.module = Rc::new(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,7 +734,7 @@ pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &st
|
||||||
-> Option<Spanned<(InternedString, ast::StrStyle)>> {
|
-> Option<Spanned<(InternedString, ast::StrStyle)>> {
|
||||||
// Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
|
// Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
|
||||||
let expr = expr.map(|mut expr| {
|
let expr = expr.map(|mut expr| {
|
||||||
expr.span.expn_id = cx.backtrace;
|
expr.span.expn_id = cx.backtrace();
|
||||||
expr
|
expr
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -884,104 +809,3 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
|
||||||
}
|
}
|
||||||
Some(es)
|
Some(es)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In order to have some notion of scoping for macros,
|
|
||||||
/// we want to implement the notion of a transformation
|
|
||||||
/// environment.
|
|
||||||
///
|
|
||||||
/// This environment maps Names to SyntaxExtensions.
|
|
||||||
pub struct SyntaxEnv {
|
|
||||||
module_data: Vec<ModuleData>,
|
|
||||||
pub current_module: Module,
|
|
||||||
|
|
||||||
/// All bang-style macro/extension names
|
|
||||||
/// encountered so far; to be used for diagnostics in resolve
|
|
||||||
pub names: HashSet<Name>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub struct Module(u32);
|
|
||||||
|
|
||||||
struct ModuleData {
|
|
||||||
parent: Module,
|
|
||||||
paths: Rc<ModulePaths>,
|
|
||||||
macros: HashMap<Name, Rc<SyntaxExtension>>,
|
|
||||||
macros_escape: bool,
|
|
||||||
in_block: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ModulePaths {
|
|
||||||
pub mod_path: Vec<ast::Ident>,
|
|
||||||
pub directory: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyntaxEnv {
|
|
||||||
fn new() -> SyntaxEnv {
|
|
||||||
let mut env = SyntaxEnv {
|
|
||||||
current_module: Module(0),
|
|
||||||
module_data: Vec::new(),
|
|
||||||
names: HashSet::new(),
|
|
||||||
};
|
|
||||||
let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() });
|
|
||||||
env.add_module(false, false, paths);
|
|
||||||
env
|
|
||||||
}
|
|
||||||
|
|
||||||
fn data(&self, module: Module) -> &ModuleData {
|
|
||||||
&self.module_data[module.0 as usize]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paths(&self) -> Rc<ModulePaths> {
|
|
||||||
self.data(self.current_module).paths.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn in_block(&self) -> bool {
|
|
||||||
self.data(self.current_module).in_block
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc<ModulePaths>)
|
|
||||||
-> Module {
|
|
||||||
let data = ModuleData {
|
|
||||||
parent: self.current_module,
|
|
||||||
paths: paths,
|
|
||||||
macros: HashMap::new(),
|
|
||||||
macros_escape: macros_escape,
|
|
||||||
in_block: in_block,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.module_data.push(data);
|
|
||||||
Module(self.module_data.len() as u32 - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find(&self, name: Name) -> Option<Rc<SyntaxExtension>> {
|
|
||||||
let mut module = self.current_module;
|
|
||||||
let mut module_data;
|
|
||||||
loop {
|
|
||||||
module_data = self.data(module);
|
|
||||||
if let Some(ext) = module_data.macros.get(&name) {
|
|
||||||
return Some(ext.clone());
|
|
||||||
}
|
|
||||||
if module == module_data.parent {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
module = module_data.parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, name: Name, ext: SyntaxExtension) {
|
|
||||||
if let NormalTT(..) = ext {
|
|
||||||
self.names.insert(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut module = self.current_module;
|
|
||||||
while self.data(module).macros_escape {
|
|
||||||
module = self.data(module).parent;
|
|
||||||
}
|
|
||||||
self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_crate_root(&mut self) -> bool {
|
|
||||||
self.current_module == Module(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use parse::token::{intern, keywords};
|
||||||
use ptr::P;
|
use ptr::P;
|
||||||
use tokenstream::TokenTree;
|
use tokenstream::TokenTree;
|
||||||
use util::small_vector::SmallVector;
|
use util::small_vector::SmallVector;
|
||||||
|
use visit::Visitor;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -32,7 +33,8 @@ use std::rc::Rc;
|
||||||
|
|
||||||
macro_rules! expansions {
|
macro_rules! expansions {
|
||||||
($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
|
($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
|
||||||
$(.$fold:ident)* $(lift .$fold_elt:ident)*;)*) => {
|
$(.$fold:ident)* $(lift .$fold_elt:ident)*,
|
||||||
|
$(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum ExpansionKind { OptExpr, $( $kind, )* }
|
pub enum ExpansionKind { OptExpr, $( $kind, )* }
|
||||||
pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
|
pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
|
||||||
|
@ -77,6 +79,17 @@ macro_rules! expansions {
|
||||||
}, )*)*
|
}, )*)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn visit_with<V: Visitor>(&self, visitor: &mut V) {
|
||||||
|
match *self {
|
||||||
|
Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
|
||||||
|
Expansion::OptExpr(None) => {}
|
||||||
|
$($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
|
||||||
|
$($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
|
||||||
|
visitor.$visit_elt(ast);
|
||||||
|
}, )*)*
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
|
@ -94,17 +107,17 @@ macro_rules! expansions {
|
||||||
}
|
}
|
||||||
|
|
||||||
expansions! {
|
expansions! {
|
||||||
Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr;
|
Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr, .visit_expr;
|
||||||
Pat: P<ast::Pat> [], "pattern", .make_pat, .fold_pat;
|
Pat: P<ast::Pat> [], "pattern", .make_pat, .fold_pat, .visit_pat;
|
||||||
Ty: P<ast::Ty> [], "type", .make_ty, .fold_ty;
|
Ty: P<ast::Ty> [], "type", .make_ty, .fold_ty, .visit_ty;
|
||||||
Stmts: SmallVector<ast::Stmt> [SmallVector, ast::Stmt],
|
Stmts: SmallVector<ast::Stmt> [SmallVector, ast::Stmt],
|
||||||
"statement", .make_stmts, lift .fold_stmt;
|
"statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
|
||||||
Items: SmallVector<P<ast::Item>> [SmallVector, P<ast::Item>],
|
Items: SmallVector<P<ast::Item>> [SmallVector, P<ast::Item>],
|
||||||
"item", .make_items, lift .fold_item;
|
"item", .make_items, lift .fold_item, lift .visit_item;
|
||||||
TraitItems: SmallVector<ast::TraitItem> [SmallVector, ast::TraitItem],
|
TraitItems: SmallVector<ast::TraitItem> [SmallVector, ast::TraitItem],
|
||||||
"trait item", .make_trait_items, lift .fold_trait_item;
|
"trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
|
||||||
ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
|
ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
|
||||||
"impl item", .make_impl_items, lift .fold_impl_item;
|
"impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExpansionKind {
|
impl ExpansionKind {
|
||||||
|
@ -127,15 +140,12 @@ impl ExpansionKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Invocation {
|
pub struct Invocation {
|
||||||
kind: InvocationKind,
|
pub kind: InvocationKind,
|
||||||
expansion_kind: ExpansionKind,
|
expansion_kind: ExpansionKind,
|
||||||
mark: Mark,
|
expansion_data: ExpansionData,
|
||||||
module: Module,
|
|
||||||
backtrace: ExpnId,
|
|
||||||
depth: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InvocationKind {
|
pub enum InvocationKind {
|
||||||
Bang {
|
Bang {
|
||||||
attrs: Vec<ast::Attribute>,
|
attrs: Vec<ast::Attribute>,
|
||||||
mac: ast::Mac,
|
mac: ast::Mac,
|
||||||
|
@ -148,6 +158,19 @@ enum InvocationKind {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Invocation {
|
||||||
|
fn span(&self) -> Span {
|
||||||
|
match self.kind {
|
||||||
|
InvocationKind::Bang { span, .. } => span,
|
||||||
|
InvocationKind::Attr { ref attr, .. } => attr.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark(&self) -> Mark {
|
||||||
|
self.expansion_data.mark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MacroExpander<'a, 'b:'a> {
|
pub struct MacroExpander<'a, 'b:'a> {
|
||||||
pub cx: &'a mut ExtCtxt<'b>,
|
pub cx: &'a mut ExtCtxt<'b>,
|
||||||
pub single_step: bool,
|
pub single_step: bool,
|
||||||
|
@ -170,7 +193,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
|
|
||||||
let items = Expansion::Items(SmallVector::many(krate.module.items));
|
let items = Expansion::Items(SmallVector::many(krate.module.items));
|
||||||
krate.module.items = self.expand(items).make_items().into();
|
krate.module.items = self.expand(items).make_items().into();
|
||||||
krate.exported_macros = self.cx.exported_macros.clone();
|
krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new());
|
||||||
|
|
||||||
if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
|
if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
|
||||||
self.cx.parse_sess.span_diagnostic.abort_if_errors();
|
self.cx.parse_sess.span_diagnostic.abort_if_errors();
|
||||||
|
@ -181,21 +204,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
|
|
||||||
// Fully expand all the invocations in `expansion`.
|
// Fully expand all the invocations in `expansion`.
|
||||||
fn expand(&mut self, expansion: Expansion) -> Expansion {
|
fn expand(&mut self, expansion: Expansion) -> Expansion {
|
||||||
self.cx.recursion_count = 0;
|
let orig_expansion_data = self.cx.current_expansion.clone();
|
||||||
|
self.cx.current_expansion.depth = 0;
|
||||||
|
|
||||||
let (expansion, mut invocations) = self.collect_invocations(expansion);
|
let (expansion, mut invocations) = self.collect_invocations(expansion);
|
||||||
invocations.reverse();
|
invocations.reverse();
|
||||||
|
|
||||||
let mut expansions = vec![vec![(0, expansion)]];
|
let mut expansions = vec![vec![(0, expansion)]];
|
||||||
while let Some(invoc) = invocations.pop() {
|
while let Some(invoc) = invocations.pop() {
|
||||||
let Invocation { mark, module, depth, backtrace, .. } = invoc;
|
let ExpansionData { depth, mark, .. } = invoc.expansion_data;
|
||||||
self.cx.syntax_env.current_module = module;
|
self.cx.current_expansion = invoc.expansion_data.clone();
|
||||||
self.cx.recursion_count = depth;
|
|
||||||
self.cx.backtrace = backtrace;
|
|
||||||
|
|
||||||
let expansion = self.expand_invoc(invoc);
|
let expansion = match self.cx.resolver.resolve_invoc(&invoc) {
|
||||||
|
Some(ext) => self.expand_invoc(invoc, ext),
|
||||||
|
None => invoc.expansion_kind.dummy(invoc.span()),
|
||||||
|
};
|
||||||
|
|
||||||
self.cx.syntax_env.current_module = module;
|
self.cx.current_expansion.depth = depth + 1;
|
||||||
self.cx.recursion_count = depth + 1;
|
|
||||||
let (expansion, new_invocations) = self.collect_invocations(expansion);
|
let (expansion, new_invocations) = self.collect_invocations(expansion);
|
||||||
|
|
||||||
if expansions.len() == depth {
|
if expansions.len() == depth {
|
||||||
|
@ -207,6 +232,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.cx.current_expansion = orig_expansion_data;
|
||||||
|
|
||||||
let mut placeholder_expander = PlaceholderExpander::new();
|
let mut placeholder_expander = PlaceholderExpander::new();
|
||||||
while let Some(expansions) = expansions.pop() {
|
while let Some(expansions) = expansions.pop() {
|
||||||
for (mark, expansion) in expansions.into_iter().rev() {
|
for (mark, expansion) in expansions.into_iter().rev() {
|
||||||
|
@ -233,30 +260,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
};
|
};
|
||||||
(expansion.fold_with(&mut collector), collector.invocations)
|
(expansion.fold_with(&mut collector), collector.invocations)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cx.cfg = crate_config;
|
self.cx.cfg = crate_config;
|
||||||
|
|
||||||
|
let mark = self.cx.current_expansion.mark;
|
||||||
|
self.cx.resolver.visit_expansion(mark, &result.0);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
|
fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
|
||||||
match invoc.kind {
|
match invoc.kind {
|
||||||
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
|
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
|
||||||
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc),
|
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion {
|
fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
|
||||||
let Invocation { expansion_kind: kind, .. } = invoc;
|
let Invocation { expansion_kind: kind, .. } = invoc;
|
||||||
let (attr, item) = match invoc.kind {
|
let (attr, item) = match invoc.kind {
|
||||||
InvocationKind::Attr { attr, item } => (attr, item),
|
InvocationKind::Attr { attr, item } => (attr, item),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let extension = match self.cx.syntax_env.find(intern(&attr.name())) {
|
|
||||||
Some(extension) => extension,
|
|
||||||
None => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
attr::mark_used(&attr);
|
attr::mark_used(&attr);
|
||||||
self.cx.bt_push(ExpnInfo {
|
self.cx.bt_push(ExpnInfo {
|
||||||
call_site: attr.span,
|
call_site: attr.span,
|
||||||
|
@ -267,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
match *extension {
|
match *ext {
|
||||||
MultiModifier(ref mac) => {
|
MultiModifier(ref mac) => {
|
||||||
let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
|
let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
|
||||||
kind.expect_from_annotatables(item)
|
kind.expect_from_annotatables(item)
|
||||||
|
@ -284,8 +308,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expand a macro invocation. Returns the result of expansion.
|
/// Expand a macro invocation. Returns the result of expansion.
|
||||||
fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion {
|
fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
|
||||||
let Invocation { mark, expansion_kind: kind, .. } = invoc;
|
let (mark, kind) = (invoc.mark(), invoc.expansion_kind);
|
||||||
let (attrs, mac, ident, span) = match invoc.kind {
|
let (attrs, mac, ident, span) = match invoc.kind {
|
||||||
InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
|
InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -306,19 +330,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let extname = path.segments[0].identifier.name;
|
let extname = path.segments[0].identifier.name;
|
||||||
let extension = if let Some(extension) = self.cx.syntax_env.find(extname) {
|
|
||||||
extension
|
|
||||||
} else {
|
|
||||||
let mut err =
|
|
||||||
self.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
|
|
||||||
self.cx.suggest_macro_name(&extname.as_str(), &mut err);
|
|
||||||
err.emit();
|
|
||||||
return kind.dummy(span);
|
|
||||||
};
|
|
||||||
|
|
||||||
let ident = ident.unwrap_or(keywords::Invalid.ident());
|
let ident = ident.unwrap_or(keywords::Invalid.ident());
|
||||||
let marked_tts = mark_tts(&tts, mark);
|
let marked_tts = mark_tts(&tts, mark);
|
||||||
let opt_expanded = match *extension {
|
let opt_expanded = match *ext {
|
||||||
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
|
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
|
||||||
if ident.name != keywords::Invalid.name() {
|
if ident.name != keywords::Invalid.name() {
|
||||||
let msg =
|
let msg =
|
||||||
|
@ -442,10 +456,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
self.invocations.push(Invocation {
|
self.invocations.push(Invocation {
|
||||||
kind: kind,
|
kind: kind,
|
||||||
expansion_kind: expansion_kind,
|
expansion_kind: expansion_kind,
|
||||||
mark: mark,
|
expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
|
||||||
module: self.cx.syntax_env.current_module,
|
|
||||||
backtrace: self.cx.backtrace,
|
|
||||||
depth: self.cx.recursion_count,
|
|
||||||
});
|
});
|
||||||
placeholder(expansion_kind, mark.as_u32())
|
placeholder(expansion_kind, mark.as_u32())
|
||||||
}
|
}
|
||||||
|
@ -462,50 +473,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If `item` is an attr invocation, remove and return the macro attribute.
|
// If `item` is an attr invocation, remove and return the macro attribute.
|
||||||
fn classify_item<T: HasAttrs>(&self, mut item: T) -> (T, Option<ast::Attribute>) {
|
fn classify_item<T: HasAttrs>(&mut self, mut item: T) -> (T, Option<ast::Attribute>) {
|
||||||
let mut attr = None;
|
let mut attr = None;
|
||||||
item = item.map_attrs(|mut attrs| {
|
item = item.map_attrs(|mut attrs| {
|
||||||
for i in 0..attrs.len() {
|
attr = self.cx.resolver.find_attr_invoc(&mut attrs);
|
||||||
if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
|
|
||||||
match *extension {
|
|
||||||
MultiModifier(..) | MultiDecorator(..) => {
|
|
||||||
attr = Some(attrs.remove(i));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attrs
|
attrs
|
||||||
});
|
});
|
||||||
(item, attr)
|
(item, attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// does this attribute list contain "macro_use" ?
|
|
||||||
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
|
||||||
for attr in attrs {
|
|
||||||
let mut is_use = attr.check_name("macro_use");
|
|
||||||
if attr.check_name("macro_escape") {
|
|
||||||
let msg = "macro_escape is a deprecated synonym for macro_use";
|
|
||||||
let mut err = self.cx.struct_span_warn(attr.span, msg);
|
|
||||||
is_use = true;
|
|
||||||
if let ast::AttrStyle::Inner = attr.node.style {
|
|
||||||
err.help("consider an outer attribute, #[macro_use] mod ...").emit();
|
|
||||||
} else {
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_use {
|
|
||||||
if !attr.is_word() {
|
|
||||||
self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
|
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
|
||||||
self.cfg.configure(node)
|
self.cfg.configure(node)
|
||||||
}
|
}
|
||||||
|
@ -574,11 +550,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
|
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
|
||||||
let paths = self.cx.syntax_env.paths();
|
let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true);
|
||||||
let module = self.cx.syntax_env.add_module(false, true, paths);
|
|
||||||
let orig_module = mem::replace(&mut self.cx.syntax_env.current_module, module);
|
|
||||||
let result = noop_fold_block(block, self);
|
let result = noop_fold_block(block, self);
|
||||||
self.cx.syntax_env.current_module = orig_module;
|
self.cx.current_expansion.in_block = orig_in_block;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,8 +587,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
|
ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
|
||||||
let mut paths = (*self.cx.syntax_env.paths()).clone();
|
let mut module = (*self.cx.current_expansion.module).clone();
|
||||||
paths.mod_path.push(item.ident);
|
module.mod_path.push(item.ident);
|
||||||
|
|
||||||
// Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
|
// Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
|
||||||
// In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
|
// In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
|
||||||
|
@ -622,28 +596,26 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||||
let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
|
let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
|
||||||
|
|
||||||
if inline_module {
|
if inline_module {
|
||||||
paths.directory.push(&*{
|
module.directory.push(&*{
|
||||||
::attr::first_attr_value_str_by_name(&item.attrs, "path")
|
::attr::first_attr_value_str_by_name(&item.attrs, "path")
|
||||||
.unwrap_or(item.ident.name.as_str())
|
.unwrap_or(item.ident.name.as_str())
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
paths.directory =
|
module.directory =
|
||||||
PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
|
PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
|
||||||
paths.directory.pop();
|
module.directory.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let macro_use = self.contains_macro_use(&item.attrs);
|
let orig_module =
|
||||||
let in_block = self.cx.syntax_env.in_block();
|
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
|
||||||
let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
|
|
||||||
let module = mem::replace(&mut self.cx.syntax_env.current_module, module);
|
|
||||||
let result = noop_fold_item(item, self);
|
let result = noop_fold_item(item, self);
|
||||||
self.cx.syntax_env.current_module = module;
|
self.cx.current_expansion.module = orig_module;
|
||||||
result
|
return result;
|
||||||
},
|
}
|
||||||
ast::ItemKind::ExternCrate(..) => {
|
ast::ItemKind::ExternCrate(..) => {
|
||||||
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
||||||
// crate root, because `$crate` won't work properly.
|
// crate root, because `$crate` won't work properly.
|
||||||
let is_crate_root = self.cx.syntax_env.is_crate_root();
|
let is_crate_root = self.cx.current_expansion.module.mod_path.len() == 1;
|
||||||
for def in self.cx.resolver.load_crate(&*item, is_crate_root) {
|
for def in self.cx.resolver.load_crate(&*item, is_crate_root) {
|
||||||
match def {
|
match def {
|
||||||
LoadedMacro::Def(def) => self.cx.insert_macro(def),
|
LoadedMacro::Def(def) => self.cx.insert_macro(def),
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub struct SyntaxContextData {
|
||||||
pub prev_ctxt: SyntaxContext,
|
pub prev_ctxt: SyntaxContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mark represents a unique id associated with a macro expansion.
|
/// A mark is a unique id associated with a macro expansion.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
|
||||||
pub struct Mark(u32);
|
pub struct Mark(u32);
|
||||||
|
|
||||||
|
@ -41,6 +41,11 @@ impl Mark {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
|
||||||
|
pub fn root() -> Self {
|
||||||
|
Mark(0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_u32(&self) -> u32 {
|
pub fn as_u32(&self) -> u32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
@ -56,8 +61,8 @@ impl HygieneData {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
HygieneData {
|
HygieneData {
|
||||||
syntax_contexts: vec![SyntaxContextData {
|
syntax_contexts: vec![SyntaxContextData {
|
||||||
outer_mark: Mark(0), // the null mark
|
outer_mark: Mark::root(),
|
||||||
prev_ctxt: SyntaxContext(0), // the empty context
|
prev_ctxt: SyntaxContext::empty(),
|
||||||
}],
|
}],
|
||||||
markings: HashMap::new(),
|
markings: HashMap::new(),
|
||||||
next_mark: Mark(1),
|
next_mark: Mark(1),
|
||||||
|
|
|
@ -74,8 +74,8 @@ pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTre
|
||||||
pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
|
pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
|
||||||
-> Box<base::MacResult+'static> {
|
-> Box<base::MacResult+'static> {
|
||||||
base::check_zero_tts(cx, sp, tts, "module_path!");
|
base::check_zero_tts(cx, sp, tts, "module_path!");
|
||||||
let paths = cx.syntax_env.paths();
|
let mod_path = &cx.current_expansion.module.mod_path;
|
||||||
let string = paths.mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
|
let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
|
||||||
|
|
||||||
base::MacEager::expr(cx.expr_str(
|
base::MacEager::expr(cx.expr_str(
|
||||||
sp,
|
sp,
|
||||||
|
|
|
@ -211,8 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||||
imported_from,
|
imported_from,
|
||||||
rhs);
|
rhs);
|
||||||
let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
|
let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
|
||||||
p.directory = cx.syntax_env.paths().directory.clone();
|
p.directory = cx.current_expansion.module.directory.clone();
|
||||||
p.restrictions = match cx.syntax_env.in_block() {
|
p.restrictions = match cx.current_expansion.in_block {
|
||||||
true => Restrictions::NO_NONINLINE_MOD,
|
true => Restrictions::NO_NONINLINE_MOD,
|
||||||
false => Restrictions::empty(),
|
false => Restrictions::empty(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,8 +11,7 @@
|
||||||
//! The compiler code necessary to implement the `#[derive]` extensions.
|
//! The compiler code necessary to implement the `#[derive]` extensions.
|
||||||
|
|
||||||
use syntax::ast::{self, MetaItem};
|
use syntax::ast::{self, MetaItem};
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
use syntax::ext::base::MultiModifier;
|
|
||||||
use syntax::ext::build::AstBuilder;
|
use syntax::ext::build::AstBuilder;
|
||||||
use syntax::feature_gate;
|
use syntax::feature_gate;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
|
@ -89,7 +88,7 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_derive(cx: &mut ExtCtxt,
|
pub fn expand_derive(cx: &mut ExtCtxt,
|
||||||
span: Span,
|
span: Span,
|
||||||
mitem: &MetaItem,
|
mitem: &MetaItem,
|
||||||
annotatable: Annotatable)
|
annotatable: Annotatable)
|
||||||
|
@ -243,10 +242,6 @@ fn expand_derive(cx: &mut ExtCtxt,
|
||||||
|
|
||||||
macro_rules! derive_traits {
|
macro_rules! derive_traits {
|
||||||
($( $name:expr => $func:path, )+) => {
|
($( $name:expr => $func:path, )+) => {
|
||||||
pub fn register_all(env: &mut SyntaxEnv) {
|
|
||||||
env.insert(intern("derive"), MultiModifier(Box::new(expand_derive)));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_builtin_trait(name: &str) -> bool {
|
pub fn is_builtin_trait(name: &str) -> bool {
|
||||||
match name {
|
match name {
|
||||||
$( $name )|+ => true,
|
$( $name )|+ => true,
|
||||||
|
|
|
@ -34,11 +34,6 @@ extern crate syntax_pos;
|
||||||
extern crate rustc_macro;
|
extern crate rustc_macro;
|
||||||
extern crate rustc_errors as errors;
|
extern crate rustc_errors as errors;
|
||||||
|
|
||||||
use syntax::ext::base::{MacroExpanderFn, NormalTT};
|
|
||||||
use syntax::ext::base::{SyntaxEnv, SyntaxExtension};
|
|
||||||
use syntax::parse::token::intern;
|
|
||||||
|
|
||||||
|
|
||||||
mod asm;
|
mod asm;
|
||||||
mod cfg;
|
mod cfg;
|
||||||
mod concat;
|
mod concat;
|
||||||
|
@ -53,28 +48,67 @@ pub mod rustc_macro_registrar;
|
||||||
// for custom_derive
|
// for custom_derive
|
||||||
pub mod deriving;
|
pub mod deriving;
|
||||||
|
|
||||||
pub fn register_builtins(env: &mut SyntaxEnv) {
|
use std::rc::Rc;
|
||||||
// utility function to simplify creating NormalTT syntax extensions
|
use syntax::ast;
|
||||||
fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
|
use syntax::ext::base::{MacroExpanderFn, MacroRulesTT, NormalTT, MultiModifier};
|
||||||
NormalTT(Box::new(f), None, false)
|
use syntax::ext::hygiene::Mark;
|
||||||
|
use syntax::parse::token::intern;
|
||||||
|
|
||||||
|
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
|
||||||
|
let mut register = |name, ext| {
|
||||||
|
resolver.add_macro(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
|
||||||
|
};
|
||||||
|
|
||||||
|
register("macro_rules", MacroRulesTT);
|
||||||
|
|
||||||
|
macro_rules! register {
|
||||||
|
($( $name:ident: $f:expr, )*) => { $(
|
||||||
|
register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false));
|
||||||
|
)* }
|
||||||
}
|
}
|
||||||
|
|
||||||
env.insert(intern("asm"), builtin_normal_expander(asm::expand_asm));
|
if enable_quotes {
|
||||||
env.insert(intern("cfg"), builtin_normal_expander(cfg::expand_cfg));
|
use syntax::ext::quote::*;
|
||||||
env.insert(intern("concat"),
|
register! {
|
||||||
builtin_normal_expander(concat::expand_syntax_ext));
|
quote_tokens: expand_quote_tokens,
|
||||||
env.insert(intern("concat_idents"),
|
quote_expr: expand_quote_expr,
|
||||||
builtin_normal_expander(concat_idents::expand_syntax_ext));
|
quote_ty: expand_quote_ty,
|
||||||
env.insert(intern("env"), builtin_normal_expander(env::expand_env));
|
quote_item: expand_quote_item,
|
||||||
env.insert(intern("option_env"),
|
quote_pat: expand_quote_pat,
|
||||||
builtin_normal_expander(env::expand_option_env));
|
quote_arm: expand_quote_arm,
|
||||||
env.insert(intern("format_args"),
|
quote_stmt: expand_quote_stmt,
|
||||||
// format_args uses `unstable` things internally.
|
quote_matcher: expand_quote_matcher,
|
||||||
NormalTT(Box::new(format::expand_format_args), None, true));
|
quote_attr: expand_quote_attr,
|
||||||
env.insert(intern("log_syntax"),
|
quote_arg: expand_quote_arg,
|
||||||
builtin_normal_expander(log_syntax::expand_syntax_ext));
|
quote_block: expand_quote_block,
|
||||||
env.insert(intern("trace_macros"),
|
quote_meta_item: expand_quote_meta_item,
|
||||||
builtin_normal_expander(trace_macros::expand_trace_macros));
|
quote_path: expand_quote_path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
deriving::register_all(env);
|
use syntax::ext::source_util::*;
|
||||||
|
register! {
|
||||||
|
line: expand_line,
|
||||||
|
column: expand_column,
|
||||||
|
file: expand_file,
|
||||||
|
stringify: expand_stringify,
|
||||||
|
include: expand_include,
|
||||||
|
include_str: expand_include_str,
|
||||||
|
include_bytes: expand_include_bytes,
|
||||||
|
module_path: expand_mod,
|
||||||
|
|
||||||
|
asm: asm::expand_asm,
|
||||||
|
cfg: cfg::expand_cfg,
|
||||||
|
concat: concat::expand_syntax_ext,
|
||||||
|
concat_idents: concat_idents::expand_syntax_ext,
|
||||||
|
env: env::expand_env,
|
||||||
|
option_env: env::expand_option_env,
|
||||||
|
log_syntax: log_syntax::expand_syntax_ext,
|
||||||
|
trace_macros: trace_macros::expand_trace_macros,
|
||||||
|
}
|
||||||
|
|
||||||
|
// format_args uses `unstable` things internally.
|
||||||
|
register("format_args", NormalTT(Box::new(format::expand_format_args), None, true));
|
||||||
|
|
||||||
|
register("derive", MultiModifier(Box::new(deriving::expand_derive)));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue