1 // Copyright 2012-2014 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.
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.
11 //! A Folder represents an AST->AST fold; it accepts an AST piece,
12 //! and returns a piece of the same type. So, for instance, macro
13 //! expansion is a Folder that walks over an AST and produces another
16 //! Note: using a Folder (other than the MacroExpander Folder) on
17 //! an AST before macro expansion is probably a bad idea. For instance,
18 //! a folder renaming item names in a module will miss all of those
19 //! that are created by the expansion of a macro.
24 use codemap::{respan, Span, Spanned};
26 use owned_slice::OwnedSlice;
27 use util::small_vector::SmallVector;
30 use std::gc::{Gc, GC};
33 // Any additions to this trait should happen in form
34 // of a call to a public `noop_*` function that only calls
35 // out to the folder again, not other `noop_*` functions.
37 // This is a necessary API workaround to the problem of not
38 // being able to call out to the super default method
39 // in an overridden default method.
41 fn fold_crate(&mut self, c: Crate) -> Crate {
42 noop_fold_crate(c, self)
45 fn fold_meta_items(&mut self, meta_items: &[Gc<MetaItem>]) -> Vec<Gc<MetaItem>> {
46 noop_fold_meta_items(meta_items, self)
49 fn fold_meta_item(&mut self, meta_item: &MetaItem) -> MetaItem {
50 noop_fold_meta_item(meta_item, self)
53 fn fold_view_path(&mut self, view_path: Gc<ViewPath>) -> Gc<ViewPath> {
54 noop_fold_view_path(view_path, self)
57 fn fold_view_item(&mut self, vi: &ViewItem) -> ViewItem {
58 noop_fold_view_item(vi, self)
61 fn fold_foreign_item(&mut self, ni: Gc<ForeignItem>) -> Gc<ForeignItem> {
62 noop_fold_foreign_item(&*ni, self)
65 fn fold_item(&mut self, i: Gc<Item>) -> SmallVector<Gc<Item>> {
66 noop_fold_item(&*i, self)
69 fn fold_item_simple(&mut self, i: &Item) -> Item {
70 noop_fold_item_simple(i, self)
73 fn fold_struct_field(&mut self, sf: &StructField) -> StructField {
74 noop_fold_struct_field(sf, self)
77 fn fold_item_underscore(&mut self, i: &Item_) -> Item_ {
78 noop_fold_item_underscore(i, self)
81 fn fold_fn_decl(&mut self, d: &FnDecl) -> P<FnDecl> {
82 noop_fold_fn_decl(d, self)
85 fn fold_type_method(&mut self, m: &TypeMethod) -> TypeMethod {
86 noop_fold_type_method(m, self)
89 fn fold_method(&mut self, m: Gc<Method>) -> SmallVector<Gc<Method>> {
90 noop_fold_method(&*m, self)
93 fn fold_block(&mut self, b: P<Block>) -> P<Block> {
94 noop_fold_block(b, self)
97 fn fold_stmt(&mut self, s: &Stmt) -> SmallVector<Gc<Stmt>> {
98 noop_fold_stmt(s, self)
101 fn fold_arm(&mut self, a: &Arm) -> Arm {
102 noop_fold_arm(a, self)
105 fn fold_pat(&mut self, p: Gc<Pat>) -> Gc<Pat> {
106 noop_fold_pat(p, self)
109 fn fold_decl(&mut self, d: Gc<Decl>) -> SmallVector<Gc<Decl>> {
110 noop_fold_decl(d, self)
113 fn fold_expr(&mut self, e: Gc<Expr>) -> Gc<Expr> {
114 noop_fold_expr(e, self)
117 fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
118 noop_fold_ty(t, self)
121 fn fold_mod(&mut self, m: &Mod) -> Mod {
122 noop_fold_mod(m, self)
125 fn fold_foreign_mod(&mut self, nm: &ForeignMod) -> ForeignMod {
126 noop_fold_foreign_mod(nm, self)
129 fn fold_variant(&mut self, v: &Variant) -> P<Variant> {
130 noop_fold_variant(v, self)
133 fn fold_ident(&mut self, i: Ident) -> Ident {
134 noop_fold_ident(i, self)
137 fn fold_uint(&mut self, i: uint) -> uint {
138 noop_fold_uint(i, self)
141 fn fold_path(&mut self, p: &Path) -> Path {
142 noop_fold_path(p, self)
145 fn fold_local(&mut self, l: Gc<Local>) -> Gc<Local> {
146 noop_fold_local(l, self)
149 fn fold_mac(&mut self, _macro: &Mac) -> Mac {
150 fail!("fold_mac disabled by default");
151 // NB: see note about macros above.
152 // if you really want a folder that
153 // works on macros, use this
154 // definition in your trait impl:
155 // fold::noop_fold_mac(_macro, self)
158 fn fold_explicit_self(&mut self, es: &ExplicitSelf) -> ExplicitSelf {
159 noop_fold_explicit_self(es, self)
162 fn fold_explicit_self_underscore(&mut self, es: &ExplicitSelf_) -> ExplicitSelf_ {
163 noop_fold_explicit_self_underscore(es, self)
166 fn fold_lifetime(&mut self, l: &Lifetime) -> Lifetime {
167 noop_fold_lifetime(l, self)
170 fn fold_lifetime_def(&mut self, l: &LifetimeDef) -> LifetimeDef {
171 noop_fold_lifetime_def(l, self)
174 fn fold_attribute(&mut self, at: Attribute) -> Attribute {
175 noop_fold_attribute(at, self)
178 fn fold_arg(&mut self, a: &Arg) -> Arg {
179 noop_fold_arg(a, self)
182 fn fold_generics(&mut self, generics: &Generics) -> Generics {
183 noop_fold_generics(generics, self)
186 fn fold_trait_ref(&mut self, p: &TraitRef) -> TraitRef {
187 noop_fold_trait_ref(p, self)
190 fn fold_struct_def(&mut self, struct_def: Gc<StructDef>) -> Gc<StructDef> {
191 noop_fold_struct_def(struct_def, self)
194 fn fold_lifetimes(&mut self, lts: &[Lifetime]) -> Vec<Lifetime> {
195 noop_fold_lifetimes(lts, self)
198 fn fold_lifetime_defs(&mut self, lts: &[LifetimeDef]) -> Vec<LifetimeDef> {
199 noop_fold_lifetime_defs(lts, self)
202 fn fold_ty_param(&mut self, tp: &TyParam) -> TyParam {
203 noop_fold_ty_param(tp, self)
206 fn fold_ty_params(&mut self, tps: &[TyParam]) -> OwnedSlice<TyParam> {
207 noop_fold_ty_params(tps, self)
210 fn fold_tt(&mut self, tt: &TokenTree) -> TokenTree {
211 noop_fold_tt(tt, self)
214 fn fold_tts(&mut self, tts: &[TokenTree]) -> Vec<TokenTree> {
215 noop_fold_tts(tts, self)
218 fn fold_token(&mut self, t: &token::Token) -> token::Token {
219 noop_fold_token(t, self)
222 fn fold_interpolated(&mut self, nt : &token::Nonterminal) -> token::Nonterminal {
223 noop_fold_interpolated(nt, self)
226 fn fold_opt_lifetime(&mut self, o_lt: &Option<Lifetime>) -> Option<Lifetime> {
227 noop_fold_opt_lifetime(o_lt, self)
230 fn fold_variant_arg(&mut self, va: &VariantArg) -> VariantArg {
231 noop_fold_variant_arg(va, self)
234 fn fold_opt_bounds(&mut self, b: &Option<OwnedSlice<TyParamBound>>)
235 -> Option<OwnedSlice<TyParamBound>> {
236 noop_fold_opt_bounds(b, self)
239 fn fold_bounds(&mut self, b: &OwnedSlice<TyParamBound>)
240 -> OwnedSlice<TyParamBound> {
241 noop_fold_bounds(b, self)
244 fn fold_ty_param_bound(&mut self, tpb: &TyParamBound) -> TyParamBound {
245 noop_fold_ty_param_bound(tpb, self)
248 fn fold_mt(&mut self, mt: &MutTy) -> MutTy {
249 noop_fold_mt(mt, self)
252 fn fold_field(&mut self, field: Field) -> Field {
253 noop_fold_field(field, self)
256 fn fold_where_clause(&mut self, where_clause: &WhereClause)
258 noop_fold_where_clause(where_clause, self)
261 fn fold_where_predicate(&mut self, where_predicate: &WherePredicate)
263 noop_fold_where_predicate(where_predicate, self)
268 fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
269 es: &[Gc<Expr>]) -> Vec<Gc<Expr>> {
270 es.iter().map(|x| f(*x)).collect()
273 fn new_id(&mut self, i: NodeId) -> NodeId {
277 fn new_span(&mut self, sp: Span) -> Span {
282 pub fn noop_fold_meta_items<T: Folder>(meta_items: &[Gc<MetaItem>], fld: &mut T)
283 -> Vec<Gc<MetaItem>> {
284 meta_items.iter().map(|x| box (GC) fld.fold_meta_item(&**x)).collect()
287 pub fn noop_fold_view_path<T: Folder>(view_path: Gc<ViewPath>, fld: &mut T) -> Gc<ViewPath> {
288 let inner_view_path = match view_path.node {
289 ViewPathSimple(ref ident, ref path, node_id) => {
290 let id = fld.new_id(node_id);
291 ViewPathSimple(ident.clone(),
295 ViewPathGlob(ref path, node_id) => {
296 let id = fld.new_id(node_id);
297 ViewPathGlob(fld.fold_path(path), id)
299 ViewPathList(ref path, ref path_list_idents, node_id) => {
300 let id = fld.new_id(node_id);
301 ViewPathList(fld.fold_path(path),
302 path_list_idents.iter().map(|path_list_ident| {
304 node: match path_list_ident.node {
305 PathListIdent { id, name } =>
310 PathListMod { id } =>
311 PathListMod { id: fld.new_id(id) }
313 span: fld.new_span(path_list_ident.span)
320 node: inner_view_path,
321 span: fld.new_span(view_path.span),
325 pub fn noop_fold_arm<T: Folder>(a: &Arm, fld: &mut T) -> Arm {
327 attrs: a.attrs.iter().map(|x| fld.fold_attribute(*x)).collect(),
328 pats: a.pats.iter().map(|x| fld.fold_pat(*x)).collect(),
329 guard: a.guard.map(|x| fld.fold_expr(x)),
330 body: fld.fold_expr(a.body),
334 pub fn noop_fold_decl<T: Folder>(d: Gc<Decl>, fld: &mut T) -> SmallVector<Gc<Decl>> {
335 let node = match d.node {
336 DeclLocal(ref l) => SmallVector::one(DeclLocal(fld.fold_local(*l))),
338 fld.fold_item(it).move_iter().map(|i| DeclItem(i)).collect()
342 node.move_iter().map(|node| {
345 span: fld.new_span(d.span),
350 pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
351 let id = fld.new_id(t.id);
352 let node = match t.node {
353 TyNil | TyBot | TyInfer => t.node.clone(),
354 TyBox(ty) => TyBox(fld.fold_ty(ty)),
355 TyUniq(ty) => TyUniq(fld.fold_ty(ty)),
356 TyVec(ty) => TyVec(fld.fold_ty(ty)),
357 TyPtr(ref mt) => TyPtr(fld.fold_mt(mt)),
358 TyRptr(ref region, ref mt) => {
359 TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
361 TyClosure(ref f) => {
362 TyClosure(box(GC) ClosureTy {
363 fn_style: f.fn_style,
364 onceness: f.onceness,
365 bounds: fld.fold_bounds(&f.bounds),
366 decl: fld.fold_fn_decl(&*f.decl),
367 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
371 TyProc(box(GC) ClosureTy {
372 fn_style: f.fn_style,
373 onceness: f.onceness,
374 bounds: fld.fold_bounds(&f.bounds),
375 decl: fld.fold_fn_decl(&*f.decl),
376 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
380 TyBareFn(box(GC) BareFnTy {
381 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
382 fn_style: f.fn_style,
384 decl: fld.fold_fn_decl(&*f.decl)
387 TyUnboxedFn(ref f) => {
388 TyUnboxedFn(box(GC) UnboxedFnTy {
389 decl: fld.fold_fn_decl(&*f.decl),
393 TyTup(ref tys) => TyTup(tys.iter().map(|&ty| fld.fold_ty(ty)).collect()),
394 TyParen(ref ty) => TyParen(fld.fold_ty(*ty)),
395 TyPath(ref path, ref bounds, id) => {
396 let id = fld.new_id(id);
397 TyPath(fld.fold_path(path),
398 fld.fold_opt_bounds(bounds),
401 TyFixedLengthVec(ty, e) => {
402 TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
404 TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)),
408 span: fld.new_span(t.span),
413 pub fn noop_fold_foreign_mod<T: Folder>(nm: &ForeignMod, fld: &mut T) -> ForeignMod {
416 view_items: nm.view_items
418 .map(|x| fld.fold_view_item(x))
422 .map(|x| fld.fold_foreign_item(*x))
427 pub fn noop_fold_variant<T: Folder>(v: &Variant, fld: &mut T) -> P<Variant> {
428 let id = fld.new_id(v.node.id);
431 TupleVariantKind(ref variant_args) => {
432 kind = TupleVariantKind(variant_args.iter().map(|x|
433 fld.fold_variant_arg(x)).collect())
435 StructVariantKind(ref struct_def) => {
436 kind = StructVariantKind(box(GC) ast::StructDef {
437 fields: struct_def.fields.iter()
438 .map(|f| fld.fold_struct_field(f)).collect(),
439 ctor_id: struct_def.ctor_id.map(|c| fld.new_id(c)),
440 super_struct: match struct_def.super_struct {
441 Some(t) => Some(fld.fold_ty(t)),
444 is_virtual: struct_def.is_virtual,
449 let attrs = v.node.attrs.iter().map(|x| fld.fold_attribute(*x)).collect();
451 let de = match v.node.disr_expr {
452 Some(e) => Some(fld.fold_expr(e)),
455 let node = ast::Variant_ {
465 span: fld.new_span(v.span),
469 pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident {
473 pub fn noop_fold_uint<T: Folder>(i: uint, _: &mut T) -> uint {
477 pub fn noop_fold_path<T: Folder>(p: &Path, fld: &mut T) -> Path {
479 span: fld.new_span(p.span),
481 segments: p.segments.iter().map(|segment| ast::PathSegment {
482 identifier: fld.fold_ident(segment.identifier),
483 lifetimes: segment.lifetimes.iter().map(|l| fld.fold_lifetime(l)).collect(),
484 types: segment.types.iter().map(|&typ| fld.fold_ty(typ)).collect(),
489 pub fn noop_fold_local<T: Folder>(l: Gc<Local>, fld: &mut T) -> Gc<Local> {
490 let id = fld.new_id(l.id); // Needs to be first, for ast_map.
493 ty: fld.fold_ty(l.ty),
494 pat: fld.fold_pat(l.pat),
495 init: l.init.map(|e| fld.fold_expr(e)),
496 span: fld.new_span(l.span),
501 pub fn noop_fold_attribute<T: Folder>(at: Attribute, fld: &mut T) -> Attribute {
503 span: fld.new_span(at.span),
504 node: ast::Attribute_ {
506 style: at.node.style,
507 value: box (GC) fld.fold_meta_item(&*at.node.value),
508 is_sugared_doc: at.node.is_sugared_doc
513 pub fn noop_fold_explicit_self_underscore<T: Folder>(es: &ExplicitSelf_, fld: &mut T)
516 SelfStatic | SelfValue(_) => *es,
517 SelfRegion(ref lifetime, m, id) => {
518 SelfRegion(fld.fold_opt_lifetime(lifetime), m, id)
520 SelfExplicit(ref typ, id) => SelfExplicit(fld.fold_ty(*typ), id),
524 pub fn noop_fold_explicit_self<T: Folder>(es: &ExplicitSelf, fld: &mut T) -> ExplicitSelf {
526 span: fld.new_span(es.span),
527 node: fld.fold_explicit_self_underscore(&es.node)
532 pub fn noop_fold_mac<T: Folder>(macro: &Mac, fld: &mut T) -> Mac {
534 node: match macro.node {
535 MacInvocTT(ref p, ref tts, ctxt) => {
536 MacInvocTT(fld.fold_path(p),
537 fld.fold_tts(tts.as_slice()),
541 span: fld.new_span(macro.span)
545 pub fn noop_fold_meta_item<T: Folder>(mi: &MetaItem, fld: &mut T) -> MetaItem {
549 MetaWord(ref id) => MetaWord((*id).clone()),
550 MetaList(ref id, ref mis) => {
551 MetaList((*id).clone(),
553 .map(|e| box (GC) fld.fold_meta_item(&**e)).collect())
555 MetaNameValue(ref id, ref s) => {
556 MetaNameValue((*id).clone(), (*s).clone())
559 span: fld.new_span(mi.span) }
562 pub fn noop_fold_arg<T: Folder>(a: &Arg, fld: &mut T) -> Arg {
563 let id = fld.new_id(a.id); // Needs to be first, for ast_map.
566 ty: fld.fold_ty(a.ty),
567 pat: fld.fold_pat(a.pat),
571 pub fn noop_fold_tt<T: Folder>(tt: &TokenTree, fld: &mut T) -> TokenTree {
573 TTTok(span, ref tok) =>
574 TTTok(span, fld.fold_token(tok)),
575 TTDelim(ref tts) => TTDelim(Rc::new(fld.fold_tts(tts.as_slice()))),
576 TTSeq(span, ref pattern, ref sep, is_optional) =>
578 Rc::new(fld.fold_tts(pattern.as_slice())),
579 sep.as_ref().map(|tok| fld.fold_token(tok)),
581 TTNonterminal(sp,ref ident) =>
582 TTNonterminal(sp,fld.fold_ident(*ident))
586 pub fn noop_fold_tts<T: Folder>(tts: &[TokenTree], fld: &mut T) -> Vec<TokenTree> {
587 tts.iter().map(|tt| fld.fold_tt(tt)).collect()
590 // apply ident folder if it's an ident, apply other folds to interpolated nodes
591 pub fn noop_fold_token<T: Folder>(t: &token::Token, fld: &mut T) -> token::Token {
593 token::IDENT(id, followed_by_colons) => {
594 token::IDENT(fld.fold_ident(id), followed_by_colons)
596 token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)),
597 token::INTERPOLATED(ref nt) => token::INTERPOLATED(fld.fold_interpolated(nt)),
602 /// apply folder to elements of interpolated nodes
604 // NB: this can occur only when applying a fold to partially expanded code, where
605 // parsed pieces have gotten implanted ito *other* macro invocations. This is relevant
606 // for macro hygiene, but possibly not elsewhere.
608 // One problem here occurs because the types for fold_item, fold_stmt, etc. allow the
609 // folder to return *multiple* items; this is a problem for the nodes here, because
610 // they insist on having exactly one piece. One solution would be to mangle the fold
611 // trait to include one-to-many and one-to-one versions of these entry points, but that
612 // would probably confuse a lot of people and help very few. Instead, I'm just going
613 // to put in dynamic checks. I think the performance impact of this will be pretty much
614 // nonexistent. The danger is that someone will apply a fold to a partially expanded
615 // node, and will be confused by the fact that their "fold_item" or "fold_stmt" isn't
616 // getting called on NtItem or NtStmt nodes. Hopefully they'll wind up reading this
617 // comment, and doing something appropriate.
619 // BTW, design choice: I considered just changing the type of, e.g., NtItem to contain
620 // multiple items, but decided against it when I looked at parse_item_or_view_item and
621 // tried to figure out what I would do with multiple items there....
622 pub fn noop_fold_interpolated<T: Folder>(nt : &token::Nonterminal, fld: &mut T)
623 -> token::Nonterminal {
625 token::NtItem(item) =>
626 token::NtItem(fld.fold_item(item)
627 // this is probably okay, because the only folds likely
628 // to peek inside interpolated nodes will be renamings/markings,
629 // which map single items to single items
630 .expect_one("expected fold to produce exactly one item")),
631 token::NtBlock(block) => token::NtBlock(fld.fold_block(block)),
632 token::NtStmt(stmt) =>
633 token::NtStmt(fld.fold_stmt(&*stmt)
634 // this is probably okay, because the only folds likely
635 // to peek inside interpolated nodes will be renamings/markings,
636 // which map single items to single items
637 .expect_one("expected fold to produce exactly one statement")),
638 token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)),
639 token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)),
640 token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)),
641 token::NtIdent(ref id, is_mod_name) =>
642 token::NtIdent(box fld.fold_ident(**id),is_mod_name),
643 token::NtMeta(meta_item) => token::NtMeta(box (GC) fld.fold_meta_item(&*meta_item)),
644 token::NtPath(ref path) => token::NtPath(box fld.fold_path(&**path)),
645 token::NtTT(tt) => token::NtTT(box (GC) fld.fold_tt(&*tt)),
646 // it looks to me like we can leave out the matchers: token::NtMatchers(matchers)
651 pub fn noop_fold_fn_decl<T: Folder>(decl: &FnDecl, fld: &mut T) -> P<FnDecl> {
653 inputs: decl.inputs.iter().map(|x| fld.fold_arg(x)).collect(), // bad copy
654 output: fld.fold_ty(decl.output),
656 variadic: decl.variadic
660 pub fn noop_fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
663 TraitTyParamBound(ref ty) => TraitTyParamBound(fld.fold_trait_ref(ty)),
664 RegionTyParamBound(ref lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
665 UnboxedFnTyParamBound(ref unboxed_function_type) => {
666 UnboxedFnTyParamBound(UnboxedFnTy {
667 decl: fld.fold_fn_decl(&*unboxed_function_type.decl),
668 kind: unboxed_function_type.kind,
674 pub fn noop_fold_ty_param<T: Folder>(tp: &TyParam, fld: &mut T) -> TyParam {
675 let id = fld.new_id(tp.id);
679 bounds: fld.fold_bounds(&tp.bounds),
680 unbound: tp.unbound.as_ref().map(|x| fld.fold_ty_param_bound(x)),
681 default: tp.default.map(|x| fld.fold_ty(x)),
686 pub fn noop_fold_ty_params<T: Folder>(tps: &[TyParam], fld: &mut T)
687 -> OwnedSlice<TyParam> {
688 tps.iter().map(|tp| fld.fold_ty_param(tp)).collect()
691 pub fn noop_fold_lifetime<T: Folder>(l: &Lifetime, fld: &mut T) -> Lifetime {
692 let id = fld.new_id(l.id);
695 span: fld.new_span(l.span),
700 pub fn noop_fold_lifetime_def<T: Folder>(l: &LifetimeDef, fld: &mut T)
704 lifetime: fld.fold_lifetime(&l.lifetime),
705 bounds: fld.fold_lifetimes(l.bounds.as_slice()),
709 pub fn noop_fold_lifetimes<T: Folder>(lts: &[Lifetime], fld: &mut T) -> Vec<Lifetime> {
710 lts.iter().map(|l| fld.fold_lifetime(l)).collect()
713 pub fn noop_fold_lifetime_defs<T: Folder>(lts: &[LifetimeDef], fld: &mut T) -> Vec<LifetimeDef> {
714 lts.iter().map(|l| fld.fold_lifetime_def(l)).collect()
717 pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: &Option<Lifetime>, fld: &mut T)
718 -> Option<Lifetime> {
719 o_lt.as_ref().map(|lt| fld.fold_lifetime(lt))
722 pub fn noop_fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
724 ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
725 lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice()),
726 where_clause: fld.fold_where_clause(&generics.where_clause),
730 pub fn noop_fold_where_clause<T: Folder>(
731 where_clause: &WhereClause,
735 id: fld.new_id(where_clause.id),
736 predicates: where_clause.predicates.iter().map(|predicate| {
737 fld.fold_where_predicate(predicate)
742 pub fn noop_fold_where_predicate<T: Folder>(
743 predicate: &WherePredicate,
747 id: fld.new_id(predicate.id),
748 span: fld.new_span(predicate.span),
749 ident: fld.fold_ident(predicate.ident),
750 bounds: predicate.bounds.map(|x| {
751 fld.fold_ty_param_bound(x)
756 pub fn noop_fold_struct_def<T: Folder>(struct_def: Gc<StructDef>,
757 fld: &mut T) -> Gc<StructDef> {
758 box(GC) ast::StructDef {
759 fields: struct_def.fields.iter().map(|f| fld.fold_struct_field(f)).collect(),
760 ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(cid)),
761 super_struct: match struct_def.super_struct {
762 Some(t) => Some(fld.fold_ty(t)),
765 is_virtual: struct_def.is_virtual,
769 pub fn noop_fold_trait_ref<T: Folder>(p: &TraitRef, fld: &mut T) -> TraitRef {
770 let id = fld.new_id(p.ref_id);
772 path: fld.fold_path(&p.path),
777 pub fn noop_fold_struct_field<T: Folder>(f: &StructField, fld: &mut T) -> StructField {
778 let id = fld.new_id(f.node.id);
780 node: ast::StructField_ {
783 ty: fld.fold_ty(f.node.ty),
784 attrs: f.node.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
786 span: fld.new_span(f.span),
790 pub fn noop_fold_field<T: Folder>(field: Field, folder: &mut T) -> Field {
792 ident: respan(field.ident.span, folder.fold_ident(field.ident.node)),
793 expr: folder.fold_expr(field.expr),
794 span: folder.new_span(field.span),
798 pub fn noop_fold_mt<T: Folder>(mt: &MutTy, folder: &mut T) -> MutTy {
800 ty: folder.fold_ty(mt.ty),
805 pub fn noop_fold_opt_bounds<T: Folder>(b: &Option<OwnedSlice<TyParamBound>>, folder: &mut T)
806 -> Option<OwnedSlice<TyParamBound>> {
807 b.as_ref().map(|bounds| folder.fold_bounds(bounds))
810 fn noop_fold_bounds<T: Folder>(bounds: &TyParamBounds, folder: &mut T)
812 bounds.map(|bound| folder.fold_ty_param_bound(bound))
815 pub fn noop_fold_variant_arg<T: Folder>(va: &VariantArg, folder: &mut T) -> VariantArg {
816 let id = folder.new_id(va.id);
818 ty: folder.fold_ty(va.ty),
823 pub fn noop_fold_view_item<T: Folder>(vi: &ViewItem, folder: &mut T)
825 let inner_view_item = match vi.node {
826 ViewItemExternCrate(ref ident, ref string, node_id) => {
827 ViewItemExternCrate(ident.clone(),
829 folder.new_id(node_id))
831 ViewItemUse(ref view_path) => {
832 ViewItemUse(folder.fold_view_path(*view_path))
836 node: inner_view_item,
837 attrs: vi.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
839 span: folder.new_span(vi.span),
843 pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
844 let id = folder.new_id(b.id); // Needs to be first, for ast_map.
845 let view_items = b.view_items.iter().map(|x| folder.fold_view_item(x)).collect();
846 let stmts = b.stmts.iter().flat_map(|s| folder.fold_stmt(&**s).move_iter()).collect();
849 view_items: view_items,
851 expr: b.expr.map(|x| folder.fold_expr(x)),
853 span: folder.new_span(b.span),
857 pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_ {
859 ItemStatic(t, m, e) => {
860 ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e))
862 ItemFn(decl, fn_style, abi, ref generics, body) => {
864 folder.fold_fn_decl(&*decl),
867 folder.fold_generics(generics),
868 folder.fold_block(body)
871 ItemMod(ref m) => ItemMod(folder.fold_mod(m)),
872 ItemForeignMod(ref nm) => ItemForeignMod(folder.fold_foreign_mod(nm)),
873 ItemTy(t, ref generics) => {
874 ItemTy(folder.fold_ty(t), folder.fold_generics(generics))
876 ItemEnum(ref enum_definition, ref generics) => {
879 variants: enum_definition.variants.iter().map(|&x| {
880 folder.fold_variant(&*x)
883 folder.fold_generics(generics))
885 ItemStruct(ref struct_def, ref generics) => {
886 let struct_def = folder.fold_struct_def(*struct_def);
887 ItemStruct(struct_def, folder.fold_generics(generics))
889 ItemImpl(ref generics, ref ifce, ty, ref impl_items) => {
890 ItemImpl(folder.fold_generics(generics),
891 ifce.as_ref().map(|p| folder.fold_trait_ref(p)),
894 .flat_map(|impl_item| {
896 MethodImplItem(x) => {
897 folder.fold_method(x)
899 .map(|x| MethodImplItem(x))
905 ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
906 let bounds = folder.fold_bounds(bounds);
907 let methods = methods.iter().flat_map(|method| {
908 let r = match *method {
909 RequiredMethod(ref m) => {
910 SmallVector::one(RequiredMethod(
911 folder.fold_type_method(m))).move_iter()
913 ProvidedMethod(method) => {
914 // the awkward collect/iter idiom here is because
915 // even though an iter and a map satisfy the same trait bound,
916 // they're not actually the same type, so the method arms
918 let methods : SmallVector<ast::TraitItem> =
919 folder.fold_method(method).move_iter()
920 .map(|m| ProvidedMethod(m)).collect();
926 ItemTrait(folder.fold_generics(generics),
931 ItemMac(ref m) => ItemMac(folder.fold_mac(m)),
935 pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMethod {
936 let id = fld.new_id(m.id); // Needs to be first, for ast_map.
939 ident: fld.fold_ident(m.ident),
940 attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
941 fn_style: m.fn_style,
943 decl: fld.fold_fn_decl(&*m.decl),
944 generics: fld.fold_generics(&m.generics),
945 explicit_self: fld.fold_explicit_self(&m.explicit_self),
946 span: fld.new_span(m.span),
951 pub fn noop_fold_mod<T: Folder>(m: &Mod, folder: &mut T) -> Mod {
953 inner: folder.new_span(m.inner),
954 view_items: m.view_items
956 .map(|x| folder.fold_view_item(x)).collect(),
957 items: m.items.iter().flat_map(|x| folder.fold_item(*x).move_iter()).collect(),
961 pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
963 module: folder.fold_mod(&c.module),
964 attrs: c.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
965 config: c.config.iter().map(|x| box (GC) folder.fold_meta_item(&**x)).collect(),
966 span: folder.new_span(c.span),
967 exported_macros: c.exported_macros
971 // fold one item into possibly many items
972 pub fn noop_fold_item<T: Folder>(i: &Item,
973 folder: &mut T) -> SmallVector<Gc<Item>> {
974 SmallVector::one(box(GC) folder.fold_item_simple(i))
978 // fold one item into exactly one item
979 pub fn noop_fold_item_simple<T: Folder>(i: &Item, folder: &mut T) -> Item {
980 let id = folder.new_id(i.id); // Needs to be first, for ast_map.
981 let node = folder.fold_item_underscore(&i.node);
982 let ident = match node {
983 // The node may have changed, recompute the "pretty" impl name.
984 ItemImpl(_, ref maybe_trait, ty, _) => {
985 ast_util::impl_pretty_name(maybe_trait, &*ty)
992 ident: folder.fold_ident(ident),
993 attrs: i.attrs.iter().map(|e| folder.fold_attribute(*e)).collect(),
996 span: folder.new_span(i.span)
1000 pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,
1001 folder: &mut T) -> Gc<ForeignItem> {
1002 let id = folder.new_id(ni.id); // Needs to be first, for ast_map.
1003 box(GC) ForeignItem {
1005 ident: folder.fold_ident(ni.ident),
1006 attrs: ni.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
1007 node: match ni.node {
1008 ForeignItemFn(ref fdec, ref generics) => {
1009 ForeignItemFn(P(FnDecl {
1010 inputs: fdec.inputs.iter().map(|a| folder.fold_arg(a)).collect(),
1011 output: folder.fold_ty(fdec.output),
1013 variadic: fdec.variadic
1014 }), folder.fold_generics(generics))
1016 ForeignItemStatic(t, m) => {
1017 ForeignItemStatic(folder.fold_ty(t), m)
1020 span: folder.new_span(ni.span),
1025 // Default fold over a method.
1026 // Invariant: produces exactly one method.
1027 pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> SmallVector<Gc<Method>> {
1028 let id = folder.new_id(m.id); // Needs to be first, for ast_map.
1029 SmallVector::one(box(GC) Method {
1030 attrs: m.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
1032 span: folder.new_span(m.span),
1033 node: match m.node {
1042 MethDecl(folder.fold_ident(ident),
1043 folder.fold_generics(generics),
1045 folder.fold_explicit_self(explicit_self),
1047 folder.fold_fn_decl(&*decl),
1048 folder.fold_block(body),
1051 MethMac(ref mac) => MethMac(folder.fold_mac(mac)),
1056 pub fn noop_fold_pat<T: Folder>(p: Gc<Pat>, folder: &mut T) -> Gc<Pat> {
1057 let id = folder.new_id(p.id);
1058 let node = match p.node {
1059 PatWild(k) => PatWild(k),
1060 PatIdent(binding_mode, ref pth1, ref sub) => {
1061 PatIdent(binding_mode,
1062 Spanned{span: folder.new_span(pth1.span),
1063 node: folder.fold_ident(pth1.node)},
1064 sub.map(|x| folder.fold_pat(x)))
1066 PatLit(e) => PatLit(folder.fold_expr(e)),
1067 PatEnum(ref pth, ref pats) => {
1068 PatEnum(folder.fold_path(pth),
1069 pats.as_ref().map(|pats| pats.iter().map(|x| folder.fold_pat(*x)).collect()))
1071 PatStruct(ref pth, ref fields, etc) => {
1072 let pth_ = folder.fold_path(pth);
1073 let fs = fields.iter().map(|f| {
1076 pat: folder.fold_pat(f.pat)
1079 PatStruct(pth_, fs, etc)
1081 PatTup(ref elts) => PatTup(elts.iter().map(|x| folder.fold_pat(*x)).collect()),
1082 PatBox(inner) => PatBox(folder.fold_pat(inner)),
1083 PatRegion(inner) => PatRegion(folder.fold_pat(inner)),
1084 PatRange(e1, e2) => {
1085 PatRange(folder.fold_expr(e1), folder.fold_expr(e2))
1087 PatVec(ref before, ref slice, ref after) => {
1088 PatVec(before.iter().map(|x| folder.fold_pat(*x)).collect(),
1089 slice.map(|x| folder.fold_pat(x)),
1090 after.iter().map(|x| folder.fold_pat(*x)).collect())
1092 PatMac(ref mac) => PatMac(folder.fold_mac(mac)),
1097 span: folder.new_span(p.span),
1102 pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
1103 let id = folder.new_id(e.id);
1104 let node = match e.node {
1106 ExprBox(folder.fold_expr(p), folder.fold_expr(e))
1108 ExprVec(ref exprs) => {
1109 ExprVec(exprs.iter().map(|&x| folder.fold_expr(x)).collect())
1111 ExprRepeat(expr, count) => {
1112 ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count))
1114 ExprTup(ref elts) => ExprTup(elts.iter().map(|x| folder.fold_expr(*x)).collect()),
1115 ExprCall(f, ref args) => {
1116 ExprCall(folder.fold_expr(f),
1117 args.iter().map(|&x| folder.fold_expr(x)).collect())
1119 ExprMethodCall(i, ref tps, ref args) => {
1121 respan(i.span, folder.fold_ident(i.node)),
1122 tps.iter().map(|&x| folder.fold_ty(x)).collect(),
1123 args.iter().map(|&x| folder.fold_expr(x)).collect())
1125 ExprBinary(binop, lhs, rhs) => {
1127 folder.fold_expr(lhs),
1128 folder.fold_expr(rhs))
1130 ExprUnary(binop, ohs) => {
1131 ExprUnary(binop, folder.fold_expr(ohs))
1133 ExprLit(_) => e.node.clone(),
1134 ExprCast(expr, ty) => {
1135 ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
1137 ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
1138 ExprIf(cond, tr, fl) => {
1139 ExprIf(folder.fold_expr(cond),
1140 folder.fold_block(tr),
1141 fl.map(|x| folder.fold_expr(x)))
1143 ExprWhile(cond, body, opt_ident) => {
1144 ExprWhile(folder.fold_expr(cond),
1145 folder.fold_block(body),
1146 opt_ident.map(|i| folder.fold_ident(i)))
1148 ExprForLoop(pat, iter, body, ref opt_ident) => {
1149 ExprForLoop(folder.fold_pat(pat),
1150 folder.fold_expr(iter),
1151 folder.fold_block(body),
1152 opt_ident.map(|i| folder.fold_ident(i)))
1154 ExprLoop(body, opt_ident) => {
1155 ExprLoop(folder.fold_block(body),
1156 opt_ident.map(|i| folder.fold_ident(i)))
1158 ExprMatch(expr, ref arms) => {
1159 ExprMatch(folder.fold_expr(expr),
1160 arms.iter().map(|x| folder.fold_arm(x)).collect())
1162 ExprFnBlock(capture_clause, ref decl, ref body) => {
1163 ExprFnBlock(capture_clause,
1164 folder.fold_fn_decl(&**decl),
1165 folder.fold_block(body.clone()))
1167 ExprProc(ref decl, ref body) => {
1168 ExprProc(folder.fold_fn_decl(&**decl),
1169 folder.fold_block(body.clone()))
1171 ExprUnboxedFn(capture_clause, kind, ref decl, ref body) => {
1172 ExprUnboxedFn(capture_clause,
1174 folder.fold_fn_decl(&**decl),
1175 folder.fold_block(*body))
1177 ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)),
1178 ExprAssign(el, er) => {
1179 ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
1181 ExprAssignOp(op, el, er) => {
1183 folder.fold_expr(el),
1184 folder.fold_expr(er))
1186 ExprField(el, id, ref tys) => {
1187 ExprField(folder.fold_expr(el),
1188 respan(id.span, folder.fold_ident(id.node)),
1189 tys.iter().map(|&x| folder.fold_ty(x)).collect())
1191 ExprTupField(el, id, ref tys) => {
1192 ExprTupField(folder.fold_expr(el),
1193 respan(id.span, folder.fold_uint(id.node)),
1194 tys.iter().map(|&x| folder.fold_ty(x)).collect())
1196 ExprIndex(el, er) => {
1197 ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
1199 ExprPath(ref pth) => ExprPath(folder.fold_path(pth)),
1200 ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
1201 ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
1203 ExprRet(e.map(|x| folder.fold_expr(x)))
1205 ExprInlineAsm(ref a) => {
1206 ExprInlineAsm(InlineAsm {
1207 inputs: a.inputs.iter().map(|&(ref c, input)| {
1208 ((*c).clone(), folder.fold_expr(input))
1210 outputs: a.outputs.iter().map(|&(ref c, out, is_rw)| {
1211 ((*c).clone(), folder.fold_expr(out), is_rw)
1216 ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)),
1217 ExprStruct(ref path, ref fields, maybe_expr) => {
1218 ExprStruct(folder.fold_path(path),
1219 fields.iter().map(|x| folder.fold_field(*x)).collect(),
1220 maybe_expr.map(|x| folder.fold_expr(x)))
1222 ExprParen(ex) => ExprParen(folder.fold_expr(ex))
1228 span: folder.new_span(e.span),
1232 pub fn noop_fold_stmt<T: Folder>(s: &Stmt,
1233 folder: &mut T) -> SmallVector<Gc<Stmt>> {
1234 let nodes = match s.node {
1235 StmtDecl(d, id) => {
1236 let id = folder.new_id(id);
1237 folder.fold_decl(d).move_iter()
1238 .map(|d| StmtDecl(d, id))
1241 StmtExpr(e, id) => {
1242 let id = folder.new_id(id);
1243 SmallVector::one(StmtExpr(folder.fold_expr(e), id))
1245 StmtSemi(e, id) => {
1246 let id = folder.new_id(id);
1247 SmallVector::one(StmtSemi(folder.fold_expr(e), id))
1249 StmtMac(ref mac, semi) => SmallVector::one(StmtMac(folder.fold_mac(mac), semi))
1252 nodes.move_iter().map(|node| box(GC) Spanned {
1254 span: folder.new_span(s.span),
1262 use util::parser_testing::{string_to_crate, matches_codepattern};
1268 // this version doesn't care about getting comments or docstrings in.
1269 fn fake_print_crate(s: &mut pprust::State,
1270 krate: &ast::Crate) -> io::IoResult<()> {
1271 s.print_mod(&krate.module, krate.attrs.as_slice())
1274 // change every identifier to "zz"
1275 struct ToZzIdentFolder;
1277 impl Folder for ToZzIdentFolder {
1278 fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
1279 token::str_to_ident("zz")
1281 fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
1282 fold::noop_fold_mac(macro, self)
1286 // maybe add to expand.rs...
1287 macro_rules! assert_pred (
1288 ($pred:expr, $predname:expr, $a:expr , $b:expr) => (
1290 let pred_val = $pred;
1293 if !(pred_val(a_val.as_slice(),b_val.as_slice())) {
1294 fail!("expected args satisfying {}, got {:?} and {:?}",
1295 $predname, a_val, b_val);
1301 // make sure idents get transformed everywhere
1302 #[test] fn ident_transformation () {
1303 let mut zz_fold = ToZzIdentFolder;
1304 let ast = string_to_crate(
1305 "#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string());
1306 let folded_crate = zz_fold.fold_crate(ast);
1308 matches_codepattern,
1309 "matches_codepattern",
1310 pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
1311 "#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string());
1314 // even inside macro defs....
1315 #[test] fn ident_transformation_in_defs () {
1316 let mut zz_fold = ToZzIdentFolder;
1317 let ast = string_to_crate(
1318 "macro_rules! a {(b $c:expr $(d $e:token)f+ => \
1319 (g $(d $d $e)+))} ".to_string());
1320 let folded_crate = zz_fold.fold_crate(ast);
1322 matches_codepattern,
1323 "matches_codepattern",
1324 pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
1325 "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))".to_string());