]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax/fold.rs
auto merge of #9005 : alexcrichton/rust/rusty-log, r=brson
[rust.git] / src / libsyntax / fold.rs
index 1e4df7811ddbc41bcb344496be187ae796abcf14..664bd3f128a45dad49d18e48a739eec10e7249e7 100644 (file)
 use parse::token;
 use opt_vec::OptVec;
 
+// this file defines an ast_fold trait for objects that can perform
+// a "fold" on Rust ASTs. It also contains a structure that implements
+// that trait, and a "default_fold" whose fields contain closures
+// that perform "default traversals", visiting all of the sub-elements
+// and re-assembling the result. The "fun_to_ident_folder" in the
+// test module provides a simple example of creating a very simple
+// fold that only looks at identifiers.
+
 pub trait ast_fold {
     fn fold_crate(@self, &Crate) -> Crate;
     fn fold_view_item(@self, &view_item) -> view_item;
@@ -35,6 +43,7 @@ pub trait ast_fold {
     fn fold_ident(@self, Ident) -> Ident;
     fn fold_path(@self, &Path) -> Path;
     fn fold_local(@self, @Local) -> @Local;
+    fn fold_mac(@self, &mac) -> mac;
     fn map_exprs(@self, @fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr];
     fn new_id(@self, NodeId) -> NodeId;
     fn new_span(@self, Span) -> Span;
@@ -64,6 +73,7 @@ pub struct AstFoldFns {
     fold_ident: @fn(Ident, @ast_fold) -> Ident,
     fold_path: @fn(&Path, @ast_fold) -> Path,
     fold_local: @fn(@Local, @ast_fold) -> @Local,
+    fold_mac: @fn(&mac_, Span, @ast_fold) -> (mac_, Span),
     map_exprs: @fn(@fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr],
     new_id: @fn(NodeId) -> NodeId,
     new_span: @fn(Span) -> Span
@@ -112,41 +122,31 @@ fn fold_arg_(a: arg, fld: @ast_fold) -> arg {
     }
 }
 
-//used in noop_fold_expr, and possibly elsewhere in the future
-fn fold_mac_(m: &mac, fld: @ast_fold) -> mac {
-    Spanned {
-        node: match m.node {
-            mac_invoc_tt(ref p,ref tts) =>
-            mac_invoc_tt(fld.fold_path(p),
-                         fold_tts(*tts,fld))
-        },
-        span: fld.new_span(m.span)
-    }
-}
-
-fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] {
+// build a new vector of tts by appling the ast_fold's fold_ident to
+// all of the identifiers in the token trees.
+pub fn fold_tts(tts : &[token_tree], f : @ast_fold) -> ~[token_tree] {
     do tts.map |tt| {
         match *tt {
             tt_tok(span, ref tok) =>
-            tt_tok(span,maybe_fold_ident(tok,fld)),
+            tt_tok(span,maybe_fold_ident(tok,f)),
             tt_delim(ref tts) =>
-            tt_delim(@mut fold_tts(**tts, fld)),
+            tt_delim(@mut fold_tts(**tts, f)),
             tt_seq(span, ref pattern, ref sep, is_optional) =>
             tt_seq(span,
-                   @mut fold_tts(**pattern, fld),
-                   sep.map(|tok|maybe_fold_ident(tok,fld)),
+                   @mut fold_tts(**pattern, f),
+                   sep.map(|tok|maybe_fold_ident(tok,f)),
                    is_optional),
             tt_nonterminal(sp,ref ident) =>
-            tt_nonterminal(sp,fld.fold_ident(*ident))
+            tt_nonterminal(sp,f.fold_ident(*ident))
         }
     }
 }
 
 // apply ident folder if it's an ident, otherwise leave it alone
-fn maybe_fold_ident(t: &token::Token, fld: @ast_fold) -> token::Token {
+fn maybe_fold_ident(t : &token::Token, f: @ast_fold) -> token::Token {
     match *t {
         token::IDENT(id,followed_by_colons) =>
-        token::IDENT(fld.fold_ident(id),followed_by_colons),
+        token::IDENT(f.fold_ident(id),followed_by_colons),
         _ => (*t).clone()
     }
 }
@@ -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();
 }
 
@@ -323,11 +324,7 @@ pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
             )
         }
         item_mac(ref m) => {
-            // FIXME #2888: we might actually want to do something here.
-            // ... okay, we're doing something. It would probably be nicer
-            // to add something to the ast_fold trait, but I'll defer
-            // that work.
-            item_mac(fold_mac_(m,fld))
+            item_mac(fld.fold_mac(m))
         }
     }
 }
