]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/fold.rs
libsyntax: Remove all `@str` from the AST
[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,
501                              string,
502                              node_id) => {
503             ViewItemExternMod(ident.clone(),
504                                  string,
505                                  folder.new_id(node_id))
506         }
507         ViewItemUse(ref view_paths) => {
508             ViewItemUse(folder.fold_view_paths(*view_paths))
509         }
510     };
511     ViewItem {
512         node: inner_view_item,
513         attrs: vi.attrs.map(|a| fold_attribute_(*a, folder)),
514         vis: vi.vis,
515         span: folder.new_span(vi.span),
516     }
517 }
518
519 pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
520     let view_items = b.view_items.map(|x| folder.fold_view_item(x));
521     let stmts = b.stmts.iter().flat_map(|s| folder.fold_stmt(*s).move_iter()).collect();
522     P(Block {
523         view_items: view_items,
524         stmts: stmts,
525         expr: b.expr.map(|x| folder.fold_expr(x)),
526         id: folder.new_id(b.id),
527         rules: b.rules,
528         span: folder.new_span(b.span),
529     })
530 }
531
532 pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_ {
533     match *i {
534         ItemStatic(t, m, e) => {
535             ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e))
536         }
537         ItemFn(decl, purity, abi, ref generics, body) => {
538             ItemFn(
539                 folder.fold_fn_decl(decl),
540                 purity,
541                 abi,
542                 fold_generics(generics, folder),
543                 folder.fold_block(body)
544             )
545         }
546         ItemMod(ref m) => ItemMod(folder.fold_mod(m)),
547         ItemForeignMod(ref nm) => ItemForeignMod(folder.fold_foreign_mod(nm)),
548         ItemTy(t, ref generics) => {
549             ItemTy(folder.fold_ty(t), fold_generics(generics, folder))
550         }
551         ItemEnum(ref enum_definition, ref generics) => {
552             ItemEnum(
553                 ast::EnumDef {
554                     variants: enum_definition.variants.map(|&x| {
555                         folder.fold_variant(x)
556                     }),
557                 },
558                 fold_generics(generics, folder))
559         }
560         ItemStruct(ref struct_def, ref generics) => {
561             let struct_def = fold_struct_def(*struct_def, folder);
562             ItemStruct(struct_def, fold_generics(generics, folder))
563         }
564         ItemImpl(ref generics, ref ifce, ty, ref methods) => {
565             ItemImpl(fold_generics(generics, folder),
566                      ifce.as_ref().map(|p| fold_trait_ref(p, folder)),
567                      folder.fold_ty(ty),
568                      methods.map(|x| folder.fold_method(*x))
569             )
570         }
571         ItemTrait(ref generics, ref traits, ref methods) => {
572             let methods = methods.map(|method| {
573                 match *method {
574                     Required(ref m) => Required(folder.fold_type_method(m)),
575                     Provided(method) => Provided(folder.fold_method(method))
576                 }
577             });
578             ItemTrait(fold_generics(generics, folder),
579                       traits.map(|p| fold_trait_ref(p, folder)),
580                       methods)
581         }
582         ItemMac(ref m) => ItemMac(folder.fold_mac(m)),
583     }
584 }
585
586 pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMethod {
587     TypeMethod {
588         ident: fld.fold_ident(m.ident),
589         attrs: m.attrs.map(|a| fold_attribute_(*a, fld)),
590         purity: m.purity,
591         decl: fld.fold_fn_decl(m.decl),
592         generics: fold_generics(&m.generics, fld),
593         explicit_self: fld.fold_explicit_self(&m.explicit_self),
594         id: fld.new_id(m.id),
595         span: fld.new_span(m.span),
596     }
597 }
598
599 pub fn noop_fold_mod<T: Folder>(m: &Mod, folder: &mut T) -> Mod {
600     ast::Mod {
601         view_items: m.view_items
602                      .iter()
603                      .map(|x| folder.fold_view_item(x)).collect(),
604         items: m.items.iter().flat_map(|x| folder.fold_item(*x).move_iter()).collect(),
605     }
606 }
607
608 pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
609     let fold_meta_item = |x| fold_meta_item_(x, folder);
610     let fold_attribute = |x| fold_attribute_(x, folder);
611
612     Crate {
613         module: folder.fold_mod(&c.module),
614         attrs: c.attrs.map(|x| fold_attribute(*x)),
615         config: c.config.map(|x| fold_meta_item(*x)),
616         span: folder.new_span(c.span),
617     }
618 }
619
620 pub fn noop_fold_item<T: Folder>(i: &Item, folder: &mut T) -> SmallVector<@Item> {
621     let fold_attribute = |x| fold_attribute_(x, folder);
622
623     SmallVector::one(@Item {
624         ident: folder.fold_ident(i.ident),
625         attrs: i.attrs.map(|e| fold_attribute(*e)),
626         id: folder.new_id(i.id),
627         node: folder.fold_item_underscore(&i.node),
628         vis: i.vis,
629         span: folder.new_span(i.span)
630     })
631 }
632
633 pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem, folder: &mut T) -> @ForeignItem {
634     @ForeignItem {
635         ident: folder.fold_ident(ni.ident),
636         attrs: ni.attrs.map(|x| fold_attribute_(*x, folder)),
637         node: match ni.node {
638             ForeignItemFn(ref fdec, ref generics) => {
639                 ForeignItemFn(P(FnDecl {
640                     inputs: fdec.inputs.map(|a| fold_arg_(a, folder)),
641                     output: folder.fold_ty(fdec.output),
642                     cf: fdec.cf,
643                     variadic: fdec.variadic
644                 }), fold_generics(generics, folder))
645             }
646             ForeignItemStatic(t, m) => {
647                 ForeignItemStatic(folder.fold_ty(t), m)
648             }
649         },
650         id: folder.new_id(ni.id),
651         span: folder.new_span(ni.span),
652         vis: ni.vis,
653     }
654 }
655
656 pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> @Method {
657     @Method {
658         ident: folder.fold_ident(m.ident),
659         attrs: m.attrs.map(|a| fold_attribute_(*a, folder)),
660         generics: fold_generics(&m.generics, folder),
661         explicit_self: folder.fold_explicit_self(&m.explicit_self),
662         purity: m.purity,
663         decl: folder.fold_fn_decl(m.decl),
664         body: folder.fold_block(m.body),
665         id: folder.new_id(m.id),
666         span: folder.new_span(m.span),
667         vis: m.vis
668     }
669 }
670
671 pub fn noop_fold_pat<T: Folder>(p: @Pat, folder: &mut T) -> @Pat {
672     let node = match p.node {
673         PatWild => PatWild,
674         PatWildMulti => PatWildMulti,
675         PatIdent(binding_mode, ref pth, ref sub) => {
676             PatIdent(binding_mode,
677                      folder.fold_path(pth),
678                      sub.map(|x| folder.fold_pat(x)))
679         }
680         PatLit(e) => PatLit(folder.fold_expr(e)),
681         PatEnum(ref pth, ref pats) => {
682             PatEnum(folder.fold_path(pth),
683                     pats.as_ref().map(|pats| pats.map(|x| folder.fold_pat(*x))))
684         }
685         PatStruct(ref pth, ref fields, etc) => {
686             let pth_ = folder.fold_path(pth);
687             let fs = fields.map(|f| {
688                 ast::FieldPat {
689                     ident: f.ident,
690                     pat: folder.fold_pat(f.pat)
691                 }
692             });
693             PatStruct(pth_, fs, etc)
694         }
695         PatTup(ref elts) => PatTup(elts.map(|x| folder.fold_pat(*x))),
696         PatUniq(inner) => PatUniq(folder.fold_pat(inner)),
697         PatRegion(inner) => PatRegion(folder.fold_pat(inner)),
698         PatRange(e1, e2) => {
699             PatRange(folder.fold_expr(e1), folder.fold_expr(e2))
700         },
701         PatVec(ref before, ref slice, ref after) => {
702             PatVec(before.map(|x| folder.fold_pat(*x)),
703                     slice.map(|x| folder.fold_pat(x)),
704                     after.map(|x| folder.fold_pat(*x)))
705         }
706     };
707
708     @Pat {
709         id: folder.new_id(p.id),
710         span: folder.new_span(p.span),
711         node: node,
712     }
713 }
714
715 pub fn noop_fold_expr<T: Folder>(e: @Expr, folder: &mut T) -> @Expr {
716     let fold_field = |x| fold_field_(x, folder);
717
718     let node = match e.node {
719         ExprVstore(e, v) => {
720             ExprVstore(folder.fold_expr(e), v)
721         }
722         ExprBox(p, e) => {
723             ExprBox(folder.fold_expr(p), folder.fold_expr(e))
724         }
725         ExprVec(ref exprs, mutt) => {
726             ExprVec(exprs.map(|&x| folder.fold_expr(x)), mutt)
727         }
728         ExprRepeat(expr, count, mutt) => {
729             ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count), mutt)
730         }
731         ExprTup(ref elts) => ExprTup(elts.map(|x| folder.fold_expr(*x))),
732         ExprCall(f, ref args, blk) => {
733             ExprCall(folder.fold_expr(f),
734                      args.map(|&x| folder.fold_expr(x)),
735                      blk)
736         }
737         ExprMethodCall(callee_id, i, ref tps, ref args, blk) => {
738             ExprMethodCall(
739                 folder.new_id(callee_id),
740                 folder.fold_ident(i),
741                 tps.map(|&x| folder.fold_ty(x)),
742                 args.map(|&x| folder.fold_expr(x)),
743                 blk
744             )
745         }
746         ExprBinary(callee_id, binop, lhs, rhs) => {
747             ExprBinary(folder.new_id(callee_id),
748                        binop,
749                        folder.fold_expr(lhs),
750                        folder.fold_expr(rhs))
751         }
752         ExprUnary(callee_id, binop, ohs) => {
753             ExprUnary(folder.new_id(callee_id), binop, folder.fold_expr(ohs))
754         }
755         ExprLit(_) => e.node.clone(),
756         ExprCast(expr, ty) => {
757             ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
758         }
759         ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
760         ExprIf(cond, tr, fl) => {
761             ExprIf(folder.fold_expr(cond),
762                    folder.fold_block(tr),
763                    fl.map(|x| folder.fold_expr(x)))
764         }
765         ExprWhile(cond, body) => {
766             ExprWhile(folder.fold_expr(cond), folder.fold_block(body))
767         }
768         ExprForLoop(pat, iter, body, ref maybe_ident) => {
769             ExprForLoop(folder.fold_pat(pat),
770                         folder.fold_expr(iter),
771                         folder.fold_block(body),
772                         maybe_ident.map(|i| folder.fold_ident(i)))
773         }
774         ExprLoop(body, opt_ident) => {
775             ExprLoop(folder.fold_block(body),
776                      opt_ident.map(|x| folder.fold_ident(x)))
777         }
778         ExprMatch(expr, ref arms) => {
779             ExprMatch(folder.fold_expr(expr),
780                       arms.map(|x| folder.fold_arm(x)))
781         }
782         ExprFnBlock(decl, body) => {
783             ExprFnBlock(folder.fold_fn_decl(decl), folder.fold_block(body))
784         }
785         ExprProc(decl, body) => {
786             ExprProc(folder.fold_fn_decl(decl), folder.fold_block(body))
787         }
788         ExprBlock(blk) => ExprBlock(folder.fold_block(blk)),
789         ExprAssign(el, er) => {
790             ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
791         }
792         ExprAssignOp(callee_id, op, el, er) => {
793             ExprAssignOp(folder.new_id(callee_id),
794                          op,
795                          folder.fold_expr(el),
796                          folder.fold_expr(er))
797         }
798         ExprField(el, id, ref tys) => {
799             ExprField(folder.fold_expr(el),
800                       folder.fold_ident(id),
801                       tys.map(|&x| folder.fold_ty(x)))
802         }
803         ExprIndex(callee_id, el, er) => {
804             ExprIndex(folder.new_id(callee_id),
805                       folder.fold_expr(el),
806                       folder.fold_expr(er))
807         }
808         ExprPath(ref pth) => ExprPath(folder.fold_path(pth)),
809         ExprLogLevel => ExprLogLevel,
810         ExprBreak(opt_ident) => ExprBreak(opt_ident),
811         ExprAgain(opt_ident) => ExprAgain(opt_ident),
812         ExprRet(ref e) => {
813             ExprRet(e.map(|x| folder.fold_expr(x)))
814         }
815         ExprInlineAsm(ref a) => {
816             ExprInlineAsm(InlineAsm {
817                 inputs: a.inputs.map(|&(ref c, input)| {
818                     ((*c).clone(), folder.fold_expr(input))
819                 }),
820                 outputs: a.outputs.map(|&(ref c, out)| {
821                     ((*c).clone(), folder.fold_expr(out))
822                 }),
823                 .. (*a).clone()
824             })
825         }
826         ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)),
827         ExprStruct(ref path, ref fields, maybe_expr) => {
828             ExprStruct(folder.fold_path(path),
829                        fields.map(|x| fold_field(*x)),
830                        maybe_expr.map(|x| folder.fold_expr(x)))
831         },
832         ExprParen(ex) => ExprParen(folder.fold_expr(ex))
833     };
834
835     @Expr {
836         id: folder.new_id(e.id),
837         node: node,
838         span: folder.new_span(e.span),
839     }
840 }
841
842 pub fn noop_fold_stmt<T: Folder>(s: &Stmt, folder: &mut T) -> SmallVector<@Stmt> {
843     let nodes = match s.node {
844         StmtDecl(d, nid) => {
845             folder.fold_decl(d).move_iter()
846                     .map(|d| StmtDecl(d, folder.new_id(nid)))
847                     .collect()
848         }
849         StmtExpr(e, nid) => {
850             SmallVector::one(StmtExpr(folder.fold_expr(e), folder.new_id(nid)))
851         }
852         StmtSemi(e, nid) => {
853             SmallVector::one(StmtSemi(folder.fold_expr(e), folder.new_id(nid)))
854         }
855         StmtMac(ref mac, semi) => SmallVector::one(StmtMac(folder.fold_mac(mac), semi))
856     };
857
858     nodes.move_iter().map(|node| @Spanned {
859         node: node,
860         span: folder.new_span(s.span),
861     }).collect()
862 }
863
864 #[cfg(test)]
865 mod test {
866     use ast;
867     use util::parser_testing::{string_to_crate, matches_codepattern};
868     use parse::token;
869     use print::pprust;
870     use super::*;
871
872     // this version doesn't care about getting comments or docstrings in.
873     fn fake_print_crate(s: &mut pprust::State, crate: &ast::Crate) {
874         pprust::print_mod(s, &crate.module, crate.attrs);
875     }
876
877     // change every identifier to "zz"
878     struct ToZzIdentFolder;
879
880     impl Folder for ToZzIdentFolder {
881         fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
882             token::str_to_ident("zz")
883         }
884     }
885
886     // maybe add to expand.rs...
887     macro_rules! assert_pred (
888         ($pred:expr, $predname:expr, $a:expr , $b:expr) => (
889             {
890                 let pred_val = $pred;
891                 let a_val = $a;
892                 let b_val = $b;
893                 if !(pred_val(a_val,b_val)) {
894                     fail!("expected args satisfying {}, got {:?} and {:?}",
895                           $predname, a_val, b_val);
896                 }
897             }
898         )
899     )
900
901     // make sure idents get transformed everywhere
902     #[test] fn ident_transformation () {
903         let mut zz_fold = ToZzIdentFolder;
904         let ast = string_to_crate(@"#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}");
905         assert_pred!(matches_codepattern,
906                      "matches_codepattern",
907                      pprust::to_str(&mut zz_fold.fold_crate(ast),fake_print_crate,
908                                     token::get_ident_interner()),
909                      ~"#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}");
910     }
911
912     // even inside macro defs....
913     #[test] fn ident_transformation_in_defs () {
914         let mut zz_fold = ToZzIdentFolder;
915         let ast = string_to_crate(@"macro_rules! a {(b $c:expr $(d $e:token)f+
916 => (g $(d $d $e)+))} ");
917         assert_pred!(matches_codepattern,
918                      "matches_codepattern",
919                      pprust::to_str(&mut zz_fold.fold_crate(ast),fake_print_crate,
920                                     token::get_ident_interner()),
921                      ~"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))");
922     }
923 }
924