]> git.lizzy.rs Git - rust.git/commitdiff
Move macro resolution into `librustc_resolve`.
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Wed, 7 Sep 2016 23:21:59 +0000 (23:21 +0000)
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Tue, 13 Sep 2016 09:40:26 +0000 (09:40 +0000)
src/librustc/session/mod.rs
src/librustc_driver/driver.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs [new file with mode: 0644]
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/hygiene.rs
src/libsyntax/ext/source_util.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax_ext/deriving/mod.rs
src/libsyntax_ext/lib.rs

index 3477ec6f99af1afc8e34878b9ea83059bc3e5e5a..49686d63ee43b8d288275d48770cae3429d50467 100644 (file)
@@ -21,7 +21,7 @@
 use util::common::duration_to_secs_str;
 use mir::transform as mir_pass;
 
-use syntax::ast::{NodeId, Name};
+use syntax::ast::NodeId;
 use errors::{self, DiagnosticBuilder};
 use errors::emitter::{Emitter, EmitterWriter};
 use syntax::json::JsonEmitter;
@@ -39,7 +39,7 @@
 
 use std::path::{Path, PathBuf};
 use std::cell::{self, Cell, RefCell};
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
 use std::env;
 use std::ffi::CString;
 use std::rc::Rc;
@@ -96,10 +96,6 @@ pub struct Session {
     pub injected_allocator: 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
     /// the localized span for the macro body) to the
     /// 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),
         injected_allocator: Cell::new(None),
         injected_panic_runtime: Cell::new(None),
-        available_macros: RefCell::new(HashSet::new()),
         imported_macro_spans: RefCell::new(HashMap::new()),
         incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
         perf_stats: PerfStats {
index 0d9bf14f12fb210af506e994fccd0a0ef536b1d9..bf50c96034dd016d7300e900f1119f341265a038 100644 (file)
@@ -50,6 +50,7 @@
 use std::path::{Path, PathBuf};
 use syntax::{ast, diagnostics, visit};
 use syntax::attr;
+use syntax::ext::base::ExtCtxt;
 use syntax::parse::{self, PResult, token};
 use syntax::util::node_count::NodeCounter;
 use syntax;
@@ -643,6 +644,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
 
     let resolver_arenas = 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", || {
         // 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,
             should_test: sess.opts.test,
         };
-        let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess,
-                                                      krate.config.clone(),
-                                                      cfg,
-                                                      &mut resolver);
-        syntax_ext::register_builtins(&mut ecx.syntax_env);
+        let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver);
         let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
         if cfg!(windows) {
             env::set_var("PATH", &old_path);
         }
-        *sess.available_macros.borrow_mut() = ecx.syntax_env.names;
         ret
     });
 
index c1e6d93a970e5f350e1b8d6ec2f8d3b491a88121..6bf45ab8f6fa0a30e1bf348f16b1c6e1eb6b7bc5 100644 (file)
@@ -54,8 +54,6 @@
 use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
 use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
 
-use syntax::ext;
-use syntax::ext::base::LoadedMacro;
 use syntax::ext::hygiene::Mark;
 use syntax::ast::{self, FloatTy};
 use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
@@ -82,6 +80,7 @@
 // registered before they are used.
 mod diagnostics;
 
+mod macros;
 mod check_unused;
 mod build_reduced_graph;
 mod resolve_imports;
@@ -1073,6 +1072,10 @@ pub struct Resolver<'a> {
     new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
 
     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> {
@@ -1154,12 +1157,6 @@ fn definitions(&mut self) -> Option<&mut Definitions> {
     }
 }
 
-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 {
     fn name(&self) -> Name;
 }
@@ -1243,6 +1240,8 @@ pub fn new(session: &'a Session,
             new_import_semantics: session.features.borrow().item_like_imports,
 
             macro_loader: macro_loader,
+            macro_names: FnvHashSet(),
+            expansion_data: vec![macros::ExpansionData::default()],
         }
     }
 
@@ -2784,8 +2783,7 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
     }
 
     fn find_best_match(&mut self, name: &str) -> SuggestionType {
-        if let Some(macro_name) = self.session.available_macros
-                                  .borrow().iter().find(|n| n.as_str() == name) {
+        if let Some(macro_name) = self.macro_names.iter().find(|n| n.as_str() == name) {
             return SuggestionType::Macro(format!("{}!", macro_name));
         }
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
new file mode 100644 (file)
index 0000000..36f501a
--- /dev/null
@@ -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;
+    }
+}
index d0e11643c64c137f77616ca85911071f674f188b..d46e2a9872e8d6ccd71904717c3bb817bf561a57 100644 (file)
 
 pub use self::SyntaxExtension::*;
 
