From 79fa9eb643cfbb807813afed6f825f6654ee7662 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 1 Sep 2016 06:44:54 +0000 Subject: [PATCH] Refactor `SyntaxEnv`. --- src/libsyntax/ext/base.rs | 169 ++++++++++++++++------------ src/libsyntax/ext/expand.rs | 64 ++++------- src/libsyntax/ext/source_util.rs | 8 +- src/libsyntax/ext/tt/macro_rules.rs | 4 +- 4 files changed, 119 insertions(+), 126 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 769a5af0262..fe2806891b8 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -24,6 +24,7 @@ use parse::token; use parse::token::{InternedString, intern, 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; @@ -463,19 +464,6 @@ pub enum SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); -pub struct BlockInfo { - /// Should macros escape from this scope? - pub macros_escape: bool, -} - -impl BlockInfo { - pub fn new() -> BlockInfo { - BlockInfo { - macros_escape: false, - } - } -} - /// The base map of methods for expanding syntax extension /// AST nodes into full ASTs fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) @@ -586,15 +574,11 @@ pub struct ExtCtxt<'a> { pub crate_root: Option<&'static str>, pub loader: &'a mut MacroLoader, - pub mod_path: Vec , pub exported_macros: Vec, pub syntax_env: SyntaxEnv, pub derive_modes: HashMap>, pub recursion_count: usize, - - pub directory: PathBuf, - pub in_block: bool, } impl<'a> ExtCtxt<'a> { @@ -602,22 +586,17 @@ pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, ecfg: expand::ExpansionConfig<'a>, loader: &'a mut MacroLoader) -> ExtCtxt<'a> { - let env = initial_syntax_expander_table(&ecfg); ExtCtxt { + syntax_env: initial_syntax_expander_table(&ecfg), parse_sess: parse_sess, cfg: cfg, backtrace: NO_EXPANSION, - mod_path: Vec::new(), ecfg: ecfg, crate_root: None, exported_macros: Vec::new(), loader: loader, - syntax_env: env, derive_modes: HashMap::new(), recursion_count: 0, - - directory: PathBuf::new(), - in_block: false, } } @@ -666,14 +645,6 @@ pub fn expansion_cause(&self) -> Span { last_macro.expect("missing expansion backtrace") } - pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); } - pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); } - pub fn mod_path(&self) -> Vec { - let mut v = Vec::new(); - v.push(token::str_to_ident(&self.ecfg.crate_name)); - v.extend(self.mod_path.iter().cloned()); - return v; - } pub fn bt_push(&mut self, ei: ExpnInfo) { self.recursion_count += 1; if self.recursion_count > self.ecfg.recursion_limit { @@ -818,6 +789,30 @@ pub fn suggest_macro_name(&mut self, } } } + + pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) { + if std_inject::no_core(&krate) { + self.crate_root = None; + } else if std_inject::no_std(&krate) { + self.crate_root = Some("core"); + } else { + self.crate_root = Some("std"); + } + + // User extensions must be added before expander.load_macros is called, + // so that macros from external crates shadow user defined extensions. + for (name, extension) in user_exts { + self.syntax_env.insert(name, extension); + } + + self.syntax_env.current_module = Module(0); + let mut paths = ModulePaths { + 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); + } } /// Extract a string literal from the macro expanded version of `expr`, @@ -904,79 +899,103 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt, /// /// This environment maps Names to SyntaxExtensions. pub struct SyntaxEnv { - chain: Vec, + module_data: Vec, + current_module: Module, + /// All bang-style macro/extension names /// encountered so far; to be used for diagnostics in resolve pub names: HashSet, } -// impl question: how to implement it? Initially, the -// env will contain only macros, so it might be painful -// to add an empty frame for every context. Let's just -// get it working, first.... +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Module(u32); -// NB! the mutability of the underlying maps means that -// if expansion is out-of-order, a deeper scope may be -// able to refer to a macro that was added to an enclosing -// scope lexically later than the deeper scope. +struct ModuleData { + parent: Module, + paths: Rc, + macros: HashMap>, + macros_escape: bool, + in_block: bool, +} -struct MapChainFrame { - info: BlockInfo, - map: HashMap>, +#[derive(Clone)] +pub struct ModulePaths { + pub mod_path: Vec, + pub directory: PathBuf, } impl SyntaxEnv { fn new() -> SyntaxEnv { - let mut map = SyntaxEnv { chain: Vec::new() , names: HashSet::new()}; - map.push_frame(); - map + 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 } - pub fn push_frame(&mut self) { - self.chain.push(MapChainFrame { - info: BlockInfo::new(), - map: HashMap::new(), - }); + fn data(&self, module: Module) -> &ModuleData { + &self.module_data[module.0 as usize] } - pub fn pop_frame(&mut self) { - assert!(self.chain.len() > 1, "too many pops on MapChain!"); - self.chain.pop(); + pub fn set_current_module(&mut self, module: Module) -> Module { + ::std::mem::replace(&mut self.current_module, module) } - fn find_escape_frame(&mut self) -> &mut MapChainFrame { - for (i, frame) in self.chain.iter_mut().enumerate().rev() { - if !frame.info.macros_escape || i == 0 { - return frame - } - } - unreachable!() + pub fn paths(&self) -> Rc { + self.data(self.current_module).paths.clone() + } + + pub fn in_block(&self) -> bool { + self.data(self.current_module).in_block } - pub fn find(&self, k: Name) -> Option> { - for frame in self.chain.iter().rev() { - if let Some(v) = frame.map.get(&k) { - return Some(v.clone()); + pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc) + -> 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> { + 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; } - None } - pub fn insert(&mut self, k: Name, v: SyntaxExtension) { - if let NormalTT(..) = v { - self.names.insert(k); + pub fn insert(&mut self, name: Name, ext: SyntaxExtension) { + if let NormalTT(..) = ext { + self.names.insert(name); } - self.find_escape_frame().map.insert(k, Rc::new(v)); - } - pub fn info(&mut self) -> &mut BlockInfo { - let last_chain_index = self.chain.len() - 1; - &mut self.chain[last_chain_index].info + 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 { // The first frame is pushed in `SyntaxEnv::new()` and the second frame is // pushed when folding the crate root pseudo-module (c.f. noop_fold_crate). - self.chain.len() <= 2 + self.current_module.0 <= 1 } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d3f8618aace..a713196032c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -26,9 +26,9 @@ use util::small_vector::SmallVector; use visit; use visit::Visitor; -use std_inject; use std::path::PathBuf; +use std::rc::Rc; macro_rules! expansions { ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident, @@ -467,24 +467,9 @@ fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { } false } - - fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T { - self.cx.syntax_env.push_frame(); - self.cx.syntax_env.info().macros_escape = macros_escape; - let result = f(self); - self.cx.syntax_env.pop_frame(); - result - } } impl<'a, 'b> Folder for MacroExpander<'a, 'b> { - fn fold_crate(&mut self, c: Crate) -> Crate { - let mut directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(c.span)); - directory.pop(); - self.cx.directory = directory; - noop_fold_crate(c, self) - } - fn fold_expr(&mut self, expr: P) -> P { let expr = expr.unwrap(); if let ast::ExprKind::Mac(mac) = expr.node { @@ -542,9 +527,12 @@ fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { } fn fold_block(&mut self, block: P) -> P { - let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true); - let result = self.with_exts_frame(false, |this| noop_fold_block(block, this)); - self.cx.in_block = was_in_block; + let paths = self.cx.syntax_env.paths(); + let module = self.cx.syntax_env.add_module(false, true, paths); + let orig_module = self.cx.syntax_env.set_current_module(module); + + let result = noop_fold_block(block, self); + self.cx.syntax_env.set_current_module(orig_module); result } @@ -578,26 +566,27 @@ fn fold_item(&mut self, item: P) -> SmallVector> { }) } ast::ItemKind::Mod(ast::Mod { inner, .. }) => { - self.cx.mod_push(item.ident); - let macro_use = self.contains_macro_use(&item.attrs); - - let directory = self.cx.directory.clone(); + let mut paths = (*self.cx.syntax_env.paths()).clone(); + paths.mod_path.push(item.ident); if item.span.contains(inner) { - self.cx.directory.push(&*{ + paths.directory.push(&*{ ::attr::first_attr_value_str_by_name(&item.attrs, "path") .unwrap_or(item.ident.name.as_str()) }); } else { - self.cx.directory = match inner { + paths.directory = match inner { syntax_pos::DUMMY_SP => PathBuf::new(), _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)), }; - self.cx.directory.pop(); + paths.directory.pop(); } - let result = self.with_exts_frame(macro_use, |this| noop_fold_item(item, this)); - self.cx.directory = directory; - self.cx.mod_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 = self.cx.syntax_env.set_current_module(module); + let result = noop_fold_item(item, self); + self.cx.syntax_env.set_current_module(module); result }, _ => noop_fold_item(item, self), @@ -744,19 +733,7 @@ pub fn expand_crate(cx: &mut ExtCtxt, pub fn expand_crate_with_expander(expander: &mut MacroExpander, user_exts: Vec, mut c: Crate) -> Crate { - if std_inject::no_core(&c) { - expander.cx.crate_root = None; - } else if std_inject::no_std(&c) { - expander.cx.crate_root = Some("core"); - } else { - expander.cx.crate_root = Some("std"); - } - - // User extensions must be added before expander.load_macros is called, - // so that macros from external crates shadow user defined extensions. - for (name, extension) in user_exts { - expander.cx.syntax_env.insert(name, extension); - } + expander.cx.initialize(user_exts, &c); let items = Expansion::Items(SmallVector::many(c.module.items)); let configured = items.fold_with(&mut expander.strip_unconfigured()); @@ -765,12 +742,11 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander, let err_count = expander.cx.parse_sess.span_diagnostic.err_count(); let mut ret = expander.fold_crate(c); - ret.exported_macros = expander.cx.exported_macros.clone(); - if expander.cx.parse_sess.span_diagnostic.err_count() > err_count { expander.cx.parse_sess.span_diagnostic.abort_if_errors(); } + ret.exported_macros = expander.cx.exported_macros.clone(); ret } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 97cb09991ec..105b2261117 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -74,11 +74,9 @@ 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::check_zero_tts(cx, sp, tts, "module_path!"); - let string = cx.mod_path() - .iter() - .map(|x| x.to_string()) - .collect::>() - .join("::"); + let paths = cx.syntax_env.paths(); + let string = paths.mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); + base::MacEager::expr(cx.expr_str( sp, token::intern_and_get_ident(&string[..]))) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index a4be84dfbf0..ed80ec9cbc4 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -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.directory.clone(); - p.restrictions = match cx.in_block { + p.directory = cx.syntax_env.paths().directory.clone(); + p.restrictions = match cx.syntax_env.in_block() { true => Restrictions::NO_NONINLINE_MOD, false => Restrictions::empty(), }; -- GitLab