]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/fold.rs
auto merge of #8718 : bblum/rust/typeof, r=pcwalton
[rust.git] / src / libsyntax / fold.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use ast::*;
12 use ast;
13 use codemap::{span, spanned};
14 use parse::token;
15 use opt_vec::OptVec;
16
17 pub trait ast_fold {
18     fn fold_crate(@self, &Crate) -> Crate;
19     fn fold_view_item(@self, &view_item) -> view_item;
20     fn fold_foreign_item(@self, @foreign_item) -> @foreign_item;
21     fn fold_item(@self, @item) -> Option<@item>;
22     fn fold_struct_field(@self, @struct_field) -> @struct_field;
23     fn fold_item_underscore(@self, &item_) -> item_;
24     fn fold_method(@self, @method) -> @method;
25     fn fold_block(@self, &Block) -> Block;
26     fn fold_stmt(@self, &stmt) -> Option<@stmt>;
27     fn fold_arm(@self, &arm) -> arm;
28     fn fold_pat(@self, @pat) -> @pat;
29     fn fold_decl(@self, @decl) -> Option<@decl>;
30     fn fold_expr(@self, @expr) -> @expr;
31     fn fold_ty(@self, &Ty) -> Ty;
32     fn fold_mod(@self, &_mod) -> _mod;
33     fn fold_foreign_mod(@self, &foreign_mod) -> foreign_mod;
34     fn fold_variant(@self, &variant) -> variant;
35     fn fold_ident(@self, ident) -> ident;
36     fn fold_path(@self, &Path) -> Path;
37     fn fold_local(@self, @Local) -> @Local;
38     fn map_exprs(@self, @fn(@expr) -> @expr, &[@expr]) -> ~[@expr];
39     fn new_id(@self, NodeId) -> NodeId;
40     fn new_span(@self, span) -> span;
41 }
42
43 // We may eventually want to be able to fold over type parameters, too
44
45 pub struct AstFoldFns {
46     //unlike the others, item_ is non-trivial
47     fold_crate: @fn(&Crate, @ast_fold) -> Crate,
48     fold_view_item: @fn(&view_item_, @ast_fold) -> view_item_,
49     fold_foreign_item: @fn(@foreign_item, @ast_fold) -> @foreign_item,
50     fold_item: @fn(@item, @ast_fold) -> Option<@item>,
51     fold_struct_field: @fn(@struct_field, @ast_fold) -> @struct_field,
52     fold_item_underscore: @fn(&item_, @ast_fold) -> item_,
53     fold_method: @fn(@method, @ast_fold) -> @method,
54     fold_block: @fn(&Block, @ast_fold) -> Block,
55     fold_stmt: @fn(&stmt_, span, @ast_fold) -> (Option<stmt_>, span),
56     fold_arm: @fn(&arm, @ast_fold) -> arm,
57     fold_pat: @fn(&pat_, span, @ast_fold) -> (pat_, span),
58     fold_decl: @fn(&decl_, span, @ast_fold) -> (Option<decl_>, span),
59     fold_expr: @fn(&expr_, span, @ast_fold) -> (expr_, span),
60     fold_ty: @fn(&ty_, span, @ast_fold) -> (ty_, span),
61     fold_mod: @fn(&_mod, @ast_fold) -> _mod,
62     fold_foreign_mod: @fn(&foreign_mod, @ast_fold) -> foreign_mod,
63     fold_variant: @fn(&variant_, span, @ast_fold) -> (variant_, span),
64     fold_ident: @fn(ident, @ast_fold) -> ident,
65     fold_path: @fn(&Path, @ast_fold) -> Path,
66     fold_local: @fn(@Local, @ast_fold) -> @Local,
67     map_exprs: @fn(@fn(@expr) -> @expr, &[@expr]) -> ~[@expr],
68     new_id: @fn(NodeId) -> NodeId,
69     new_span: @fn(span) -> span
70 }
71
72 pub type ast_fold_fns = @AstFoldFns;
73
74 /* some little folds that probably aren't useful to have in ast_fold itself*/
75
76 //used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
77 fn fold_meta_item_(mi: @MetaItem, fld: @ast_fold) -> @MetaItem {
78     @spanned {
79         node:
80             match mi.node {
81                 MetaWord(id) => MetaWord(id),
82                 MetaList(id, ref mis) => {
83                     let fold_meta_item = |x| fold_meta_item_(x, fld);
84                     MetaList(
85                         id,
86                         mis.map(|e| fold_meta_item(*e))
87                     )
88                 }
89                 MetaNameValue(id, s) => MetaNameValue(id, s)
90             },
91         span: fld.new_span(mi.span) }
92 }
93 //used in noop_fold_item and noop_fold_crate
94 fn fold_attribute_(at: Attribute, fld: @ast_fold) -> Attribute {
95     spanned {
96         span: fld.new_span(at.span),
97         node: ast::Attribute_ {
98             style: at.node.style,
99             value: fold_meta_item_(at.node.value, fld),
100             is_sugared_doc: at.node.is_sugared_doc
101         }
102     }
103 }
104
105 //used in noop_fold_foreign_item and noop_fold_fn_decl
106 fn fold_arg_(a: arg, fld: @ast_fold) -> arg {
107     ast::arg {
108         is_mutbl: a.is_mutbl,
109         ty: fld.fold_ty(&a.ty),
110         pat: fld.fold_pat(a.pat),
111         id: fld.new_id(a.id),
112     }
113 }
114
115 //used in noop_fold_expr, and possibly elsewhere in the future
116 fn fold_mac_(m: &mac, fld: @ast_fold) -> mac {
117     spanned {
118         node: match m.node {
119             mac_invoc_tt(ref p,ref tts) =>
120             mac_invoc_tt(fld.fold_path(p),
121                          fold_tts(*tts,fld))
122         },
123         span: fld.new_span(m.span)
124     }
125 }
126
127 fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] {
128     do tts.map |tt| {
129         match *tt {
130             tt_tok(span, ref tok) =>
131             tt_tok(span,maybe_fold_ident(tok,fld)),
132             tt_delim(ref tts) =>
133             tt_delim(@mut fold_tts(**tts, fld)),
134             tt_seq(span, ref pattern, ref sep, is_optional) =>
135             tt_seq(span,
136                    @mut fold_tts(**pattern, fld),
137                    sep.map(|tok|maybe_fold_ident(tok,fld)),
138                    is_optional),
139             tt_nonterminal(sp,ref ident) =>
140             tt_nonterminal(sp,fld.fold_ident(*ident))
141         }
142     }
143 }
144
145 // apply ident folder if it's an ident, otherwise leave it alone
146 fn maybe_fold_ident(t: &token::Token, fld: @ast_fold) -> token::Token {
147     match *t {
148         token::IDENT(id,followed_by_colons) =>
149         token::IDENT(fld.fold_ident(id),followed_by_colons),
150         _ => (*t).clone()
151     }
152 }
153
154 pub fn fold_fn_decl(decl: &ast::fn_decl, fld: @ast_fold) -> ast::fn_decl {
155     ast::fn_decl {
156         inputs: decl.inputs.map(|x| fold_arg_(/*bad*/ (*x).clone(), fld)),
157         output: fld.fold_ty(&decl.output),
158         cf: decl.cf,
159     }
160 }
161
162 fn fold_ty_param_bound(tpb: &TyParamBound, fld: @ast_fold) -> TyParamBound {
163     match *tpb {
164         TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
165         RegionTyParamBound => RegionTyParamBound
166     }
167 }
168
169 pub fn fold_ty_param(tp: TyParam,
170                      fld: @ast_fold) -> TyParam {
171     TyParam {ident: tp.ident,
172              id: fld.new_id(tp.id),
173              bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld))}
174 }
175
176 pub fn fold_ty_params(tps: &OptVec<TyParam>,
177                       fld: @ast_fold) -> OptVec<TyParam> {
178     let tps = /*bad*/ (*tps).clone();
179     tps.map_move(|tp| fold_ty_param(tp, fld))
180 }
181
182 pub fn fold_lifetime(l: &Lifetime,
183                      fld: @ast_fold) -> Lifetime {
184     Lifetime {id: fld.new_id(l.id),
185               span: fld.new_span(l.span),
186               ident: l.ident}
187 }
188
189 pub fn fold_lifetimes(lts: &OptVec<Lifetime>,
190                       fld: @ast_fold) -> OptVec<Lifetime> {
191     lts.map(|l| fold_lifetime(l, fld))
192 }
193
194 pub fn fold_generics(generics: &Generics, fld: @ast_fold) -> Generics {
195     Generics {ty_params: fold_ty_params(&generics.ty_params, fld),
196               lifetimes: fold_lifetimes(&generics.lifetimes, fld)}
197 }
198
199 pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate {
200     let fold_meta_item = |x| fold_meta_item_(x, fld);
201     let fold_attribute = |x| fold_attribute_(x, fld);
202
203     Crate {
204         module: fld.fold_mod(&c.module),
205         attrs: c.attrs.map(|x| fold_attribute(*x)),
206         config: c.config.map(|x| fold_meta_item(*x)),
207         span: fld.new_span(c.span),
208     }
209 }
210
211 fn noop_fold_view_item(vi: &view_item_, _fld: @ast_fold) -> view_item_ {
212     return /* FIXME (#2543) */ (*vi).clone();
213 }
214
215
216 fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold)
217     -> @foreign_item {
218     let fold_arg = |x| fold_arg_(x, fld);
219     let fold_attribute = |x| fold_attribute_(x, fld);
220
221     @ast::foreign_item {
222         ident: fld.fold_ident(ni.ident),
223         attrs: ni.attrs.map(|x| fold_attribute(*x)),
224         node:
225             match ni.node {
226                 foreign_item_fn(ref fdec, ref generics) => {
227                     foreign_item_fn(
228                         ast::fn_decl {
229                             inputs: fdec.inputs.map(|a|
230                                 fold_arg(/*bad*/(*a).clone())),
231                             output: fld.fold_ty(&fdec.output),
232                             cf: fdec.cf,
233                         },
234                         fold_generics(generics, fld))
235                 }
236                 foreign_item_static(ref t, m) => {
237                     foreign_item_static(fld.fold_ty(t), m)
238                 }
239             },
240         id: fld.new_id(ni.id),
241         span: fld.new_span(ni.span),
242         vis: ni.vis,
243     }
244 }
245
246 pub fn noop_fold_item(i: @item, fld: @ast_fold) -> Option<@item> {
247     let fold_attribute = |x| fold_attribute_(x, fld);
248
249     Some(@ast::item { ident: fld.fold_ident(i.ident),
250                       attrs: i.attrs.map(|e| fold_attribute(*e)),
251                       id: fld.new_id(i.id),
252                       node: fld.fold_item_underscore(&i.node),
253                       vis: i.vis,
254                       span: fld.new_span(i.span) })
255 }
256
257 fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold)
258                        -> @struct_field {
259     let fold_attribute = |x| fold_attribute_(x, fld);
260
261     @spanned {
262         node: ast::struct_field_ {
263             kind: sf.node.kind,
264             id: sf.node.id,
265             ty: fld.fold_ty(&sf.node.ty),
266             attrs: sf.node.attrs.map(|e| fold_attribute(*e))
267         },
268         span: sf.span
269     }
270 }
271
272 pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
273     match *i {
274         item_static(ref t, m, e) => item_static(fld.fold_ty(t), m, fld.fold_expr(e)),
275         item_fn(ref decl, purity, abi, ref generics, ref body) => {
276             item_fn(
277                 fold_fn_decl(decl, fld),
278                 purity,
279                 abi,
280                 fold_generics(generics, fld),
281                 fld.fold_block(body)
282             )
283         }
284         item_mod(ref m) => item_mod(fld.fold_mod(m)),
285         item_foreign_mod(ref nm) => {
286             item_foreign_mod(fld.fold_foreign_mod(nm))
287         }
288         item_ty(ref t, ref generics) => {
289             item_ty(fld.fold_ty(t), fold_generics(generics, fld))
290         }
291         item_enum(ref enum_definition, ref generics) => {
292             item_enum(
293                 ast::enum_def {
294                     variants: do enum_definition.variants.map |x| {
295                         fld.fold_variant(x)
296                     },
297                 },
298                 fold_generics(generics, fld))
299         }
300         item_struct(ref struct_def, ref generics) => {
301             let struct_def = fold_struct_def(*struct_def, fld);
302             item_struct(struct_def, /* FIXME (#2543) */ (*generics).clone())
303         }
304         item_impl(ref generics, ref ifce, ref ty, ref methods) => {
305             item_impl(
306                 fold_generics(generics, fld),
307                 ifce.map(|p| fold_trait_ref(p, fld)),
308                 fld.fold_ty(ty),
309                 methods.map(|x| fld.fold_method(*x))
310             )
311         }
312         item_trait(ref generics, ref traits, ref methods) => {
313             let methods = do methods.map |method| {
314                 match *method {
315                     required(*) => (*method).clone(),
316                     provided(method) => provided(fld.fold_method(method))
317                 }
318             };
319             item_trait(
320                 fold_generics(generics, fld),
321                 traits.map(|p| fold_trait_ref(p, fld)),
322                 methods
323             )
324         }
325         item_mac(ref m) => {
326             // FIXME #2888: we might actually want to do something here.
327             // ... okay, we're doing something. It would probably be nicer
328             // to add something to the ast_fold trait, but I'll defer
329             // that work.
330             item_mac(fold_mac_(m,fld))
331         }
332     }
333 }
334
335 fn fold_struct_def(struct_def: @ast::struct_def, fld: @ast_fold)
336                 -> @ast::struct_def {
337     @ast::struct_def {
338         fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)),
339         ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)),
340     }
341 }
342
343 fn fold_trait_ref(p: &trait_ref, fld: @ast_fold) -> trait_ref {
344     ast::trait_ref {
345         path: fld.fold_path(&p.path),
346         ref_id: fld.new_id(p.ref_id),
347     }
348 }
349
350 fn fold_struct_field(f: @struct_field, fld: @ast_fold) -> @struct_field {
351     @spanned {
352         node: ast::struct_field_ {
353             kind: f.node.kind,
354             id: fld.new_id(f.node.id),
355             ty: fld.fold_ty(&f.node.ty),
356             attrs: /* FIXME (#2543) */ f.node.attrs.clone(),
357         },
358         span: fld.new_span(f.span),
359     }
360 }
361
362 fn noop_fold_method(m: @method, fld: @ast_fold) -> @method {
363     @ast::method {
364         ident: fld.fold_ident(m.ident),
365         attrs: /* FIXME (#2543) */ m.attrs.clone(),
366         generics: fold_generics(&m.generics, fld),
367         explicit_self: m.explicit_self,
368         purity: m.purity,
369         decl: fold_fn_decl(&m.decl, fld),
370         body: fld.fold_block(&m.body),
371         id: fld.new_id(m.id),
372         span: fld.new_span(m.span),
373         self_id: fld.new_id(m.self_id),
374         vis: m.vis,
375     }
376 }
377
378
379 pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
380     let view_items = b.view_items.map(|x| fld.fold_view_item(x));
381     let mut stmts = ~[];
382     for stmt in b.stmts.iter() {
383         match fld.fold_stmt(*stmt) {
384             None => {}
385             Some(stmt) => stmts.push(stmt)
386         }
387     }
388     ast::Block {
389         view_items: view_items,
390         stmts: stmts,
391         expr: b.expr.map(|x| fld.fold_expr(*x)),
392         id: fld.new_id(b.id),
393         rules: b.rules,
394         span: b.span,
395     }
396 }
397
398 fn noop_fold_stmt(s: &stmt_, fld: @ast_fold) -> Option<stmt_> {
399     let fold_mac = |x| fold_mac_(x, fld);
400     match *s {
401         stmt_decl(d, nid) => {
402             match fld.fold_decl(d) {
403                 Some(d) => Some(stmt_decl(d, fld.new_id(nid))),
404                 None => None,
405             }
406         }
407         stmt_expr(e, nid) => {
408             Some(stmt_expr(fld.fold_expr(e), fld.new_id(nid)))
409         }
410         stmt_semi(e, nid) => {
411             Some(stmt_semi(fld.fold_expr(e), fld.new_id(nid)))
412         }
413         stmt_mac(ref mac, semi) => Some(stmt_mac(fold_mac(mac), semi))
414     }
415 }
416
417 fn noop_fold_arm(a: &arm, fld: @ast_fold) -> arm {
418     arm {
419         pats: a.pats.map(|x| fld.fold_pat(*x)),
420         guard: a.guard.map_move(|x| fld.fold_expr(x)),
421         body: fld.fold_block(&a.body),
422     }
423 }
424
425 pub fn noop_fold_pat(p: &pat_, fld: @ast_fold) -> pat_ {
426     match *p {
427         pat_wild => pat_wild,
428         pat_ident(binding_mode, ref pth, ref sub) => {
429             pat_ident(
430                 binding_mode,
431                 fld.fold_path(pth),
432                 sub.map_move(|x| fld.fold_pat(x))
433             )
434         }
435         pat_lit(e) => pat_lit(fld.fold_expr(e)),
436         pat_enum(ref pth, ref pats) => {
437             pat_enum(
438                 fld.fold_path(pth),
439                 pats.map(|pats| pats.map(|x| fld.fold_pat(*x)))
440             )
441         }
442         pat_struct(ref pth, ref fields, etc) => {
443             let pth_ = fld.fold_path(pth);
444             let fs = do fields.map |f| {
445                 ast::field_pat {
446                     ident: f.ident,
447                     pat: fld.fold_pat(f.pat)
448                 }
449             };
450             pat_struct(pth_, fs, etc)
451         }
452         pat_tup(ref elts) => pat_tup(elts.map(|x| fld.fold_pat(*x))),
453         pat_box(inner) => pat_box(fld.fold_pat(inner)),
454         pat_uniq(inner) => pat_uniq(fld.fold_pat(inner)),
455         pat_region(inner) => pat_region(fld.fold_pat(inner)),
456         pat_range(e1, e2) => {
457             pat_range(fld.fold_expr(e1), fld.fold_expr(e2))
458         },
459         pat_vec(ref before, ref slice, ref after) => {
460             pat_vec(
461                 before.map(|x| fld.fold_pat(*x)),
462                 slice.map_move(|x| fld.fold_pat(x)),
463                 after.map(|x| fld.fold_pat(*x))
464             )
465         }
466     }
467 }
468
469 fn noop_fold_decl(d: &decl_, fld: @ast_fold) -> Option<decl_> {
470     match *d {
471         decl_local(ref l) => Some(decl_local(fld.fold_local(*l))),
472         decl_item(it) => {
473             match fld.fold_item(it) {
474                 Some(it_folded) => Some(decl_item(it_folded)),
475                 None => None,
476             }
477         }
478     }
479 }
480
481 pub fn wrap<T>(f: @fn(&T, @ast_fold) -> T)
482             -> @fn(&T, span, @ast_fold) -> (T, span) {
483     let result: @fn(&T, span, @ast_fold) -> (T, span) = |x, s, fld| {
484         (f(x, fld), s)
485     };
486     result
487 }
488
489 pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
490     fn fold_field_(field: Field, fld: @ast_fold) -> Field {
491         ast::Field {
492             ident: fld.fold_ident(field.ident),
493             expr: fld.fold_expr(field.expr),
494             span: fld.new_span(field.span),
495         }
496     }
497     let fold_field = |x| fold_field_(x, fld);
498
499     let fold_mac = |x| fold_mac_(x, fld);
500
501     match *e {
502         expr_vstore(e, v) => {
503             expr_vstore(fld.fold_expr(e), v)
504         }
505         expr_vec(ref exprs, mutt) => {
506             expr_vec(fld.map_exprs(|x| fld.fold_expr(x), *exprs), mutt)
507         }
508         expr_repeat(expr, count, mutt) => {
509             expr_repeat(fld.fold_expr(expr), fld.fold_expr(count), mutt)
510         }
511         expr_tup(ref elts) => expr_tup(elts.map(|x| fld.fold_expr(*x))),
512         expr_call(f, ref args, blk) => {
513             expr_call(
514                 fld.fold_expr(f),
515                 fld.map_exprs(|x| fld.fold_expr(x), *args),
516                 blk
517             )
518         }
519         expr_method_call(callee_id, f, i, ref tps, ref args, blk) => {
520             expr_method_call(
521                 fld.new_id(callee_id),
522                 fld.fold_expr(f),
523                 fld.fold_ident(i),
524                 tps.map(|x| fld.fold_ty(x)),
525                 fld.map_exprs(|x| fld.fold_expr(x), *args),
526                 blk
527             )
528         }
529         expr_binary(callee_id, binop, lhs, rhs) => {
530             expr_binary(
531                 fld.new_id(callee_id),
532                 binop,
533                 fld.fold_expr(lhs),
534                 fld.fold_expr(rhs)
535             )
536         }
537         expr_unary(callee_id, binop, ohs) => {
538             expr_unary(
539                 fld.new_id(callee_id),
540                 binop,
541                 fld.fold_expr(ohs)
542             )
543         }
544         expr_do_body(f) => expr_do_body(fld.fold_expr(f)),
545         expr_lit(_) => (*e).clone(),
546         expr_cast(expr, ref ty) => {
547             expr_cast(fld.fold_expr(expr), (*ty).clone())
548         }
549         expr_addr_of(m, ohs) => expr_addr_of(m, fld.fold_expr(ohs)),
550         expr_if(cond, ref tr, fl) => {
551             expr_if(
552                 fld.fold_expr(cond),
553                 fld.fold_block(tr),
554                 fl.map_move(|x| fld.fold_expr(x))
555             )
556         }
557         expr_while(cond, ref body) => {
558             expr_while(fld.fold_expr(cond), fld.fold_block(body))
559         }
560         expr_for_loop(pat, iter, ref body) => {
561             expr_for_loop(fld.fold_pat(pat),
562                           fld.fold_expr(iter),
563                           fld.fold_block(body))
564         }
565         expr_loop(ref body, opt_ident) => {
566             expr_loop(
567                 fld.fold_block(body),
568                 opt_ident.map_move(|x| fld.fold_ident(x))
569             )
570         }
571         expr_match(expr, ref arms) => {
572             expr_match(
573                 fld.fold_expr(expr),
574                 arms.map(|x| fld.fold_arm(x))
575             )
576         }
577         expr_fn_block(ref decl, ref body) => {
578             expr_fn_block(
579                 fold_fn_decl(decl, fld),
580                 fld.fold_block(body)
581             )
582         }
583         expr_block(ref blk) => expr_block(fld.fold_block(blk)),
584         expr_assign(el, er) => {
585             expr_assign(fld.fold_expr(el), fld.fold_expr(er))
586         }
587         expr_assign_op(callee_id, op, el, er) => {
588             expr_assign_op(
589                 fld.new_id(callee_id),
590                 op,
591                 fld.fold_expr(el),
592                 fld.fold_expr(er)
593             )
594         }
595         expr_field(el, id, ref tys) => {
596             expr_field(
597                 fld.fold_expr(el), fld.fold_ident(id),
598                 tys.map(|x| fld.fold_ty(x))
599             )
600         }
601         expr_index(callee_id, el, er) => {
602             expr_index(
603                 fld.new_id(callee_id),
604                 fld.fold_expr(el),
605                 fld.fold_expr(er)
606             )
607         }
608         expr_path(ref pth) => expr_path(fld.fold_path(pth)),
609         expr_self => expr_self,
610         expr_break(ref opt_ident) => {
611             expr_break(opt_ident.map_move(|x| fld.fold_ident(x)))
612         }
613         expr_again(ref opt_ident) => {
614             expr_again(opt_ident.map_move(|x| fld.fold_ident(x)))
615         }
616         expr_ret(ref e) => {
617             expr_ret(e.map_move(|x| fld.fold_expr(x)))
618         }
619         expr_log(lv, e) => {
620             expr_log(
621                 fld.fold_expr(lv),
622                 fld.fold_expr(e)
623             )
624         }
625         expr_inline_asm(ref a) => {
626             expr_inline_asm(inline_asm {
627                 inputs: a.inputs.map(|&(c, input)| (c, fld.fold_expr(input))),
628                 outputs: a.outputs.map(|&(c, out)| (c, fld.fold_expr(out))),
629                 .. (*a).clone()
630             })
631         }
632         expr_mac(ref mac) => expr_mac(fold_mac(mac)),
633         expr_struct(ref path, ref fields, maybe_expr) => {
634             expr_struct(
635                 fld.fold_path(path),
636                 fields.map(|x| fold_field(*x)),
637                 maybe_expr.map_move(|x| fld.fold_expr(x))
638             )
639         },
640         expr_paren(ex) => expr_paren(fld.fold_expr(ex))
641     }
642 }
643
644 pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
645     let fold_mac = |x| fold_mac_(x, fld);
646     fn fold_mt(mt: &mt, fld: @ast_fold) -> mt {
647         mt {
648             ty: ~fld.fold_ty(mt.ty),
649             mutbl: mt.mutbl,
650         }
651     }
652     fn fold_field(f: TypeField, fld: @ast_fold) -> TypeField {
653         ast::TypeField {
654             ident: fld.fold_ident(f.ident),
655             mt: fold_mt(&f.mt, fld),
656             span: fld.new_span(f.span),
657         }
658     }
659     fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
660                         -> Option<OptVec<TyParamBound>> {
661         do b.map |bounds| {
662             do bounds.map |bound| { fold_ty_param_bound(bound, fld) }
663         }
664     }
665     match *t {
666         ty_nil | ty_bot | ty_infer => (*t).clone(),
667         ty_box(ref mt) => ty_box(fold_mt(mt, fld)),
668         ty_uniq(ref mt) => ty_uniq(fold_mt(mt, fld)),
669         ty_vec(ref mt) => ty_vec(fold_mt(mt, fld)),
670         ty_ptr(ref mt) => ty_ptr(fold_mt(mt, fld)),
671         ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, fld)),
672         ty_closure(ref f) => {
673             ty_closure(@TyClosure {
674                 sigil: f.sigil,
675                 purity: f.purity,
676                 region: f.region,
677                 onceness: f.onceness,
678                 bounds: fold_opt_bounds(&f.bounds, fld),
679                 decl: fold_fn_decl(&f.decl, fld),
680                 lifetimes: f.lifetimes.clone(),
681             })
682         }
683         ty_bare_fn(ref f) => {
684             ty_bare_fn(@TyBareFn {
685                 lifetimes: f.lifetimes.clone(),
686                 purity: f.purity,
687                 abis: f.abis,
688                 decl: fold_fn_decl(&f.decl, fld)
689             })
690         }
691         ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(ty))),
692         ty_path(ref path, ref bounds, id) =>
693             ty_path(fld.fold_path(path), fold_opt_bounds(bounds, fld), fld.new_id(id)),
694         ty_fixed_length_vec(ref mt, e) => {
695             ty_fixed_length_vec(
696                 fold_mt(mt, fld),
697                 fld.fold_expr(e)
698             )
699         }
700         ty_typeof(e) => ty_typeof(fld.fold_expr(e)),
701         ty_mac(ref mac) => ty_mac(fold_mac(mac))
702     }
703 }
704
705 // ...nor do modules
706 pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod {
707     ast::_mod {
708         view_items: m.view_items.iter().map(|x| fld.fold_view_item(x)).collect(),
709         items: m.items.iter().filter_map(|x| fld.fold_item(*x)).collect(),
710     }
711 }
712
713 fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod {
714     ast::foreign_mod {
715         sort: nm.sort,
716         abis: nm.abis,
717         view_items: nm.view_items.iter().map(|x| fld.fold_view_item(x)).collect(),
718         items: nm.items.iter().map(|x| fld.fold_foreign_item(*x)).collect(),
719     }
720 }
721
722 fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ {
723     fn fold_variant_arg_(va: variant_arg, fld: @ast_fold) -> variant_arg {
724         ast::variant_arg { ty: fld.fold_ty(&va.ty), id: fld.new_id(va.id) }
725     }
726     let fold_variant_arg = |x| fold_variant_arg_(x, fld);
727
728     let kind;
729     match v.kind {
730         tuple_variant_kind(ref variant_args) => {
731             kind = tuple_variant_kind(do variant_args.map |x| {
732                 fold_variant_arg(/*bad*/ (*x).clone())
733             })
734         }
735         struct_variant_kind(ref struct_def) => {
736             kind = struct_variant_kind(@ast::struct_def {
737                 fields: struct_def.fields.iter()
738                     .map(|f| fld.fold_struct_field(*f)).collect(),
739                 ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c))
740             })
741         }
742     }
743
744     let fold_attribute = |x| fold_attribute_(x, fld);
745     let attrs = v.attrs.map(|x| fold_attribute(*x));
746
747     let de = match v.disr_expr {
748       Some(e) => Some(fld.fold_expr(e)),
749       None => None
750     };
751     ast::variant_ {
752         name: v.name,
753         attrs: attrs,
754         kind: kind,
755         id: fld.new_id(v.id),
756         disr_expr: de,
757         vis: v.vis,
758     }
759 }
760
761 fn noop_fold_ident(i: ident, _fld: @ast_fold) -> ident {
762     i
763 }
764
765 fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path {
766     ast::Path {
767         span: fld.new_span(p.span),
768         global: p.global,
769         segments: p.segments.map(|segment| ast::PathSegment {
770             identifier: fld.fold_ident(segment.identifier),
771             lifetime: segment.lifetime,
772             types: segment.types.map(|typ| fld.fold_ty(typ)),
773         })
774     }
775 }
776
777 fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local {
778     @Local {
779         is_mutbl: l.is_mutbl,
780         ty: fld.fold_ty(&l.ty),
781         pat: fld.fold_pat(l.pat),
782         init: l.init.map_move(|e| fld.fold_expr(e)),
783         id: fld.new_id(l.id),
784         span: fld.new_span(l.span),
785     }
786 }
787
788 /* temporarily eta-expand because of a compiler bug with using `fn<T>` as a
789    value */
790 fn noop_map_exprs(f: @fn(@expr) -> @expr, es: &[@expr]) -> ~[@expr] {
791     es.map(|x| f(*x))
792 }
793
794 fn noop_id(i: NodeId) -> NodeId { return i; }
795
796 fn noop_span(sp: span) -> span { return sp; }
797
798 pub fn default_ast_fold() -> ast_fold_fns {
799     @AstFoldFns {
800         fold_crate: noop_fold_crate,
801         fold_view_item: noop_fold_view_item,
802         fold_foreign_item: noop_fold_foreign_item,
803         fold_item: noop_fold_item,
804         fold_struct_field: noop_fold_struct_field,
805         fold_item_underscore: noop_fold_item_underscore,
806         fold_method: noop_fold_method,
807         fold_block: noop_fold_block,
808         fold_stmt: |x, s, fld| (noop_fold_stmt(x, fld), s),
809         fold_arm: noop_fold_arm,
810         fold_pat: wrap(noop_fold_pat),
811         fold_decl: |x, s, fld| (noop_fold_decl(x, fld), s),
812         fold_expr: wrap(noop_fold_expr),
813         fold_ty: wrap(noop_fold_ty),
814         fold_mod: noop_fold_mod,
815         fold_foreign_mod: noop_fold_foreign_mod,
816         fold_variant: wrap(noop_fold_variant),
817         fold_ident: noop_fold_ident,
818         fold_path: noop_fold_path,
819         fold_local: noop_fold_local,
820         map_exprs: noop_map_exprs,
821         new_id: noop_id,
822         new_span: noop_span,
823     }
824 }
825
826 impl ast_fold for AstFoldFns {
827     /* naturally, a macro to write these would be nice */
828     fn fold_crate(@self, c: &Crate) -> Crate {
829         (self.fold_crate)(c, self as @ast_fold)
830     }
831     fn fold_view_item(@self, x: &view_item) -> view_item {
832         ast::view_item {
833             node: (self.fold_view_item)(&x.node, self as @ast_fold),
834             attrs: x.attrs.iter().map(|a| fold_attribute_(*a, self as @ast_fold)).collect(),
835             vis: x.vis,
836             span: (self.new_span)(x.span),
837         }
838     }
839     fn fold_foreign_item(@self, x: @foreign_item) -> @foreign_item {
840         (self.fold_foreign_item)(x, self as @ast_fold)
841     }
842     fn fold_item(@self, i: @item) -> Option<@item> {
843         (self.fold_item)(i, self as @ast_fold)
844     }
845     fn fold_struct_field(@self, sf: @struct_field) -> @struct_field {
846         @spanned {
847             node: ast::struct_field_ {
848                 kind: sf.node.kind,
849                 id: sf.node.id,
850                 ty: self.fold_ty(&sf.node.ty),
851                 attrs: sf.node.attrs.clone(),
852             },
853             span: (self.new_span)(sf.span),
854         }
855     }
856     fn fold_item_underscore(@self, i: &item_) -> item_ {
857         (self.fold_item_underscore)(i, self as @ast_fold)
858     }
859     fn fold_method(@self, x: @method) -> @method {
860         (self.fold_method)(x, self as @ast_fold)
861     }
862     fn fold_block(@self, x: &Block) -> Block {
863         (self.fold_block)(x, self as @ast_fold)
864     }
865     fn fold_stmt(@self, x: &stmt) -> Option<@stmt> {
866         let (n_opt, s) = (self.fold_stmt)(&x.node, x.span, self as @ast_fold);
867         match n_opt {
868             Some(n) => Some(@spanned { node: n, span: (self.new_span)(s) }),
869             None => None,
870         }
871     }
872     fn fold_arm(@self, x: &arm) -> arm {
873         (self.fold_arm)(x, self as @ast_fold)
874     }
875     fn fold_pat(@self, x: @pat) -> @pat {
876         let (n, s) =  (self.fold_pat)(&x.node, x.span, self as @ast_fold);
877         @pat {
878             id: (self.new_id)(x.id),
879             node: n,
880             span: (self.new_span)(s),
881         }
882     }
883     fn fold_decl(@self, x: @decl) -> Option<@decl> {
884         let (n_opt, s) = (self.fold_decl)(&x.node, x.span, self as @ast_fold);
885         match n_opt {
886             Some(n) => Some(@spanned { node: n, span: (self.new_span)(s) }),
887             None => None,
888         }
889     }
890     fn fold_expr(@self, x: @expr) -> @expr {
891         let (n, s) = (self.fold_expr)(&x.node, x.span, self as @ast_fold);
892         @expr {
893             id: (self.new_id)(x.id),
894             node: n,
895             span: (self.new_span)(s),
896         }
897     }
898     fn fold_ty(@self, x: &Ty) -> Ty {
899         let (n, s) = (self.fold_ty)(&x.node, x.span, self as @ast_fold);
900         Ty {
901             id: (self.new_id)(x.id),
902             node: n,
903             span: (self.new_span)(s),
904         }
905     }
906     fn fold_mod(@self, x: &_mod) -> _mod {
907         (self.fold_mod)(x, self as @ast_fold)
908     }
909     fn fold_foreign_mod(@self, x: &foreign_mod) -> foreign_mod {
910         (self.fold_foreign_mod)(x, self as @ast_fold)
911     }
912     fn fold_variant(@self, x: &variant) -> variant {
913         let (n, s) = (self.fold_variant)(&x.node, x.span, self as @ast_fold);
914         spanned { node: n, span: (self.new_span)(s) }
915     }
916     fn fold_ident(@self, x: ident) -> ident {
917         (self.fold_ident)(x, self as @ast_fold)
918     }
919     fn fold_path(@self, x: &Path) -> Path {
920         (self.fold_path)(x, self as @ast_fold)
921     }
922     fn fold_local(@self, x: @Local) -> @Local {
923         (self.fold_local)(x, self as @ast_fold)
924     }
925     fn map_exprs(@self,
926                  f: @fn(@expr) -> @expr,
927                  e: &[@expr])
928               -> ~[@expr] {
929         (self.map_exprs)(f, e)
930     }
931     fn new_id(@self, node_id: ast::NodeId) -> NodeId {
932         (self.new_id)(node_id)
933     }
934     fn new_span(@self, span: span) -> span {
935         (self.new_span)(span)
936     }
937 }
938
939 pub trait AstFoldExtensions {
940     fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute];
941 }
942
943 impl AstFoldExtensions for @ast_fold {
944     fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute] {
945         attrs.map(|x| fold_attribute_(*x, *self))
946     }
947 }
948
949 pub fn make_fold(afp: ast_fold_fns) -> @ast_fold {
950     afp as @ast_fold
951 }
952
953 #[cfg(test)]
954 mod test {
955     use ast;
956     use util::parser_testing::{string_to_crate, matches_codepattern};
957     use parse::token;
958     use print::pprust;
959     use super::*;
960
961     // taken from expand
962     // given a function from idents to idents, produce
963     // an ast_fold that applies that function:
964     pub fn fun_to_ident_folder(f: @fn(ast::ident)->ast::ident) -> @ast_fold{
965         let afp = default_ast_fold();
966         let f_pre = @AstFoldFns{
967             fold_ident : |id, _| f(id),
968             .. *afp
969         };
970         make_fold(f_pre)
971     }
972
973     // this version doesn't care about getting comments or docstrings in.
974     fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) {
975         pprust::print_mod(s, &crate.module, crate.attrs);
976     }
977
978     // change every identifier to "zz"
979     pub fn to_zz() -> @fn(ast::ident)->ast::ident {
980         let zz_id = token::str_to_ident("zz");
981         |_id| {zz_id}
982     }
983
984     // maybe add to expand.rs...
985     macro_rules! assert_pred (
986         ($pred:expr, $predname:expr, $a:expr , $b:expr) => (
987             {
988                 let pred_val = $pred;
989                 let a_val = $a;
990                 let b_val = $b;
991                 if !(pred_val(a_val,b_val)) {
992                     fail!("expected args satisfying %s, got %? and %?",
993                           $predname, a_val, b_val);
994                 }
995             }
996         )
997     )
998
999     // make sure idents get transformed everywhere
1000     #[test] fn ident_transformation () {
1001         let zz_fold = fun_to_ident_folder(to_zz());
1002         let ast = string_to_crate(@"#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}");
1003         assert_pred!(matches_codepattern,
1004                      "matches_codepattern",
1005                      pprust::to_str(&zz_fold.fold_crate(ast),fake_print_crate,
1006                                     token::get_ident_interner()),
1007                      ~"#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}");
1008     }
1009
1010     // even inside macro defs....
1011     #[test] fn ident_transformation_in_defs () {
1012         let zz_fold = fun_to_ident_folder(to_zz());
1013         let ast = string_to_crate(@"macro_rules! a {(b $c:expr $(d $e:token)f+
1014 => (g $(d $d $e)+))} ");
1015         assert_pred!(matches_codepattern,
1016                      "matches_codepattern",
1017                      pprust::to_str(&zz_fold.fold_crate(ast),fake_print_crate,
1018                                     token::get_ident_interner()),
1019                      ~"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))");
1020     }
1021 }