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