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