@@ -169,7 +169,6 @@ use ast::{enum_def, expr, ident, Generics, struct_def};
169
169
170
170
use ext:: base:: ExtCtxt ;
171
171
use ext:: build:: AstBuilder ;
172
- use ext:: deriving:: * ;
173
172
use codemap:: { span, respan} ;
174
173
use opt_vec;
175
174
@@ -184,18 +183,28 @@ pub fn expand_deriving_generic(cx: @ExtCtxt,
184
183
_mitem : @ast:: meta_item ,
185
184
in_items : ~[ @ast:: item ] ,
186
185
trait_def : & TraitDef ) -> ~[ @ast:: item ] {
187
- let expand_enum: ExpandDerivingEnumDefFn =
188
- |cx, span, enum_def, type_ident, generics| {
189
- trait_def. expand_enum_def ( cx, span, enum_def, type_ident, generics)
190
- } ;
191
- let expand_struct: ExpandDerivingStructDefFn =
192
- |cx, span, struct_def, type_ident, generics| {
193
- trait_def. expand_struct_def ( cx, span, struct_def, type_ident, generics)
194
- } ;
195
-
196
- expand_deriving ( cx, span, in_items,
197
- expand_struct,
198
- expand_enum)
186
+ let mut result = ~[ ] ;
187
+ for in_items. each |item| {
188
+ result. push ( * item) ;
189
+ match item. node {
190
+ ast:: item_struct( struct_def, ref generics) => {
191
+ result. push ( trait_def. expand_struct_def ( cx,
192
+ span,
193
+ struct_def,
194
+ item. ident ,
195
+ generics) ) ;
196
+ }
197
+ ast:: item_enum( ref enum_definition, ref generics) => {
198
+ result. push ( trait_def. expand_enum_def ( cx,
199
+ span,
200
+ enum_definition,
201
+ item. ident ,
202
+ generics) ) ;
203
+ }
204
+ _ => ( )
205
+ }
206
+ }
207
+ result
199
208
}
200
209
201
210
pub struct TraitDef < ' self > {
@@ -301,23 +310,71 @@ pub type EnumNonMatchFunc<'self> =
301
310
302
311
303
312
impl<' self> TraitDef <' self> {
313
+ /**
314
+ *
315
+ * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
316
+ * 'z, A, ..., Z>`, creates an impl like:
317
+ *
318
+ * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
319
+ *
320
+ * where B1, B2, ... are the bounds given by `bounds_paths`.'
321
+ *
322
+ */
304
323
fn create_derived_impl ( & self , cx : @ExtCtxt , span : span ,
305
324
type_ident : ident , generics : & Generics ,
306
325
methods : ~[ @ast:: method ] ) -> @ast:: item {
307
326
let trait_path = self . path . to_path ( cx, span, type_ident, generics) ;
308
327
309
- let trait_generics = self . generics . to_generics ( cx, span, type_ident, generics) ;
328
+ let mut trait_generics = self . generics . to_generics ( cx, span, type_ident, generics) ;
329
+ // Copy the lifetimes
330
+ for generics. lifetimes. each |l| {
331
+ trait_generics. lifetimes . push ( copy * l)
332
+ } ;
333
+ // Create the type parameters.
334
+ for generics. ty_params. each |ty_param| {
335
+ // I don't think this can be moved out of the loop, since
336
+ // a TyParamBound requires an ast id
337
+ let mut bounds = opt_vec:: from (
338
+ // extra restrictions on the generics parameters to the type being derived upon
339
+ do self . additional_bounds . map |p| {
340
+ cx. typarambound ( p. to_path ( cx, span, type_ident, generics) )
341
+ } ) ;
342
+ // require the current trait
343
+ bounds. push ( cx. typarambound ( trait_path) ) ;
344
+
345
+ trait_generics. ty_params . push ( cx. typaram ( ty_param. ident , @bounds) ) ;
346
+ }
347
+
348
+ // Create the reference to the trait.
349
+ let trait_ref = cx. trait_ref ( trait_path) ;
310
350
311
- let additional_bounds = opt_vec :: from (
312
- do self . additional_bounds . map |p | {
313
- p . to_path ( cx , span, type_ident , generics )
314
- } ) ;
351
+ // Create the type parameters on the `self` path.
352
+ let self_ty_params = do generics . ty_params . map |ty_param | {
353
+ cx . ty_ident ( span, ty_param . ident )
354
+ } ;
315
355
316
- create_derived_impl ( cx, span,
317
- type_ident, generics,
318
- methods, trait_path,
319
- trait_generics,
320
- additional_bounds)
356
+ let self_lifetime = if generics. lifetimes . is_empty ( ) {
357
+ None
358
+ } else {
359
+ Some ( @* generics. lifetimes . get ( 0 ) )
360
+ } ;
361
+
362
+ // Create the type of `self`.
363
+ let self_type = cx. ty_path ( cx. path_all ( span, false , ~[ type_ident ] , self_lifetime,
364
+ opt_vec:: take_vec ( self_ty_params) ) ) ;
365
+
366
+ let doc_attr = cx. attribute (
367
+ span,
368
+ cx. meta_name_value ( span,
369
+ ~"doc", ast:: lit_str ( @~"Automatically derived. ") ) ) ;
370
+ cx. item (
371
+ span,
372
+ :: parse:: token:: special_idents:: clownshoes_extensions,
373
+ ~[ doc_attr] ,
374
+ ast:: item_impl ( trait_generics,
375
+ Some ( trait_ref) ,
376
+ self_type,
377
+ methods. map ( |x| * x) ) )
321
378
}
322
379
323
380
fn expand_struct_def ( & self , cx : @ExtCtxt ,
@@ -834,6 +891,124 @@ fn summarise_struct(cx: @ExtCtxt, span: span,
834
891
}
835
892
}
836
893
894
+ pub fn create_subpatterns ( cx : @ExtCtxt ,
895
+ span : span ,
896
+ field_paths : ~[ @ast:: Path ] ,
897
+ mutbl : ast:: mutability )
898
+ -> ~[ @ast:: pat ] {
899
+ do field_paths. map |& path| {
900
+ cx. pat ( span, ast:: pat_ident ( ast:: bind_by_ref ( mutbl) , path, None ) )
901
+ }
902
+ }
903
+
904
+ #[ deriving( Eq ) ] // dogfooding!
905
+ enum StructType {
906
+ Unknown , Record , Tuple
907
+ }
908
+
909
+ fn create_struct_pattern ( cx : @ExtCtxt ,
910
+ span : span ,
911
+ struct_ident : ident ,
912
+ struct_def : & struct_def ,
913
+ prefix : & str ,
914
+ mutbl : ast:: mutability )
915
+ -> ( @ast:: pat , ~[ ( Option < ident > , @expr) ] ) {
916
+ if struct_def. fields . is_empty ( ) {
917
+ return (
918
+ cx. pat_ident_binding_mode (
919
+ span, struct_ident, ast:: bind_infer) ,
920
+ ~[ ] ) ;
921
+ }
922
+
923
+ let matching_path = cx. path ( span, ~[ struct_ident ] ) ;
924
+
925
+ let mut paths = ~[ ] ;
926
+ let mut ident_expr = ~[ ] ;
927
+ let mut struct_type = Unknown ;
928
+
929
+ for struct_def. fields. eachi |i, struct_field| {
930
+ let opt_id = match struct_field. node . kind {
931
+ ast:: named_field( ident, _) if ( struct_type == Unknown ||
932
+ struct_type == Record ) => {
933
+ struct_type = Record ;
934
+ Some ( ident)
935
+ }
936
+ ast:: unnamed_field if ( struct_type == Unknown ||
937
+ struct_type == Tuple ) => {
938
+ struct_type = Tuple ;
939
+ None
940
+ }
941
+ _ => {
942
+ cx. span_bug ( span, "A struct with named and unnamed fields in `deriving`" ) ;
943
+ }
944
+ } ;
945
+ let path = cx. path_ident ( span,
946
+ cx. ident_of ( fmt ! ( "%s_%u" , prefix, i) ) ) ;
947
+ paths. push ( path) ;
948
+ ident_expr. push ( ( opt_id, cx. expr_path ( path) ) ) ;
949
+ }
950
+
951
+ let subpats = create_subpatterns ( cx, span, paths, mutbl) ;
952
+
953
+ // struct_type is definitely not Unknown, since struct_def.fields
954
+ // must be nonempty to reach here
955
+ let pattern = if struct_type == Record {
956
+ let field_pats = do vec:: build |push| {
957
+ for vec:: each2( subpats, ident_expr) |& pat, & ( id, _) | {
958
+ // id is guaranteed to be Some
959
+ push( ast:: field_pat { ident : id. get( ) , pat : pat } )
960
+ }
961
+ } ;
962
+ cx. pat_struct ( span, matching_path, field_pats)
963
+ } else {
964
+ cx. pat_enum ( span, matching_path, subpats)
965
+ } ;
966
+
967
+ ( pattern, ident_expr)
968
+ }
969
+
970
+ fn create_enum_variant_pattern ( cx : @ExtCtxt ,
971
+ span : span ,
972
+ variant : & ast:: variant ,
973
+ prefix : & str ,
974
+ mutbl : ast:: mutability )
975
+ -> ( @ast:: pat , ~[ ( Option < ident > , @expr) ] ) {
976
+
977
+ let variant_ident = variant. node . name ;
978
+ match variant. node . kind {
979
+ ast:: tuple_variant_kind( ref variant_args) => {
980
+ if variant_args. is_empty ( ) {
981
+ return ( cx. pat_ident_binding_mode (
982
+ span, variant_ident, ast:: bind_infer) , ~[ ] ) ;
983
+ }
984
+
985
+ let matching_path = cx. path_ident ( span, variant_ident) ;
986
+
987
+ let mut paths = ~[ ] ;
988
+ let mut ident_expr = ~[ ] ;
989
+ for uint:: range( 0 , variant_args. len( ) ) |i| {
990
+ let path = cx. path_ident ( span,
991
+ cx. ident_of ( fmt ! ( "%s_%u" , prefix, i) ) ) ;
992
+
993
+ paths. push ( path) ;
994
+ ident_expr. push ( ( None , cx. expr_path ( path) ) ) ;
995
+ }
996
+
997
+ let subpats = create_subpatterns ( cx, span, paths, mutbl) ;
998
+
999
+ ( cx. pat_enum ( span, matching_path, subpats) ,
1000
+ ident_expr)
1001
+ }
1002
+ ast:: struct_variant_kind( struct_def) => {
1003
+ create_struct_pattern ( cx, span,
1004
+ variant_ident, struct_def,
1005
+ prefix,
1006
+ mutbl)
1007
+ }
1008
+ }
1009
+ }
1010
+
1011
+
837
1012
838
1013
/* helpful premade recipes */
839
1014
0 commit comments