Refactor `SyntaxEnv`.

This commit is contained in:
Jeffrey Seyfried 2016-09-01 06:44:54 +00:00
parent 4ed2c0ea7c
commit 79fa9eb643
4 changed files with 120 additions and 127 deletions

View File

@ -24,6 +24,7 @@ use parse::parser;
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<ast::Ident> ,
pub exported_macros: Vec<ast::MacroDef>,
pub syntax_env: SyntaxEnv,
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
pub recursion_count: usize,
pub directory: PathBuf,
pub in_block: bool,
}
impl<'a> ExtCtxt<'a> {
@ -602,22 +586,17 @@ impl<'a> ExtCtxt<'a> {
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 @@ impl<'a> ExtCtxt<'a> {
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<ast::Ident> {
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 @@ impl<'a> ExtCtxt<'a> {
}
}
}
pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, 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<MapChainFrame>,
module_data: Vec<ModuleData>,
current_module: Module,
/// All bang-style macro/extension names
/// encountered so far; to be used for diagnostics in resolve
pub names: HashSet<Name>,
}
// 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<ModulePaths>,
macros: HashMap<Name, Rc<SyntaxExtension>>,
macros_escape: bool,
in_block: bool,
}
struct MapChainFrame {
info: BlockInfo,
map: HashMap<Name, Rc<SyntaxExtension>>,
#[derive(Clone)]
pub struct ModulePaths {
pub mod_path: Vec<ast::Ident>,
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
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());
}
}
unreachable!()
}
pub fn find(&self, k: Name) -> Option<Rc<SyntaxExtension>> {
for frame in self.chain.iter().rev() {
if let Some(v) = frame.map.get(&k) {
return Some(v.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
}
}

View File

@ -26,9 +26,9 @@ use tokenstream::TokenTree;
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 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
false
}
fn with_exts_frame<T, F: FnOnce(&mut Self) -> 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<ast::Expr>) -> P<ast::Expr> {
let expr = expr.unwrap();
if let ast::ExprKind::Mac(mac) = expr.node {
@ -542,9 +527,12 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
}
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
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 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
})
}
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<NamedSyntaxExtension>,
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
}

View File

@ -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::MacResult+'static> {
base::check_zero_tts(cx, sp, tts, "module_path!");
let string = cx.mod_path()
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("::");
let paths = cx.syntax_env.paths();
let string = paths.mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
base::MacEager::expr(cx.expr_str(
sp,
token::intern_and_get_ident(&string[..])))

View 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.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(),
};