-use ast;
-use ast::{Name, PatKind};
+use ast::{self, Attribute, Name, PatKind};
 use attr::HasAttrs;
 use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
 use syntax_pos::{Span, ExpnId, NO_EXPANSION};
 use errors::DiagnosticBuilder;
-use ext;
-use ext::expand;
+use ext::expand::{self, Invocation, Expansion};
+use ext::hygiene::Mark;
 use ext::tt::macro_rules;
 use parse;
 use parse::parser;
 use parse::token;
-use parse::token::{InternedString, intern, str_to_ident};
+use parse::token::{InternedString, str_to_ident};
 use ptr::P;
 use std_inject;
 use util::small_vector::SmallVector;
-use util::lev_distance::find_best_match_for_name;
 use fold::Folder;
 use feature_gate;
 
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
 use std::path::PathBuf;
 use std::rc::Rc;
 use tokenstream;
@@ -44,7 +42,7 @@ pub enum Annotatable {
 }
 
 impl HasAttrs for Annotatable {
-    fn attrs(&self) -> &[ast::Attribute] {
+    fn attrs(&self) -> &[Attribute] {
         match *self {
             Annotatable::Item(ref item) => &item.attrs,
             Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
@@ -52,7 +50,7 @@ fn attrs(&self) -> &[ast::Attribute] {
         }
     }
 
-    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 {
             Annotatable::Item(item) => Annotatable::Item(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);
 
-/// 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 {
-    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool)
-                  -> Vec<LoadedMacro>;
+    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> 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 {
@@ -558,9 +480,31 @@ pub enum LoadedMacro {
 
 pub struct 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()
     }
+
+    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;
@@ -569,16 +513,12 @@ fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<LoadedMacro> {
 pub struct ExtCtxt<'a> {
     pub parse_sess: &'a parse::ParseSess,
     pub cfg: ast::CrateConfig,
-    pub backtrace: ExpnId,
     pub ecfg: expand::ExpansionConfig<'a>,
     pub crate_root: Option<&'static str>,
     pub resolver: &'a mut Resolver,
-
     pub exported_macros: Vec<ast::MacroDef>,
-
-    pub syntax_env: SyntaxEnv,
     pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
-    pub recursion_count: usize,
+    pub current_expansion: ExpansionData,
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -587,16 +527,20 @@ pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
                resolver: &'a mut Resolver)
                -> ExtCtxt<'a> {
         ExtCtxt {
-            syntax_env: initial_syntax_expander_table(&ecfg),
             parse_sess: parse_sess,
             cfg: cfg,
-            backtrace: NO_EXPANSION,
             ecfg: ecfg,
             crate_root: None,
             exported_macros: Vec::new(),
             resolver: resolver,
             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 @@ pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
         -> parser::Parser<'a> {
         parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg())
     }
-
     pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
     pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
     pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
     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,
             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.
     ///
     /// Stops backtracing at include! boundary.
     pub fn expansion_cause(&self) -> Span {
-        let mut expn_id = self.backtrace;
+        let mut expn_id = self.backtrace();
         let mut last_macro = None;
         loop {
             if self.codemap().with_expn_info(expn_id, |info| {
@@ -646,15 +589,15 @@ pub fn expansion_cause(&self) -> Span {
     }
 
     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,
                             &format!("recursion limit reached while expanding the macro `{}`",
                                     ei.callee.name()));
         }
 
         let mut call_site = ei.call_site;
-        call_site.expn_id = self.backtrace;
-        self.backtrace = self.codemap().record_expansion(ExpnInfo {
+        call_site.expn_id = self.backtrace();
+        self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo {
             call_site: call_site,
             callee: ei.callee
         });
@@ -667,14 +610,11 @@ pub fn insert_macro(&mut self, def: ast::MacroDef) {
         }
         if def.use_locally {
             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,
-                                name: &str,
-                                ext: Box<MultiItemModifier>,
-                                sp: Span) {
+    pub fn insert_custom_derive(&mut self, name: &str, ext: Box<MultiItemModifier>, sp: Span) {
         if !self.ecfg.enable_rustc_macro() {
             feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
                                            "rustc_macro",
@@ -685,8 +625,7 @@ pub fn insert_custom_derive(&mut self,
         }
         let name = token::intern_and_get_ident(name);
         if self.derive_modes.insert(name.clone(), ext).is_some() {
-            self.span_err(sp, &format!("cannot shadow existing derive mode `{}`",
-                                       name));
+            self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
         }
     }
 
@@ -765,20 +704,6 @@ pub fn name_of(&self, st: &str) -> ast::Name {
         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) {
         if std_inject::no_core(&krate) {
             self.crate_root = None;
@@ -789,16 +714,16 @@ pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::
         }
 
         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 paths = ModulePaths {
+        let mut module = ModuleData {
             mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
             directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
         };
-        paths.directory.pop();
-        self.syntax_env.module_data[0].paths = Rc::new(paths);
+        module.directory.pop();
+        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)>> {
     // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
     let expr = expr.map(|mut expr| {
-        expr.span.expn_id = cx.backtrace;
+        expr.span.expn_id = cx.backtrace();
         expr
     });
 
@@ -884,104 +809,3 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
     }
     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)
-    }
-}
index d8365391153bc1422748fb7430c79084b97e4e62..beb1687dfdc72578173cb23711ea52d05db27486 100644 (file)
@@ -25,6 +25,7 @@
 use ptr::P;
 use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
+use visit::Visitor;
 
 use std::mem;
 use std::path::PathBuf;
@@ -32,7 +33,8 @@
 
 macro_rules! expansions {
     ($($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)]
         pub enum ExpansionKind { OptExpr, $( $kind, )*  }
         pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
@@ -77,6 +79,17 @@ pub fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
                     }, )*)*
                 }
             }
+
+            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> {
@@ -94,17 +107,17 @@ fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
 }
 
 expansions! {
-    Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr;
-    Pat: P<ast::Pat>   [], "pattern",    .make_pat,  .fold_pat;
-    Ty: P<ast::Ty>     [], "type",       .make_ty,   .fold_ty;
+    Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr, .visit_expr;
+    Pat: P<ast::Pat>   [], "pattern",    .make_pat,  .fold_pat,  .visit_pat;
+    Ty: P<ast::Ty>     [], "type",       .make_ty,   .fold_ty,   .visit_ty;
     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>],
-        "item",       .make_items,       lift .fold_item;
+        "item",       .make_items,       lift .fold_item, lift .visit_item;
     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],
-        "impl item",  .make_impl_items,  lift .fold_impl_item;
+        "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
 }
 
 impl ExpansionKind {
@@ -127,15 +140,12 @@ fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I)
 }
 
 pub struct Invocation {
-    kind: InvocationKind,
+    pub kind: InvocationKind,
     expansion_kind: ExpansionKind,
-    mark: Mark,
-    module: Module,
-    backtrace: ExpnId,
-    depth: usize,
+    expansion_data: ExpansionData,
 }
 
