Skip to content

Commit 79fa9eb

Browse files
committed
Refactor SyntaxEnv.
1 parent 4ed2c0e commit 79fa9eb

File tree

4 files changed

+119
-126
lines changed

4 files changed

+119
-126
lines changed

src/libsyntax/ext/base.rs

Lines changed: 94 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use parse::parser;
2424
use parse::token;
2525
use parse::token::{InternedString, intern, str_to_ident};
2626
use ptr::P;
27+
use std_inject;
2728
use util::small_vector::SmallVector;
2829
use util::lev_distance::find_best_match_for_name;
2930
use fold::Folder;
@@ -463,19 +464,6 @@ pub enum SyntaxExtension {
463464

464465
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
465466

466-
pub struct BlockInfo {
467-
/// Should macros escape from this scope?
468-
pub macros_escape: bool,
469-
}
470-
471-
impl BlockInfo {
472-
pub fn new() -> BlockInfo {
473-
BlockInfo {
474-
macros_escape: false,
475-
}
476-
}
477-
}
478-
479467
/// The base map of methods for expanding syntax extension
480468
/// AST nodes into full ASTs
481469
fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
@@ -586,38 +574,29 @@ pub struct ExtCtxt<'a> {
586574
pub crate_root: Option<&'static str>,
587575
pub loader: &'a mut MacroLoader,
588576

589-
pub mod_path: Vec<ast::Ident> ,
590577
pub exported_macros: Vec<ast::MacroDef>,
591578

592579
pub syntax_env: SyntaxEnv,
593580
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
594581
pub recursion_count: usize,
595-
596-
pub directory: PathBuf,
597-
pub in_block: bool,
598582
}
599583

600584
impl<'a> ExtCtxt<'a> {
601585
pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
602586
ecfg: expand::ExpansionConfig<'a>,
603587
loader: &'a mut MacroLoader)
604588
-> ExtCtxt<'a> {
605-
let env = initial_syntax_expander_table(&ecfg);
606589
ExtCtxt {
590+
syntax_env: initial_syntax_expander_table(&ecfg),
607591
parse_sess: parse_sess,
608592
cfg: cfg,
609593
backtrace: NO_EXPANSION,
610-
mod_path: Vec::new(),
611594
ecfg: ecfg,
612595
crate_root: None,
613596
exported_macros: Vec::new(),
614597
loader: loader,
615-
syntax_env: env,
616598
derive_modes: HashMap::new(),
617599
recursion_count: 0,
618-
619-
directory: PathBuf::new(),
620-
in_block: false,
621600
}
622601
}
623602

@@ -666,14 +645,6 @@ impl<'a> ExtCtxt<'a> {
666645
last_macro.expect("missing expansion backtrace")
667646
}
668647

669-
pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
670-
pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
671-
pub fn mod_path(&self) -> Vec<ast::Ident> {
672-
let mut v = Vec::new();
673-
v.push(token::str_to_ident(&self.ecfg.crate_name));
674-
v.extend(self.mod_path.iter().cloned());
675-
return v;
676-
}
677648
pub fn bt_push(&mut self, ei: ExpnInfo) {
678649
self.recursion_count += 1;
679650
if self.recursion_count > self.ecfg.recursion_limit {
@@ -818,6 +789,30 @@ impl<'a> ExtCtxt<'a> {
818789
}
819790
}
820791
}
792+
793+
pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
794+
if std_inject::no_core(&krate) {
795+
self.crate_root = None;
796+
} else if std_inject::no_std(&krate) {
797+
self.crate_root = Some("core");
798+
} else {
799+
self.crate_root = Some("std");
800+
}
801+
802+
// User extensions must be added before expander.load_macros is called,
803+
// so that macros from external crates shadow user defined extensions.
804+
for (name, extension) in user_exts {
805+
self.syntax_env.insert(name, extension);
806+
}
807+
808+
self.syntax_env.current_module = Module(0);
809+
let mut paths = ModulePaths {
810+
mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
811+
directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
812+
};
813+
paths.directory.pop();
814+
self.syntax_env.module_data[0].paths = Rc::new(paths);
815+
}
821816
}
822817

823818
/// Extract a string literal from the macro expanded version of `expr`,
@@ -904,79 +899,103 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
904899
///
905900
/// This environment maps Names to SyntaxExtensions.
906901
pub struct SyntaxEnv {
907-
chain: Vec<MapChainFrame>,
902+
module_data: Vec<ModuleData>,
903+
current_module: Module,
904+
908905
/// All bang-style macro/extension names
909906
/// encountered so far; to be used for diagnostics in resolve
910907
pub names: HashSet<Name>,
911908
}
912909