@@ -396,7 +393,6 @@ pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
 }
 
 fn noop_fold_stmt(s: &Stmt_, fld: @ast_fold) -> Option<Stmt_> {
-    let fold_mac = |x| fold_mac_(x, fld);
     match *s {
         StmtDecl(d, nid) => {
             match fld.fold_decl(d) {
@@ -410,7 +406,7 @@ fn noop_fold_stmt(s: &Stmt_, fld: @ast_fold) -> Option<Stmt_> {
         StmtSemi(e, nid) => {
             Some(StmtSemi(fld.fold_expr(e), fld.new_id(nid)))
         }
-        StmtMac(ref mac, semi) => Some(StmtMac(fold_mac(mac), semi))
+        StmtMac(ref mac, semi) => Some(StmtMac(fld.fold_mac(mac), semi))
     }
 }
 
@@ -478,6 +474,12 @@ fn noop_fold_decl(d: &Decl_, fld: @ast_fold) -> Option<Decl_> {
     }
 }
 
+// lift a function in ast-thingy X fold -> ast-thingy to a function
+// in (ast-thingy X span X fold) -> (ast-thingy X span). Basically,
+// carries the span around.
+// It seems strange to me that the call to new_fold doesn't happen
+// here but instead in the impl down below.... probably just an
+// accident?
 pub fn wrap<T>(f: @fn(&T, @ast_fold) -> T)
             -> @fn(&T, Span, @ast_fold) -> (T, Span) {
     let result: @fn(&T, Span, @ast_fold) -> (T, Span) = |x, s, fld| {
@@ -496,8 +498,6 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
     }
     let fold_field = |x| fold_field_(x, fld);
 
-    let fold_mac = |x| fold_mac_(x, fld);
-
     match *e {
         ExprVstore(e, v) => {
             ExprVstore(fld.fold_expr(e), v)
@@ -544,7 +544,7 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
         ExprDoBody(f) => ExprDoBody(fld.fold_expr(f)),
         ExprLit(_) => (*e).clone(),
         ExprCast(expr, ref ty) => {
-            ExprCast(fld.fold_expr(expr), (*ty).clone())
+            ExprCast(fld.fold_expr(expr), fld.fold_ty(ty))
         }
         ExprAddrOf(m, ohs) => ExprAddrOf(m, fld.fold_expr(ohs)),
         ExprIf(cond, ref tr, fl) => {
@@ -557,10 +557,11 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
         ExprWhile(cond, ref body) => {
             ExprWhile(fld.fold_expr(cond), fld.fold_block(body))
         }
-        ExprForLoop(pat, iter, ref body) => {
+        ExprForLoop(pat, iter, ref body, opt_ident) => {
             ExprForLoop(fld.fold_pat(pat),
-                          fld.fold_expr(iter),
-                          fld.fold_block(body))
+                        fld.fold_expr(iter),
+                        fld.fold_block(body),
+                        opt_ident.map_move(|x| fld.fold_ident(x)))
         }
         ExprLoop(ref body, opt_ident) => {
             ExprLoop(
@@ -624,7 +625,7 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
                 .. (*a).clone()
             })
         }
-        ExprMac(ref mac) => ExprMac(fold_mac(mac)),
+        ExprMac(ref mac) => ExprMac(fld.fold_mac(mac)),
         ExprStruct(ref path, ref fields, maybe_expr) => {
             ExprStruct(
                 fld.fold_path(path),
@@ -637,7 +638,6 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
 }
 
 pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
-    let fold_mac = |x| fold_mac_(x, fld);
     fn fold_mt(mt: &mt, fld: @ast_fold) -> mt {
         mt {
             ty: ~fld.fold_ty(mt.ty),
@@ -693,7 +693,7 @@ fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
             )
         }
         ty_typeof(e) => ty_typeof(fld.fold_expr(e)),
-        ty_mac(ref mac) => ty_mac(fold_mac(mac))
+        ty_mac(ref mac) => ty_mac(fld.fold_mac(mac))
     }
 }
 
@@ -780,6 +780,19 @@ fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local {
     }
 }
 
+// the default macro traversal. visit the path
+// using fold_path, and the tts using fold_tts,
+// and the span using new_span
+fn noop_fold_mac(m: &mac_, fld: @ast_fold) -> mac_ {
+    match *m {
+        mac_invoc_tt(ref p,ref tts,ctxt) =>
+        mac_invoc_tt(fld.fold_path(p),
+                     fold_tts(*tts,fld),
+                     ctxt)
+    }
+}
+
+
 /* temporarily eta-expand because of a compiler bug with using `fn<T>` as a
    value */
 fn noop_map_exprs(f: @fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] {
@@ -812,6 +825,7 @@ pub fn default_ast_fold() -> ast_fold_fns {
         fold_ident: noop_fold_ident,
         fold_path: noop_fold_path,
         fold_local: noop_fold_local,
+        fold_mac: wrap(noop_fold_mac),
         map_exprs: noop_map_exprs,
         new_id: noop_id,
         new_span: noop_span,
@@ -917,6 +931,10 @@ fn fold_path(@self, x: &Path) -> Path {
     fn fold_local(@self, x: @Local) -> @Local {
         (self.fold_local)(x, self as @ast_fold)
     }
+    fn fold_mac(@self, x: &mac) -> mac {
+        let (n, s) = (self.fold_mac)(&x.node, x.span, self as @ast_fold);
+        Spanned { node: n, span: (self.new_span)(s) }
+    }
     fn map_exprs(@self,
                  f: @fn(@Expr) -> @Expr,
                  e: &[@Expr])
@@ -941,6 +959,8 @@ fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute] {
     }
 }
 
+// brson agrees with me that this function's existence is probably
+// not a good or useful thing.
 pub fn make_fold(afp: ast_fold_fns) -> @ast_fold {
     afp as @ast_fold
 }
@@ -1013,4 +1033,15 @@ macro_rules! assert_pred (
                                     token::get_ident_interner()),
                      ~"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))");
     }
+
+    // and in cast expressions... this appears to be an existing bug.
+    #[test] fn ident_transformation_in_types () {
+        let zz_fold = fun_to_ident_folder(to_zz());
+        let ast = string_to_crate(@"fn a() {let z = 13 as int;}");
+        assert_pred!(matches_codepattern,
+                     "matches_codepattern",
+                     pprust::to_str(&zz_fold.fold_crate(ast),fake_print_crate,
+                                    token::get_ident_interner()),
+                     ~"fn zz(){let zz=13 as zz;}");
+    }
 }