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.
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.
13 use ext::base::ext_ctxt;
16 use codemap::{span, spanned};
20 pub fn expand_deriving_encodable(
30 expand_deriving_encodable_struct_def,
31 expand_deriving_encodable_enum_def
35 fn create_derived_encodable_impl(
42 let encoder_ty_param = build::mk_ty_param(
46 build::mk_trait_ty_param_bound_global(
51 cx.ident_of(~"serialize"),
52 cx.ident_of(~"Encoder"),
58 // All the type parameters need to bound to the trait.
59 let generic_ty_params = opt_vec::with(encoder_ty_param);
61 let methods = [method];
62 let trait_path = build::mk_raw_path_global_(
66 cx.ident_of(~"serialize"),
67 cx.ident_of(~"Encodable")
70 build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E"))
85 // Creates a method from the given set of statements conforming to the
86 // signature of the `encodable` method.
87 fn create_encode_method(
92 // Create the `e` parameter.
93 let e_arg_type = build::mk_ty_rptr(
96 build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")),
99 let e_arg = build::mk_arg(cx, span, cx.ident_of(~"__e"), e_arg_type);
101 // Create the type of the return value.
102 let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span };
104 // Create the function declaration.
105 let inputs = ~[e_arg];
106 let fn_decl = build::mk_fn_decl(inputs, output_type);
108 // Create the body block.
109 let body_block = build::mk_block_(cx, span, statements);
111 // Create the method.
112 let self_ty = spanned { node: sty_region(None, m_imm), span: span };
113 let method_ident = cx.ident_of(~"encode");
117 generics: ast_util::empty_generics(),
124 self_id: cx.next_id(),
129 fn call_substructure_encode_method(
134 // Gather up the parameters we want to chain along.
135 let e_ident = cx.ident_of(~"__e");
136 let e_expr = build::mk_path(cx, span, ~[e_ident]);
138 // Call the substructure method.
139 let encode_ident = cx.ident_of(~"encode");
140 build::mk_method_call(
149 fn expand_deriving_encodable_struct_def(
152 struct_def: &struct_def,
156 // Create the method.
157 let method = expand_deriving_encodable_struct_method(
164 // Create the implementation.
165 create_derived_encodable_impl(
174 fn expand_deriving_encodable_enum_def(
177 enum_definition: &enum_def,
181 // Create the method.
182 let method = expand_deriving_encodable_enum_method(
189 // Create the implementation.
190 create_derived_encodable_impl(
199 fn expand_deriving_encodable_struct_method(
203 struct_def: &struct_def
205 let self_ident = cx.ident_of(~"self");
207 // Create the body of the method.
209 let mut statements = ~[];
210 for struct_def.fields.each |struct_field| {
211 match struct_field.node.kind {
212 named_field(ident, _, _) => {
213 // Create the accessor for this field.
214 let self_field = build::mk_access(
221 // Call the substructure method.
222 let encode_expr = call_substructure_encode_method(
228 let e_ident = cx.ident_of(~"__e");
229 let e_arg = build::mk_arg(cx,
232 build::mk_ty_infer(cx, span));
234 let blk_expr = build::mk_lambda(
237 build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)),
241 let call_expr = build::mk_method_call(
244 build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
245 cx.ident_of(~"emit_struct_field"),
247 build::mk_base_str(cx, span, cx.str_of(ident)),
248 build::mk_uint(cx, span, idx),
253 statements.push(build::mk_stmt(cx, span, call_expr));
258 ~"unnamed fields with `deriving(Encodable)`"
265 let e_arg = build::mk_arg(cx,
268 build::mk_ty_infer(cx, span));
270 let emit_struct_stmt = build::mk_method_call(
276 ~[cx.ident_of(~"__e")]
278 cx.ident_of(~"emit_struct"),
280 build::mk_base_str(cx, span, cx.str_of(type_ident)),
281 build::mk_uint(cx, span, statements.len()),
282 build::mk_lambda_stmts(
285 build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)),
291 let statements = ~[build::mk_stmt(cx, span, emit_struct_stmt)];
293 // Create the method itself.
294 return create_encode_method(cx, span, statements);
297 fn expand_deriving_encodable_enum_method(
300 type_ident: ast::ident,
301 enum_definition: &enum_def
303 // Create the arms of the match in the method body.
304 let arms = do enum_definition.variants.mapi |i, variant| {
305 // Create the matching pattern.
306 let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
308 // Feed the discriminant to the encode function.
311 // Feed each argument in this variant to the encode function
313 let variant_arg_len = variant_arg_count(cx, span, variant);
314 for uint::range(0, variant_arg_len) |j| {
315 // Create the expression for this field.
316 let field_ident = cx.ident_of(~"__self_" + j.to_str());
317 let field = build::mk_path(cx, span, ~[ field_ident ]);
319 // Call the substructure method.
320 let expr = call_substructure_encode_method(cx, span, field);
322 let e_ident = cx.ident_of(~"__e");
323 let e_arg = build::mk_arg(cx,
326 build::mk_ty_infer(cx, span));
328 let blk_expr = build::mk_lambda(
331 build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)),
335 let call_expr = build::mk_method_call(
338 build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
339 cx.ident_of(~"emit_enum_variant_arg"),
341 build::mk_uint(cx, span, j),
346 stmts.push(build::mk_stmt(cx, span, call_expr));
349 // Create the pattern body.
350 let e_arg = build::mk_arg(cx,
353 build::mk_ty_infer(cx, span));
354 let call_expr = build::mk_method_call(
357 build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
358 cx.ident_of(~"emit_enum_variant"),
360 build::mk_base_str(cx, span, cx.str_of(variant.node.name)),
361 build::mk_uint(cx, span, i),
362 build::mk_uint(cx, span, variant_arg_len),
363 build::mk_lambda_stmts(
366 build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)),
372 let match_body_block = build::mk_simple_block(cx, span, call_expr);
378 body: match_body_block,
382 let e_ident = cx.ident_of(~"__e");
383 let e_arg = build::mk_arg(cx,
386 build::mk_ty_infer(cx, span));
388 // Create the method body.
389 let lambda_expr = build::mk_lambda(
392 build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)),
393 expand_enum_or_struct_match(cx, span, arms)
396 let call_expr = build::mk_method_call(
399 build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
400 cx.ident_of(~"emit_enum"),
402 build::mk_base_str(cx, span, cx.str_of(type_ident)),
407 let stmt = build::mk_stmt(cx, span, call_expr);
409 // Create the method.
410 create_encode_method(cx, span, ~[stmt])