]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/fold.rs
10df264676e335f6919a423c48989b7da6d38578
[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 ast_util;
14 use codemap::{respan, Span, Spanned};
15 use parse::token;
16 use owned_slice::OwnedSlice;
17 use util::small_vector::SmallVector;
18
19 use std::rc::Rc;
20
21 // We may eventually want to be able to fold over type parameters, too.
22 pub trait Folder {
23     fn fold_crate(&mut self, c: Crate) -> Crate {
24         noop_fold_crate(c, self)
25     }
26
27     fn fold_meta_items(&mut self, meta_items: &[@MetaItem]) -> Vec<@MetaItem> {
28         meta_items.iter().map(|x| fold_meta_item_(*x, self)).collect()
29     }
30
31     fn fold_view_path(&mut self, view_path: @ViewPath) -> @ViewPath {
32         let inner_view_path = match view_path.node {
33             ViewPathSimple(ref ident, ref path, node_id) => {
34                 let id = self.new_id(node_id);
35                 ViewPathSimple(ident.clone(),
36                                self.fold_path(path),
37                                id)
38             }
39             ViewPathGlob(ref path, node_id) => {
40                 let id = self.new_id(node_id);
41                 ViewPathGlob(self.fold_path(path), id)
42             }
43             ViewPathList(ref path, ref path_list_idents, node_id) => {
44                 let id = self.new_id(node_id);
45                 ViewPathList(self.fold_path(path),
46                              path_list_idents.iter().map(|path_list_ident| {
47                                 let id = self.new_id(path_list_ident.node
48                                                                     .id);
49                                 Spanned {
50                                     node: PathListIdent_ {
51                                         name: path_list_ident.node
52                                                              .name
53                                                              .clone(),
54                                         id: id,
55                                     },
56                                     span: self.new_span(
57                                         path_list_ident.span)
58                                 }
59                              }).collect(),
60                              id)
61             }
62         };
63         @Spanned {
64             node: inner_view_path,
65             span: self.new_span(view_path.span),
66         }
67     }
68
69     fn fold_view_item(&mut self, vi: &ViewItem) -> ViewItem {
70         noop_fold_view_item(vi, self)
71     }
72
73     fn fold_foreign_item(&mut self, ni: @ForeignItem) -> @ForeignItem {
74         noop_fold_foreign_item(ni, self)
75     }
76
77     fn fold_item(&mut self, i: @Item) -> SmallVector<@Item> {
78         noop_fold_item(i, self)
79     }
80
81     fn fold_struct_field(&mut self, sf: &StructField) -> StructField {
82         let id = self.new_id(sf.node.id);
83         Spanned {
84             node: ast::StructField_ {
85                 kind: sf.node.kind,
86                 id: id,
87                 ty: self.fold_ty(sf.node.ty),
88                 attrs: sf.node.attrs.iter().map(|e| fold_attribute_(*e, self)).collect()
89             },
90             span: self.new_span(sf.span)
91         }
92     }
93
94     fn fold_item_underscore(&mut self, i: &Item_) -> Item_ {
95         noop_fold_item_underscore(i, self)
96     }
97
98     fn fold_fn_decl(&mut self, d: &FnDecl) -> P<FnDecl> {
99         noop_fold_fn_decl(d, self)
100     }
101
102     fn fold_type_method(&mut self, m: &TypeMethod) -> TypeMethod {
103         noop_fold_type_method(m, self)
104     }
105
106     fn fold_method(&mut self, m: @Method) -> @Method {
107         noop_fold_method(m, self)
108     }
109
110     fn fold_block(&mut self, b: P<Block>) -> P<Block> {
111         noop_fold_block(b, self)
112     }
113
114     fn fold_stmt(&mut self, s: &Stmt) -> SmallVector<@Stmt> {
115         noop_fold_stmt(s, self)
116     }
117
118     fn fold_arm(&mut self, a: &Arm) -> Arm {
119         Arm {
120             attrs: a.attrs.iter().map(|x| fold_attribute_(*x, self)).collect(),
121             pats: a.pats.iter().map(|x| self.fold_pat(*x)).collect(),
122             guard: a.guard.map(|x| self.fold_expr(x)),
123             body: self.fold_expr(a.body),
124         }
125     }
126
127     fn fold_pat(&mut self, p: @Pat) -> @Pat {
128         noop_fold_pat(p, self)
129     }
130
131     fn fold_decl(&mut self, d: @Decl) -> SmallVector<@Decl> {
132         let node = match d.node {
133             DeclLocal(ref l) => SmallVector::one(DeclLocal(self.fold_local(*l))),
134             DeclItem(it) => {
135                 self.fold_item(it).move_iter().map(|i| DeclItem(i)).collect()
136             }
137         };
138
139         node.move_iter().map(|node| {
140             @Spanned {
141                 node: node,
142                 span: self.new_span(d.span),
143             }
144         }).collect()
145     }
146
147     fn fold_expr(&mut self, e: @Expr) -> @Expr {
148         noop_fold_expr(e, self)
149     }
150
151     fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
152         let id = self.new_id(t.id);
153         let node = match t.node {
154             TyNil | TyBot | TyInfer => t.node.clone(),
155             TyBox(ty) => TyBox(self.fold_ty(ty)),
156             TyUniq(ty) => TyUniq(self.fold_ty(ty)),
157             TyVec(ty) => TyVec(self.fold_ty(ty)),
158             TyPtr(ref mt) => TyPtr(fold_mt(mt, self)),
159             TyRptr(ref region, ref mt) => {
160                 TyRptr(fold_opt_lifetime(region, self), fold_mt(mt, self))
161             }
162             TyClosure(ref f, ref region) => {
163                 TyClosure(@ClosureTy {
164                     fn_style: f.fn_style,
165                     onceness: f.onceness,
166                     bounds: fold_opt_bounds(&f.bounds, self),
167                     decl: self.fold_fn_decl(f.decl),
168                     lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(),
169                 }, fold_opt_lifetime(region, self))
170             }
171             TyProc(ref f) => {
172                 TyProc(@ClosureTy {
173                     fn_style: f.fn_style,
174                     onceness: f.onceness,
175                     bounds: fold_opt_bounds(&f.bounds, self),
176                     decl: self.fold_fn_decl(f.decl),
177                     lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(),
178                 })
179             }
180             TyBareFn(ref f) => {
181                 TyBareFn(@BareFnTy {
182                     lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(),
183                     fn_style: f.fn_style,
184                     abi: f.abi,
185                     decl: self.fold_fn_decl(f.decl)
186                 })
187             }
188             TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()),
189             TyPath(ref path, ref bounds, id) => {
190                 let id = self.new_id(id);
191                 TyPath(self.fold_path(path),
192                        fold_opt_bounds(bounds, self),
193                        id)
194             }
195             TyFixedLengthVec(ty, e) => {
196                 TyFixedLengthVec(self.fold_ty(ty), self.fold_expr(e))
197             }
198             TyTypeof(expr) => TyTypeof(self.fold_expr(expr)),
199         };
200         P(Ty {
201             id: id,
202             span: self.new_span(t.span),
203             node: node,
204         })
205     }
206
207     fn fold_mod(&mut self, m: &Mod) -> Mod {
208         noop_fold_mod(m, self)
209     }
210
211     fn fold_foreign_mod(&mut self, nm: &ForeignMod) -> ForeignMod {
212         ast::ForeignMod {
213             abi: nm.abi,
214             view_items: nm.view_items
215                           .iter()
216                           .map(|x| self.fold_view_item(x))
217                           .collect(),
218             items: nm.items
219                      .iter()
220                      .map(|x| self.fold_foreign_item(*x))
221                      .collect(),
222         }
223     }
224
225     fn fold_variant(&mut self, v: &Variant) -> P<Variant> {
226         let id = self.new_id(v.node.id);
227         let kind;
228         match v.node.kind {
229             TupleVariantKind(ref variant_args) => {
230                 kind = TupleVariantKind(variant_args.iter().map(|x|
231                     fold_variant_arg_(x, self)).collect())
232             }
233             StructVariantKind(ref struct_def) => {
234                 kind = StructVariantKind(@ast::StructDef {
235                     fields: struct_def.fields.iter()
236                         .map(|f| self.fold_struct_field(f)).collect(),
237                     ctor_id: struct_def.ctor_id.map(|c| self.new_id(c)),
238                     super_struct: match struct_def.super_struct {
239                         Some(t) => Some(self.fold_ty(t)),
240                         None => None
241                     },
242                     is_virtual: struct_def.is_virtual,
243                 })
244             }
245         }
246
247         let attrs = v.node.attrs.iter().map(|x| fold_attribute_(*x, self)).collect();
248
249         let de = match v.node.disr_expr {
250           Some(e) => Some(self.fold_expr(e)),
251           None => None
252         };
253         let node = ast::Variant_ {
254             name: v.node.name,
255             attrs: attrs,
256             kind: kind,
257             id: id,
258             disr_expr: de,
259             vis: v.node.vis,
260         };
261         P(Spanned {
262             node: node,
263             span: self.new_span(v.span),
264         })
265     }
266
267     fn fold_ident(&mut self, i: Ident) -> Ident {
268         i
269     }
270
271     fn fold_path(&mut self, p: &Path) -> Path {
272         ast::Path {
273             span: self.new_span(p.span),
274             global: p.global,
275             segments: p.segments.iter().map(|segment| ast::PathSegment {
276                 identifier: self.fold_ident(segment.identifier),
277                 lifetimes: segment.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(),
278                 types: segment.types.iter().map(|&typ| self.fold_ty(typ)).collect(),
279             }).collect()
280         }
281     }
282
283     fn fold_local(&mut self, l: @Local) -> @Local {
284         let id = self.new_id(l.id); // Needs to be first, for ast_map.
285         @Local {
286             id: id,
287             ty: self.fold_ty(l.ty),
288             pat: self.fold_pat(l.pat),
289             init: l.init.map(|e| self.fold_expr(e)),
290             span: self.new_span(l.span),
291         }
292     }
293
294     fn fold_mac(&mut self, macro: &Mac) -> Mac {
295         Spanned {
296             node: match macro.node {
297                 MacInvocTT(ref p, ref tts, ctxt) => {
298                     MacInvocTT(self.fold_path(p),
299                                fold_tts(tts.as_slice(), self),
300                                ctxt)
301                 }
302             },
303             span: self.new_span(macro.span)
304         }
305     }
306
307     fn map_exprs(&self, f: |@Expr| -> @Expr, es: &[@Expr]) -> Vec<@Expr> {
308         es.iter().map(|x| f(*x)).collect()
309     }
310
311     fn new_id(&mut self, i: NodeId) -> NodeId {
312         i
313     }
314
315     fn new_span(&mut self, sp: Span) -> Span {
316         sp
317     }
318
319     fn fold_explicit_self(&mut self, es: &ExplicitSelf) -> ExplicitSelf {
320         Spanned {
321             span: self.new_span(es.span),
322             node: self.fold_explicit_self_(&es.node)
323         }
324     }
325
326     fn fold_explicit_self_(&mut self, es: &ExplicitSelf_) -> ExplicitSelf_ {
327         match *es {
328             SelfStatic | SelfValue | SelfUniq => *es,
329             SelfRegion(ref lifetime, m) => {
330                 SelfRegion(fold_opt_lifetime(lifetime, self), m)
331             }
332         }
333     }
334
335     fn fold_lifetime(&mut self, l: &Lifetime) -> Lifetime {
336         noop_fold_lifetime(l, self)
337     }
338 }
339
340 /* some little folds that probably aren't useful to have in Folder itself*/
341
342 //used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
343 fn fold_meta_item_<T: Folder>(mi: @MetaItem, fld: &mut T) -> @MetaItem {
344     @Spanned {
345         node:
346             match mi.node {
347                 MetaWord(ref id) => MetaWord((*id).clone()),
348                 MetaList(ref id, ref mis) => {
349                     MetaList((*id).clone(), mis.iter().map(|e| fold_meta_item_(*e, fld)).collect())
350                 }
351                 MetaNameValue(ref id, ref s) => {
352                     MetaNameValue((*id).clone(), (*s).clone())
353                 }
354             },
355         span: fld.new_span(mi.span) }
356 }
357
358 //used in noop_fold_item and noop_fold_crate
359 fn fold_attribute_<T: Folder>(at: Attribute, fld: &mut T) -> Attribute {
360     Spanned {
361         span: fld.new_span(at.span),
362         node: ast::Attribute_ {
363             style: at.node.style,
364             value: fold_meta_item_(at.node.value, fld),
365             is_sugared_doc: at.node.is_sugared_doc
366         }
367     }
368 }
369
370 //used in noop_fold_foreign_item and noop_fold_fn_decl
371 fn fold_arg_<T: Folder>(a: &Arg, fld: &mut T) -> Arg {
372     let id = fld.new_id(a.id); // Needs to be first, for ast_map.
373     Arg {
374         id: id,
375         ty: fld.fold_ty(a.ty),
376         pat: fld.fold_pat(a.pat),
377     }
378 }
379
380 // build a new vector of tts by appling the Folder's fold_ident to
381 // all of the identifiers in the token trees.
382 //
383 // This is part of hygiene magic. As far as hygiene is concerned, there
384 // are three types of let pattern bindings or loop labels:
385 //      - those defined and used in non-macro part of the program
386 //      - those used as part of macro invocation arguments
387 //      - those defined and used inside macro definitions
388 // Lexically, type 1 and 2 are in one group and type 3 the other. If they
389 // clash, in order for let and loop label to work hygienically, one group
390 // or the other needs to be renamed. The problem is that type 2 and 3 are
391 // parsed together (inside the macro expand function). After being parsed and
392 // AST being constructed, they can no longer be distinguished from each other.
393 //
394 // For that reason, type 2 let bindings and loop labels are actually renamed
395 // in the form of tokens instead of AST nodes, here. There are wasted effort
396 // since many token::IDENT are not necessary part of let bindings and most
397 // token::LIFETIME are certainly not loop labels. But we can't tell in their
398 // token form. So this is less ideal and hacky but it works.
399 pub fn fold_tts<T: Folder>(tts: &[TokenTree], fld: &mut T) -> Vec<TokenTree> {
400     tts.iter().map(|tt| {
401         match *tt {
402             TTTok(span, ref tok) =>
403             TTTok(span,maybe_fold_ident(tok,fld)),
404             TTDelim(ref tts) => TTDelim(Rc::new(fold_tts(tts.as_slice(), fld))),
405             TTSeq(span, ref pattern, ref sep, is_optional) =>
406             TTSeq(span,
407                   Rc::new(fold_tts(pattern.as_slice(), fld)),
408                   sep.as_ref().map(|tok|maybe_fold_ident(tok,fld)),
409                   is_optional),
410             TTNonterminal(sp,ref ident) =>
411             TTNonterminal(sp,fld.fold_ident(*ident))
412         }
413     }).collect()
414 }
415
416 // apply ident folder if it's an ident, otherwise leave it alone
417 fn maybe_fold_ident<T: Folder>(t: &token::Token, fld: &mut T) -> token::Token {
418     match *t {
419         token::IDENT(id, followed_by_colons) => {
420             token::IDENT(fld.fold_ident(id), followed_by_colons)
421         }
422         token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)),
423         _ => (*t).clone()
424     }
425 }
426
427 pub fn noop_fold_fn_decl<T: Folder>(decl: &FnDecl, fld: &mut T) -> P<FnDecl> {
428     P(FnDecl {
429         inputs: decl.inputs.iter().map(|x| fold_arg_(x, fld)).collect(), // bad copy
430         output: fld.fold_ty(decl.output),
431         cf: decl.cf,
432         variadic: decl.variadic
433     })
434 }
435
436 fn fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
437                                     -> TyParamBound {
438     match *tpb {
439         TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
440         StaticRegionTyParamBound => StaticRegionTyParamBound,
441         OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
442     }
443 }
444
445 pub fn fold_ty_param<T: Folder>(tp: &TyParam, fld: &mut T) -> TyParam {
446     let id = fld.new_id(tp.id);
447     TyParam {
448         ident: tp.ident,
449         id: id,
450         sized: tp.sized,
451         bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)),
452         default: tp.default.map(|x| fld.fold_ty(x)),
453         span: tp.span
454     }
455 }
456
457 pub fn fold_ty_params<T: Folder>(tps: &OwnedSlice<TyParam>, fld: &mut T)
458                                    -> OwnedSlice<TyParam> {
459     tps.map(|tp| fold_ty_param(tp, fld))
460 }
461
462 pub fn noop_fold_lifetime<T: Folder>(l: &Lifetime, fld: &mut T) -> Lifetime {
463     let id = fld.new_id(l.id);
464     Lifetime {
465         id: id,
466         span: fld.new_span(l.span),
467         name: l.name
468     }
469 }
470
471 pub fn fold_lifetimes<T: Folder>(lts: &Vec<Lifetime>, fld: &mut T)
472                                    -> Vec<Lifetime> {
473     lts.iter().map(|l| fld.fold_lifetime(l)).collect()
474 }
475
476 pub fn fold_opt_lifetime<T: Folder>(o_lt: &Option<Lifetime>, fld: &mut T)
477                                       -> Option<Lifetime> {
478     o_lt.as_ref().map(|lt| fld.fold_lifetime(lt))
479 }
480
481 pub fn fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
482     Generics {ty_params: fold_ty_params(&generics.ty_params, fld),
483               lifetimes: fold_lifetimes(&generics.lifetimes, fld)}
484 }
485
486 fn fold_struct_def<T: Folder>(struct_def: @StructDef, fld: &mut T) -> @StructDef {
487     @ast::StructDef {
488         fields: struct_def.fields.iter().map(|f| fold_struct_field(f, fld)).collect(),
489         ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(cid)),
490         super_struct: match struct_def.super_struct {
491             Some(t) => Some(fld.fold_ty(t)),
492             None => None
493         },
494         is_virtual: struct_def.is_virtual,
495     }
496 }
497
498 fn fold_trait_ref<T: Folder>(p: &TraitRef, fld: &mut T) -> TraitRef {
499     let id = fld.new_id(p.ref_id);
500     ast::TraitRef {
501         path: fld.fold_path(&p.path),
502         ref_id: id,
503     }
504 }
505
506 fn fold_struct_field<T: Folder>(f: &StructField, fld: &mut T) -> StructField {
507     let id = fld.new_id(f.node.id);
508     Spanned {
509         node: ast::StructField_ {
510             kind: f.node.kind,
511             id: id,
512             ty: fld.fold_ty(f.node.ty),
513             attrs: f.node.attrs.iter().map(|a| fold_attribute_(*a, fld)).collect(),
514         },
515         span: fld.new_span(f.span),
516     }
517 }
518
519 fn fold_field_<T: Folder>(field: Field, folder: &mut T) -> Field {
520     ast::Field {
521         ident: respan(field.ident.span, folder.fold_ident(field.ident.node)),
522         expr: folder.fold_expr(field.expr),
523         span: folder.new_span(field.span),
524     }
525 }
526
527 fn fold_mt<T: Folder>(mt: &MutTy, folder: &mut T) -> MutTy {
528     MutTy {
529         ty: folder.fold_ty(mt.ty),
530         mutbl: mt.mutbl,
531     }
532 }
533
534 fn fold_opt_bounds<T: Folder>(b: &Option<OwnedSlice<TyParamBound>>, folder: &mut T)
535                               -> Option<OwnedSlice<TyParamBound>> {
536     b.as_ref().map(|bounds| {
537         bounds.map(|bound| {
538             fold_ty_param_bound(bound, folder)
539         })
540     })
541 }
542
543 fn fold_variant_arg_<T: Folder>(va: &VariantArg, folder: &mut T) -> VariantArg {
544     let id = folder.new_id(va.id);
545     ast::VariantArg {
546         ty: folder.fold_ty(va.ty),
547         id: id,
548     }
549 }
550
551 pub fn noop_fold_view_item<T: Folder>(vi: &ViewItem, folder: &mut T)
552                                        -> ViewItem{
553     let inner_view_item = match vi.node {
554         ViewItemExternCrate(ref ident, ref string, node_id) => {
555             ViewItemExternCrate(ident.clone(),
556                               (*string).clone(),
557                               folder.new_id(node_id))
558         }
559         ViewItemUse(ref view_path) => {
560             ViewItemUse(folder.fold_view_path(*view_path))
561         }
562     };
563     ViewItem {
564         node: inner_view_item,
565         attrs: vi.attrs.iter().map(|a| fold_attribute_(*a, folder)).collect(),
566         vis: vi.vis,
567         span: folder.new_span(vi.span),
568     }
569 }
570
571 pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
572     let id = folder.new_id(b.id); // Needs to be first, for ast_map.
573     let view_items = b.view_items.iter().map(|x| folder.fold_view_item(x)).collect();
574     let stmts = b.stmts.iter().flat_map(|s| folder.fold_stmt(*s).move_iter()).collect();
575     P(Block {
576         id: id,
577         view_items: view_items,
578         stmts: stmts,
579         expr: b.expr.map(|x| folder.fold_expr(x)),
580         rules: b.rules,
581         span: folder.new_span(b.span),
582     })
583 }
584
585 pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_ {
586     match *i {
587         ItemStatic(t, m, e) => {
588             ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e))
589         }
590         ItemFn(decl, fn_style, abi, ref generics, body) => {
591             ItemFn(
592                 folder.fold_fn_decl(decl),
593                 fn_style,
594                 abi,
595                 fold_generics(generics, folder),
596                 folder.fold_block(body)
597             )
598         }
599         ItemMod(ref m) => ItemMod(folder.fold_mod(m)),
600         ItemForeignMod(ref nm) => ItemForeignMod(folder.fold_foreign_mod(nm)),
601         ItemTy(t, ref generics) => {
602             ItemTy(folder.fold_ty(t), fold_generics(generics, folder))
603         }
604         ItemEnum(ref enum_definition, ref generics) => {
605             ItemEnum(
606                 ast::EnumDef {
607                     variants: enum_definition.variants.iter().map(|&x| {
608                         folder.fold_variant(x)
609                     }).collect(),
610                 },
611                 fold_generics(generics, folder))
612         }
613         ItemStruct(ref struct_def, ref generics) => {
614             let struct_def = fold_struct_def(*struct_def, folder);
615             ItemStruct(struct_def, fold_generics(generics, folder))
616         }
617         ItemImpl(ref generics, ref ifce, ty, ref methods) => {
618             ItemImpl(fold_generics(generics, folder),
619                      ifce.as_ref().map(|p| fold_trait_ref(p, folder)),
620                      folder.fold_ty(ty),
621                      methods.iter().map(|x| folder.fold_method(*x)).collect()
622             )
623         }
624         ItemTrait(ref generics, ref sized, ref traits, ref methods) => {
625             let methods = methods.iter().map(|method| {
626                 match *method {
627                     Required(ref m) => Required(folder.fold_type_method(m)),
628                     Provided(method) => Provided(folder.fold_method(method))
629                 }
630             }).collect();
631             ItemTrait(fold_generics(generics, folder),
632                       *sized,
633                       traits.iter().map(|p| fold_trait_ref(p, folder)).collect(),
634                       methods)
635         }
636         ItemMac(ref m) => ItemMac(folder.fold_mac(m)),
637     }
638 }
639
640 pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMethod {
641     let id = fld.new_id(m.id); // Needs to be first, for ast_map.
642     TypeMethod {
643         id: id,
644         ident: fld.fold_ident(m.ident),
645         attrs: m.attrs.iter().map(|a| fold_attribute_(*a, fld)).collect(),
646         fn_style: m.fn_style,
647         decl: fld.fold_fn_decl(m.decl),
648         generics: fold_generics(&m.generics, fld),
649         explicit_self: fld.fold_explicit_self(&m.explicit_self),
650         span: fld.new_span(m.span),
651     }
652 }
653
654 pub fn noop_fold_mod<T: Folder>(m: &Mod, folder: &mut T) -> Mod {
655     ast::Mod {
656         inner: folder.new_span(m.inner),
657         view_items: m.view_items
658                      .iter()
659                      .map(|x| folder.fold_view_item(x)).collect(),
660         items: m.items.iter().flat_map(|x| folder.fold_item(*x).move_iter()).collect(),
661     }
662 }
663
664 pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
665     Crate {
666         module: folder.fold_mod(&c.module),
667         attrs: c.attrs.iter().map(|x| fold_attribute_(*x, folder)).collect(),
668         config: c.config.iter().map(|x| fold_meta_item_(*x, folder)).collect(),
669         span: folder.new_span(c.span),
670     }
671 }
672
673 pub fn noop_fold_item<T: Folder>(i: &Item, folder: &mut T) -> SmallVector<@Item> {
674     let id = folder.new_id(i.id); // Needs to be first, for ast_map.
675     let node = folder.fold_item_underscore(&i.node);
676     let ident = match node {
677         // The node may have changed, recompute the "pretty" impl name.
678         ItemImpl(_, ref maybe_trait, ty, _) => {
679             ast_util::impl_pretty_name(maybe_trait, ty)
680         }
681         _ => i.ident
682     };
683
684     SmallVector::one(@Item {
685         id: id,
686         ident: folder.fold_ident(ident),
687         attrs: i.attrs.iter().map(|e| fold_attribute_(*e, folder)).collect(),
688         node: node,
689         vis: i.vis,
690         span: folder.new_span(i.span)
691     })
692 }
693
694 pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem, folder: &mut T) -> @ForeignItem {
695     let id = folder.new_id(ni.id); // Needs to be first, for ast_map.
696     @ForeignItem {
697         id: id,
698         ident: folder.fold_ident(ni.ident),
699         attrs: ni.attrs.iter().map(|x| fold_attribute_(*x, folder)).collect(),
700         node: match ni.node {
701             ForeignItemFn(ref fdec, ref generics) => {
702                 ForeignItemFn(P(FnDecl {
703                     inputs: fdec.inputs.iter().map(|a| fold_arg_(a, folder)).collect(),
704                     output: folder.fold_ty(fdec.output),
705                     cf: fdec.cf,
706                     variadic: fdec.variadic
707                 }), fold_generics(generics, folder))
708             }
709             ForeignItemStatic(t, m) => {
710                 ForeignItemStatic(folder.fold_ty(t), m)
711             }
712         },
713         span: folder.new_span(ni.span),
714         vis: ni.vis,
715     }
716 }
717
718 pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> @Method {
719     let id = folder.new_id(m.id); // Needs to be first, for ast_map.
720     @Method {
721         id: id,
722         ident: folder.fold_ident(m.ident),
723         attrs: m.attrs.iter().map(|a| fold_attribute_(*a, folder)).collect(),
724         generics: fold_generics(&m.generics, folder),
725         explicit_self: folder.fold_explicit_self(&m.explicit_self),
726         fn_style: m.fn_style,
727         decl: folder.fold_fn_decl(m.decl),
728         body: folder.fold_block(m.body),
729         span: folder.new_span(m.span),
730         vis: m.vis
731     }
732 }
733
734 pub fn noop_fold_pat<T: Folder>(p: @Pat, folder: &mut T) -> @Pat {
735     let id = folder.new_id(p.id);
736     let node = match p.node {
737         PatWild => PatWild,
738         PatWildMulti => PatWildMulti,
739         PatIdent(binding_mode, ref pth, ref sub) => {
740             PatIdent(binding_mode,
741                      folder.fold_path(pth),
742                      sub.map(|x| folder.fold_pat(x)))
743         }
744         PatLit(e) => PatLit(folder.fold_expr(e)),
745         PatEnum(ref pth, ref pats) => {
746             PatEnum(folder.fold_path(pth),
747                     pats.as_ref().map(|pats| pats.iter().map(|x| folder.fold_pat(*x)).collect()))
748         }
749         PatStruct(ref pth, ref fields, etc) => {
750             let pth_ = folder.fold_path(pth);
751             let fs = fields.iter().map(|f| {
752                 ast::FieldPat {
753                     ident: f.ident,
754                     pat: folder.fold_pat(f.pat)
755                 }
756             }).collect();
757             PatStruct(pth_, fs, etc)
758         }
759         PatTup(ref elts) => PatTup(elts.iter().map(|x| folder.fold_pat(*x)).collect()),
760         PatUniq(inner) => PatUniq(folder.fold_pat(inner)),
761         PatRegion(inner) => PatRegion(folder.fold_pat(inner)),
762         PatRange(e1, e2) => {
763             PatRange(folder.fold_expr(e1), folder.fold_expr(e2))
764         },
765         PatVec(ref before, ref slice, ref after) => {
766             PatVec(before.iter().map(|x| folder.fold_pat(*x)).collect(),
767                     slice.map(|x| folder.fold_pat(x)),
768                     after.iter().map(|x| folder.fold_pat(*x)).collect())
769         }
770     };
771
772     @Pat {
773         id: id,
774         span: folder.new_span(p.span),
775         node: node,
776     }
777 }
778
779 pub fn noop_fold_expr<T: Folder>(e: @Expr, folder: &mut T) -> @Expr {
780     let id = folder.new_id(e.id);
781     let node = match e.node {
782         ExprVstore(e, v) => {
783             ExprVstore(folder.fold_expr(e), v)
784         }
785         ExprBox(p, e) => {
786             ExprBox(folder.fold_expr(p), folder.fold_expr(e))
787         }
788         ExprVec(ref exprs) => {
789             ExprVec(exprs.iter().map(|&x| folder.fold_expr(x)).collect())
790         }
791         ExprRepeat(expr, count) => {
792             ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count))
793         }
794         ExprTup(ref elts) => ExprTup(elts.iter().map(|x| folder.fold_expr(*x)).collect()),
795         ExprCall(f, ref args) => {
796             ExprCall(folder.fold_expr(f),
797                      args.iter().map(|&x| folder.fold_expr(x)).collect())
798         }
799         ExprMethodCall(i, ref tps, ref args) => {
800             ExprMethodCall(
801                 respan(i.span, folder.fold_ident(i.node)),
802                 tps.iter().map(|&x| folder.fold_ty(x)).collect(),
803                 args.iter().map(|&x| folder.fold_expr(x)).collect())
804         }
805         ExprBinary(binop, lhs, rhs) => {
806             ExprBinary(binop,
807                        folder.fold_expr(lhs),
808                        folder.fold_expr(rhs))
809         }
810         ExprUnary(binop, ohs) => {
811             ExprUnary(binop, folder.fold_expr(ohs))
812         }
813         ExprLit(_) => e.node.clone(),
814         ExprCast(expr, ty) => {
815             ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
816         }
817         ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
818         ExprIf(cond, tr, fl) => {
819             ExprIf(folder.fold_expr(cond),
820                    folder.fold_block(tr),
821                    fl.map(|x| folder.fold_expr(x)))
822         }
823         ExprWhile(cond, body) => {
824             ExprWhile(folder.fold_expr(cond), folder.fold_block(body))
825         }
826         ExprForLoop(pat, iter, body, ref maybe_ident) => {
827             ExprForLoop(folder.fold_pat(pat),
828                         folder.fold_expr(iter),
829                         folder.fold_block(body),
830                         maybe_ident.map(|i| folder.fold_ident(i)))
831         }
832         ExprLoop(body, opt_ident) => {
833             ExprLoop(folder.fold_block(body),
834                      opt_ident.map(|x| folder.fold_ident(x)))
835         }
836         ExprMatch(expr, ref arms) => {
837             ExprMatch(folder.fold_expr(expr),
838                       arms.iter().map(|x| folder.fold_arm(x)).collect())
839         }
840         ExprFnBlock(decl, body) => {
841             ExprFnBlock(folder.fold_fn_decl(decl), folder.fold_block(body))
842         }
843         ExprProc(decl, body) => {
844             ExprProc(folder.fold_fn_decl(decl), folder.fold_block(body))
845         }
846         ExprBlock(blk) => ExprBlock(folder.fold_block(blk)),
847         ExprAssign(el, er) => {
848             ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
849         }
850         ExprAssignOp(op, el, er) => {
851             ExprAssignOp(op,
852                          folder.fold_expr(el),
853                          folder.fold_expr(er))
854         }
855         ExprField(el, id, ref tys) => {
856             ExprField(folder.fold_expr(el),
857                       folder.fold_ident(id),
858                       tys.iter().map(|&x| folder.fold_ty(x)).collect())
859         }
860         ExprIndex(el, er) => {
861             ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
862         }
863         ExprPath(ref pth) => ExprPath(folder.fold_path(pth)),
864         ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
865         ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
866         ExprRet(ref e) => {
867             ExprRet(e.map(|x| folder.fold_expr(x)))
868         }
869         ExprInlineAsm(ref a) => {
870             ExprInlineAsm(InlineAsm {
871                 inputs: a.inputs.iter().map(|&(ref c, input)| {
872                     ((*c).clone(), folder.fold_expr(input))
873                 }).collect(),
874                 outputs: a.outputs.iter().map(|&(ref c, out)| {
875                     ((*c).clone(), folder.fold_expr(out))
876                 }).collect(),
877                 .. (*a).clone()
878             })
879         }
880         ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)),
881         ExprStruct(ref path, ref fields, maybe_expr) => {
882             ExprStruct(folder.fold_path(path),
883                        fields.iter().map(|x| fold_field_(*x, folder)).collect(),
884                        maybe_expr.map(|x| folder.fold_expr(x)))
885         },
886         ExprParen(ex) => ExprParen(folder.fold_expr(ex))
887     };
888
889     @Expr {
890         id: id,
891         node: node,
892         span: folder.new_span(e.span),
893     }
894 }
895
896 pub fn noop_fold_stmt<T: Folder>(s: &Stmt, folder: &mut T) -> SmallVector<@Stmt> {
897     let nodes = match s.node {
898         StmtDecl(d, id) => {
899             let id = folder.new_id(id);
900             folder.fold_decl(d).move_iter()
901                     .map(|d| StmtDecl(d, id))
902                     .collect()
903         }
904         StmtExpr(e, id) => {
905             let id = folder.new_id(id);
906             SmallVector::one(StmtExpr(folder.fold_expr(e), id))
907         }
908         StmtSemi(e, id) => {
909             let id = folder.new_id(id);
910             SmallVector::one(StmtSemi(folder.fold_expr(e), id))
911         }
912         StmtMac(ref mac, semi) => SmallVector::one(StmtMac(folder.fold_mac(mac), semi))
913     };
914
915     nodes.move_iter().map(|node| @Spanned {
916         node: node,
917         span: folder.new_span(s.span),
918     }).collect()
919 }
920
921 #[cfg(test)]
922 mod test {
923     use std::io;
924     use ast;
925     use util::parser_testing::{string_to_crate, matches_codepattern};
926     use parse::token;
927     use print::pprust;
928     use super::*;
929
930     // this version doesn't care about getting comments or docstrings in.
931     fn fake_print_crate(s: &mut pprust::State,
932                         krate: &ast::Crate) -> io::IoResult<()> {
933         s.print_mod(&krate.module, krate.attrs.as_slice())
934     }
935
936     // change every identifier to "zz"
937     struct ToZzIdentFolder;
938
939     impl Folder for ToZzIdentFolder {
940         fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
941             token::str_to_ident("zz")
942         }
943     }
944
945     // maybe add to expand.rs...
946     macro_rules! assert_pred (
947         ($pred:expr, $predname:expr, $a:expr , $b:expr) => (
948             {
949                 let pred_val = $pred;
950                 let a_val = $a;
951                 let b_val = $b;
952                 if !(pred_val(a_val.as_slice(),b_val.as_slice())) {
953                     fail!("expected args satisfying {}, got {:?} and {:?}",
954                           $predname, a_val, b_val);
955                 }
956             }
957         )
958     )
959
960     // make sure idents get transformed everywhere
961     #[test] fn ident_transformation () {
962         let mut zz_fold = ToZzIdentFolder;
963         let ast = string_to_crate(
964             "#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_strbuf());
965         let folded_crate = zz_fold.fold_crate(ast);
966         assert_pred!(
967             matches_codepattern,
968             "matches_codepattern",
969             pprust::to_str(|s| fake_print_crate(s, &folded_crate)),
970             "#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_strbuf());
971     }
972
973     // even inside macro defs....
974     #[test] fn ident_transformation_in_defs () {
975         let mut zz_fold = ToZzIdentFolder;
976         let ast = string_to_crate(
977             "macro_rules! a {(b $c:expr $(d $e:token)f+ => \
978              (g $(d $d $e)+))} ".to_strbuf());
979         let folded_crate = zz_fold.fold_crate(ast);
980         assert_pred!(
981             matches_codepattern,
982             "matches_codepattern",
983             pprust::to_str(|s| fake_print_crate(s, &folded_crate)),
984             "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))".to_strbuf());
985     }
986 }