8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use core:: prelude:: * ;
12
-
13
- use ast;
14
- use ast:: * ;
11
+ use ast:: { meta_item, item, expr} ;
12
+ use codemap:: span;
15
13
use ext:: base:: ext_ctxt;
16
14
use ext:: build;
17
- use ext:: deriving:: * ;
18
- use codemap:: { span, spanned} ;
19
- use ast_util;
20
- use opt_vec;
15
+ use ext:: deriving:: generic:: * ;
16
+ use core:: option:: { None , Some } ;
21
17
22
- use core:: uint;
23
18
24
19
pub fn expand_deriving_clone( cx : @ext_ctxt ,
25
20
span : span ,
26
- _ : @meta_item ,
21
+ mitem : @meta_item ,
27
22
in_items: ~[ @item] )
28
23
-> ~[ @item] {
29
- expand_deriving ( cx ,
30
- span ,
31
- in_items ,
32
- expand_deriving_clone_struct_def ,
33
- expand_deriving_clone_enum_def )
24
+ let trait_def = TraitDef {
25
+ path: ~[ ~"core", ~"clone", ~"Clone "] ,
26
+ additional_bounds : ~[ ] ,
27
+ methods : ~[
28
+ MethodDef {
29
+ name : ~"clone",
30
+ nargs : 0 ,
31
+ output_type : None , // return Self
32
+ combine_substructure : cs_clone
33
+ }
34
+ ]
35
+ } ;
36
+
37
+ expand_deriving_generic ( cx, span,
38
+ mitem, in_items,
39
+ & trait_def)
34
40
}
35
41
36
42
pub fn expand_deriving_obsolete ( cx: @ext_ctxt,
@@ -42,252 +48,52 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt,
42
48
in_items
43
49
}
44
50
45
- fn create_derived_clone_impl ( cx : @ext_ctxt ,
46
- span : span ,
47
- type_ident : ident ,
48
- generics : & Generics ,
49
- method : @method )
50
- -> @item {
51
- let methods = [ method ] ;
52
- let trait_path = ~[
53
- cx. ident_of ( ~"core") ,
54
- cx. ident_of ( ~"clone") ,
55
- cx. ident_of ( ~"Clone ") ,
56
- ] ;
57
- let trait_path = build:: mk_raw_path_global ( span, trait_path) ;
58
- create_derived_impl ( cx, span, type_ident, generics, methods, trait_path,
59
- opt_vec:: Empty , opt_vec:: Empty )
60
- }
61
- // Creates a method from the given expression conforming to the signature of
62
- // the `clone` method.
63
- fn create_clone_method ( cx: @ext_ctxt,
64
- span: span,
65
- +type_ident: ast:: ident,
66
- generics: & Generics ,
67
- expr: @ast:: expr)
68
- -> @method {
69
- // Create the type parameters of the return value.
70
- let mut output_ty_params = ~[ ] ;
71
- for generics. ty_params . each |ty_param| {
72
- let path = build:: mk_ty_path ( cx, span, ~[ ty_param. ident ] ) ;
73
- output_ty_params. push ( path) ;
74
- }
75
-
76
- // Create the type of the return value.
77
- let output_type_path = build:: mk_raw_path_ ( span,
78
- ~[ type_ident ] ,
79
- output_ty_params) ;
80
- let output_type = ast:: ty_path ( output_type_path, cx. next_id ( ) ) ;
81
- let output_type = @ast:: Ty {
82
- id : cx. next_id ( ) ,
83
- node : output_type,
84
- span : span
85
- } ;
86
-
87
- // Create the function declaration.
88
- let fn_decl = build:: mk_fn_decl ( ~[ ] , output_type) ;
89
-
90
- // Create the body block.
91
- let body_block = build:: mk_simple_block ( cx, span, expr) ;
92
-
93
- // Create the self type and method identifier.
94
- let self_ty = spanned { node : sty_region ( None , m_imm) , span : span } ;
95
- let method_ident = cx. ident_of ( ~"clone") ;
96
-
97
- // Create the method.
98
- @ast:: method {
99
- ident : method_ident,
100
- attrs : ~[ ] ,
101
- generics : ast_util:: empty_generics ( ) ,
102
- self_ty : self_ty,
103
- purity : impure_fn,
104
- decl : fn_decl,
105
- body : body_block,
106
- id : cx. next_id ( ) ,
107
- span : span,
108
- self_id : cx. next_id ( ) ,
109
- vis : public,
51
+ fn cs_clone ( cx: @ext_ctxt, span: span,
52
+ substr: & Substructure ) -> @expr {
53
+ let clone_ident = substr. method_ident ;
54
+ let ctor_ident;
55
+ let all_fields;
56
+ let subcall = |field|
57
+ build:: mk_method_call ( cx, span, field, clone_ident, ~[ ] ) ;
58
+
59
+ match * substr. fields {
60
+ Struct ( af) => {
61
+ ctor_ident = ~[ substr. type_ident ] ;
62
+ all_fields = af;
63
+ }
64
+ EnumMatching ( _, variant, af) => {
65
+ ctor_ident = ~[ variant. node . name ] ;
66
+ all_fields = af;
67
+ } ,
68
+ EnumNonMatching ( * ) => cx. bug ( "Non-matching enum variants in `deriving(Clone)`" )
110
69
}
111
- }
112
-
113
- fn call_substructure_clone_method( cx: @ext_ctxt,
114
- span: span,
115
- self_field: @expr)
116
- -> @expr {
117
- // Call the substructure method.
118
- let clone_ident = cx. ident_of ( ~"clone") ;
119
- build:: mk_method_call ( cx, span,
120
- self_field, clone_ident,
121
- ~[ ] )
122
- }
123
-
124
- fn expand_deriving_clone_struct_def ( cx: @ext_ctxt,
125
- span: span,
126
- struct_def: & struct_def,
127
- type_ident: ident,
128
- generics: & Generics )
129
- -> @item {
130
- // Create the method.
131
- let method = if !is_struct_tuple ( struct_def) {
132
- expand_deriving_clone_struct_method ( cx,
133
- span,
134
- struct_def,
135
- type_ident,
136
- generics)
137
- } else {
138
- expand_deriving_clone_tuple_struct_method ( cx,
139
- span,
140
- struct_def,
141
- type_ident,
142
- generics)
143
- } ;
144
-
145
- // Create the implementation.
146
- create_derived_clone_impl ( cx, span, type_ident, generics, method)
147
- }
148
-
149
- fn expand_deriving_clone_enum_def( cx: @ext_ctxt,
150
- span: span,
151
- enum_definition: & enum_def,
152
- type_ident: ident,
153
- generics: & Generics )
154
- -> @item {
155
- // Create the method.
156
- let method = expand_deriving_clone_enum_method ( cx,
157
- span,
158
- enum_definition,
159
- type_ident,
160
- generics) ;
161
-
162
- // Create the implementation.
163
- create_derived_clone_impl ( cx, span, type_ident, generics, method)
164
- }
165
-
166
- fn expand_deriving_clone_struct_method( cx: @ext_ctxt,
167
- span: span,
168
- struct_def: & struct_def,
169
- type_ident: ident,
170
- generics: & Generics )
171
- -> @method {
172
- let self_ident = cx. ident_of ( ~"self ") ;
173
-
174
- // Create the new fields.
175
- let mut fields = ~[ ] ;
176
- for struct_def. fields . each |struct_field| {
177
- match struct_field. node . kind {
178
- named_field( ident, _, _) => {
179
- // Create the accessor for this field.
180
- let self_field = build:: mk_access ( cx,
181
- span,
182
- ~[ self_ident ] ,
183
- ident) ;
184
70
185
- // Call the substructure method.
186
- let call = call_substructure_clone_method ( cx,
187
- span,
188
- self_field) ;
189
-
190
- let field = build:: Field { ident : ident, ex : call } ;
191
- fields. push ( field) ;
192
- }
193
- unnamed_field => {
194
- cx. span_bug ( span, ~"unnamed fields in `deriving ( Clone ) `") ;
71
+ match all_fields {
72
+ [ ( None , _, _) , .. _] => {
73
+ // enum-like
74
+ let subcalls = all_fields. map ( |& ( _, self_f, _) | subcall ( self_f) ) ;
75
+ build:: mk_call ( cx, span, ctor_ident, subcalls)
76
+ } ,
77
+ _ => {
78
+ // struct-like
79
+ let fields = do all_fields. map |& ( o_id, self_f, _) | {
80
+ let ident = match o_id {
81
+ Some ( i) => i,
82
+ None => cx. span_bug ( span,
83
+ ~"unnamed field in normal struct \
84
+ in `deriving ( Clone ) `")
85
+ } ;
86
+ build:: Field { ident : ident, ex : subcall ( self_f) }
87
+ } ;
88
+
89
+ if fields. is_empty ( ) {
90
+ // no fields, so construct like `None`
91
+ build:: mk_path ( cx, span, ctor_ident)
92
+ } else {
93
+ build:: mk_struct_e ( cx, span,
94
+ ctor_ident,
95
+ fields)
195
96
}
196
97
}
197
98
}
198
-
199
- // Create the struct literal.
200
- let struct_literal = build:: mk_struct_e ( cx,
201
- span,
202
- ~[ type_ident ] ,
203
- fields) ;
204
- create_clone_method ( cx, span, type_ident, generics, struct_literal)
205
- }
206
-
207
- fn expand_deriving_clone_tuple_struct_method( cx: @ext_ctxt,
208
- span: span,
209
- struct_def: & struct_def,
210
- type_ident: ident,
211
- generics: & Generics )
212
- -> @method {
213
- // Create the pattern for the match.
214
- let matching_path = build:: mk_raw_path ( span, ~[ type_ident ] ) ;
215
- let field_count = struct_def. fields . len ( ) ;
216
- let subpats = create_subpatterns ( cx, span, ~"__self", field_count) ;
217
- let pat = build:: mk_pat_enum ( cx, span, matching_path, subpats) ;
218
-
219
- // Create the new fields.
220
- let mut subcalls = ~[ ] ;
221
- for uint:: range( 0 , struct_def. fields . len ( ) ) |i| {
222
- // Create the expression for this field.
223
- let field_ident = cx. ident_of ( ~"__self_" + i. to_str ( ) ) ;
224
- let field = build:: mk_path ( cx, span, ~[ field_ident ] ) ;
225
-
226
- // Call the substructure method.
227
- let subcall = call_substructure_clone_method ( cx, span, field) ;
228
- subcalls. push ( subcall) ;
229
- }
230
-
231
- // Create the call to the struct constructor.
232
- let call = build:: mk_call ( cx, span, ~[ type_ident ] , subcalls) ;
233
-
234
- // Create the pattern body.
235
- let match_body_block = build:: mk_simple_block ( cx, span, call) ;
236
-
237
- // Create the arm.
238
- let arm = ast:: arm {
239
- pats : ~[ pat ] ,
240
- guard : None ,
241
- body : match_body_block
242
- } ;
243
-
244
- // Create the method body.
245
- let self_match_expr = expand_enum_or_struct_match ( cx, span, ~[ arm ] ) ;
246
-
247
- // Create the method.
248
- create_clone_method ( cx, span, type_ident, generics, self_match_expr)
249
- }
250
-
251
- fn expand_deriving_clone_enum_method( cx: @ext_ctxt,
252
- span: span,
253
- enum_definition: & enum_def,
254
- type_ident: ident,
255
- generics: & Generics )
256
- -> @method {
257
- // Create the arms of the match in the method body.
258
- let arms = do enum_definition. variants . map |variant| {
259
- // Create the matching pattern.
260
- let pat = create_enum_variant_pattern ( cx, span, variant, ~"__self") ;
261
-
262
- // Iterate over the variant arguments, creating the subcalls.
263
- let mut subcalls = ~[ ] ;
264
- for uint:: range( 0 , variant_arg_count( cx, span, variant) ) |j| {
265
- // Create the expression for this field.
266
- let field_ident = cx. ident_of ( ~"__self_" + j. to_str ( ) ) ;
267
- let field = build:: mk_path ( cx, span, ~[ field_ident ] ) ;
268
-
269
- // Call the substructure method.
270
- let subcall = call_substructure_clone_method ( cx, span, field) ;
271
- subcalls. push ( subcall) ;
272
- }
273
-
274
- // Create the call to the enum variant (if necessary).
275
- let call = if subcalls. len ( ) > 0 {
276
- build:: mk_call ( cx, span, ~[ variant. node . name ] , subcalls)
277
- } else {
278
- build:: mk_path ( cx, span, ~[ variant. node . name ] )
279
- } ;
280
-
281
- // Create the pattern body.
282
- let match_body_block = build:: mk_simple_block ( cx, span, call) ;
283
-
284
- // Create the arm.
285
- ast:: arm { pats : ~[ pat ] , guard : None , body : match_body_block }
286
- } ;
287
-
288
- // Create the method body.
289
- let self_match_expr = expand_enum_or_struct_match ( cx, span, arms) ;
290
-
291
- // Create the method.
292
- create_clone_method( cx, span, type_ident, generics, self_match_expr)
293
99
}
0 commit comments