diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 588968365b1aa..d99363d7ee5f7 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -14,6 +14,8 @@ use ast::*; use ast; use ast_util; use codemap::{span, spanned}; +use core::cast; +use core::local_data; use opt_vec; use parse::token; use visit; @@ -623,12 +625,18 @@ pub enum Privacy { pub fn new_ident(name: Name) -> ident { ident {name: name, ctxt: 0}} /// Extend a syntax context with a given mark -pub fn new_mark (m:Mrk, tail:SyntaxContext,table:&mut SCTable) +pub fn new_mark(m:Mrk, tail:SyntaxContext) -> SyntaxContext { + new_mark_internal(m,tail,get_sctable()) +} + +// Extend a syntax context with a given mark and table +// FIXME #4536 : currently pub to allow testing +pub fn new_mark_internal(m:Mrk, tail:SyntaxContext,table:&mut SCTable) -> SyntaxContext { let key = (tail,m); // FIXME #5074 : can't use more natural style because we're missing // flow-sensitivity. Results in two lookups on a hash table hit. - // also applies to new_rename, below. + // also applies to new_rename_internal, below. // let try_lookup = table.mark_memo.find(&key); match table.mark_memo.contains_key(&key) { false => { @@ -646,7 +654,13 @@ pub fn new_mark (m:Mrk, tail:SyntaxContext,table:&mut SCTable) } /// Extend a syntax context with a given rename -pub fn new_rename (id:ident, to:Name, tail:SyntaxContext, table: &mut SCTable) +pub fn new_rename(id:ident, to:Name, tail:SyntaxContext) -> SyntaxContext { + new_rename_internal(id, to, tail, get_sctable()) +} + +// Extend a syntax context with a given rename and sctable +// FIXME #4536 : currently pub to allow testing +pub fn new_rename_internal(id:ident, to:Name, tail:SyntaxContext, table: &mut SCTable) -> SyntaxContext { let key = (tail,id,to); // FIXME #5074 @@ -668,7 +682,8 @@ pub fn new_rename (id:ident, to:Name, tail:SyntaxContext, table: &mut SCTable) /// Make a fresh syntax context table with EmptyCtxt in slot zero /// and IllegalCtxt in slot one. -pub fn new_sctable() -> SCTable { +// FIXME #4536 : currently pub to allow testing +pub fn new_sctable_internal() -> SCTable { SCTable { table: ~[EmptyCtxt,IllegalCtxt], mark_memo: HashMap::new(), @@ -676,6 +691,23 @@ pub fn new_sctable() -> SCTable { } } +// fetch the SCTable from TLS, create one if it doesn't yet exist. +pub fn get_sctable() -> @mut SCTable { + unsafe { + let sctable_key = (cast::transmute::<(uint, uint), + &fn(v: @@mut SCTable)>( + (-4 as uint, 0u))); + match local_data::local_data_get(sctable_key) { + None => { + let new_table = @@mut new_sctable_internal(); + local_data::local_data_set(sctable_key,new_table); + *new_table + }, + Some(intr) => *intr + } + } +} + /// Add a value to the end of a vec, return its index fn idx_push(vec: &mut ~[T], val: T) -> uint { vec.push(val); @@ -683,19 +715,25 @@ fn idx_push(vec: &mut ~[T], val: T) -> uint { } /// Resolve a syntax object to a name, per MTWT. -pub fn resolve (id : ident, table : &mut SCTable) -> Name { +pub fn resolve(id : ident) -> Name { + resolve_internal(id, get_sctable()) +} + +// Resolve a syntax object to a name, per MTWT. +// FIXME #4536 : currently pub to allow testing +pub fn resolve_internal(id : ident, table : &mut SCTable) -> Name { match table.table[id.ctxt] { EmptyCtxt => id.name, // ignore marks here: - Mark(_,subctxt) => resolve (ident{name:id.name, ctxt: subctxt},table), + Mark(_,subctxt) => resolve_internal(ident{name:id.name, ctxt: subctxt},table), // do the rename if necessary: Rename(ident{name,ctxt},toname,subctxt) => { // this could be cached or computed eagerly: - let resolvedfrom = resolve(ident{name:name,ctxt:ctxt},table); - let resolvedthis = resolve(ident{name:id.name,ctxt:subctxt},table); + let resolvedfrom = resolve_internal(ident{name:name,ctxt:ctxt},table); + let resolvedthis = resolve_internal(ident{name:id.name,ctxt:subctxt},table); if ((resolvedthis == resolvedfrom) - && (marksof (ctxt,resolvedthis,table) - == marksof (subctxt,resolvedthis,table))) { + && (marksof(ctxt,resolvedthis,table) + == marksof(subctxt,resolvedthis,table))) { toname } else { resolvedthis @@ -797,8 +835,8 @@ mod test { -> SyntaxContext { tscs.foldr(tail, |tsc : &TestSC,tail : SyntaxContext| {match *tsc { - M(mrk) => new_mark(mrk,tail,table), - R(ident,name) => new_rename(ident,name,tail,table)}}) + M(mrk) => new_mark_internal(mrk,tail,table), + R(ident,name) => new_rename_internal(ident,name,tail,table)}}) } // gather a SyntaxContext back into a vector of TestSCs @@ -823,7 +861,7 @@ mod test { } #[test] fn test_unfold_refold(){ - let mut t = new_sctable(); + let mut t = new_sctable_internal(); let test_sc = ~[M(3),R(id(101,0),14),M(9)]; assert_eq!(unfold_test_sc(copy test_sc,empty_ctxt,&mut t),4); @@ -837,11 +875,11 @@ mod test { // in a vector. v[0] will be the outermost mark. fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxContext { mrks.foldr(tail, |mrk:&Mrk,tail:SyntaxContext| - {new_mark(*mrk,tail,table)}) + {new_mark_internal(*mrk,tail,table)}) } #[test] fn unfold_marks_test() { - let mut t = new_sctable(); + let mut t = new_sctable_internal(); assert_eq!(unfold_marks(~[3,7],empty_ctxt,&mut t),3); assert_eq!(t.table[2],Mark(7,0)); @@ -851,7 +889,7 @@ mod test { #[test] fn test_marksof () { let stopname = 242; let name1 = 243; - let mut t = new_sctable(); + let mut t = new_sctable_internal(); assert_eq!(marksof (empty_ctxt,stopname,&t),~[]); // FIXME #5074: ANF'd to dodge nested calls { let ans = unfold_marks(~[4,98],empty_ctxt,&mut t); @@ -865,13 +903,13 @@ mod test { // rename where stop doesn't match: { let chain = ~[M(9), R(id(name1, - new_mark (4, empty_ctxt,&mut t)), + new_mark_internal (4, empty_ctxt,&mut t)), 100101102), M(14)]; let ans = unfold_test_sc(chain,empty_ctxt,&mut t); assert_eq! (marksof (ans, stopname, &t), ~[9,14]);} // rename where stop does match - { let name1sc = new_mark(4, empty_ctxt, &mut t); + { let name1sc = new_mark_internal(4, empty_ctxt, &mut t); let chain = ~[M(9), R(id(name1, name1sc), stopname), @@ -883,30 +921,30 @@ mod test { #[test] fn resolve_tests () { let a = 40; - let mut t = new_sctable(); + let mut t = new_sctable_internal(); // - ctxt is MT - assert_eq!(resolve(id(a,empty_ctxt),&mut t),a); + assert_eq!(resolve_internal(id(a,empty_ctxt),&mut t),a); // - simple ignored marks { let sc = unfold_marks(~[1,2,3],empty_ctxt,&mut t); - assert_eq!(resolve(id(a,sc),&mut t),a);} + assert_eq!(resolve_internal(id(a,sc),&mut t),a);} // - orthogonal rename where names don't match { let sc = unfold_test_sc(~[R(id(50,empty_ctxt),51),M(12)],empty_ctxt,&mut t); - assert_eq!(resolve(id(a,sc),&mut t),a);} + assert_eq!(resolve_internal(id(a,sc),&mut t),a);} // - rename where names do match, but marks don't - { let sc1 = new_mark(1,empty_ctxt,&mut t); + { let sc1 = new_mark_internal(1,empty_ctxt,&mut t); let sc = unfold_test_sc(~[R(id(a,sc1),50), M(1), M(2)], empty_ctxt,&mut t); - assert_eq!(resolve(id(a,sc),&mut t), a);} + assert_eq!(resolve_internal(id(a,sc),&mut t), a);} // - rename where names and marks match { let sc1 = unfold_test_sc(~[M(1),M(2)],empty_ctxt,&mut t); let sc = unfold_test_sc(~[R(id(a,sc1),50),M(1),M(2)],empty_ctxt,&mut t); - assert_eq!(resolve(id(a,sc),&mut t), 50); } + assert_eq!(resolve_internal(id(a,sc),&mut t), 50); } // - rename where names and marks match by literal sharing { let sc1 = unfold_test_sc(~[M(1),M(2)],empty_ctxt,&mut t); let sc = unfold_test_sc(~[R(id(a,sc1),50)],sc1,&mut t); - assert_eq!(resolve(id(a,sc),&mut t), 50); } + assert_eq!(resolve_internal(id(a,sc),&mut t), 50); } // - two renames of the same var.. can only happen if you use // local-expand to prevent the inner binding from being renamed // during the rename-pass caused by the first: @@ -914,28 +952,28 @@ mod test { { let sc = unfold_test_sc(~[R(id(a,empty_ctxt),50), R(id(a,empty_ctxt),51)], empty_ctxt,&mut t); - assert_eq!(resolve(id(a,sc),&mut t), 51); } + assert_eq!(resolve_internal(id(a,sc),&mut t), 51); } // the simplest double-rename: - { let a_to_a50 = new_rename(id(a,empty_ctxt),50,empty_ctxt,&mut t); - let a50_to_a51 = new_rename(id(a,a_to_a50),51,a_to_a50,&mut t); - assert_eq!(resolve(id(a,a50_to_a51),&mut t),51); + { let a_to_a50 = new_rename_internal(id(a,empty_ctxt),50,empty_ctxt,&mut t); + let a50_to_a51 = new_rename_internal(id(a,a_to_a50),51,a_to_a50,&mut t); + assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t),51); // mark on the outside doesn't stop rename: - let sc = new_mark(9,a50_to_a51,&mut t); - assert_eq!(resolve(id(a,sc),&mut t),51); + let sc = new_mark_internal(9,a50_to_a51,&mut t); + assert_eq!(resolve_internal(id(a,sc),&mut t),51); // but mark on the inside does: let a50_to_a51_b = unfold_test_sc(~[R(id(a,a_to_a50),51), M(9)], a_to_a50, &mut t); - assert_eq!(resolve(id(a,a50_to_a51_b),&mut t),50);} + assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t),50);} } #[test] fn hashing_tests () { - let mut t = new_sctable(); - assert_eq!(new_mark(12,empty_ctxt,&mut t),2); - assert_eq!(new_mark(13,empty_ctxt,&mut t),3); + let mut t = new_sctable_internal(); + assert_eq!(new_mark_internal(12,empty_ctxt,&mut t),2); + assert_eq!(new_mark_internal(13,empty_ctxt,&mut t),3); // using the same one again should result in the same index: - assert_eq!(new_mark(12,empty_ctxt,&mut t),2); + assert_eq!(new_mark_internal(12,empty_ctxt,&mut t),2); // I'm assuming that the rename table will behave the same.... } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f5edc50377e81..96a0461de1eb2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -15,17 +15,15 @@ use ast::{crate, decl_local, expr_, expr_mac, mac_invoc_tt}; use ast::{item_mac, local_, stmt_, stmt_decl, stmt_mac, stmt_expr, stmt_semi}; use ast::{SCTable, illegal_ctxt}; use ast; -use ast_util::{new_rename, new_mark, resolve, new_sctable}; +use ast_util::{new_rename, new_mark, resolve, get_sctable}; use attr; use codemap; use codemap::{span, CallInfo, ExpandedFrom, NameAndSpan, spanned}; -use core::cast; -use core::local_data; use ext::base::*; use fold::*; use parse; use parse::{parse_item_from_source_str}; -use parse::token::{ident_to_str, intern}; +use parse::token::{ident_to_str, intern, fresh_name}; use visit; use visit::{Visitor,mk_vt}; @@ -369,7 +367,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, // return a visitor that extracts the pat_ident paths // from a given pattern and puts them in a mutable -// array (passed in to the traversal +// array (passed in to the traversal) pub fn new_name_finder() -> @Visitor<@mut ~[ast::ident]> { let default_visitor = visit::default_visitor(); @Visitor{ @@ -395,8 +393,6 @@ pub fn new_name_finder() -> @Visitor<@mut ~[ast::ident]> { } } - - pub fn expand_block(extsbox: @mut SyntaxEnv, cx: @ExtCtxt, blk: &blk_, @@ -422,14 +418,13 @@ fn get_block_info(exts : SyntaxEnv) -> BlockInfo { // given a mutable list of renames, return a tree-folder that applies those // renames. fn renames_to_fold(renames : @mut ~[(ast::ident,ast::Name)]) -> @ast_fold { - let table = local_sctable_get(); let afp = default_ast_fold(); let f_pre = @AstFoldFns { fold_ident: |id,_| { // the individual elements are memoized... it would // also be possible to memoize on the whole list at once. let new_ctxt = renames.foldl(id.ctxt,|ctxt,&(from,to)| { - new_rename(from,to,*ctxt,table) + new_rename(from,to,*ctxt) }); ast::ident{name:id.name,ctxt:new_ctxt} }, @@ -446,22 +441,6 @@ fn apply_pending_renames(folder : @ast_fold, stmt : ast::stmt) -> @ast::stmt { } } -// fetch the SCTable from TLS, create one if it doesn't yet exist. -fn local_sctable_get() -> @mut SCTable { - unsafe { - let sctable_key = (cast::transmute::<(uint, uint), - &fn(v: @@mut SCTable)>( - (-4 as uint, 0u))); - match local_data::local_data_get(sctable_key) { - None => { - let new_table = @@mut new_sctable(); - local_data::local_data_set(sctable_key,new_table); - *new_table - }, - Some(intr) => *intr - } - } -} pub fn new_span(cx: @ExtCtxt, sp: span) -> span { @@ -732,35 +711,33 @@ pub fn fun_to_ident_folder(f: @fn(ast::ident)->ast::ident) -> @ast_fold{ // update the ctxts in a path to get a rename node pub fn new_ident_renamer(from: ast::ident, - to: ast::Name, - table: @mut SCTable) -> + to: ast::Name) -> @fn(ast::ident)->ast::ident { |id : ast::ident| ast::ident{ name: id.name, - ctxt: new_rename(from,to,id.ctxt,table) + ctxt: new_rename(from,to,id.ctxt) } } // update the ctxts in a path to get a mark node -pub fn new_ident_marker(mark: uint, - table: @mut SCTable) -> +pub fn new_ident_marker(mark: uint) -> @fn(ast::ident)->ast::ident { |id : ast::ident| ast::ident{ name: id.name, - ctxt: new_mark(mark,id.ctxt,table) + ctxt: new_mark(mark,id.ctxt) } } // perform resolution (in the MTWT sense) on all of the // idents in the tree. This is the final step in expansion. -pub fn new_ident_resolver(table: @mut SCTable) -> +pub fn new_ident_resolver() -> @fn(ast::ident)->ast::ident { |id : ast::ident| ast::ident { - name : resolve(id,table), + name : resolve(id), ctxt : illegal_ctxt } } @@ -771,16 +748,18 @@ mod test { use super::*; use ast; use ast::{attribute_, attr_outer, meta_word, empty_ctxt}; - use ast_util::{new_sctable}; + use ast_util::{get_sctable}; use codemap; use codemap::spanned; use parse; - use parse::token::{gensym}; - use core::io; - use core::option::{None, Some}; + use parse::token::{gensym, intern, get_ident_interner}; + use print::pprust; use util::parser_testing::{string_to_item, string_to_pat, strs_to_idents}; use visit::{mk_vt,Visitor}; + use core::io; + use core::option::{None, Some}; + // make sure that fail! is present #[test] fn fail_exists_test () { let src = ~"fn main() { fail!(\"something appropriately gloomy\");}"; @@ -883,22 +862,27 @@ mod test { #[test] fn renaming () { - let maybe_item_ast = string_to_item(@~"fn a() -> int { let b = 13; b} "); + let maybe_item_ast = string_to_item(@~"fn a() -> int { let b = 13; b }"); let item_ast = match maybe_item_ast { Some(x) => x, None => fail!("test case fail") }; - let table = @mut new_sctable(); - let a_name = 100; // enforced by testing_interner - let a2_name = gensym("a2"); + let a_name = intern("a"); + let a2_name = intern("a2"); let renamer = new_ident_renamer(ast::ident{name:a_name,ctxt:empty_ctxt}, - a2_name,table); + a2_name); let renamed_ast = fun_to_ident_folder(renamer).fold_item(item_ast).get(); - let resolver = new_ident_resolver(table); + let resolver = new_ident_resolver(); let resolved_ast = fun_to_ident_folder(resolver).fold_item(renamed_ast).get(); - io::print(fmt!("ast: %?\n",resolved_ast)) + let resolved_as_str = pprust::item_to_str(resolved_ast, + get_ident_interner()); + assert_eq!(resolved_as_str,~"fn a2() -> int { let b = 13; b }"); + + } + // sigh... it looks like I have two different renaming mechanisms, now... + #[test] fn pat_idents(){ let pat = string_to_pat(@~"(a,Foo{x:c @ (b,9),y:Bar(4,d)})");