summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJohn Clements <clements@racket-lang.org>2013-07-08 15:55:14 -0700
committerJohn Clements <clements@racket-lang.org>2013-09-06 13:35:11 -0700
commitb9bb4abcb66804e4b78704068703f0dab5c72887 (patch)
treec422f4da5953db7897eb1526e735dd8c6545b1b9 /src/libsyntax
parent2c51e262f367f0f079135a5a176706ea5ef78f78 (diff)
downloadrust-b9bb4abcb66804e4b78704068703f0dab5c72887.tar.gz
rust-b9bb4abcb66804e4b78704068703f0dab5c72887.zip
capturing macros now implemented
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs92
-rw-r--r--src/libsyntax/ext/expand.rs151
-rw-r--r--src/libsyntax/ext/quote.rs59
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs4
-rw-r--r--src/libsyntax/fold.rs1
5 files changed, 222 insertions, 85 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index ac3fc717500..24f70bfeaa8 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -33,6 +33,10 @@ pub struct MacroDef {
     ext: SyntaxExtension
 }
 
+// No context arg for an Item Decorator macro, simply because
+// adding it would require adding a ctxt field to all items.
+// we could do this if it turns out to be useful.
+
 pub type ItemDecoratorFun = @fn(@ExtCtxt,
                              Span,
                              @ast::MetaItem,
@@ -41,15 +45,34 @@ pub type ItemDecoratorFun = @fn(@ExtCtxt,
 
 pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
                                    Span,
-                                   &[ast::token_tree])
+                                   &[ast::token_tree],
+                                   ast::SyntaxContext)
                                 -> MacResult;
 
 pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
                                        Span,
                                        ast::Ident,
+                                       ~[ast::token_tree],
+                                       ast::SyntaxContext)
+                                    -> MacResult;
+
+// oog... in order to make the presentation of builtin_normal_tt_no_ctxt
+// and builtin_ident_tt_no_ctxt palatable, we need one-off types for
+// functions that don't consume a ctxt:
+
+pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt,
+                                   Span,
+                                   &[ast::token_tree])
+                                -> MacResult;
+
+pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt,
+                                       Span,
+                                       ast::Ident,
                                        ~[ast::token_tree])
                                     -> MacResult;
 