913-
// impl question: how to implement it? Initially, the
914-
// env will contain only macros, so it might be painful
915-
// to add an empty frame for every context. Let's just
916-
// get it working, first....
910+
#[derive(Copy, Clone, PartialEq, Eq)]
911+
pub struct Module(u32);
917912

918-
// NB! the mutability of the underlying maps means that
919-
// if expansion is out-of-order, a deeper scope may be
920-
// able to refer to a macro that was added to an enclosing
921-
// scope lexically later than the deeper scope.
913+
struct ModuleData {
914+
parent: Module,
915+
paths: Rc<ModulePaths>,
916+
macros: HashMap<Name, Rc<SyntaxExtension>>,
917+
macros_escape: bool,
918+
in_block: bool,
919+
}
922920

923-
struct MapChainFrame {
924-
info: BlockInfo,
925-
map: HashMap<Name, Rc<SyntaxExtension>>,
921+
#[derive(Clone)]
922+
pub struct ModulePaths {
923+
pub mod_path: Vec<ast::Ident>,
924+
pub directory: PathBuf,
926925
}
927926

928927
impl SyntaxEnv {
929928
fn new() -> SyntaxEnv {
930-
let mut map = SyntaxEnv { chain: Vec::new() , names: HashSet::new()};
931-
map.push_frame();
932-
map
929+
let mut env = SyntaxEnv {
930+
current_module: Module(0),
931+
module_data: Vec::new(),
932+
names: HashSet::new(),
933+
};
934+
let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() });
935+
env.add_module(false, false, paths);
936+
env
933937
}
934938

935-
pub fn push_frame(&mut self) {
936-
self.chain.push(MapChainFrame {
937-
info: BlockInfo::new(),
938-
map: HashMap::new(),
939-
});
939+
fn data(&self, module: Module) -> &ModuleData {
940+
&self.module_data[module.0 as usize]
940941
}
941942

942-
pub fn pop_frame(&mut self) {
943-
assert!(self.chain.len() > 1, "too many pops on MapChain!");
944-
self.chain.pop();
943+
pub fn set_current_module(&mut self, module: Module) -> Module {
944+
::std::mem::replace(&mut self.current_module, module)
945945
}
946946

947-
fn find_escape_frame(&mut self) -> &mut MapChainFrame {
948-
for (i, frame) in self.chain.iter_mut().enumerate().rev() {
949-
if !frame.info.macros_escape || i == 0 {
950-
return frame
951-
}
952-
}
953-
unreachable!()
947+
pub fn paths(&self) -> Rc<ModulePaths> {
948+
self.data(self.current_module).paths.clone()
949+
}
950+
951+
pub fn in_block(&self) -> bool {
952+
self.data(self.current_module).in_block
954953
}
955954

956-
pub fn find(&self, k: Name) -> Option<Rc<SyntaxExtension>> {
957-
for frame in self.chain.iter().rev() {
958-
if let Some(v) = frame.map.get(&k) {
959-
return Some(v.clone());
955+
pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc<ModulePaths>)
956+
-> Module {
957+
let data = ModuleData {
958+
parent: self.current_module,
959+
paths: paths,
960+
macros: HashMap::new(),
961+
macros_escape: macros_escape,
962+
in_block: in_block,
963+
};
964+
965+
self.module_data.push(data);
966+
Module(self.module_data.len() as u32 - 1)
967+
}
968+
969+
pub fn find(&self, name: Name) -> Option<Rc<SyntaxExtension>> {
970+
let mut module = self.current_module;
971+
let mut module_data;
972+
loop {
973+
module_data = self.data(module);
974+
if let Some(ext) = module_data.macros.get(&name) {
975+
return Some(ext.clone());
960976
}
977+
if module == module_data.parent {
978+
return None;
979+
}
980+
module = module_data.parent;
961981
}
962-
None
963982
}
964983

965-
pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
966-
if let NormalTT(..) = v {
967-
self.names.insert(k);
984+
pub fn insert(&mut self, name: Name, ext: SyntaxExtension) {
985+
if let NormalTT(..) = ext {
986+
self.names.insert(name);
968987
}
969-
self.find_escape_frame().map.insert(k, Rc::new(v));
970-
}
971988

972-
pub fn info(&mut self) -> &mut BlockInfo {
973-
let last_chain_index = self.chain.len() - 1;
974-
&mut self.chain[last_chain_index].info
989+
let mut module = self.current_module;
990+
while self.data(module).macros_escape {
991+
module = self.data(module).parent;
992+
}
993+
self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext));
975994
}
976995

977996
pub fn is_crate_root(&mut self) -> bool {
978997
// The first frame is pushed in `SyntaxEnv::new()` and the second frame is
979998
// pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
980-
self.chain.len() <= 2
999+
self.current_module.0 <= 1
9811000
}
9821001
}

src/libsyntax/ext/expand.rs

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ use tokenstream::TokenTree;
2626
use util::small_vector::SmallVector;
2727
use visit;
2828
use visit::Visitor;
29-
use std_inject;
3029

3130
use std::path::PathBuf;
31+
use std::rc::Rc;
3232

3333
macro_rules! expansions {
3434
($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
@@ -467,24 +467,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
467467
}
468468
false
469469
}
470-
471-
fn with_exts_frame<T, F: FnOnce(&mut Self) -> T>(&mut self, macros_escape: bool, f: F) -> T {
472-
self.cx.syntax_env.push_frame();
473-
self.cx.syntax_env.info().macros_escape = macros_escape;
474-
let result = f(self);
475-
self.cx.syntax_env.pop_frame();
476-
result
477-
}
478470
}
479471

480472
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
481-
fn fold_crate(&mut self, c: Crate) -> Crate {
482-
let mut directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(c.span));
483-
directory.pop();
484-
self.cx.directory = directory;
485-
noop_fold_crate(c, self)
486-
}
487-
488473
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
489474
let expr = expr.unwrap();
490475
if let ast::ExprKind::Mac(mac) = expr.node {
@@ -542,9 +527,12 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
542527
}
543528

544529
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
545-
let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
546-
let result = self.with_exts_frame(false, |this| noop_fold_block(block, this));
547-
self.cx.in_block = was_in_block;
530+
let paths = self.cx.syntax_env.paths();
531+
let module = self.cx.syntax_env.add_module(false, true, paths);
532+
let orig_module = self.cx.syntax_env.set_current_module(module);
533+
534+
let result = noop_fold_block(block, self);
535+
self.cx.syntax_env.set_current_module(orig_module);
548536
result
549537
}
550538

