diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fbaeab03e8a..25edcf63faa 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -23,7 +23,7 @@ use parse; use parse::{parse_item_from_source_str}; use parse::token; -use parse::token::{fresh_name, ident_to_str, intern}; +use parse::token::{fresh_mark, fresh_name, ident_to_str, intern}; use visit; use visit::Visitor; @@ -67,7 +67,9 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, }, }); - let expanded = match expandfun(cx, mac.span, *tts) { + let fm = fresh_mark(); + let marked_tts = mark_tts(*tts,fm); + let expanded = match expandfun(cx, mac.span, marked_tts) { MRExpr(e) => e, MRAny(expr_maker,_,_) => expr_maker(), _ => { @@ -259,6 +261,12 @@ fn mk_simple_path(ident: ast::Ident, span: Span) -> ast::Path { } } +// apply a fresh mark to the given token trees. Used prior to expansion of a macro. +fn mark_tts(tts : &[token_tree], m : Mrk) -> ~[token_tree] { + fold_tts(tts,new_ident_marker(m)) +} + + // This is a secondary mechanism for invoking syntax extensions on items: // "decorator" attributes, such as #[auto_encode]. These are invoked by an // attribute prefixing an item, and are interpreted by feeding the item @@ -1285,7 +1293,7 @@ pub fn new_ident_renamer(from: ast::Ident, // update the ctxts in a path to get a mark node -pub fn new_ident_marker(mark: uint) -> +pub fn new_ident_marker(mark: Mrk) -> @fn(ast::Ident)->ast::Ident { |id : ast::Ident| ast::Ident{ @@ -1461,18 +1469,18 @@ fn expand_and_resolve_and_pretty_print (crate_str : @str) -> ~str { #[test] fn automatic_renaming () { - // "fn a() -> int { let b = 13; let c = b; b+c }" - // --> b & c should get new names, in the expr too. - // "macro_rules! f (($x:ident) => ($x + b)) fn a() -> int { let b = 13; f!(b)}" - // --> one should be renamed, one should not. - let teststrs = ~[// b & c should get new names throughout, in the expr too: @"fn a() -> int { let b = 13; let c = b; b+c }", // the use of b before the + should be renamed, the other one not: @"macro_rules! f (($x:ident) => ($x + b)) fn a() -> int { let b = 13; f!(b)}", // the b before the plus should not be renamed (requires marks) - @"macro_rules! f (($x:ident) => ({let b=9; ($x + b)})) fn a() -> int { f!(b)}"]; + @"macro_rules! f (($x:ident) => ({let b=9; ($x + b)})) fn a() -> int { f!(b)}", + // the z flows into and out of two macros (g & f) along one path, and one (just g) along the + // other, so the result of the whole thing should be "let z_123 = 3; z_123" + @"macro_rules! g (($x:ident) => ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)})) + fn a(){g!(z)}" + ]; for s in teststrs.iter() { // we need regexps to test these! std::io::println(expand_and_resolve_and_pretty_print(*s)); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 750ec0be984..52c148e7ba2 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -126,7 +126,7 @@ fn fold_mac_(m: &mac, fld: @ast_fold) -> mac { // build a new vector of tts by appling the given function to // all of the identifiers in the token trees. -pub fn fold_tts(tts : &[token_tree], f: @fn(ident)->ident) -> ~[token_tree] { +pub fn fold_tts(tts : &[token_tree], f: @fn(Ident)->Ident) -> ~[token_tree] { do tts.map |tt| { match *tt { tt_tok(span, ref tok) => @@ -145,7 +145,7 @@ pub fn fold_tts(tts : &[token_tree], f: @fn(ident)->ident) -> ~[token_tree] { } // apply ident folder if it's an ident, otherwise leave it alone -fn maybe_fold_ident(t : &token::Token, f: @fn(ident)->ident) -> token::Token { +fn maybe_fold_ident(t : &token::Token, f: @fn(Ident)->Ident) -> token::Token { match *t { token::IDENT(id,followed_by_colons) => token::IDENT(f(id),followed_by_colons), diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 8de597733ae..66f121727af 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast; -use ast::Name; +use ast::{Name, Mrk}; use ast_util; use parse::token; use util::interner::StrInterner; @@ -557,6 +557,11 @@ pub fn fresh_name(src_name : &ast::Ident) -> Name { gensym(fmt!("%s_%u",ident_to_str(src_name),num)) } +// create a fresh mark. +pub fn fresh_mark() -> Mrk { + gensym("mark") +} + /** * All the valid words that have meaning in the Rust language. *