+
+
 pub enum MacResult {
     MRExpr(@ast::Expr),
     MRItem(@ast::item),
@@ -78,6 +101,7 @@ pub enum SyntaxExtension {
     IdentTT(SyntaxExpanderTTItemFun, Option<Span>),
 }
 
+
 // The SyntaxEnv is the environment that's threaded through the expansion
 // of macros. It contains bindings for macros, and also a special binding
 // for " block" (not a legal identifier) that maps to a BlockInfo
@@ -109,12 +133,16 @@ type RenameList = ~[(ast::Ident,Name)];
 // AST nodes into full ASTs
 pub fn syntax_expander_table() -> SyntaxEnv {
     // utility function to simplify creating NormalTT syntax extensions
-    fn builtin_normal_tt(f: SyntaxExpanderTTFun) -> @Transformer {
-        @SE(NormalTT(f, None))
+    // that ignore their contexts
+    fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) -> @Transformer {
+        let wrapped_expander : SyntaxExpanderTTFun = |a,b,c,d|{f(a,b,c)};
+        @SE(NormalTT(wrapped_expander, None))
     }
     // utility function to simplify creating IdentTT syntax extensions
-    fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
-        @SE(IdentTT(f, None))
+    // that ignore their contexts
+    fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer {
+        let wrapped_expander : SyntaxExpanderTTItemFun = |a,b,c,d,e|{f(a,b,c,d)};
+        @SE(IdentTT(wrapped_expander, None))
     }
     let mut syntax_expanders = HashMap::new();
     // NB identifier starts with space, and can't conflict with legal idents
@@ -124,16 +152,16 @@ pub fn syntax_expander_table() -> SyntaxEnv {
                                 pending_renames : @mut ~[]
                             }));
     syntax_expanders.insert(intern(&"macro_rules"),
-                            builtin_item_tt(
+                            builtin_item_tt_no_ctxt(
                                 ext::tt::macro_rules::add_new_extension));
     syntax_expanders.insert(intern(&"fmt"),
-                            builtin_normal_tt(ext::fmt::expand_syntax_ext));
+                            builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
     syntax_expanders.insert(intern(&"format"),
-                            builtin_normal_tt(ext::ifmt::expand_format));
+                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_format));
     syntax_expanders.insert(intern(&"write"),
-                            builtin_normal_tt(ext::ifmt::expand_write));
+                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_write));
     syntax_expanders.insert(intern(&"writeln"),
-                            builtin_normal_tt(ext::ifmt::expand_writeln));
+                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln));
     syntax_expanders.insert(
         intern(&"auto_encode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
@@ -141,16 +169,16 @@ pub fn syntax_expander_table() -> SyntaxEnv {
         intern(&"auto_decode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
     syntax_expanders.insert(intern(&"env"),
-                            builtin_normal_tt(ext::env::expand_env));
+                            builtin_normal_tt_no_ctxt(ext::env::expand_env));
     syntax_expanders.insert(intern(&"option_env"),
-                            builtin_normal_tt(ext::env::expand_option_env));
+                            builtin_normal_tt_no_ctxt(ext::env::expand_option_env));
     syntax_expanders.insert(intern("bytes"),
-                            builtin_normal_tt(ext::bytes::expand_syntax_ext));
+                            builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext));
     syntax_expanders.insert(intern("concat_idents"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::concat_idents::expand_syntax_ext));
     syntax_expanders.insert(intern(&"log_syntax"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::log_syntax::expand_syntax_ext));
     syntax_expanders.insert(intern(&"deriving"),
                             @SE(ItemDecorator(
@@ -158,49 +186,49 @@ pub fn syntax_expander_table() -> SyntaxEnv {
 
     // Quasi-quoting expanders
     syntax_expanders.insert(intern(&"quote_tokens"),
-                       builtin_normal_tt(ext::quote::expand_quote_tokens));
+        @SE(NormalTT(ext::quote::expand_quote_tokens, None)));
     syntax_expanders.insert(intern(&"quote_expr"),
-                       builtin_normal_tt(ext::quote::expand_quote_expr));
+        @SE(NormalTT(ext::quote::expand_quote_expr, None)));
     syntax_expanders.insert(intern(&"quote_ty"),
-                       builtin_normal_tt(ext::quote::expand_quote_ty));
+        @SE(NormalTT(ext::quote::expand_quote_ty, None)));
     syntax_expanders.insert(intern(&"quote_item"),
-                       builtin_normal_tt(ext::quote::expand_quote_item));
+        @SE(NormalTT(ext::quote::expand_quote_item, None)));
     syntax_expanders.insert(intern(&"quote_pat"),
-                       builtin_normal_tt(ext::quote::expand_quote_pat));
+        @SE(NormalTT(ext::quote::expand_quote_pat, None)));
     syntax_expanders.insert(intern(&"quote_stmt"),
-                       builtin_normal_tt(ext::quote::expand_quote_stmt));
+        @SE(NormalTT(ext::quote::expand_quote_stmt, None)));
 
     syntax_expanders.insert(intern(&"line"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_line));
     syntax_expanders.insert(intern(&"col"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_col));
     syntax_expanders.insert(intern(&"file"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_file));
     syntax_expanders.insert(intern(&"stringify"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_stringify));
     syntax_expanders.insert(intern(&"include"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_include));
     syntax_expanders.insert(intern(&"include_str"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_include_str));
     syntax_expanders.insert(intern(&"include_bin"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_include_bin));
     syntax_expanders.insert(intern(&"module_path"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_mod));
     syntax_expanders.insert(intern(&"asm"),
-                            builtin_normal_tt(ext::asm::expand_asm));
+                            builtin_normal_tt_no_ctxt(ext::asm::expand_asm));
     syntax_expanders.insert(intern(&"cfg"),
-                            builtin_normal_tt(ext::cfg::expand_cfg));
+                            builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg));
     syntax_expanders.insert(
         intern(&"trace_macros"),
-        builtin_normal_tt(ext::trace_macros::expand_trace_macros));
+        builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros));
     MapChain::new(~syntax_expanders)
 }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index a62b015c6cb..91a56590435 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, NodeId, DeclLocal, EMPTY_CTXT, Expr_, ExprMac};
