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
}
}