mk_expr(cx, span, ast::expr_fn_block(fn_decl, blk))
}
pub fn mk_lambda(cx: @ext_ctxt,
- span: span,
- fn_decl: ast::fn_decl,
- expr: @ast::expr)
- -> @ast::expr {
+ span: span,
+ fn_decl: ast::fn_decl,
+ expr: @ast::expr)
+ -> @ast::expr {
let blk = mk_simple_block(cx, span, expr);
mk_lambda_(cx, span, fn_decl, blk)
}
let blk = mk_block(cx, span, ~[], stmts, None);
mk_lambda(cx, span, fn_decl, blk)
}
+pub fn mk_lambda_no_args(cx: @ext_ctxt,
+ span: span,
+ expr: @ast::expr)
+ -> @ast::expr {
+ let fn_decl = mk_fn_decl(~[], mk_ty_infer(cx, span));
+ mk_lambda(cx, span, fn_decl, expr)
+}
pub fn mk_copy(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
mk_expr(cx, sp, ast::expr_copy(e))
}
pub fn mk_pat(cx: @ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat {
@ast::pat { id: cx.next_id(), node: pat, span: span }
}
+pub fn mk_pat_wild(cx: @ext_ctxt, span: span) -> @ast::pat {
+ mk_pat(cx, span, ast::pat_wild)
+}
+pub fn mk_pat_lit(cx: @ext_ctxt,
+ span: span,
+ expr: @ast::expr) -> @ast::pat {
+ mk_pat(cx, span, ast::pat_lit(expr))
+}
pub fn mk_pat_ident(cx: @ext_ctxt,
span: span,
ident: ast::ident) -> @ast::pat {
mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_copy)
}
+
pub fn mk_pat_ident_with_binding_mode(cx: @ext_ctxt,
span: span,
ident: ast::ident,
}
pub fn mk_lifetime(cx: @ext_ctxt,
span: span,
- ident: ast::ident) -> ast::Lifetime
-{
+ ident: ast::ident)
+ -> ast::Lifetime {
ast::Lifetime { id: cx.next_id(), span: span, ident: ident }
}
-
+pub fn mk_arm(cx: @ext_ctxt,
+ span: span,
+ pats: ~[@ast::pat],
+ expr: @ast::expr)
+ -> ast::arm {
+ ast::arm {
+ pats: pats,
+ guard: None,
+ body: mk_simple_block(cx, span, expr)
+ }
+}
+pub fn mk_unreachable(cx: @ext_ctxt, span: span) -> @ast::expr {
+ let loc = cx.codemap().lookup_char_pos(span.lo);
+ mk_call_global(
+ cx,
+ span,
+ ~[
+ cx.ident_of(~"core"),
+ cx.ident_of(~"sys"),
+ cx.ident_of(~"begin_unwind"),
+ ],
+ ~[
+ mk_uniq_str(cx, span, ~"internal error: entered unreachable code"),
+ mk_uniq_str(cx, span, loc.file.name),
+ mk_uint(cx, span, loc.line),
+ ]
+ )
+}
+pub fn mk_unreachable_arm(cx: @ext_ctxt, span: span) -> ast::arm {
+ mk_arm(cx, span, ~[mk_pat_wild(cx, span)], mk_unreachable(cx, span))
+}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::prelude::*;
+
+use ast;
+use ast::*;
+use ext::base::ext_ctxt;
+use ext::build;
+use ext::deriving::*;
+use codemap::{span, spanned};
+use ast_util;
+use opt_vec;
+
+use core::uint;
+
+pub fn expand_deriving_decodable(
+ cx: @ext_ctxt,
+ span: span,
+ _mitem: @meta_item,
+ in_items: ~[@item]
+) -> ~[@item] {
+ expand_deriving(
+ cx,
+ span,
+ in_items,
+ expand_deriving_decodable_struct_def,
+ expand_deriving_decodable_enum_def
+ )
+}
+
+fn create_derived_decodable_impl(
+ cx: @ext_ctxt,
+ span: span,
+ type_ident: ident,
+ generics: &Generics,
+ method: @method
+) -> @item {
+ let decoder_ty_param = build::mk_ty_param(
+ cx,
+ cx.ident_of(~"__D"),
+ @opt_vec::with(
+ build::mk_trait_ty_param_bound_global(
+ cx,
+ span,
+ ~[
+ cx.ident_of(~"std"),
+ cx.ident_of(~"serialize"),
+ cx.ident_of(~"Decoder"),
+ ]
+ )
+ )
+ );
+
+ // All the type parameters need to bound to the trait.
+ let generic_ty_params = opt_vec::with(decoder_ty_param);
+
+ let methods = [method];
+ let trait_path = build::mk_raw_path_global_(
+ span,
+ ~[
+ cx.ident_of(~"std"),
+ cx.ident_of(~"serialize"),
+ cx.ident_of(~"Decodable")
+ ],
+ ~[
+ build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D"))
+ ]
+ );
+ create_derived_impl(
+ cx,
+ span,
+ type_ident,
+ generics,
+ methods,
+ trait_path,
+ generic_ty_params
+ )
+}
+
+// Creates a method from the given set of statements conforming to the
+// signature of the `decodable` method.
+fn create_decode_method(
+ cx: @ext_ctxt,
+ span: span,
+ type_ident: ast::ident,
+ generics: &Generics,
+ expr: @ast::expr
+) -> @method {
+ // Create the `e` parameter.
+ let d_arg_type = build::mk_ty_rptr(
+ cx,
+ span,
+ build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")),
+ ast::m_imm
+ );
+ let d_ident = cx.ident_of(~"__d");
+ let d_arg = build::mk_arg(cx, span, d_ident, d_arg_type);
+
+ // Create the type of the return value.
+ let output_type = create_self_type_with_params(
+ cx,
+ span,
+ type_ident,
+ generics
+ );
+
+ // Create the function declaration.
+ let inputs = ~[d_arg];
+ let fn_decl = build::mk_fn_decl(inputs, output_type);
+
+ // Create the body block.
+ let body_block = build::mk_simple_block(cx, span, expr);
+
+ // Create the method.
+ let self_ty = spanned { node: sty_static, span: span };
+ let method_ident = cx.ident_of(~"decode");
+ @ast::method {
+ ident: method_ident,
+ attrs: ~[],
+ generics: ast_util::empty_generics(),
+ self_ty: self_ty,
+ purity: impure_fn,
+ decl: fn_decl,
+ body: body_block,
+ id: cx.next_id(),
+ span: span,
+ self_id: cx.next_id(),
+ vis: public
+ }
+}
+
+fn call_substructure_decode_method(
+ cx: @ext_ctxt,
+ span: span
+) -> @ast::expr {
+ // Call the substructure method.
+ build::mk_call_(
+ cx,
+ span,
+ build::mk_path_global(
+ cx,
+ span,
+ ~[
+ cx.ident_of(~"std"),
+ cx.ident_of(~"serialize"),
+ cx.ident_of(~"Decodable"),
+ cx.ident_of(~"decode"),
+ ]
+ ),
+ ~[
+ build::mk_path(cx, span, ~[cx.ident_of(~"__d")])
+ ]
+ )
+}
+
+fn expand_deriving_decodable_struct_def(
+ cx: @ext_ctxt,
+ span: span,
+ struct_def: &struct_def,
+ type_ident: ident,
+ generics: &Generics
+) -> @item {
+ // Create the method.
+ let method = expand_deriving_decodable_struct_method(
+ cx,
+ span,
+ struct_def,
+ type_ident,
+ generics
+ );
+
+ // Create the implementation.
+ create_derived_decodable_impl(
+ cx,
+ span,
+ type_ident,
+ generics,
+ method
+ )
+}
+
+fn expand_deriving_decodable_enum_def(
+ cx: @ext_ctxt,
+ span: span,
+ enum_definition: &enum_def,
+ type_ident: ident,
+ generics: &Generics
+) -> @item {
+ // Create the method.
+ let method = expand_deriving_decodable_enum_method(
+ cx,
+ span,
+ enum_definition,
+ type_ident,
+ generics
+ );
+
+ // Create the implementation.
+ create_derived_decodable_impl(
+ cx,
+ span,
+ type_ident,
+ generics,
+ method
+ )
+}
+
+fn create_read_struct_field(
+ cx: @ext_ctxt,
+ span: span,
+ idx: uint,
+ ident: ident
+) -> build::Field {
+ // Call the substructure method.
+ let decode_expr = call_substructure_decode_method(cx, span);
+
+ let call_expr = build::mk_method_call(
+ cx,
+ span,
+ build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+ cx.ident_of(~"read_struct_field"),
+ ~[
+ build::mk_base_str(cx, span, cx.str_of(ident)),
+ build::mk_uint(cx, span, idx),
+ build::mk_lambda_no_args(cx, span, decode_expr),
+ ]
+ );
+
+ build::Field { ident: ident, ex: call_expr }
+}
+
+fn create_read_struct_arg(
+ cx: @ext_ctxt,
+ span: span,
+ idx: uint,
+ ident: ident
+) -> build::Field {
+ // Call the substructure method.
+ let decode_expr = call_substructure_decode_method(cx, span);
+
+ let call_expr = build::mk_method_call(
+ cx,
+ span,
+ build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+ cx.ident_of(~"read_struct_arg"),
+ ~[
+ build::mk_uint(cx, span, idx),
+ build::mk_lambda_no_args(cx, span, decode_expr),
+ ]
+ );
+
+ build::Field { ident: ident, ex: call_expr }
+}
+
+fn expand_deriving_decodable_struct_method(
+ cx: @ext_ctxt,
+ span: span,
+ struct_def: &struct_def,
+ type_ident: ident,
+ generics: &Generics
+) -> @method {
+ // Create the body of the method.
+ let mut i = 0;
+ let mut fields = ~[];
+ for struct_def.fields.each |struct_field| {
+ match struct_field.node.kind {
+ named_field(ident, _, _) => {
+ fields.push(create_read_struct_field(cx, span, i, ident));
+ }
+ unnamed_field => {
+ cx.span_unimpl(
+ span,
+ ~"unnamed fields with `deriving(Decodable)`"
+ );
+ }
+ }
+ i += 1;
+ }
+
+ let read_struct_expr = build::mk_method_call(
+ cx,
+ span,
+ build::mk_path(
+ cx,
+ span,
+ ~[cx.ident_of(~"__d")]
+ ),
+ cx.ident_of(~"read_struct"),
+ ~[
+ build::mk_base_str(cx, span, cx.str_of(type_ident)),
+ build::mk_uint(cx, span, fields.len()),
+ build::mk_lambda_no_args(
+ cx,
+ span,
+ build::mk_struct_e(
+ cx,
+ span,
+ ~[type_ident],
+ fields
+ )
+ ),
+ ]
+ );
+
+ // Create the method itself.
+ create_decode_method(cx, span, type_ident, generics, read_struct_expr)
+}
+
+fn create_read_variant_arg(
+ cx: @ext_ctxt,
+ span: span,
+ idx: uint,
+ variant: &ast::variant
+) -> ast::arm {
+ // Create the matching pattern.
+ let pat = build::mk_pat_lit(cx, span, build::mk_uint(cx, span, idx));
+
+ // Feed each argument in this variant to the decode function
+ // as well.
+ let variant_arg_len = variant_arg_count(cx, span, variant);
+
+ let expr = if variant_arg_len == 0 {
+ build::mk_path(cx, span, ~[variant.node.name])
+ } else {
+ // Feed the discriminant to the decode function.
+ let mut args = ~[];
+
+ for uint::range(0, variant_arg_len) |j| {
+ // Call the substructure method.
+ let expr = call_substructure_decode_method(cx, span);
+
+ let call_expr = build::mk_method_call(
+ cx,
+ span,
+ build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+ cx.ident_of(~"read_enum_variant_arg"),
+ ~[
+ build::mk_uint(cx, span, j),
+ build::mk_lambda_no_args(cx, span, expr),
+ ]
+ );
+
+ args.push(call_expr);
+ }
+
+ build::mk_call(
+ cx,
+ span,
+ ~[variant.node.name],
+ args
+ )
+ };
+
+ // Create the arm.
+ build::mk_arm(cx, span, ~[pat], expr)
+}
+
+fn create_read_enum_variant(
+ cx: @ext_ctxt,
+ span: span,
+ enum_definition: &enum_def
+) -> @expr {
+ // Create a vector that contains all the variant names.
+ let expr_arm_names = build::mk_base_vec_e(
+ cx,
+ span,
+ do enum_definition.variants.map |variant| {
+ build::mk_base_str(
+ cx,
+ span,
+ cx.str_of(variant.node.name)
+ )
+ }
+ );
+
+ // Create the arms of the match in the method body.
+ let mut arms = do enum_definition.variants.mapi |i, variant| {
+ create_read_variant_arg(cx, span, i, variant)
+ };
+
+ // Add the impossible case arm.
+ arms.push(build::mk_unreachable_arm(cx, span));
+
+ // Create the read_enum_variant expression.
+ build::mk_method_call(
+ cx,
+ span,
+ build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+ cx.ident_of(~"read_enum_variant"),
+ ~[
+ expr_arm_names,
+ build::mk_lambda(
+ cx,
+ span,
+ build::mk_fn_decl(
+ ~[
+ build::mk_arg(
+ cx,
+ span,
+ cx.ident_of(~"__i"),
+ build::mk_ty_infer(cx, span)
+ )
+ ],
+ build::mk_ty_infer(cx, span)
+ ),
+ build::mk_expr(
+ cx,
+ span,
+ ast::expr_match(
+ build::mk_path(cx, span, ~[cx.ident_of(~"__i")]),
+ arms
+ )
+ )
+ )
+ ]
+ )
+}
+
+fn expand_deriving_decodable_enum_method(
+ cx: @ext_ctxt,
+ span: span,
+ enum_definition: &enum_def,
+ type_ident: ast::ident,
+ generics: &Generics
+) -> @method {
+ let read_enum_variant_expr = create_read_enum_variant(
+ cx,
+ span,
+ enum_definition
+ );
+
+ // Create the read_enum expression
+ let read_enum_expr = build::mk_method_call(
+ cx,
+ span,
+ build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+ cx.ident_of(~"read_enum"),
+ ~[
+ build::mk_base_str(cx, span, cx.str_of(type_ident)),
+ build::mk_lambda_no_args(cx, span, read_enum_variant_expr),
+ ]
+ );
+
+ // Create the method.
+ create_decode_method(cx, span, type_ident, generics, read_enum_expr)
+}