+use ast::{Block, Crate, NodeId, DeclLocal, EMPTY_CTXT, Expr_, ExprMac, SyntaxContext};
 use ast::{Local, Ident, mac_invoc_tt};
 use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
 use ast::{ILLEGAL_CTXT, SCTable, token_tree};
@@ -42,6 +42,11 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
         // entry-point for all syntax extensions.
         ExprMac(ref mac) => {
             match (*mac).node {
+                // it would almost certainly be cleaner to pass the whole
+                // macro invocation in, rather than pulling it apart and
+                // marking the tts and the ctxt separately. This also goes
+                // for the other three macro invocation chunks of code
+                // in this file.
                 // Token-tree macros:
                 mac_invoc_tt(ref pth, ref tts, ctxt) => {
                     if (pth.segments.len() > 1u) {
@@ -70,7 +75,8 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                             let fm = fresh_mark();
                             // mark before:
                             let marked_before = mark_tts(*tts,fm);
-                            let expanded = match expandfun(cx, mac.span, marked_before) {
+                            let marked_ctxt = new_mark(fm, ctxt);
+                            let expanded = match expandfun(cx, mac.span, marked_before, marked_ctxt) {
                                 MRExpr(e) => e,
                                 MRAny(expr_maker,_,_) => expr_maker(),
                                 _ => {
@@ -367,9 +373,9 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
                        cx: @ExtCtxt, it: @ast::item,
                        fld: @ast_fold)
                     -> Option<@ast::item> {
-    let (pth, tts) = match it.node {
+    let (pth, tts, ctxt) = match it.node {
         item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => {
-            (pth, (*tts).clone())
+            (pth, (*tts).clone(), ctxt)
         }
         _ => cx.span_bug(it.span, "invalid item macro invocation")
     };
@@ -396,10 +402,9 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
                 }
             });
             // mark before expansion:
-            let marked_tts = mark_tts(tts,fm);
-            // mark after expansion:
-            // RIGHT HERE: can't apply mark_item to MacResult ... :(
-            expander(cx, it.span, marked_tts)
+            let marked_before = mark_tts(tts,fm);
+            let marked_ctxt = new_mark(fm,ctxt);
+            expander(cx, it.span, marked_before, marked_ctxt)
         }
         Some(@SE(IdentTT(expander, span))) => {
             if it.ident.name == parse::token::special_idents::invalid.name {
@@ -417,7 +422,8 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
             let fm = fresh_mark();
             // mark before expansion:
             let marked_tts = mark_tts(tts,fm);
-        expander(cx, it.span, it.ident, marked_tts)
+            let marked_ctxt = new_mark(fm,ctxt);
+            expander(cx, it.span, it.ident, marked_tts, marked_ctxt)
         }
         _ => cx.span_fatal(
             it.span, fmt!("%s! is not legal in item position", extnamestr))
@@ -468,11 +474,11 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                 -> (Option<Stmt_>, Span) {
     // why the copying here and not in expand_expr?
     // looks like classic changed-in-only-one-place
-    let (mac, pth, tts, semi) = match *s {
+    let (mac, pth, tts, semi, ctxt) = match *s {
         StmtMac(ref mac, semi) => {
             match mac.node {
                 mac_invoc_tt(ref pth, ref tts, ctxt) => {
-                    ((*mac).clone(), pth, (*tts).clone(), semi)
+                    ((*mac).clone(), pth, (*tts).clone(), semi, ctxt)
                 }
             }
         }
@@ -498,7 +504,8 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
             let fm = fresh_mark();
             // mark before expansion:
             let marked_tts = mark_tts(tts,fm);
-            let expanded = match expandfun(cx, mac.span, marked_tts) {
+            let marked_ctxt = new_mark(fm,ctxt);
+            let expanded = match expandfun(cx, mac.span, marked_tts, marked_ctxt) {
                 MRExpr(e) =>
                     @codemap::Spanned { node: StmtExpr(e, cx.next_id()),
                                     span: e.span},
@@ -893,25 +900,6 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
     context as @mut Visitor<()>
 }
 
-// given a mutable list of renames, return a tree-folder that applies those
-// renames.
-// FIXME #4536: currently pub to allow testing
-pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold {
-    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.iter().fold(id.ctxt,|ctxt,&(from,to)| {
-                new_rename(from,to,ctxt)
-            });
-            ast::Ident{name:id.name,ctxt:new_ctxt}
-        },
-        .. *afp
-    };
-    make_fold(f_pre)
-}
-
 // expand a block. pushes a new exts_frame, then calls expand_block_elts
 pub fn expand_block(extsbox: @mut SyntaxEnv,
                     _cx: @ExtCtxt,
@@ -1427,6 +1415,7 @@ pub trait CtxtFn{
     fn f(&self, ast::SyntaxContext) -> ast::SyntaxContext;
 }
 
+// a renamer adds a rename to the syntax context
 pub struct Renamer {
     from : ast::Ident,
     to : ast::Name
@@ -1438,6 +1427,22 @@ impl CtxtFn for Renamer {
     }
 }
 
+// a renamer that performs a whole bunch of renames
+pub struct MultiRenamer {
+    renames : @mut ~[(ast::Ident,ast::Name)]
+}
+
+impl CtxtFn for MultiRenamer {
+    fn f(&self, starting_ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
+        // the individual elements are memoized... it would
+        // also be possible to memoize on the whole list at once.
+        self.renames.iter().fold(starting_ctxt,|ctxt,&(from,to)| {
+            new_rename(from,to,ctxt)
+        })
+    }
+}
+
+// a marker adds the given mark to the syntax context
 pub struct Marker { mark : Mrk }
 
 impl CtxtFn for Marker {
@@ -1446,6 +1451,15 @@ impl CtxtFn for Marker {
     }
 }
 
+// a repainter just replaces the given context with the one it's closed over
+pub struct Repainter { ctxt : SyntaxContext }
+
+impl CtxtFn for Repainter {
+    fn f(&self, ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
+        self.ctxt
+    }
+}
+
 // given a function from ctxts to ctxts, produce
 // an ast_fold that applies that function to all ctxts:
 pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
@@ -1454,7 +1468,7 @@ pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
         |ast::Ident{name, ctxt}, _| {
         ast::Ident{name:name,ctxt:cf.f(ctxt)}
     };
-    let fm : @fn(&ast::mac_, span, @ast_fold) -> (ast::mac_,span) =
+    let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) =
         |m, sp, fld| {
         match *m {
             mac_invoc_tt(ref path, ref tts, ctxt) =>
@@ -1472,6 +1486,15 @@ pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
     }
 }
 
+
+
+// given a mutable list of renames, return a tree-folder that applies those
+// renames.
+// FIXME #4536: currently pub to allow testing
+pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns {
+    fun_to_ctxt_folder(@MultiRenamer{renames : renames})
+}
+
 // just a convenience:
 pub fn new_mark_folder(m : Mrk) -> @AstFoldFns { fun_to_ctxt_folder(@Marker{mark:m}) }
 pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns {
@@ -1513,6 +1536,12 @@ fn mark_item(expr : @ast::item, m : Mrk) -> Option<@ast::item> {
     new_mark_folder(m).fold_item(expr)
 }
 
+// replace all contexts in a given expr with the given mark. Used
+// for capturing macros
+pub fn replace_ctxts(expr : @ast::Expr, ctxt : SyntaxContext) -> @ast::Expr {
+    fun_to_ctxt_folder(@Repainter{ctxt:ctxt}).fold_expr(expr)
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
@@ -1522,7 +1551,7 @@ mod test {
     use codemap;
     use codemap::Spanned;
     use parse;
-    use parse::token::{gensym, intern, get_ident_interner};
+    use parse::token::{gensym, intern, get_ident_interner, ident_to_str};
     use print::pprust;
     use std;
     use std::vec;
@@ -1656,8 +1685,9 @@ mod test {
         }
     }
 
-    fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) {
-        pprust::print_mod(s, &crate.module, crate.attrs);
+    fn fake_print_crate(crate: @ast::Crate) {
+        let s = pprust::rust_printer(std::io::stderr(),get_ident_interner());
+        pprust::print_crate_(s, crate);
     }
 
     fn expand_crate_str(crate_str: @str) -> @ast::Crate {
@@ -1784,6 +1814,57 @@ mod test {
         }
     }
 
+    #[test] fn quote_expr_test() {
+        quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_expr!(dontcare);}");
+    }
+    #[test] fn quote_item_test() {
+        quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_item!(dontcare);}");
+    }
+    #[test] fn quote_pat_test() {
+        quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_pat!(dontcare);}");
+    }
+    #[test] fn quote_ty_test() {
+        quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_ty!(dontcare);}");
+    }
+    #[test] fn quote_tokens_test() {
+        quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_tokens!(dontcare);}");
+    }
+
+    fn quote_ext_cx_test(crate_str : @str) {
+        let crate = expand_crate_str(crate_str);
+        // find the ext_cx binding
+        let bindings = @mut ~[];
+        visit::walk_crate(&mut new_name_finder(bindings), crate, ());
+        let cxbinds : ~[&ast::Ident] = bindings.iter().filter(|b|{@"ext_cx" == (ident_to_str(*b))}).collect();
+        let cxbind = match cxbinds {
+            [b] => b,
+            _ => fail!("expected just one binding for ext_cx")
+        };
+        let resolved_binding = mtwt_resolve(*cxbind);
+        // find all the ext_cx varrefs:
+        let varrefs = @mut ~[];
+        visit::walk_crate(&mut new_path_finder(varrefs), crate, ());
+        // the ext_cx binding should bind all of the ext_cx varrefs:
+        for (idx,v) in varrefs.iter().filter(|p|{ p.segments.len() == 1
+                    && (@"ext_cx" == (ident_to_str(&p.segments[0].identifier)))
+            }).enumerate() {
+            if (mtwt_resolve(v.segments[0].identifier) != resolved_binding) {
+                std::io::println("uh oh, ext_cx binding didn't match ext_cx varref:");
+                std::io::println(fmt!("this is varref # %?",idx));
+                std::io::println(fmt!("binding: %?",cxbind));
+                std::io::println(fmt!("resolves to: %?",resolved_binding));
+                std::io::println(fmt!("varref: %?",v.segments[0]));
+                std::io::println(fmt!("resolves to: %?",mtwt_resolve(v.segments[0].identifier)));
+                let table = get_sctable();
+                std::io::println("SC table:");
+                for (idx,val) in table.table.iter().enumerate() {
+                    std::io::println(fmt!("%4u : %?",idx,val));
+                }
+            }
+            assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding);
+        };
+    }
+
     #[test]
     fn pat_idents(){
         let pat = string_to_pat(@"(a,Foo{x:c @ (b,9),y:Bar(4,d)})");
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 4e8b7467c5c..d1299cf56cb 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -12,6 +12,7 @@ use ast;
 use codemap::{BytePos, Pos, Span};
 use ext::base::ExtCtxt;
 use ext::base;
+use ext::expand;
 use ext::build::AstBuilder;
 use parse::token::*;
 use parse::token;
@@ -291,47 +292,73 @@ pub mod rt {
 
 pub fn expand_quote_tokens(cx: @ExtCtxt,
                            sp: Span,
-                           tts: &[ast::token_tree]) -> base::MacResult {
+                           tts: &[ast::token_tree],
+                           ctxt: ast::SyntaxContext) -> base::MacResult {
     let (cx_expr, expr) = expand_tts(cx, sp, tts);
-    base::MRExpr(expand_wrapper(cx, sp, cx_expr, expr))
+    let expanded = expand_wrapper(cx, sp, cx_expr, expr);
+    // repaint the expanded code so it's as though it was the original text.
+    let repainted = expand::replace_ctxts(expanded,ctxt);
+    base::MRExpr(repainted)
 }
 
 pub fn expand_quote_expr(cx: @ExtCtxt,
                          sp: Span,
-                         tts: &[ast::token_tree]) -> base::MacResult {
-    base::MRExpr(expand_parse_call(cx, sp, "parse_expr", ~[], tts))
+                         tts: &[ast::token_tree],
+                         ctxt: ast::SyntaxContext) -> base::MacResult {
+    let expanded = expand_parse_call(cx, sp, "parse_expr", ~[], tts);
+    // repaint the expanded code so it's as though it was the original text.
+    let repainted = expand::replace_ctxts(expanded,ctxt);
+    base::MRExpr(repainted)
 }
 
+// these probably need to be capturing, too...
+
 pub fn expand_quote_item(cx: @ExtCtxt,
                          sp: Span,
-                         tts: &[ast::token_tree]) -> base::MacResult {
+                         tts: &[ast::token_tree],
+                         ctxt: ast::SyntaxContext) -> base::MacResult {
     let e_attrs = cx.expr_vec_uniq(sp, ~[]);
-    base::MRExpr(expand_parse_call(cx, sp, "parse_item",
-                                    ~[e_attrs], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_item",
+                                    ~[e_attrs], tts);
+    // repaint the expanded code so it's as though it was the original text.
+    let repainted = expand::replace_ctxts(expanded,ctxt);
+    base::MRExpr(repainted)
 }
 
 pub fn expand_quote_pat(cx: @ExtCtxt,
                         sp: Span,
-                        tts: &[ast::token_tree]) -> base::MacResult {
+                        tts: &[ast::token_tree],
+                        ctxt: ast::SyntaxContext) -> base::MacResult {
     let e_refutable = cx.expr_lit(sp, ast::lit_bool(true));
-    base::MRExpr(expand_parse_call(cx, sp, "parse_pat",
-                                    ~[e_refutable], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_pat",
+                                    ~[e_refutable], tts);
+    // repaint the expanded code so it's as though it was the original text.
+    let repainted = expand::replace_ctxts(expanded,ctxt);
+    base::MRExpr(repainted)
 }
 
 pub fn expand_quote_ty(cx: @ExtCtxt,
                        sp: Span,
-                       tts: &[ast::token_tree]) -> base::MacResult {
+                       tts: &[ast::token_tree],
+                       ctxt: ast::SyntaxContext) -> base::MacResult {
     let e_param_colons = cx.expr_lit(sp, ast::lit_bool(false));
-    base::MRExpr(expand_parse_call(cx, sp, "parse_ty",
-                                    ~[e_param_colons], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_ty",
+                                     ~[e_param_colons], tts);
+    // repaint the expanded code so it's as though it was the original text.
+    let repainted = expand::replace_ctxts(expanded,ctxt);
+    base::MRExpr(repainted)
 }
 
 pub fn expand_quote_stmt(cx: @ExtCtxt,
                          sp: Span,
-                         tts: &[ast::token_tree]) -> base::MacResult {
+                         tts: &[ast::token_tree],
+                         ctxt: ast::SyntaxContext) -> base::MacResult {
     let e_attrs = cx.expr_vec_uniq(sp, ~[]);
-    base::MRExpr(expand_parse_call(cx, sp, "parse_stmt",
-                                    ~[e_attrs], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_stmt",
+                                    ~[e_attrs], tts);
+    // repaint the expanded code so it's as though it was the original text.
+    let repainted = expand::replace_ctxts(expanded,ctxt);
+    base::MRExpr(repainted)
 }
 
 fn ids_ext(strs: ~[~str]) -> ~[ast::Ident] {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 2145e4297e7..074ec3cd195 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -150,8 +150,8 @@ pub fn add_new_extension(cx: @ExtCtxt,
         cx.span_fatal(best_fail_spot, best_fail_msg);
     }
 
-    let exp: @fn(@ExtCtxt, Span, &[ast::token_tree]) -> MacResult =
-        |cx, sp, arg| generic_extension(cx, sp, name, arg, *lhses, *rhses);
+    let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult =
+        |cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses);
 
     return MRDef(MacroDef{
         name: ident_to_str(&name),
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 823e018a718..b805d55830f 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -209,6 +209,7 @@ pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate {
 }
 
 fn noop_fold_view_item(vi: &view_item_, _fld: @ast_fold) -> view_item_ {
+    // FIXME #7654: doesn't iterate over idents in a view_item_use
     return /* FIXME (#2543) */ (*vi).clone();
 }