Refactor `SyntaxEnv`.
This commit is contained in:
parent
4ed2c0ea7c
commit
79fa9eb643
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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[..])))
|
||||
|
|
|
@ -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(),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue