]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/deriving/clone.rs
libsyntax: Mechanically change `~[T]` to `Vec<T>`
[rust.git] / src / libsyntax / ext / deriving / clone.rs
1 // Copyright 2012-2013 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::{MetaItem, Item, Expr};
12 use codemap::Span;
13 use ext::base::ExtCtxt;
14 use ext::build::AstBuilder;
15 use ext::deriving::generic::*;
16
17 pub fn expand_deriving_clone(cx: &mut ExtCtxt,
18                              span: Span,
19                              mitem: @MetaItem,
20                              item: @Item,
21                              push: |@Item|) {
22     let trait_def = TraitDef {
23         span: span,
24         attributes: Vec::new(),
25         path: Path::new(vec!("std", "clone", "Clone")),
26         additional_bounds: Vec::new(),
27         generics: LifetimeBounds::empty(),
28         methods: vec!(
29             MethodDef {
30                 name: "clone",
31                 generics: LifetimeBounds::empty(),
32                 explicit_self: borrowed_explicit_self(),
33                 args: Vec::new(),
34                 ret_ty: Self,
35                 inline: true,
36                 const_nonmatching: false,
37                 combine_substructure: |c, s, sub| cs_clone("Clone", c, s, sub)
38             }
39         )
40     };
41
42     trait_def.expand(cx, mitem, item, push)
43 }
44
45 pub fn expand_deriving_deep_clone(cx: &mut ExtCtxt,
46                                   span: Span,
47                                   mitem: @MetaItem,
48                                   item: @Item,
49                                   push: |@Item|) {
50     let trait_def = TraitDef {
51         span: span,
52         attributes: Vec::new(),
53         path: Path::new(vec!("std", "clone", "DeepClone")),
54         additional_bounds: Vec::new(),
55         generics: LifetimeBounds::empty(),
56         methods: vec!(
57             MethodDef {
58                 name: "deep_clone",
59                 generics: LifetimeBounds::empty(),
60                 explicit_self: borrowed_explicit_self(),
61                 args: Vec::new(),
62                 ret_ty: Self,
63                 inline: true,
64                 const_nonmatching: false,
65                 // cs_clone uses the ident passed to it, i.e. it will
66                 // call deep_clone (not clone) here.
67                 combine_substructure: |c, s, sub| cs_clone("DeepClone", c, s, sub)
68             }
69         )
70     };
71
72     trait_def.expand(cx, mitem, item, push)
73 }
74
75 fn cs_clone(
76     name: &str,
77     cx: &mut ExtCtxt, trait_span: Span,
78     substr: &Substructure) -> @Expr {
79     let clone_ident = substr.method_ident;
80     let ctor_ident;
81     let all_fields;
82     let subcall = |field: &FieldInfo|
83         cx.expr_method_call(field.span, field.self_, clone_ident, Vec::new());
84
85     match *substr.fields {
86         Struct(ref af) => {
87             ctor_ident = substr.type_ident;
88             all_fields = af;
89         }
90         EnumMatching(_, variant, ref af) => {
91             ctor_ident = variant.node.name;
92             all_fields = af;
93         },
94         EnumNonMatching(..) => cx.span_bug(trait_span,
95                                            format!("non-matching enum variants in `deriving({})`",
96                                                   name)),
97         StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span,
98                                                          format!("static method in `deriving({})`",
99                                                                  name))
100     }
101
102     if all_fields.len() >= 1 && all_fields[0].name.is_none() {
103         // enum-like
104         let subcalls = all_fields.map(subcall);
105         cx.expr_call_ident(trait_span, ctor_ident, subcalls)
106     } else {
107         // struct-like
108         let fields = all_fields.map(|field| {
109             let ident = match field.name {
110                 Some(i) => i,
111                 None => cx.span_bug(trait_span,
112                                     format!("unnamed field in normal struct in `deriving({})`",
113                                             name))
114             };
115             cx.field_imm(field.span, ident, subcall(field))
116         });
117
118         if fields.is_empty() {
119             // no fields, so construct like `None`
120             cx.expr_ident(trait_span, ctor_ident)
121         } else {
122             cx.expr_struct_ident(trait_span, ctor_ident, fields)
123         }
124     }
125 }