1
1
/// The compiler code necessary to implement the #[deriving_eq] and
2
2
/// #[deriving_ord] extensions.
3
3
4
- use ast:: { and, bind_by_value, binop, blk, default_blk, deref, enum_def, expr} ;
4
+ use ast:: { and, bind_by_ref, binop, blk, default_blk, deref, enum_def} ;
5
+ use ast:: { enum_variant_kind, expr} ;
5
6
use ast:: { expr_, expr_addr_of, expr_binary, expr_call, expr_field, expr_lit} ;
6
7
use ast:: { expr_match, expr_path, expr_unary, ident, infer, item, item_} ;
7
8
use ast:: { item_class, item_enum, item_impl, lit_bool, m_imm, meta_item} ;
8
9
use ast:: { method, named_field, or, pat, pat_ident, pat_wild, path, public} ;
9
- use ast:: { pure_fn, re_anon, return_val, struct_def, sty_region, ty_path} ;
10
- use ast:: { ty_rptr, unnamed_field} ;
10
+ use ast:: { pure_fn, re_anon, return_val, struct_def, struct_variant_kind} ;
11
+ use ast:: { sty_region, tuple_variant_kind, ty_path} ;
12
+ use ast:: { ty_rptr, unnamed_field, variant} ;
11
13
use base:: ext_ctxt;
12
14
use codemap:: span;
13
15
use parse:: token:: special_idents:: clownshoes_extensions;
@@ -174,6 +176,99 @@ fn create_derived_impl(cx: ext_ctxt,
174
176
return create_impl_item ( cx, span, move impl_item) ;
175
177
}
176
178
179
+ fn create_enum_variant_pattern ( cx : ext_ctxt ,
180
+ span : span ,
181
+ variant : & ast:: variant ,
182
+ prefix : ~str )
183
+ -> @ast:: pat {
184
+ let variant_ident = variant. node . name ;
185
+ match variant. node . kind {
186
+ tuple_variant_kind( ref variant_args) => {
187
+ if variant_args. len ( ) == 0 {
188
+ return build:: mk_pat_ident ( cx, span, variant_ident) ;
189
+ }
190
+
191
+ let subpats = dvec:: DVec ( ) ;
192
+ for variant_args. each |_variant_arg| {
193
+ // Create the subidentifier.
194
+ let index = subpats. len ( ) . to_str ( ) ;
195
+ let ident = cx. ident_of ( prefix + index) ;
196
+
197
+ // Create the subpattern.
198
+ let subpath = build:: mk_raw_path ( span, ~[ ident ] ) ;
199
+ let subpat = pat_ident ( bind_by_ref ( m_imm) , subpath, None ) ;
200
+ let subpat = build:: mk_pat ( cx, span, move subpat) ;
201
+ subpats. push ( subpat) ;
202
+ }
203
+
204
+ let matching_path = build:: mk_raw_path ( span, ~[ variant_ident ] ) ;
205
+ let subpats = dvec:: unwrap ( move subpats) ;
206
+ return build:: mk_pat_enum ( cx, span, matching_path, move subpats) ;
207
+ }
208
+ struct_variant_kind( * ) => {
209
+ cx. span_unimpl ( span, ~"struct variants for `deriving`") ;
210
+ }
211
+ enum_variant_kind( * ) => {
212
+ cx. span_unimpl ( span, ~"enum variants for `deriving`") ;
213
+ }
214
+ }
215
+ }
216
+
217
+ fn call_substructure_method ( cx : ext_ctxt ,
218
+ span : span ,
219
+ self_field : @expr,
220
+ other_field_ref : @expr,
221
+ method_ident : ident ,
222
+ junction : Junction ,
223
+ chain_expr : & mut Option <@expr>) {
224
+ // Call the substructure method.
225
+ let self_method = build:: mk_access_ ( cx, span, self_field, method_ident) ;
226
+ let self_call = build:: mk_call_ ( cx,
227
+ span,
228
+ self_method,
229
+ ~[ other_field_ref ] ) ;
230
+
231
+ // Connect to the outer expression if necessary.
232
+ * chain_expr = match * chain_expr {
233
+ None => Some ( self_call) ,
234
+ Some ( copy old_outer_expr) => {
235
+ let binop = junction. to_binop ( ) ;
236
+ let chain_expr = build:: mk_binary ( cx,
237
+ span,
238
+ binop,
239
+ old_outer_expr,
240
+ self_call) ;
241
+ Some ( chain_expr)
242
+ }
243
+ } ;
244
+ }
245
+
246
+ fn finish_chain_expr ( cx : ext_ctxt ,
247
+ span : span ,
248
+ chain_expr : Option <@expr>,
249
+ junction : Junction )
250
+ -> @expr {
251
+ match chain_expr {
252
+ None => {
253
+ match junction {
254
+ Conjunction => build:: mk_bool ( cx, span, true ) ,
255
+ Disjunction => build:: mk_bool ( cx, span, false ) ,
256
+ }
257
+ }
258
+ Some ( ref outer_expr) => * outer_expr,
259
+ }
260
+ }
261
+
262
+ fn variant_arg_count ( cx : ext_ctxt , span : span , variant : & variant ) -> uint {
263
+ match variant. node . kind {
264
+ tuple_variant_kind( args) => args. len ( ) ,
265
+ struct_variant_kind( struct_def) => struct_def. fields . len ( ) ,
266
+ enum_variant_kind( * ) => {
267
+ cx. span_bug ( span, ~"variant_arg_count: enum variants deprecated")
268
+ }
269
+ }
270
+ }
271
+
177
272
fn expand_deriving_struct_def ( cx : ext_ctxt ,
178
273
span : span ,
179
274
struct_def : & struct_def ,
@@ -209,8 +304,6 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
209
304
let self_ident = cx. ident_of ( ~"self ") ;
210
305
let other_ident = cx. ident_of ( ~"__other") ;
211
306
212
- let binop = junction. to_binop ( ) ;
213
-
214
307
// Create the body of the method.
215
308
let mut outer_expr = None ;
216
309
for struct_def. fields. each |struct_field| {
@@ -232,27 +325,13 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
232
325
ident) ;
233
326
234
327
// Call the substructure method.
235
- let self_method = build:: mk_access_ ( cx,
236
- span,
237
- self_field,
238
- method_ident) ;
239
- let self_call = build:: mk_call_ ( cx,
240
- span,
241
- self_method,
242
- ~[ other_field_ref ] ) ;
243
-
244
- // Connect to the outer expression if necessary.
245
- outer_expr = match outer_expr {
246
- None => Some ( self_call) ,
247
- Some ( old_outer_expr) => {
248
- let chain_expr = build:: mk_binary ( cx,
249
- span,
250
- binop,
251
- old_outer_expr,
252
- self_call) ;
253
- Some ( chain_expr)
254
- }
255
- } ;
328
+ call_substructure_method ( cx,
329
+ span,
330
+ self_field,
331
+ other_field_ref,
332
+ method_ident,
333
+ junction,
334
+ & mut outer_expr) ;
256
335
}
257
336
unnamed_field => {
258
337
cx. span_unimpl ( span, ~"unnamed fields with `deriving_eq`") ;
@@ -261,12 +340,7 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
261
340
}
262
341
263
342
// Create the method itself.
264
- let body;
265
- match outer_expr {
266
- None => cx. span_unimpl ( span, ~"empty structs with `deriving_eq`") ,
267
- Some ( outer_expr) => body = outer_expr,
268
- }
269
-
343
+ let body = finish_chain_expr ( cx, span, outer_expr, junction) ;
270
344
return create_method ( cx, span, method_ident, type_ident, body) ;
271
345
}
272
346
@@ -305,8 +379,6 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
305
379
let self_ident = cx. ident_of ( ~"self ") ;
306
380
let other_ident = cx. ident_of ( ~"__other") ;
307
381
308
- let _binop = junction. to_binop ( ) ;
309
-
310
382
let is_eq;
311
383
match junction {
312
384
Conjunction => is_eq = true ,
@@ -317,13 +389,40 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
317
389
let self_arms = dvec:: DVec ( ) ;
318
390
for enum_definition. variants. each |self_variant| {
319
391
let other_arms = dvec:: DVec ( ) ;
320
- let self_variant_ident = self_variant. node . name ;
321
392
322
393
// Create the matching pattern.
323
- let matching_pat = build:: mk_pat_ident ( cx, span, self_variant_ident) ;
394
+ let matching_pat = create_enum_variant_pattern ( cx,
395
+ span,
396
+ self_variant,
397
+ ~"__other") ;
324
398
325
399
// Create the matching pattern body.
326
- let matching_body_expr = build:: mk_bool ( cx, span, is_eq) ;
400
+ let mut matching_body_expr = None ;
401
+ for uint:: range( 0 , variant_arg_count( cx, span, self_variant) ) |i| {
402
+ // Create the expression for the other field.
403
+ let other_field_ident = cx. ident_of ( ~"__other" + i. to_str ( ) ) ;
404
+ let other_field = build:: mk_path ( cx,
405
+ span,
406
+ ~[ other_field_ident ] ) ;
407
+
408
+ // Create the expression for this field.
409
+ let self_field_ident = cx. ident_of ( ~"__self" + i. to_str ( ) ) ;
410
+ let self_field = build:: mk_path ( cx, span, ~[ self_field_ident ] ) ;
411
+
412
+ // Call the substructure method.
413
+ call_substructure_method ( cx,
414
+ span,
415
+ self_field,
416
+ other_field,
417
+ method_ident,
418
+ junction,
419
+ & mut matching_body_expr) ;
420
+ }
421
+
422
+ let matching_body_expr = finish_chain_expr ( cx,
423
+ span,
424
+ matching_body_expr,
425
+ junction) ;
327
426
let matching_body_block = build:: mk_simple_block ( cx,
328
427
span,
329
428
matching_body_expr) ;
@@ -358,7 +457,10 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
358
457
other_arms. push ( move nonmatching_arm) ;
359
458
360
459
// Create the self pattern.
361
- let self_pat = build:: mk_pat_ident ( cx, span, self_variant_ident) ;
460
+ let self_pat = create_enum_variant_pattern ( cx,
461
+ span,
462
+ self_variant,
463
+ ~"__self") ;
362
464
363
465
// Create the self pattern body.
364
466
let other_expr = build:: mk_path ( cx, span, ~[ other_ident ] ) ;
0 commit comments