Skip to content

Commit 0643df2

Browse files
committed
libsyntax: Implement #[deriving_clone]
1 parent c639a78 commit 0643df2

8 files changed

+333
-16
lines changed

src/libsyntax/ext/base.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ pub fn syntax_expander_table() -> SyntaxEnv {
155155
syntax_expanders.insert(@~"deriving_iter_bytes",
156156
@SE(ItemDecorator(
157157
ext::deriving::expand_deriving_iter_bytes)));
158+
syntax_expanders.insert(@~"deriving_clone",
159+
@SE(ItemDecorator(
160+
ext::deriving::expand_deriving_clone)));
158161

159162
// Quasi-quoting expanders
160163
syntax_expanders.insert(@~"quote_tokens",

src/libsyntax/ext/deriving.rs

Lines changed: 285 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use core::prelude::*;
1515

1616
use ast;
1717
use ast::{TraitTyParamBound, Ty, and, bind_by_ref, binop, deref, enum_def};
18-
use ast::{enum_variant_kind, expr, expr_match, ident, item, item_};
18+
use ast::{enum_variant_kind, expr, expr_match, ident, impure_fn, item, item_};
1919
use ast::{item_enum, item_impl, item_struct, Generics};
2020
use ast::{m_imm, meta_item, method};
2121
use ast::{named_field, or, pat, pat_ident, pat_wild, public, pure_fn};
@@ -84,6 +84,18 @@ pub fn expand_deriving_iter_bytes(cx: ext_ctxt,
8484
expand_deriving_iter_bytes_enum_def)
8585
}
8686

87+
pub fn expand_deriving_clone(cx: ext_ctxt,
88+
span: span,
89+
_: @meta_item,
90+
in_items: ~[@item])
91+
-> ~[@item] {
92+
expand_deriving(cx,
93+
span,
94+
in_items,
95+
expand_deriving_clone_struct_def,
96+
expand_deriving_clone_enum_def)
97+
}
98+
8799
fn expand_deriving(cx: ext_ctxt,
88100
span: span,
89101
in_items: ~[@item],
@@ -303,6 +315,21 @@ fn create_derived_iter_bytes_impl(cx: ext_ctxt,
303315
create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
304316
}
305317

318+
fn create_derived_clone_impl(cx: ext_ctxt,
319+
span: span,
320+
type_ident: ident,
321+
generics: &Generics,
322+
method: @method)
323+
-> @item {
324+
let methods = [ method ];
325+
let trait_path = [
326+
cx.ident_of(~"core"),
327+
cx.ident_of(~"clone"),
328+
cx.ident_of(~"Clone"),
329+
];
330+
create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
331+
}
332+
306333
// Creates a method from the given set of statements conforming to the
307334
// signature of the `iter_bytes` method.
308335
fn create_iter_bytes_method(cx: ext_ctxt,
@@ -352,6 +379,58 @@ fn create_iter_bytes_method(cx: ext_ctxt,
352379
}
353380
}
354381

382+
// Creates a method from the given expression conforming to the signature of
383+
// the `clone` method.
384+
fn create_clone_method(cx: ext_ctxt,
385+
span: span,
386+
+type_ident: ast::ident,
387+
generics: &Generics,
388+
expr: @ast::expr)
389+
-> @method {
390+
// Create the type parameters of the return value.
391+
let mut output_ty_params = ~[];
392+
for generics.ty_params.each |ty_param| {
393+
let path = build::mk_ty_path(cx, span, ~[ ty_param.ident ]);
394+
output_ty_params.push(path);
395+
}
396+
397+
// Create the type of the return value.
398+
let output_type_path = build::mk_raw_path_(span,
399+
~[ type_ident ],
400+
output_ty_params);
401+
let output_type = ast::ty_path(output_type_path, cx.next_id());
402+
let output_type = @ast::Ty {
403+
id: cx.next_id(),
404+
node: output_type,
405+
span: span
406+
};
407+
408+
// Create the function declaration.
409+
let fn_decl = build::mk_fn_decl(~[], output_type);
410+
411+
// Create the body block.
412+
let body_block = build::mk_simple_block(cx, span, expr);
413+
414+
// Create the self type and method identifier.
415+
let self_ty = spanned { node: sty_region(m_imm), span: span };
416+
let method_ident = cx.ident_of(~"clone");
417+
418+
// Create the method.
419+
@ast::method {
420+
ident: method_ident,
421+
attrs: ~[],
422+
generics: ast_util::empty_generics(),
423+
self_ty: self_ty,
424+
purity: impure_fn,
425+
decl: fn_decl,
426+
body: body_block,
427+
id: cx.next_id(),
428+
span: span,
429+
self_id: cx.next_id(),
430+
vis: public,
431+
}
432+
}
433+
355434
fn create_subpatterns(cx: ext_ctxt,
356435
span: span,
357436
prefix: ~str,
@@ -372,6 +451,15 @@ fn create_subpatterns(cx: ext_ctxt,
372451
return dvec::unwrap(subpats);
373452
}
374453

454+
fn is_struct_tuple(struct_def: &struct_def) -> bool {
455+
struct_def.fields.len() > 0 && struct_def.fields.all(|f| {
456+
match f.node.kind {
457+
named_field(*) => false,
458+
unnamed_field => true
459+
}
460+
})
461+
}
462+
375463
fn create_enum_variant_pattern(cx: ext_ctxt,
376464
span: span,
377465
variant: &variant,
@@ -488,6 +576,16 @@ fn call_substructure_iter_bytes_method(cx: ext_ctxt,
488576
build::mk_stmt(cx, span, self_call)
489577
}
490578

579+
fn call_substructure_clone_method(cx: ext_ctxt,
580+
span: span,
581+
self_field: @expr)
582+
-> @expr {
583+
// Call the substructure method.
584+
let clone_ident = cx.ident_of(~"clone");
585+
let self_method = build::mk_access_(cx, span, self_field, clone_ident);
586+
build::mk_call_(cx, span, self_method, ~[])
587+
}
588+
491589
fn variant_arg_count(cx: ext_ctxt, span: span, variant: &variant) -> uint {
492590
match variant.node.kind {
493591
tuple_variant_kind(ref args) => args.len(),
@@ -508,21 +606,12 @@ fn expand_deriving_eq_struct_def(cx: ext_ctxt,
508606
let eq_ident = cx.ident_of(~"eq");
509607
let ne_ident = cx.ident_of(~"ne");
510608

511-
let is_struct_tuple =
512-
struct_def.fields.len() > 0 && struct_def.fields.all(|f| {
513-
match f.node.kind {
514-
named_field(*) => false,
515-
unnamed_field => true
516-
}
517-
});
518-
519-
let derive_struct_fn = if is_struct_tuple {
609+
let derive_struct_fn = if is_struct_tuple(struct_def) {
520610
expand_deriving_eq_struct_tuple_method
521611
} else {
522612
expand_deriving_eq_struct_method
523613
};
524614

525-
526615
let eq_method = derive_struct_fn(cx,
527616
span,
528617
struct_def,
@@ -618,6 +707,48 @@ fn expand_deriving_iter_bytes_enum_def(cx: ext_ctxt,
618707
method);
619708
}
620709

710+
fn expand_deriving_clone_struct_def(cx: ext_ctxt,
711+
span: span,
712+
struct_def: &struct_def,
713+
type_ident: ident,
714+
generics: &Generics)
715+
-> @item {
716+
// Create the method.
717+
let method = if !is_struct_tuple(struct_def) {
718+
expand_deriving_clone_struct_method(cx,
719+
span,
720+
struct_def,
721+
type_ident,
722+
generics)
723+
} else {
724+
expand_deriving_clone_tuple_struct_method(cx,
725+
span,
726+
struct_def,
727+
type_ident,
728+
generics)
729+
};
730+
731+
// Create the implementation.
732+
create_derived_clone_impl(cx, span, type_ident, generics, method)
733+
}
734+
735+
fn expand_deriving_clone_enum_def(cx: ext_ctxt,
736+
span: span,
737+
enum_definition: &enum_def,
738+
type_ident: ident,
739+
generics: &Generics)
740+
-> @item {
741+
// Create the method.
742+
let method = expand_deriving_clone_enum_method(cx,
743+
span,
744+
enum_definition,
745+
type_ident,
746+
generics);
747+
748+
// Create the implementation.
749+
create_derived_clone_impl(cx, span, type_ident, generics, method)
750+
}
751+
621752
fn expand_deriving_eq_struct_method(cx: ext_ctxt,
622753
span: span,
623754
struct_def: &struct_def,
@@ -709,6 +840,93 @@ fn expand_deriving_iter_bytes_struct_method(cx: ext_ctxt,
709840
return create_iter_bytes_method(cx, span, statements);
710841
}
711842

843+
fn expand_deriving_clone_struct_method(cx: ext_ctxt,
844+
span: span,
845+
struct_def: &struct_def,
846+
type_ident: ident,
847+
generics: &Generics)
848+
-> @method {
849+
let self_ident = cx.ident_of(~"self");
850+
851+
// Create the new fields.
852+
let mut fields = ~[];
853+
for struct_def.fields.each |struct_field| {
854+
match struct_field.node.kind {
855+
named_field(ident, _, _) => {
856+
// Create the accessor for this field.
857+
let self_field = build::mk_access(cx,
858+
span,
859+
~[ self_ident ],
860+
ident);
861+
862+
// Call the substructure method.
863+
let call = call_substructure_clone_method(cx,
864+
span,
865+
self_field);
866+
867+
let field = build::Field { ident: ident, ex: call };
868+
fields.push(field);
869+
}
870+
unnamed_field => {
871+
cx.span_bug(span,
872+
~"unnamed fields in \
873+
expand_deriving_clone_struct_method");
874+
}
875+
}
876+
}
877+
878+
// Create the struct literal.
879+
let struct_literal = build::mk_struct_e(cx,
880+
span,
881+
~[ type_ident ],
882+
fields);
883+
create_clone_method(cx, span, type_ident, generics, struct_literal)
884+
}
885+
886+
fn expand_deriving_clone_tuple_struct_method(cx: ext_ctxt,
887+
span: span,
888+
struct_def: &struct_def,
889+
type_ident: ident,
890+
generics: &Generics)
891+
-> @method {
892+
// Create the pattern for the match.
893+
let matching_path = build::mk_raw_path(span, ~[ type_ident ]);
894+
let field_count = struct_def.fields.len();
895+
let subpats = create_subpatterns(cx, span, ~"__self", field_count);
896+
let pat = build::mk_pat_enum(cx, span, matching_path, subpats);
897+
898+
// Create the new fields.
899+
let mut subcalls = ~[];
900+
for uint::range(0, struct_def.fields.len()) |i| {
901+
// Create the expression for this field.
902+
let field_ident = cx.ident_of(~"__self" + i.to_str());
903+
let field = build::mk_path(cx, span, ~[ field_ident ]);
904+
905+
// Call the substructure method.
906+
let subcall = call_substructure_clone_method(cx, span, field);
907+
subcalls.push(subcall);
908+
}
909+
910+
// Create the call to the struct constructor.
911+
let call = build::mk_call(cx, span, ~[ type_ident ], subcalls);
912+
913+
// Create the pattern body.
914+
let match_body_block = build::mk_simple_block(cx, span, call);
915+
916+
// Create the arm.
917+
let arm = ast::arm {
918+
pats: ~[ pat ],
919+
guard: None,
920+
body: match_body_block
921+
};
922+
923+
// Create the method body.
924+
let self_match_expr = expand_enum_or_struct_match(cx, span, ~[ arm ]);
925+
926+
// Create the method.
927+
create_clone_method(cx, span, type_ident, generics, self_match_expr)
928+
}
929+
712930
fn expand_deriving_eq_enum_method(cx: ext_ctxt,
713931
span: span,
714932
enum_definition: &enum_def,
@@ -904,6 +1122,17 @@ fn expand_deriving_eq_struct_tuple_method(cx: ext_ctxt,
9041122
type_ident, generics, self_match_expr)
9051123
}
9061124

1125+
fn expand_enum_or_struct_match(cx: ext_ctxt,
1126+
span: span,
1127+
arms: ~[ ast::arm ])
1128+
-> @expr {
1129+
let self_ident = cx.ident_of(~"self");
1130+
let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
1131+
let self_expr = build::mk_unary(cx, span, deref, self_expr);
1132+
let self_match_expr = expr_match(self_expr, arms);
1133+
build::mk_expr(cx, span, self_match_expr)
1134+
}
1135+
9071136
fn expand_deriving_iter_bytes_enum_method(cx: ext_ctxt,
9081137
span: span,
9091138
enum_definition: &enum_def)
@@ -953,14 +1182,54 @@ fn expand_deriving_iter_bytes_enum_method(cx: ext_ctxt,
9531182
};
9541183

9551184
// Create the method body.
956-
let self_ident = cx.ident_of(~"self");
957-
let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
958-
let self_expr = build::mk_unary(cx, span, deref, self_expr);
959-
let self_match_expr = expr_match(self_expr, arms);
960-
let self_match_expr = build::mk_expr(cx, span, self_match_expr);
1185+
let self_match_expr = expand_enum_or_struct_match(cx, span, arms);
9611186
let self_match_stmt = build::mk_stmt(cx, span, self_match_expr);
9621187

9631188
// Create the method.
9641189
create_iter_bytes_method(cx, span, ~[ self_match_stmt ])
9651190
}
9661191

1192+
fn expand_deriving_clone_enum_method(cx: ext_ctxt,
1193+
span: span,
1194+
enum_definition: &enum_def,
1195+
type_ident: ident,
1196+
generics: &Generics)
1197+
-> @method {
1198+
// Create the arms of the match in the method body.
1199+
let arms = do enum_definition.variants.map |variant| {
1200+
// Create the matching pattern.
1201+
let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
1202+
1203+
// Iterate over the variant arguments, creating the subcalls.
1204+
let mut subcalls = ~[];
1205+
for uint::range(0, variant_arg_count(cx, span, variant)) |j| {
1206+
// Create the expression for this field.
1207+
let field_ident = cx.ident_of(~"__self" + j.to_str());
1208+
let field = build::mk_path(cx, span, ~[ field_ident ]);
1209+
1210+
// Call the substructure method.
1211+
let subcall = call_substructure_clone_method(cx, span, field);
1212+
subcalls.push(subcall);
1213+
}
1214+
1215+
// Create the call to the enum variant (if necessary).
1216+
let call = if subcalls.len() > 0 {
1217+
build::mk_call(cx, span, ~[ variant.node.name ], subcalls)
1218+
} else {
1219+
build::mk_path(cx, span, ~[ variant.node.name ])
1220+
};
1221+
1222+
// Create the pattern body.
1223+
let match_body_block = build::mk_simple_block(cx, span, call);
1224+
1225+
// Create the arm.
1226+
ast::arm { pats: ~[ pat ], guard: None, body: match_body_block }
1227+
};
1228+
1229+
// Create the method body.
1230+
let self_match_expr = expand_enum_or_struct_match(cx, span, arms);
1231+
1232+
// Create the method.
1233+
create_clone_method(cx, span, type_ident, generics, self_match_expr)
1234+
}
1235+

0 commit comments

Comments
 (0)