@@ -578,26 +566,27 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
578566
})
579567
}
580568
ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
581-
self.cx.mod_push(item.ident);
582-
let macro_use = self.contains_macro_use(&item.attrs);
583-
584-
let directory = self.cx.directory.clone();
569+
let mut paths = (*self.cx.syntax_env.paths()).clone();
570+
paths.mod_path.push(item.ident);
585571
if item.span.contains(inner) {
586-
self.cx.directory.push(&*{
572+
paths.directory.push(&*{
587573
::attr::first_attr_value_str_by_name(&item.attrs, "path")
588574
.unwrap_or(item.ident.name.as_str())
589575
});
590576
} else {
591-
self.cx.directory = match inner {
577+
paths.directory = match inner {
592578
syntax_pos::DUMMY_SP => PathBuf::new(),
593579
_ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
594580
};
595-
self.cx.directory.pop();
581+
paths.directory.pop();
596582
}
597-
let result = self.with_exts_frame(macro_use, |this| noop_fold_item(item, this));
598-
self.cx.directory = directory;
599583

600-
self.cx.mod_pop();
584+
let macro_use = self.contains_macro_use(&item.attrs);
585+
let in_block = self.cx.syntax_env.in_block();
586+
let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
587+
let module = self.cx.syntax_env.set_current_module(module);
588+
let result = noop_fold_item(item, self);
589+
self.cx.syntax_env.set_current_module(module);
601590
result
602591
},
603592
_ => noop_fold_item(item, self),
@@ -744,19 +733,7 @@ pub fn expand_crate(cx: &mut ExtCtxt,
744733
pub fn expand_crate_with_expander(expander: &mut MacroExpander,
745734
user_exts: Vec<NamedSyntaxExtension>,
746735
mut c: Crate) -> Crate {
747-
if std_inject::no_core(&c) {
748-
expander.cx.crate_root = None;
749-
} else if std_inject::no_std(&c) {
750-
expander.cx.crate_root = Some("core");
751-
} else {
752-
expander.cx.crate_root = Some("std");
753-
}
754-
755-
// User extensions must be added before expander.load_macros is called,
756-
// so that macros from external crates shadow user defined extensions.
757-
for (name, extension) in user_exts {
758-
expander.cx.syntax_env.insert(name, extension);
759-
}
736+
expander.cx.initialize(user_exts, &c);
760737

761738
let items = Expansion::Items(SmallVector::many(c.module.items));
762739
let configured = items.fold_with(&mut expander.strip_unconfigured());
@@ -765,12 +742,11 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
765742

766743
let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
767744
let mut ret = expander.fold_crate(c);
768-
ret.exported_macros = expander.cx.exported_macros.clone();
769-
770745
if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
771746
expander.cx.parse_sess.span_diagnostic.abort_if_errors();
772747
}
773748

749+
ret.exported_macros = expander.cx.exported_macros.clone();
774750
ret
775751
}
776752

0 commit comments

Comments
 (0)