about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorJohn Clements <clements@racket-lang.org>2014-07-04 12:19:15 -0700
committerJohn Clements <clements@racket-lang.org>2014-07-04 13:20:14 -0700
commit0ba15c99f31f769bd015871202000e48c77066ca (patch)
tree8347686222fbf2e37350bc52e9b88454d0335b19 /src/libsyntax/ext
parent92708322fd19747100ff5eda2e4584bc9d1f2b38 (diff)
downloadrust-0ba15c99f31f769bd015871202000e48c77066ca.tar.gz
rust-0ba15c99f31f769bd015871202000e48c77066ca.zip
hygiene for item fn args
also, introduce fn_decl_arg_bindings and expand_and_rename abstractions
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/expand.rs56
1 files changed, 49 insertions, 7 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index e2c8782e13c..c472f293f92 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -386,6 +386,19 @@ fn expand_item_modifiers(mut it: Gc<ast::Item>, fld: &mut MacroExpander)
     expand_item_modifiers(it, fld)
 }
 
+/// Expand item_underscore
+fn expand_item_underscore(item: &ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
+    match *item {
+        ast::ItemFn(decl, fn_style, abi, ref generics, body) => {
+            let (rewritten_fn_decl, rewritten_body)
+                = expand_and_rename_fn_decl_and_block(decl,body,fld);
+            let expanded_generics = fold::fold_generics(generics,fld);
+            ast::ItemFn(rewritten_fn_decl, fn_style, abi, expanded_generics, rewritten_body)
+        }
+        _ => noop_fold_item_underscore(&*item, fld)
+    }
+}
+
 // does this attribute list contain "macro_escape" ?
 fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
     attr::contains_name(attrs, "macro_escape")
@@ -656,6 +669,7 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
     }
 }
 
+// expand the arm of a 'match', renaming for macro hygiene
 fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
     // expand pats... they might contain macro uses:
     let expanded_pats : Vec<Gc<ast::Pat>> = arm.pats.iter().map(|pat| fld.fold_pat(*pat)).collect();
@@ -665,17 +679,15 @@ fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
     // all of the pats must have the same set of bindings, so use the
     // first one to extract them and generate new names:
     let first_pat = expanded_pats.get(0);
-    // code duplicated from 'let', above. Perhaps this can be lifted
-    // into a separate function:
     let idents = pattern_bindings(*first_pat);
-    let new_pending_renames =
+    let new_renames =
         idents.iter().map(|id| (*id,fresh_name(id))).collect();
     // apply the renaming, but only to the PatIdents:
-    let mut rename_pats_fld = PatIdentRenamer{renames:&new_pending_renames};
+    let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
     let rewritten_pats =
         expanded_pats.iter().map(|pat| rename_pats_fld.fold_pat(*pat)).collect();
     // apply renaming and then expansion to the guard and the body:
-    let mut rename_fld = IdentRenamer{renames:&new_pending_renames};
+    let mut rename_fld = IdentRenamer{renames:&new_renames};
     let rewritten_guard =
         arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
     let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body));
@@ -687,8 +699,6 @@ fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
     }
 }
 
-
-
 /// A visitor that extracts the PatIdent (binding) paths
 /// from a given thingy and puts them in a mutable
 /// array
@@ -721,6 +731,15 @@ fn pattern_bindings(pat : &ast::Pat) -> Vec<ast::Ident> {
     name_finder.ident_accumulator
 }
 
+/// find the PatIdent paths in a
+fn fn_decl_arg_bindings(fn_decl: &ast::FnDecl) -> Vec<ast::Ident> {
+    let mut pat_idents = PatIdentFinder{ident_accumulator:Vec::new()};
+    for arg in fn_decl.inputs.iter() {
+        pat_idents.visit_pat(arg.pat,());
+    }
+    pat_idents.ident_accumulator
+}
+
 // expand a block. pushes a new exts_frame, then calls expand_block_elts
 fn expand_block(blk: &Block, fld: &mut MacroExpander) -> P<Block> {
     // see note below about treatment of exts table
@@ -882,6 +901,25 @@ impl<'a> Folder for PatIdentRenamer<'a> {
     }
 }
 
+/// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
+/// PatIdents in its arguments to perform renaming in the FnDecl and
+/// the block, returning both the new FnDecl and the new Block.
+fn expand_and_rename_fn_decl_and_block(fn_decl: &ast::FnDecl, block: Gc<ast::Block>,
+                                       fld: &mut MacroExpander)
+    -> (Gc<ast::FnDecl>, Gc<ast::Block>) {
+    let expanded_decl = fld.fold_fn_decl(fn_decl);
+    let idents = fn_decl_arg_bindings(expanded_decl);
+    let renames =
+        idents.iter().map(|id : &ast::Ident| (*id,fresh_name(id))).collect();
+    // first, a renamer for the PatIdents, for the fn_decl:
+    let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
+    let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
+    // now, a renamer for *all* idents, for the body:
+    let mut rename_fld = IdentRenamer{renames: &renames};
+    let rewritten_body = fld.fold_block(rename_fld.fold_block(block));
+    (rewritten_fn_decl,rewritten_body)
+}
+
 /// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b> {
     pub extsbox: SyntaxEnv,
@@ -901,6 +939,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         expand_item(item, self)
     }
 
+    fn fold_item_underscore(&mut self, item: &ast::Item_) -> ast::Item_ {
+        expand_item_underscore(item, self)
+    }
+
     fn fold_stmt(&mut self, stmt: &ast::Stmt) -> SmallVector<Gc<ast::Stmt>> {
         expand_stmt(stmt, self)
     }