-enum InvocationKind {
+pub enum InvocationKind {
     Bang {
         attrs: Vec<ast::Attribute>,
         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 cx: &'a mut ExtCtxt<'b>,
     pub single_step: bool,
@@ -170,7 +193,7 @@ fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
 
         let items = Expansion::Items(SmallVector::many(krate.module.items));
         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 {
             self.cx.parse_sess.span_diagnostic.abort_if_errors();
@@ -181,21 +204,23 @@ fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
 
     // Fully expand all the invocations in `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);
         invocations.reverse();
 
         let mut expansions = vec![vec![(0, expansion)]];
         while let Some(invoc) = invocations.pop() {
-            let Invocation { mark, module, depth, backtrace, .. } = invoc;
-            self.cx.syntax_env.current_module = module;
-            self.cx.recursion_count = depth;
-            self.cx.backtrace = backtrace;
+            let ExpansionData { depth, mark, .. } = invoc.expansion_data;
+            self.cx.current_expansion = invoc.expansion_data.clone();
 
-            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.recursion_count = depth + 1;
+            self.cx.current_expansion.depth = depth + 1;
             let (expansion, new_invocations) = self.collect_invocations(expansion);
 
             if expansions.len() == depth {
@@ -207,6 +232,8 @@ fn expand(&mut self, expansion: Expansion) -> Expansion {
             }
         }
 
+        self.cx.current_expansion = orig_expansion_data;
+
         let mut placeholder_expander = PlaceholderExpander::new();
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
@@ -233,30 +260,27 @@ fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invoc
             };
             (expansion.fold_with(&mut collector), collector.invocations)
         };
-
         self.cx.cfg = crate_config;
+
+        let mark = self.cx.current_expansion.mark;
+        self.cx.resolver.visit_expansion(mark, &result.0);
         result
     }
 
-    fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
+    fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
         match invoc.kind {
-            InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
-            InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc),
+            InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
+            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 (attr, item) = match invoc.kind {
             InvocationKind::Attr { attr, item } => (attr, item),
             _ => unreachable!(),
         };
 
-        let extension = match self.cx.syntax_env.find(intern(&attr.name())) {
-            Some(extension) => extension,
-            None => unreachable!(),
-        };
-
         attr::mark_used(&attr);
         self.cx.bt_push(ExpnInfo {
             call_site: attr.span,
@@ -267,7 +291,7 @@ fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion {
             }
         });
 
-        match *extension {
+        match *ext {
             MultiModifier(ref mac) => {
                 let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
                 kind.expect_from_annotatables(item)
@@ -284,8 +308,8 @@ fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion {
     }
 
     /// Expand a macro invocation. Returns the result of expansion.
-    fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion {
-        let Invocation { mark, expansion_kind: kind, .. } = invoc;
+    fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
+        let (mark, kind) = (invoc.mark(), invoc.expansion_kind);
         let (attrs, mac, ident, span) = match invoc.kind {
             InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
             _ => unreachable!(),
@@ -306,19 +330,9 @@ fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion {
         }
 
         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 marked_tts = mark_tts(&tts, mark);
-        let opt_expanded = match *extension {
+        let opt_expanded = match *ext {
             NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                 if ident.name != keywords::Invalid.name() {
                     let msg =
@@ -442,10 +456,7 @@ fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Ex
         self.invocations.push(Invocation {
             kind: kind,
             expansion_kind: expansion_kind,
-            mark: mark,
-            module: self.cx.syntax_env.current_module,
-            backtrace: self.cx.backtrace,
-            depth: self.cx.recursion_count,
+            expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
         });
         placeholder(expansion_kind, mark.as_u32())
     }
@@ -462,50 +473,15 @@ fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: Expans
     }
 
     // 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;
         item = item.map_attrs(|mut attrs| {
-            for i in 0..attrs.len() {
-                if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
-                    match *extension {
-                        MultiModifier(..) | MultiDecorator(..) => {
-                            attr = Some(attrs.remove(i));
-                            break;
-                        }
-                        _ => {}
-                    }
-                }
-            }
+            attr = self.cx.resolver.find_attr_invoc(&mut attrs);
             attrs
         });
         (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> {
         self.cfg.configure(node)
     }
@@ -574,11 +550,9 @@ fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
     }
 
     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
-        let paths = self.cx.syntax_env.paths();
-        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 orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true);
         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
     }
 
@@ -613,8 +587,8 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                 })
             }
             ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
-                let mut paths = (*self.cx.syntax_env.paths()).clone();
-                paths.mod_path.push(item.ident);
+                let mut module = (*self.cx.current_expansion.module).clone();
+                module.mod_path.push(item.ident);
 
                 // 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`).
@@ -622,28 +596,26 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                 let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
 
                 if inline_module {
-                    paths.directory.push(&*{
+                    module.directory.push(&*{
                         ::attr::first_attr_value_str_by_name(&item.attrs, "path")
                             .unwrap_or(item.ident.name.as_str())
                     });
                 } else {
-                    paths.directory =
+                    module.directory =
                         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 in_block = self.cx.syntax_env.in_block();
-                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 orig_module =
+                    mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
                 let result = noop_fold_item(item, self);
-                self.cx.syntax_env.current_module = module;
-                result
-            },
+                self.cx.current_expansion.module = orig_module;
+                return result;
+            }
             ast::ItemKind::ExternCrate(..) => {
                 // We need to error on `#[macro_use] extern crate` when it isn't at the
                 // 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) {
                     match def {
                         LoadedMacro::Def(def) => self.cx.insert_macro(def),
index 27e8eab62e11482aaa9785943dd8f8d558567bd8..34126fac4ac784c888a282a0e947ba8685998400 100644 (file)
@@ -29,7 +29,7 @@ pub struct SyntaxContextData {
     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)]
 pub struct Mark(u32);
 
@@ -41,6 +41,11 @@ pub fn fresh() -> Self {
         })
     }
 
+    /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
+    pub fn root() -> Self {
+        Mark(0)
+    }
+
     pub fn as_u32(&self) -> u32 {
         self.0
     }
@@ -56,8 +61,8 @@ impl HygieneData {
     fn new() -> Self {
         HygieneData {
             syntax_contexts: vec![SyntaxContextData {
-                outer_mark: Mark(0), // the null mark
-                prev_ctxt: SyntaxContext(0), // the empty context
+                outer_mark: Mark::root(),
+                prev_ctxt: SyntaxContext::empty(),
             }],
             markings: HashMap::new(),
             next_mark: Mark(1),
index 105b2261117385bbaf258e771ccdb49df7d82903..e75e41d0c2d4bf61238d35b61ebe895d824fac8a 100644 (file)
@@ -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])
                   -> Box<base::MacResult+'static> {
     base::check_zero_tts(cx, sp, tts, "module_path!");
-    let paths = cx.syntax_env.paths();
-    let string = paths.mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
+    let mod_path = &cx.current_expansion.module.mod_path;
+    let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
 
     base::MacEager::expr(cx.expr_str(
             sp,
index ed80ec9cbc49e1d5781ebfccf54e67f6420e41f7..51ef45b97be6f336aef5e6e510b15d57b62f6887 100644 (file)
@@ -211,8 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                                            imported_from,
                                            rhs);
                 let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
-                p.directory = cx.syntax_env.paths().directory.clone();
-                p.restrictions = match cx.syntax_env.in_block() {
+                p.directory = cx.current_expansion.module.directory.clone();
+                p.restrictions = match cx.current_expansion.in_block {
                     true => Restrictions::NO_NONINLINE_MOD,
                     false => Restrictions::empty(),
                 };
index fcbce3638908249fd5ecb6135ffb65afe4ba983b..6162beb80eccc7d9eb53c92cabd9c8e7b5f9e251 100644 (file)
@@ -11,8 +11,7 @@
 //! The compiler code necessary to implement the `#[derive]` extensions.
 
 use syntax::ast::{self, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
-use syntax::ext::base::MultiModifier;
+use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
 use syntax::feature_gate;
 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,
                  mitem: &MetaItem,
                  annotatable: Annotatable)
@@ -243,10 +242,6 @@ fn expand_derive(cx: &mut ExtCtxt,
 
 macro_rules! derive_traits {
     ($( $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 {
             match name {
                 $( $name )|+ => true,
index 2065d92fd6ed7fbc86cd5b79324d984971857217..3a6212e5445ce6d687940e3e36a1ea37369d0be6 100644 (file)
 extern crate rustc_macro;
 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 cfg;
 mod concat;
 // for custom_derive
 pub mod deriving;
 
-pub fn register_builtins(env: &mut SyntaxEnv) {
-    // utility function to simplify creating NormalTT syntax extensions
-    fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
-        NormalTT(Box::new(f), None, false)
+use std::rc::Rc;
+use syntax::ast;
+use syntax::ext::base::{MacroExpanderFn, MacroRulesTT, NormalTT, MultiModifier};
+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));
-    env.insert(intern("cfg"), builtin_normal_expander(cfg::expand_cfg));
-    env.insert(intern("concat"),
-               builtin_normal_expander(concat::expand_syntax_ext));
-    env.insert(intern("concat_idents"),
-               builtin_normal_expander(concat_idents::expand_syntax_ext));
-    env.insert(intern("env"), builtin_normal_expander(env::expand_env));
-    env.insert(intern("option_env"),
-               builtin_normal_expander(env::expand_option_env));
-    env.insert(intern("format_args"),
-               // format_args uses `unstable` things internally.
-               NormalTT(Box::new(format::expand_format_args), None, true));
-    env.insert(intern("log_syntax"),
-               builtin_normal_expander(log_syntax::expand_syntax_ext));
-    env.insert(intern("trace_macros"),
-               builtin_normal_expander(trace_macros::expand_trace_macros));
-
-    deriving::register_all(env);
+    if enable_quotes {
+        use syntax::ext::quote::*;
+        register! {
+            quote_tokens: expand_quote_tokens,
+            quote_expr: expand_quote_expr,
+            quote_ty: expand_quote_ty,
+            quote_item: expand_quote_item,
+            quote_pat: expand_quote_pat,
+            quote_arm: expand_quote_arm,
+            quote_stmt: expand_quote_stmt,
+            quote_matcher: expand_quote_matcher,
+            quote_attr: expand_quote_attr,
+            quote_arg: expand_quote_arg,
+            quote_block: expand_quote_block,
+            quote_meta_item: expand_quote_meta_item,
+            quote_path: expand_quote_path,
+        }
+    }
+
+    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)));
 }