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