]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/fold.rs
36565395e598899df3b6842ae07d65afc515d20d
[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::{span, spanned};
14 use opt_vec::OptVec;
15
16 pub trait ast_fold {
17     fn fold_crate(@self, &crate) -> crate;
18     fn fold_view_item(@self, @view_item) -> @view_item;
19     fn fold_foreign_item(@self, @foreign_item) -> @foreign_item;
20     fn fold_item(@self, @item) -> Option<@item>;
21     fn fold_struct_field(@self, @struct_field) -> @struct_field;
22     fn fold_item_underscore(@self, &item_) -> item_;
23     fn fold_method(@self, @method) -> @method;
24     fn fold_block(@self, &blk) -> blk;
25     fn fold_stmt(@self, &stmt) -> @stmt;
26     fn fold_arm(@self, &arm) -> arm;
27     fn fold_pat(@self, @pat) -> @pat;
28     fn fold_decl(@self, @decl) -> @decl;
29     fn fold_expr(@self, @expr) -> @expr;
30     fn fold_ty(@self, @Ty) -> @Ty;
31     fn fold_mod(@self, &_mod) -> _mod;
32     fn fold_foreign_mod(@self, &foreign_mod) -> foreign_mod;
33     fn fold_variant(@self, &variant) -> variant;
34     fn fold_ident(@self, ident) -> ident;
35     fn fold_path(@self, @Path) -> @Path;
36     fn fold_local(@self, @local) -> @local;
37     fn map_exprs(@self, @fn(@expr) -> @expr, &[@expr]) -> ~[@expr];
38     fn new_id(@self, node_id) -> node_id;
39     fn new_span(@self, span) -> span;
40 }
41
42 // We may eventually want to be able to fold over type parameters, too
43
44 pub struct AstFoldFns {
45     //unlike the others, item_ is non-trivial
46     fold_crate: @fn(&crate_, span, @ast_fold) -> (crate_, span),
47     fold_view_item: @fn(view_item_, @ast_fold) -> view_item_,
48     fold_foreign_item: @fn(@foreign_item, @ast_fold) -> @foreign_item,
49     fold_item: @fn(@item, @ast_fold) -> Option<@item>,
50     fold_struct_field: @fn(@struct_field, @ast_fold) -> @struct_field,
51     fold_item_underscore: @fn(&item_, @ast_fold) -> item_,
52     fold_method: @fn(@method, @ast_fold) -> @method,
53     fold_block: @fn(&blk_, span, @ast_fold) -> (blk_, span),
54     fold_stmt: @fn(&stmt_, span, @ast_fold) -> (stmt_, span),
55     fold_arm: @fn(&arm, @ast_fold) -> arm,
56     fold_pat: @fn(&pat_, span, @ast_fold) -> (pat_, span),
57     fold_decl: @fn(&decl_, span, @ast_fold) -> (decl_, span),
58     fold_expr: @fn(&expr_, span, @ast_fold) -> (expr_, span),
59     fold_ty: @fn(&ty_, span, @ast_fold) -> (ty_, span),
60     fold_mod: @fn(&_mod, @ast_fold) -> _mod,
61     fold_foreign_mod: @fn(&foreign_mod, @ast_fold) -> foreign_mod,
62     fold_variant: @fn(&variant_, span, @ast_fold) -> (variant_, span),
63     fold_ident: @fn(ident, @ast_fold) -> ident,
64     fold_path: @fn(@Path, @ast_fold) -> Path,
65     fold_local: @fn(&local_, span, @ast_fold) -> (local_, span),
66     map_exprs: @fn(@fn(@expr) -> @expr, &[@expr]) -> ~[@expr],
67     new_id: @fn(node_id) -> node_id,
68     new_span: @fn(span) -> span
69 }
70
71 pub type ast_fold_fns = @AstFoldFns;
72
73 /* some little folds that probably aren't useful to have in ast_fold itself*/
74
75 //used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
76 fn fold_meta_item_(mi: @meta_item, fld: @ast_fold) -> @meta_item {
77     @spanned {
78         node:
79             match mi.node {
80                 meta_word(id) => meta_word(id),
81                 meta_list(id, ref mis) => {
82                     let fold_meta_item = |x| fold_meta_item_(x, fld);
83                     meta_list(
84                         id,
85                         mis.map(|e| fold_meta_item(*e))
86                     )
87                 }
88                 meta_name_value(id, s) => {
89                     meta_name_value(id, /* FIXME (#2543) */ copy s)
90                 }
91             },
92         span: fld.new_span(mi.span) }
93 }
94 //used in noop_fold_item and noop_fold_crate
95 fn fold_attribute_(at: attribute, fld: @ast_fold) -> attribute {
96     spanned {
97         node: ast::attribute_ {
98             style: at.node.style,
99             value: fold_meta_item_(at.node.value, fld),
100             is_sugared_doc: at.node.is_sugared_doc,
101         },
102         span: fld.new_span(at.span),
103     }
104 }
105 //used in noop_fold_foreign_item and noop_fold_fn_decl
106 fn fold_arg_(a: arg, fld: @ast_fold) -> arg {
107     ast::arg {
108         is_mutbl: a.is_mutbl,
109         ty: fld.fold_ty(a.ty),
110         pat: fld.fold_pat(a.pat),
111         id: fld.new_id(a.id),
112     }
113 }
114 //used in noop_fold_expr, and possibly elsewhere in the future
115 fn fold_mac_(m: mac, fld: @ast_fold) -> mac {
116     spanned {
117         node: match m.node { mac_invoc_tt(*) => copy m.node },
118         span: fld.new_span(m.span),
119     }
120 }
121
122 pub fn fold_fn_decl(decl: &ast::fn_decl, fld: @ast_fold) -> ast::fn_decl {
123     ast::fn_decl {
124         inputs: decl.inputs.map(|x| fold_arg_(*x, fld)),
125         output: fld.fold_ty(decl.output),
126         cf: decl.cf,
127     }
128 }
129
130 fn fold_ty_param_bound(tpb: &TyParamBound, fld: @ast_fold) -> TyParamBound {
131     match *tpb {
132         TraitTyParamBound(ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
133         RegionTyParamBound => RegionTyParamBound
134     }
135 }
136
137 pub fn fold_ty_param(tp: TyParam,
138                      fld: @ast_fold) -> TyParam {
139     TyParam {ident: tp.ident,
140              id: fld.new_id(tp.id),
141              bounds: @tp.bounds.map(|x| fold_ty_param_bound(x, fld))}
142 }
143
144 pub fn fold_ty_params(tps: &OptVec<TyParam>,
145                       fld: @ast_fold) -> OptVec<TyParam> {
146     tps.map(|tp| fold_ty_param(*tp, fld))
147 }
148
149 pub fn fold_lifetime(l: &Lifetime,
150                      fld: @ast_fold) -> Lifetime {
151     Lifetime {id: fld.new_id(l.id),
152               span: fld.new_span(l.span),
153               ident: l.ident}
154 }
155
156 pub fn fold_lifetimes(lts: &OptVec<Lifetime>,
157                       fld: @ast_fold) -> OptVec<Lifetime> {
158     lts.map(|l| fold_lifetime(l, fld))
159 }
160
161 pub fn fold_generics(generics: &Generics, fld: @ast_fold) -> Generics {
162     Generics {ty_params: fold_ty_params(&generics.ty_params, fld),
163               lifetimes: fold_lifetimes(&generics.lifetimes, fld)}
164 }
165
166 pub fn noop_fold_crate(c: &crate_, fld: @ast_fold) -> crate_ {
167     let fold_meta_item = |x| fold_meta_item_(x, fld);
168     let fold_attribute = |x| fold_attribute_(x, fld);
169
170     crate_ {
171         module: fld.fold_mod(&c.module),
172         attrs: c.attrs.map(|x| fold_attribute(*x)),
173         config: c.config.map(|x| fold_meta_item(*x)),
174     }
175 }
176
177 fn noop_fold_view_item(vi: view_item_, _fld: @ast_fold) -> view_item_ {
178     return /* FIXME (#2543) */ copy vi;
179 }
180
181
182 fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold)
183     -> @foreign_item {
184     let fold_arg = |x| fold_arg_(x, fld);
185     let fold_attribute = |x| fold_attribute_(x, fld);
186
187     @ast::foreign_item {
188         ident: fld.fold_ident(ni.ident),
189         attrs: ni.attrs.map(|x| fold_attribute(*x)),
190         node:
191             match ni.node {
192                 foreign_item_fn(ref fdec, purity, ref generics) => {
193                     foreign_item_fn(
194                         ast::fn_decl {
195                             inputs: fdec.inputs.map(|a| fold_arg(*a)),
196                             output: fld.fold_ty(fdec.output),
197                             cf: fdec.cf,
198                         },
199                         purity,
200                         fold_generics(generics, fld))
201                 }
202                 foreign_item_const(t) => {
203                     foreign_item_const(fld.fold_ty(t))
204                 }
205             },
206         id: fld.new_id(ni.id),
207         span: fld.new_span(ni.span),
208         vis: ni.vis,
209     }
210 }
211
212 pub fn noop_fold_item(i: @item, fld: @ast_fold) -> Option<@item> {
213     let fold_attribute = |x| fold_attribute_(x, fld);
214
215     Some(@ast::item { ident: fld.fold_ident(i.ident),
216                       attrs: i.attrs.map(|e| fold_attribute(*e)),
217                       id: fld.new_id(i.id),
218                       node: fld.fold_item_underscore(&i.node),
219                       vis: i.vis,
220                       span: fld.new_span(i.span) })
221 }
222
223 fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold)
224                        -> @struct_field {
225     let fold_attribute = |x| fold_attribute_(x, fld);
226
227     @spanned { node: ast::struct_field_ { kind: copy sf.node.kind,
228                                           id: sf.node.id,
229                                           ty: fld.fold_ty(sf.node.ty),
230                                           attrs: sf.node.attrs.map(|e| fold_attribute(*e)) },
231                span: sf.span }
232 }
233
234 pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
235     match *i {
236         item_const(t, e) => item_const(fld.fold_ty(t), fld.fold_expr(e)),
237         item_fn(ref decl, purity, abi, ref generics, ref body) => {
238             item_fn(
239                 fold_fn_decl(decl, fld),
240                 purity,
241                 abi,
242                 fold_generics(generics, fld),
243                 fld.fold_block(body)
244             )
245         }
246         item_mod(ref m) => item_mod(fld.fold_mod(m)),
247         item_foreign_mod(ref nm) => {
248             item_foreign_mod(fld.fold_foreign_mod(nm))
249         }
250         item_ty(t, ref generics) => {
251             item_ty(fld.fold_ty(t), fold_generics(generics, fld))
252         }
253         item_enum(ref enum_definition, ref generics) => {
254             item_enum(
255                 ast::enum_def {
256                     variants: do enum_definition.variants.map |x| {
257                         fld.fold_variant(x)
258                     },
259                 },
260                 fold_generics(generics, fld))
261         }
262         item_struct(ref struct_def, ref generics) => {
263             let struct_def = fold_struct_def(*struct_def, fld);
264             item_struct(struct_def, /* FIXME (#2543) */ copy *generics)
265         }
266         item_impl(ref generics, ifce, ty, ref methods) => {
267             item_impl(
268                 fold_generics(generics, fld),
269                 ifce.map(|p| fold_trait_ref(*p, fld)),
270                 fld.fold_ty(ty),
271                 methods.map(|x| fld.fold_method(*x))
272             )
273         }
274         item_trait(ref generics, ref traits, ref methods) => {
275             let methods = do methods.map |method| {
276                 match *method {
277                     required(*) => copy *method,
278                     provided(method) => provided(fld.fold_method(method))
279                 }
280             };
281             item_trait(
282                 fold_generics(generics, fld),
283                 traits.map(|p| fold_trait_ref(*p, fld)),
284                 methods
285             )
286         }
287         item_mac(ref m) => {
288             // FIXME #2888: we might actually want to do something here.
289             item_mac(copy *m)
290         }
291     }
292 }
293
294 fn fold_struct_def(struct_def: @ast::struct_def, fld: @ast_fold)
295                 -> @ast::struct_def {
296     @ast::struct_def {
297         fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)),
298         ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)),
299     }
300 }
301
302 fn fold_trait_ref(p: @trait_ref, fld: @ast_fold) -> @trait_ref {
303     @ast::trait_ref {
304         path: fld.fold_path(p.path),
305         ref_id: fld.new_id(p.ref_id),
306     }
307 }
308
309 fn fold_struct_field(f: @struct_field, fld: @ast_fold) -> @struct_field {
310     @spanned {
311         node: ast::struct_field_ {
312             kind: copy f.node.kind,
313             id: fld.new_id(f.node.id),
314             ty: fld.fold_ty(f.node.ty),
315             attrs: /* FIXME (#2543) */ copy f.node.attrs,
316         },
317         span: fld.new_span(f.span),
318     }
319 }
320
321 fn noop_fold_method(m: @method, fld: @ast_fold) -> @method {
322     @ast::method {
323         ident: fld.fold_ident(m.ident),
324         attrs: /* FIXME (#2543) */ copy m.attrs,
325         generics: fold_generics(&m.generics, fld),
326         self_ty: m.self_ty,
327         purity: m.purity,
328         decl: fold_fn_decl(&m.decl, fld),
329         body: fld.fold_block(&m.body),
330         id: fld.new_id(m.id),
331         span: fld.new_span(m.span),
332         self_id: fld.new_id(m.self_id),
333         vis: m.vis,
334     }
335 }
336
337
338 pub fn noop_fold_block(b: &blk_, fld: @ast_fold) -> blk_ {
339     ast::blk_ {
340         view_items: b.view_items.map(|x| fld.fold_view_item(*x)),
341         stmts: b.stmts.map(|x| fld.fold_stmt(*x)),
342         expr: b.expr.map(|x| fld.fold_expr(*x)),
343         id: fld.new_id(b.id),
344         rules: b.rules,
345     }
346 }
347
348 fn noop_fold_stmt(s: &stmt_, fld: @ast_fold) -> stmt_ {
349     let fold_mac = |x| fold_mac_(x, fld);
350     match *s {
351         stmt_decl(d, nid) => stmt_decl(fld.fold_decl(d), fld.new_id(nid)),
352         stmt_expr(e, nid) => stmt_expr(fld.fold_expr(e), fld.new_id(nid)),
353         stmt_semi(e, nid) => stmt_semi(fld.fold_expr(e), fld.new_id(nid)),
354         stmt_mac(ref mac, semi) => stmt_mac(fold_mac((*mac)), semi)
355     }
356 }
357
358 fn noop_fold_arm(a: &arm, fld: @ast_fold) -> arm {
359     arm {
360         pats: a.pats.map(|x| fld.fold_pat(*x)),
361         guard: a.guard.map(|x| fld.fold_expr(*x)),
362         body: fld.fold_block(&a.body),
363     }
364 }
365
366 pub fn noop_fold_pat(p: &pat_, fld: @ast_fold) -> pat_ {
367     match *p {
368         pat_wild => pat_wild,
369         pat_ident(binding_mode, pth, ref sub) => {
370             pat_ident(
371                 binding_mode,
372                 fld.fold_path(pth),
373                 sub.map(|x| fld.fold_pat(*x))
374             )
375         }
376         pat_lit(e) => pat_lit(fld.fold_expr(e)),
377         pat_enum(pth, ref pats) => {
378             pat_enum(
379                 fld.fold_path(pth),
380                 pats.map(|pats| pats.map(|x| fld.fold_pat(*x)))
381             )
382         }
383         pat_struct(pth, ref fields, etc) => {
384             let pth_ = fld.fold_path(pth);
385             let fs = do fields.map |f| {
386                 ast::field_pat {
387                     ident: /* FIXME (#2543) */ copy f.ident,
388                     pat: fld.fold_pat(f.pat)
389                 }
390             };
391             pat_struct(pth_, fs, etc)
392         }
393         pat_tup(ref elts) => pat_tup(elts.map(|x| fld.fold_pat(*x))),
394         pat_box(inner) => pat_box(fld.fold_pat(inner)),
395         pat_uniq(inner) => pat_uniq(fld.fold_pat(inner)),
396         pat_region(inner) => pat_region(fld.fold_pat(inner)),
397         pat_range(e1, e2) => {
398             pat_range(fld.fold_expr(e1), fld.fold_expr(e2))
399         },
400         pat_vec(ref before, ref slice, ref after) => {
401             pat_vec(
402                 before.map(|x| fld.fold_pat(*x)),
403                 slice.map(|x| fld.fold_pat(*x)),
404                 after.map(|x| fld.fold_pat(*x))
405             )
406         }
407     }
408 }
409
410 fn noop_fold_decl(d: &decl_, fld: @ast_fold) -> decl_ {
411     match *d {
412         decl_local(ref ls) => decl_local(ls.map(|x| fld.fold_local(*x))),
413         decl_item(it) => {
414             match fld.fold_item(it) {
415                 Some(it_folded) => decl_item(it_folded),
416                 None => decl_local(~[]),
417             }
418         }
419     }
420 }
421
422 pub fn wrap<T>(f: @fn(&T, @ast_fold) -> T)
423             -> @fn(&T, span, @ast_fold) -> (T, span) {
424     let result: @fn(&T, span, @ast_fold) -> (T, span) = |x, s, fld| {
425         (f(x, fld), s)
426     };
427     result
428 }
429
430 pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
431     fn fold_field_(field: field, fld: @ast_fold) -> field {
432         spanned {
433             node: ast::field_ {
434                 mutbl: field.node.mutbl,
435                 ident: fld.fold_ident(field.node.ident),
436                 expr: fld.fold_expr(field.node.expr),
437             },
438             span: fld.new_span(field.span),
439         }
440     }
441     let fold_field = |x| fold_field_(x, fld);
442
443     let fold_mac = |x| fold_mac_(x, fld);
444
445     match *e {
446         expr_vstore(e, v) => {
447             expr_vstore(fld.fold_expr(e), v)
448         }
449         expr_vec(ref exprs, mutt) => {
450             expr_vec(fld.map_exprs(|x| fld.fold_expr(x), *exprs), mutt)
451         }
452         expr_repeat(expr, count, mutt) => {
453             expr_repeat(fld.fold_expr(expr), fld.fold_expr(count), mutt)
454         }
455         expr_tup(ref elts) => expr_tup(elts.map(|x| fld.fold_expr(*x))),
456         expr_call(f, ref args, blk) => {
457             expr_call(
458                 fld.fold_expr(f),
459                 fld.map_exprs(|x| fld.fold_expr(x), *args),
460                 blk
461             )
462         }
463         expr_method_call(f, i, ref tps, ref args, blk) => {
464             expr_method_call(
465                 fld.fold_expr(f),
466                 fld.fold_ident(i),
467                 tps.map(|x| fld.fold_ty(*x)),
468                 fld.map_exprs(|x| fld.fold_expr(x), *args),
469                 blk
470             )
471         }
472         expr_binary(binop, lhs, rhs) => {
473             expr_binary(binop, fld.fold_expr(lhs), fld.fold_expr(rhs))
474         }
475         expr_unary(binop, ohs) => expr_unary(binop, fld.fold_expr(ohs)),
476         expr_loop_body(f) => expr_loop_body(fld.fold_expr(f)),
477         expr_do_body(f) => expr_do_body(fld.fold_expr(f)),
478         expr_lit(_) => copy *e,
479         expr_cast(expr, ty) => expr_cast(fld.fold_expr(expr), ty),
480         expr_addr_of(m, ohs) => expr_addr_of(m, fld.fold_expr(ohs)),
481         expr_if(cond, ref tr, fl) => {
482             expr_if(
483                 fld.fold_expr(cond),
484                 fld.fold_block(tr),
485                 fl.map(|x| fld.fold_expr(*x))
486             )
487         }
488         expr_while(cond, ref body) => {
489             expr_while(fld.fold_expr(cond), fld.fold_block(body))
490         }
491         expr_loop(ref body, opt_ident) => {
492             expr_loop(
493                 fld.fold_block(body),
494                 opt_ident.map(|x| fld.fold_ident(*x))
495             )
496         }
497         expr_match(expr, ref arms) => {
498             expr_match(
499                 fld.fold_expr(expr),
500                 arms.map(|x| fld.fold_arm(x))
501             )
502         }
503         expr_fn_block(ref decl, ref body) => {
504             expr_fn_block(
505                 fold_fn_decl(decl, fld),
506                 fld.fold_block(body)
507             )
508         }
509         expr_block(ref blk) => expr_block(fld.fold_block(blk)),
510         expr_copy(e) => expr_copy(fld.fold_expr(e)),
511         expr_assign(el, er) => {
512             expr_assign(fld.fold_expr(el), fld.fold_expr(er))
513         }
514         expr_swap(el, er) => {
515             expr_swap(fld.fold_expr(el), fld.fold_expr(er))
516         }
517         expr_assign_op(op, el, er) => {
518             expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er))
519         }
520         expr_field(el, id, ref tys) => {
521             expr_field(
522                 fld.fold_expr(el), fld.fold_ident(id),
523                 tys.map(|x| fld.fold_ty(*x))
524             )
525         }
526         expr_index(el, er) => {
527             expr_index(fld.fold_expr(el), fld.fold_expr(er))
528         }
529         expr_path(pth) => expr_path(fld.fold_path(pth)),
530         expr_break(ref opt_ident) => {
531             expr_break(opt_ident.map(|x| fld.fold_ident(*x)))
532         }
533         expr_again(ref opt_ident) => {
534             expr_again(opt_ident.map(|x| fld.fold_ident(*x)))
535         }
536         expr_ret(ref e) => {
537             expr_ret(e.map(|x| fld.fold_expr(*x)))
538         }
539         expr_log(lv, e) => {
540             expr_log(
541                 fld.fold_expr(lv),
542                 fld.fold_expr(e)
543             )
544         }
545         expr_inline_asm(a) => {
546             expr_inline_asm(inline_asm {
547                 inputs: a.inputs.map(|&(c, in)| (c, fld.fold_expr(in))),
548                 outputs: a.outputs.map(|&(c, out)| (c, fld.fold_expr(out))),
549                 .. a
550             })
551         }
552         expr_mac(ref mac) => expr_mac(fold_mac((*mac))),
553         expr_struct(path, ref fields, maybe_expr) => {
554             expr_struct(
555                 fld.fold_path(path),
556                 fields.map(|x| fold_field(*x)),
557                 maybe_expr.map(|x| fld.fold_expr(*x))
558             )
559         },
560         expr_paren(ex) => expr_paren(fld.fold_expr(ex))
561     }
562 }
563
564 pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
565     let fold_mac = |x| fold_mac_(x, fld);
566     fn fold_mt(mt: &mt, fld: @ast_fold) -> mt {
567         mt {
568             ty: fld.fold_ty(mt.ty),
569             mutbl: mt.mutbl,
570         }
571     }
572     fn fold_field(f: ty_field, fld: @ast_fold) -> ty_field {
573         spanned {
574             node: ast::ty_field_ {
575                 ident: fld.fold_ident(f.node.ident),
576                 mt: fold_mt(&f.node.mt, fld),
577             },
578             span: fld.new_span(f.span),
579         }
580     }
581     match *t {
582         ty_nil | ty_bot | ty_infer => copy *t,
583         ty_box(ref mt) => ty_box(fold_mt(mt, fld)),
584         ty_uniq(ref mt) => ty_uniq(fold_mt(mt, fld)),
585         ty_vec(ref mt) => ty_vec(fold_mt(mt, fld)),
586         ty_ptr(ref mt) => ty_ptr(fold_mt(mt, fld)),
587         ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, fld)),
588         ty_closure(ref f) => {
589             ty_closure(@TyClosure {
590                 sigil: f.sigil,
591                 purity: f.purity,
592                 region: f.region,
593                 onceness: f.onceness,
594                 decl: fold_fn_decl(&f.decl, fld),
595                 lifetimes: f.lifetimes,
596             })
597         }
598         ty_bare_fn(ref f) => {
599             ty_bare_fn(@TyBareFn {
600                 lifetimes: f.lifetimes,
601                 purity: f.purity,
602                 abis: f.abis,
603                 decl: fold_fn_decl(&f.decl, fld)
604             })
605         }
606         ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))),
607         ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),
608         ty_fixed_length_vec(ref mt, e) => {
609             ty_fixed_length_vec(
610                 fold_mt(mt, fld),
611                 fld.fold_expr(e)
612             )
613         }
614         ty_mac(ref mac) => ty_mac(fold_mac(*mac))
615     }
616 }
617
618 // ...nor do modules
619 pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod {
620     ast::_mod {
621         view_items: vec::map(m.view_items, |x| fld.fold_view_item(*x)),
622         items: vec::filter_mapped(m.items, |x| fld.fold_item(*x)),
623     }
624 }
625
626 fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod {
627     ast::foreign_mod {
628         sort: nm.sort,
629         abis: nm.abis,
630         view_items: vec::map(nm.view_items, |x| fld.fold_view_item(*x)),
631         items: vec::map(nm.items, |x| fld.fold_foreign_item(*x)),
632     }
633 }
634
635 fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ {
636     fn fold_variant_arg_(va: variant_arg, fld: @ast_fold) -> variant_arg {
637         ast::variant_arg { ty: fld.fold_ty(va.ty), id: fld.new_id(va.id) }
638     }
639     let fold_variant_arg = |x| fold_variant_arg_(x, fld);
640
641     let kind;
642     match v.kind {
643         tuple_variant_kind(ref variant_args) => {
644             kind = tuple_variant_kind(do variant_args.map |x| {
645                 fold_variant_arg(*x)
646             })
647         }
648         struct_variant_kind(struct_def) => {
649             kind = struct_variant_kind(@ast::struct_def {
650                 fields: vec::map(struct_def.fields,
651                                  |f| fld.fold_struct_field(*f)),
652                 ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c))
653             })
654         }
655     }
656
657     let fold_attribute = |x| fold_attribute_(x, fld);
658     let attrs = v.attrs.map(|x| fold_attribute(*x));
659
660     let de = match v.disr_expr {
661       Some(e) => Some(fld.fold_expr(e)),
662       None => None
663     };
664     ast::variant_ {
665         name: /* FIXME (#2543) */ copy v.name,
666         attrs: attrs,
667         kind: kind,
668         id: fld.new_id(v.id),
669         disr_expr: de,
670         vis: v.vis,
671     }
672 }
673
674 fn noop_fold_ident(i: ident, _fld: @ast_fold) -> ident {
675     /* FIXME (#2543) */ copy i
676 }
677
678 fn noop_fold_path(p: @Path, fld: @ast_fold) -> Path {
679     ast::Path {
680         span: fld.new_span(p.span),
681         global: p.global,
682         idents: p.idents.map(|x| fld.fold_ident(*x)),
683         rp: p.rp,
684         types: p.types.map(|x| fld.fold_ty(*x)),
685     }
686 }
687
688 fn noop_fold_local(l: &local_, fld: @ast_fold) -> local_ {
689     local_ {
690         is_mutbl: l.is_mutbl,
691         ty: fld.fold_ty(l.ty),
692         pat: fld.fold_pat(l.pat),
693         init: l.init.map(|e| fld.fold_expr(*e)),
694         id: fld.new_id(l.id),
695     }
696 }
697
698 /* temporarily eta-expand because of a compiler bug with using `fn<T>` as a
699    value */
700 fn noop_map_exprs(f: @fn(@expr) -> @expr, es: &[@expr]) -> ~[@expr] {
701     es.map(|x| f(*x))
702 }
703
704 fn noop_id(i: node_id) -> node_id { return i; }
705
706 fn noop_span(sp: span) -> span { return sp; }
707
708 pub fn default_ast_fold() -> ast_fold_fns {
709     @AstFoldFns {
710         fold_crate: wrap(noop_fold_crate),
711         fold_view_item: noop_fold_view_item,
712         fold_foreign_item: noop_fold_foreign_item,
713         fold_item: noop_fold_item,
714         fold_struct_field: noop_fold_struct_field,
715         fold_item_underscore: noop_fold_item_underscore,
716         fold_method: noop_fold_method,
717         fold_block: wrap(noop_fold_block),
718         fold_stmt: wrap(noop_fold_stmt),
719         fold_arm: noop_fold_arm,
720         fold_pat: wrap(noop_fold_pat),
721         fold_decl: wrap(noop_fold_decl),
722         fold_expr: wrap(noop_fold_expr),
723         fold_ty: wrap(noop_fold_ty),
724         fold_mod: noop_fold_mod,
725         fold_foreign_mod: noop_fold_foreign_mod,
726         fold_variant: wrap(noop_fold_variant),
727         fold_ident: noop_fold_ident,
728         fold_path: noop_fold_path,
729         fold_local: wrap(noop_fold_local),
730         map_exprs: noop_map_exprs,
731         new_id: noop_id,
732         new_span: noop_span,
733     }
734 }
735
736 impl ast_fold for AstFoldFns {
737     /* naturally, a macro to write these would be nice */
738     fn fold_crate(@self, c: &crate) -> crate {
739         let (n, s) = (self.fold_crate)(&c.node, c.span, self as @ast_fold);
740         spanned { node: n, span: (self.new_span)(s) }
741     }
742     fn fold_view_item(@self, x: @view_item) ->
743        @view_item {
744         @ast::view_item {
745             node: (self.fold_view_item)(x.node, self as @ast_fold),
746             attrs: vec::map(x.attrs, |a|
747                   fold_attribute_(*a, self as @ast_fold)),
748             vis: x.vis,
749             span: (self.new_span)(x.span),
750         }
751     }
752     fn fold_foreign_item(@self, x: @foreign_item) -> @foreign_item {
753         (self.fold_foreign_item)(x, self as @ast_fold)
754     }
755     fn fold_item(@self, i: @item) -> Option<@item> {
756         (self.fold_item)(i, self as @ast_fold)
757     }
758     fn fold_struct_field(@self, sf: @struct_field) -> @struct_field {
759         @spanned {
760             node: ast::struct_field_ {
761                 kind: copy sf.node.kind,
762                 id: sf.node.id,
763                 ty: (self as @ast_fold).fold_ty(sf.node.ty),
764                 attrs: copy sf.node.attrs,
765             },
766             span: (self.new_span)(sf.span),
767         }
768     }
769     fn fold_item_underscore(@self, i: &item_) -> item_ {
770         (self.fold_item_underscore)(i, self as @ast_fold)
771     }
772     fn fold_method(@self, x: @method) -> @method {
773         (self.fold_method)(x, self as @ast_fold)
774     }
775     fn fold_block(@self, x: &blk) -> blk {
776         let (n, s) = (self.fold_block)(&x.node, x.span, self as @ast_fold);
777         spanned { node: n, span: (self.new_span)(s) }
778     }
779     fn fold_stmt(@self, x: &stmt) -> @stmt {
780         let (n, s) = (self.fold_stmt)(&x.node, x.span, self as @ast_fold);
781         @spanned { node: n, span: (self.new_span)(s) }
782     }
783     fn fold_arm(@self, x: &arm) -> arm {
784         (self.fold_arm)(x, self as @ast_fold)
785     }
786     fn fold_pat(@self, x: @pat) -> @pat {
787         let (n, s) =  (self.fold_pat)(&x.node, x.span, self as @ast_fold);
788         @pat {
789             id: (self.new_id)(x.id),
790             node: n,
791             span: (self.new_span)(s),
792         }
793     }
794     fn fold_decl(@self, x: @decl) -> @decl {
795         let (n, s) = (self.fold_decl)(&x.node, x.span, self as @ast_fold);
796         @spanned { node: n, span: (self.new_span)(s) }
797     }
798     fn fold_expr(@self, x: @expr) -> @expr {
799         let (n, s) = (self.fold_expr)(&x.node, x.span, self as @ast_fold);
800         @expr {
801             id: (self.new_id)(x.id),
802             callee_id: (self.new_id)(x.callee_id),
803             node: n,
804             span: (self.new_span)(s),
805         }
806     }
807     fn fold_ty(@self, x: @Ty) -> @Ty {
808         let (n, s) = (self.fold_ty)(&x.node, x.span, self as @ast_fold);
809         @Ty {
810             id: (self.new_id)(x.id),
811             node: n,
812             span: (self.new_span)(s),
813         }
814     }
815     fn fold_mod(@self, x: &_mod) -> _mod {
816         (self.fold_mod)(x, self as @ast_fold)
817     }
818     fn fold_foreign_mod(@self, x: &foreign_mod) -> foreign_mod {
819         (self.fold_foreign_mod)(x, self as @ast_fold)
820     }
821     fn fold_variant(@self, x: &variant) -> variant {
822         let (n, s) = (self.fold_variant)(&x.node, x.span, self as @ast_fold);
823         spanned { node: n, span: (self.new_span)(s) }
824     }
825     fn fold_ident(@self, x: ident) -> ident {
826         (self.fold_ident)(x, self as @ast_fold)
827     }
828     fn fold_path(@self, x: @Path) -> @Path {
829         @(self.fold_path)(x, self as @ast_fold)
830     }
831     fn fold_local(@self, x: @local) -> @local {
832         let (n, s) = (self.fold_local)(&x.node, x.span, self as @ast_fold);
833         @spanned { node: n, span: (self.new_span)(s) }
834     }
835     fn map_exprs(@self,
836                  f: @fn(@expr) -> @expr,
837                  e: &[@expr])
838               -> ~[@expr] {
839         (self.map_exprs)(f, e)
840     }
841     fn new_id(@self, node_id: ast::node_id) -> node_id {
842         (self.new_id)(node_id)
843     }
844     fn new_span(@self, span: span) -> span {
845         (self.new_span)(span)
846     }
847 }
848
849 pub trait AstFoldExtensions {
850     fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute];
851 }
852
853 impl AstFoldExtensions for @ast_fold {
854     fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute] {
855         attrs.map(|x| fold_attribute_(*x, *self))
856     }
857 }
858
859 pub fn make_fold(afp: ast_fold_fns) -> @ast_fold {
860     afp as @ast_fold
861 }
862
863 //
864 // Local Variables:
865 // mode: rust
866 // fill-column: 78;
867 // indent-tabs-mode: nil
868 // c-basic-offset: 4
869 // buffer-file-coding-system: utf-8-unix
870 // End:
871 //