auto merge of #5819 : erickt/rust/incoming, r=erickt

Good morning,

This first patch series adds support for `#[deriving(Decodable, Encodable)]`, but does not yet remove `#[auto_encode]` and `#[auto_decode]`. I need a snapshot to remove the old code. Along the way it also extends support for tuple structs and struct enum variants.

Also, it includes a minor fix to the pretty printer. We decided a while ago to use 4 spaces to indent a match arm instead of 2. This updates the pretty printer to reflect that.
This commit is contained in:
bors 2013-04-11 06:55:01 -07:00
commit 2f8b36fc16
16 changed files with 1464 additions and 203 deletions

View file

@ -732,12 +732,12 @@ fn mk_struct_ser_impl(
)
);
// ast for `__s.emit_field($(name), $(idx), $(expr_lambda))`
// ast for `__s.emit_struct_field($(name), $(idx), $(expr_lambda))`
cx.stmt(
cx.expr_method_call(
span,
cx.expr_var(span, ~"__s"),
cx.ident_of(~"emit_field"),
cx.ident_of(~"emit_struct_field"),
~[
cx.lit_str(span, @cx.str_of(field.ident)),
cx.lit_uint(span, idx),
@ -786,11 +786,11 @@ fn mk_struct_deser_impl(
)
);
// ast for `__d.read_field($(name), $(idx), $(expr_lambda))`
// ast for `__d.read_struct_field($(name), $(idx), $(expr_lambda))`
let expr: @ast::expr = cx.expr_method_call(
span,
cx.expr_var(span, ~"__d"),
cx.ident_of(~"read_field"),
cx.ident_of(~"read_struct_field"),
~[
cx.lit_str(span, @cx.str_of(field.ident)),
cx.lit_uint(span, idx),
@ -1253,20 +1253,35 @@ mod test {
self.add_to_log(CallToEmitEnumVariantArg (idx)); f();
}
fn emit_seq(&self, +_len: uint, f: &fn()) {
self.add_unknown_to_log(); f();
fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) {
self.emit_enum_variant(name, id, cnt, f)
}
fn emit_seq_elt(&self, +_idx: uint, f: &fn()) {
self.add_unknown_to_log(); f();
fn emit_enum_struct_variant_field(&self, _name: &str, idx: uint, f: &fn()) {
self.emit_enum_variant_arg(idx, f)
}
fn emit_struct(&self, name: &str, +len: uint, f: &fn()) {
self.add_to_log(CallToEmitStruct (name.to_str(),len)); f();
}
fn emit_field(&self, name: &str, +idx: uint, f: &fn()) {
fn emit_struct_field(&self, name: &str, +idx: uint, f: &fn()) {
self.add_to_log(CallToEmitField (name.to_str(),idx)); f();
}
fn emit_tuple(&self, _len: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}
fn emit_tuple_arg(&self, _idx: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}
fn emit_tuple_struct(&self, _name: &str, _len: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}
fn emit_tuple_struct_arg(&self, _idx: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}
fn emit_option(&self, f: &fn()) {
self.add_to_log(CallToEmitOption);
f();
@ -1279,6 +1294,13 @@ mod test {
f();
}
fn emit_seq(&self, +_len: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}
fn emit_seq_elt(&self, +_idx: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}
fn emit_map(&self, _len: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}

View file

@ -64,12 +64,7 @@ pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr)
mk_expr(cx, sp, ast::expr_unary(op, e))
}
pub fn mk_raw_path(sp: span, +idents: ~[ast::ident]) -> @ast::Path {
let p = @ast::Path { span: sp,
global: false,
idents: idents,
rp: None,
types: ~[] };
return p;
mk_raw_path_(sp, idents, ~[])
}
pub fn mk_raw_path_(sp: span,
+idents: ~[ast::ident],
@ -82,11 +77,16 @@ pub fn mk_raw_path_(sp: span,
types: types }
}
pub fn mk_raw_path_global(sp: span, +idents: ~[ast::ident]) -> @ast::Path {
mk_raw_path_global_(sp, idents, ~[])
}
pub fn mk_raw_path_global_(sp: span,
+idents: ~[ast::ident],
+types: ~[@ast::Ty]) -> @ast::Path {
@ast::Path { span: sp,
global: true,
idents: idents,
rp: None,
types: ~[] }
types: types }
}
pub fn mk_path(cx: @ext_ctxt, sp: span, +idents: ~[ast::ident])
-> @ast::expr {
@ -271,6 +271,36 @@ pub fn mk_simple_block(cx: @ext_ctxt,
span: span,
}
}
pub fn mk_lambda_(cx: @ext_ctxt,
span: span,
fn_decl: ast::fn_decl,
blk: ast::blk)
-> @ast::expr {
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 {
let blk = mk_simple_block(cx, span, expr);
mk_lambda_(cx, span, fn_decl, blk)
}
pub fn mk_lambda_stmts(cx: @ext_ctxt,
span: span,
fn_decl: ast::fn_decl,
stmts: ~[@ast::stmt])
-> @ast::expr {
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))
}
@ -280,11 +310,20 @@ pub fn mk_managed(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
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,
@ -337,12 +376,35 @@ pub fn mk_ty_path_global(cx: @ext_ctxt,
let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
ty
}
pub fn mk_ty_rptr(cx: @ext_ctxt,
span: span,
ty: @ast::Ty,
mutbl: ast::mutability)
-> @ast::Ty {
@ast::Ty {
id: cx.next_id(),
span: span,
node: ast::ty_rptr(
None,
ast::mt { ty: ty, mutbl: mutbl }
),
}
}
pub fn mk_ty_infer(cx: @ext_ctxt, span: span) -> @ast::Ty {
@ast::Ty {
id: cx.next_id(),
node: ast::ty_infer,
span: span,
}
}
pub fn mk_trait_ref_global(cx: @ext_ctxt,
span: span,
+idents: ~[ ast::ident ])
-> @ast::trait_ref
{
let path = build::mk_raw_path_global(span, idents);
mk_trait_ref_(cx, build::mk_raw_path_global(span, idents))
}
pub fn mk_trait_ref_(cx: @ext_ctxt, path: @ast::Path) -> @ast::trait_ref {
@ast::trait_ref {
path: path,
ref_id: cx.next_id()
@ -371,6 +433,16 @@ pub fn mk_arg(cx: @ext_ctxt,
pub fn mk_fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl {
ast::fn_decl { inputs: inputs, output: output, cf: ast::return_val }
}
pub fn mk_trait_ty_param_bound_global(cx: @ext_ctxt,
span: span,
+idents: ~[ast::ident])
-> ast::TyParamBound {
ast::TraitTyParamBound(mk_trait_ref_global(cx, span, idents))
}
pub fn mk_trait_ty_param_bound_(cx: @ext_ctxt,
path: @ast::Path) -> ast::TyParamBound {
ast::TraitTyParamBound(mk_trait_ref_(cx, path))
}
pub fn mk_ty_param(cx: @ext_ctxt,
ident: ast::ident,
bounds: @OptVec<ast::TyParamBound>)
@ -379,8 +451,38 @@ pub fn mk_ty_param(cx: @ext_ctxt,
}
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))
}

View file

@ -17,6 +17,7 @@ use ext::build;
use ext::deriving::*;
use codemap::{span, spanned};
use ast_util;
use opt_vec;
use core::uint;
@ -48,12 +49,13 @@ fn create_derived_clone_impl(cx: @ext_ctxt,
method: @method)
-> @item {
let methods = [ method ];
let trait_path = [
let trait_path = ~[
cx.ident_of(~"core"),
cx.ident_of(~"clone"),
cx.ident_of(~"Clone"),
];
create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
let trait_path = build::mk_raw_path_global(span, trait_path);
create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty)
}
// Creates a method from the given expression conforming to the signature of
// the `clone` method.
@ -188,9 +190,7 @@ fn expand_deriving_clone_struct_method(cx: @ext_ctxt,
fields.push(field);
}
unnamed_field => {
cx.span_bug(span,
~"unnamed fields in \
expand_deriving_clone_struct_method");
cx.span_bug(span, ~"unnamed fields in `deriving(Clone)`");
}
}
}

View file

@ -0,0 +1,454 @@
// 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)
}

View file

@ -0,0 +1,388 @@
// 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_encodable(
cx: @ext_ctxt,
span: span,
_mitem: @meta_item,
in_items: ~[@item]
) -> ~[@item] {
expand_deriving(
cx,
span,
in_items,
expand_deriving_encodable_struct_def,
expand_deriving_encodable_enum_def
)
}
fn create_derived_encodable_impl(
cx: @ext_ctxt,
span: span,
type_ident: ident,
generics: &Generics,
method: @method
) -> @item {
let encoder_ty_param = build::mk_ty_param(
cx,
cx.ident_of(~"__E"),
@opt_vec::with(
build::mk_trait_ty_param_bound_global(
cx,
span,
~[
cx.ident_of(~"std"),
cx.ident_of(~"serialize"),
cx.ident_of(~"Encoder"),
]
)
)
);
// All the type parameters need to bound to the trait.
let generic_ty_params = opt_vec::with(encoder_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(~"Encodable")
],
~[
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E"))
]
);
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 `encodable` method.
fn create_encode_method(
cx: @ext_ctxt,
span: span,
+statements: ~[@stmt]
) -> @method {
// Create the `e` parameter.
let e_arg_type = build::mk_ty_rptr(
cx,
span,
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")),
ast::m_imm
);
let e_ident = cx.ident_of(~"__e");
let e_arg = build::mk_arg(cx, span, e_ident, e_arg_type);
// Create the type of the return value.
let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span };
// Create the function declaration.
let inputs = ~[e_arg];
let fn_decl = build::mk_fn_decl(inputs, output_type);
// Create the body block.
let body_block = build::mk_block_(cx, span, statements);
// Create the method.
let self_ty = spanned { node: sty_region(None, m_imm), span: span };
let method_ident = cx.ident_of(~"encode");
@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_encode_method(
cx: @ext_ctxt,
span: span,
self_field: @expr
) -> @ast::expr {
// Gather up the parameters we want to chain along.
let e_ident = cx.ident_of(~"__e");
let e_expr = build::mk_path(cx, span, ~[e_ident]);
// Call the substructure method.
let encode_ident = cx.ident_of(~"encode");
build::mk_method_call(
cx,
span,
self_field,
encode_ident,
~[e_expr]
)
}
fn expand_deriving_encodable_struct_def(
cx: @ext_ctxt,
span: span,
struct_def: &struct_def,
type_ident: ident,
generics: &Generics
) -> @item {
// Create the method.
let method = expand_deriving_encodable_struct_method(
cx,
span,
type_ident,
struct_def
);
// Create the implementation.
create_derived_encodable_impl(
cx,
span,
type_ident,
generics,
method
)
}
fn expand_deriving_encodable_enum_def(
cx: @ext_ctxt,
span: span,
enum_definition: &enum_def,
type_ident: ident,
generics: &Generics
) -> @item {
// Create the method.
let method = expand_deriving_encodable_enum_method(
cx,
span,
type_ident,
enum_definition
);
// Create the implementation.
create_derived_encodable_impl(
cx,
span,
type_ident,
generics,
method
)
}
fn expand_deriving_encodable_struct_method(
cx: @ext_ctxt,
span: span,
type_ident: ident,
struct_def: &struct_def
) -> @method {
let self_ident = cx.ident_of(~"self");
// Create the body of the method.
let mut idx = 0;
let mut statements = ~[];
for struct_def.fields.each |struct_field| {
match struct_field.node.kind {
named_field(ident, _, _) => {
// Create the accessor for this field.
let self_field = build::mk_access(
cx,
span,
~[self_ident],
ident
);
// Call the substructure method.
let encode_expr = call_substructure_encode_method(
cx,
span,
self_field
);
let blk_expr = build::mk_lambda(
cx,
span,
build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
encode_expr
);
let call_expr = build::mk_method_call(
cx,
span,
build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
cx.ident_of(~"emit_struct_field"),
~[
build::mk_base_str(cx, span, cx.str_of(ident)),
build::mk_uint(cx, span, idx),
blk_expr
]
);
statements.push(build::mk_stmt(cx, span, call_expr));
}
unnamed_field => {
cx.span_unimpl(
span,
~"unnamed fields with `deriving(Encodable)`"
);
}
}
idx += 1;
}
let emit_struct_stmt = build::mk_method_call(
cx,
span,
build::mk_path(
cx,
span,
~[cx.ident_of(~"__e")]
),
cx.ident_of(~"emit_struct"),
~[
build::mk_base_str(cx, span, cx.str_of(type_ident)),
build::mk_uint(cx, span, statements.len()),
build::mk_lambda_stmts(
cx,
span,
build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
statements
),
]
);
let statements = ~[build::mk_stmt(cx, span, emit_struct_stmt)];
// Create the method itself.
return create_encode_method(cx, span, statements);
}
fn expand_deriving_encodable_enum_method(
cx: @ext_ctxt,
span: span,
type_ident: ast::ident,
enum_definition: &enum_def
) -> @method {
// Create the arms of the match in the method body.
let arms = do enum_definition.variants.mapi |i, variant| {
// Create the matching pattern.
let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
// Feed the discriminant to the encode function.
let mut stmts = ~[];
// Feed each argument in this variant to the encode function
// as well.
let variant_arg_len = variant_arg_count(cx, span, variant);
for uint::range(0, variant_arg_len) |j| {
// Create the expression for this field.
let field_ident = cx.ident_of(~"__self" + j.to_str());
let field = build::mk_path(cx, span, ~[ field_ident ]);
// Call the substructure method.
let expr = call_substructure_encode_method(cx, span, field);
let blk_expr = build::mk_lambda(
cx,
span,
build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
expr
);
let call_expr = build::mk_method_call(
cx,
span,
build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
cx.ident_of(~"emit_enum_variant_arg"),
~[
build::mk_uint(cx, span, j),
blk_expr,
]
);
stmts.push(build::mk_stmt(cx, span, call_expr));
}
// Create the pattern body.
let call_expr = build::mk_method_call(
cx,
span,
build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
cx.ident_of(~"emit_enum_variant"),
~[
build::mk_base_str(cx, span, cx.str_of(variant.node.name)),
build::mk_uint(cx, span, i),
build::mk_uint(cx, span, variant_arg_len),
build::mk_lambda_stmts(
cx,
span,
build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
stmts
)
]
);
let match_body_block = build::mk_simple_block(cx, span, call_expr);
// Create the arm.
ast::arm {
pats: ~[pat],
guard: None,
body: match_body_block,
}
};
// Create the method body.
let lambda_expr = build::mk_lambda(
cx,
span,
build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
expand_enum_or_struct_match(cx, span, arms)
);
let call_expr = build::mk_method_call(
cx,
span,
build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
cx.ident_of(~"emit_enum"),
~[
build::mk_base_str(cx, span, cx.str_of(type_ident)),
lambda_expr,
]
);
let stmt = build::mk_stmt(cx, span, call_expr);
// Create the method.
create_encode_method(cx, span, ~[stmt])
}

View file

@ -17,6 +17,7 @@ use ext::build;
use ext::deriving::*;
use codemap::{span, spanned};
use ast_util;
use opt_vec;
use core::uint;
@ -124,12 +125,13 @@ fn create_derived_eq_impl(cx: @ext_ctxt,
ne_method: @method)
-> @item {
let methods = [ eq_method, ne_method ];
let trait_path = [
let trait_path = ~[
cx.ident_of(~"core"),
cx.ident_of(~"cmp"),
cx.ident_of(~"Eq")
];
create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
let trait_path = build::mk_raw_path_global(span, trait_path);
create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty)
}
fn call_substructure_eq_method(cx: @ext_ctxt,
@ -289,7 +291,7 @@ fn expand_deriving_eq_struct_method(cx: @ext_ctxt,
&mut outer_expr);
}
unnamed_field => {
cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`");
cx.span_unimpl(span, ~"unnamed fields with `deriving(Eq)`");
}
}
}

View file

@ -17,6 +17,7 @@ use ext::build;
use ext::deriving::*;
use codemap::{span, spanned};
use ast_util;
use opt_vec;
use core::uint;
@ -49,12 +50,13 @@ fn create_derived_iter_bytes_impl(cx: @ext_ctxt,
method: @method)
-> @item {
let methods = [ method ];
let trait_path = [
let trait_path = ~[
cx.ident_of(~"core"),
cx.ident_of(~"to_bytes"),
cx.ident_of(~"IterBytes")
];
create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
let trait_path = build::mk_raw_path_global(span, trait_path);
create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty)
}
// Creates a method from the given set of statements conforming to the
@ -191,7 +193,7 @@ fn expand_deriving_iter_bytes_struct_method(cx: @ext_ctxt,
}
unnamed_field => {
cx.span_unimpl(span,
~"unnamed fields with `deriving_iter_bytes`");
~"unnamed fields with `deriving(IterBytes)`");
}
}
}

View file

@ -14,7 +14,7 @@
use core::prelude::*;
use ast;
use ast::{TraitTyParamBound, Ty, bind_by_ref, deref, enum_def};
use ast::{Ty, bind_by_ref, deref, enum_def};
use ast::{expr, expr_match, ident, item, item_};
use ast::{item_enum, item_impl, item_struct, Generics};
use ast::{m_imm, meta_item, method};
@ -33,6 +33,8 @@ use core::uint;
pub mod clone;
pub mod eq;
pub mod iter_bytes;
pub mod encodable;
pub mod decodable;
type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt,
span,
@ -76,6 +78,10 @@ pub fn expand_meta_deriving(cx: @ext_ctxt,
titem, in_items),
~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx,
titem.span, titem, in_items),
~"Encodable" => encodable::expand_deriving_encodable(cx,
titem.span, titem, in_items),
~"Decodable" => decodable::expand_deriving_decodable(cx,
titem.span, titem, in_items),
tname => {
cx.span_err(titem.span, fmt!("unknown \
`deriving` trait: `%s`", tname));
@ -153,12 +159,13 @@ pub fn create_self_type_with_params(cx: @ext_ctxt,
}
pub fn create_derived_impl(cx: @ext_ctxt,
span: span,
type_ident: ident,
generics: &Generics,
methods: &[@method],
trait_path: &[ident])
-> @item {
span: span,
type_ident: ident,
generics: &Generics,
methods: &[@method],
trait_path: @ast::Path,
mut impl_ty_params: opt_vec::OptVec<ast::TyParam>)
-> @item {
/*!
*
* Given that we are deriving a trait `Tr` for a type `T<'a, ...,
@ -175,29 +182,16 @@ pub fn create_derived_impl(cx: @ext_ctxt,
build::mk_lifetime(cx, l.span, l.ident)
});
// Create the type parameters.
let impl_ty_params = generics.ty_params.map(|ty_param| {
let bound = build::mk_trait_ref_global(cx,
span,
trait_path.map(|x| *x));
let bounds = @opt_vec::with(TraitTyParamBound(bound));
build::mk_ty_param(cx, ty_param.ident, bounds)
});
// Create the reference to the trait.
let trait_path = ast::Path {
span: span,
global: true,
idents: trait_path.map(|x| *x),
rp: None,
types: ~[]
let trait_ref = build::mk_trait_ref_(cx, trait_path);
// Create the type parameters.
for generics.ty_params.each |ty_param| {
let bounds = @opt_vec::with(
build::mk_trait_ty_param_bound_(cx, trait_path)
);
impl_ty_params.push(build::mk_ty_param(cx, ty_param.ident, bounds));
};
let trait_path = @trait_path;
let trait_ref = ast::trait_ref {
path: trait_path,
ref_id: cx.next_id()
};
let trait_ref = @trait_ref;
// Create the type of `self`.
let self_type = create_self_type_with_params(cx,

View file

@ -95,7 +95,6 @@ pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps {
}
pub static indent_unit: uint = 4u;
pub static match_indent_unit: uint = 2u;
pub static default_columns: uint = 78u;
@ -1227,16 +1226,16 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
print_block(s, blk);
}
ast::expr_match(expr, ref arms) => {
cbox(s, match_indent_unit);
cbox(s, indent_unit);
ibox(s, 4);
word_nbsp(s, ~"match");
print_expr(s, expr);
space(s.s);
bopen(s);
let len = (*arms).len();
for (*arms).eachi |i, arm| {
let len = arms.len();
for arms.eachi |i, arm| {
space(s.s);
cbox(s, match_indent_unit);
cbox(s, indent_unit);
ibox(s, 0u);
let mut first = true;
for arm.pats.each |p| {
@ -1269,7 +1268,7 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
ast::expr_block(ref blk) => {
// the block will close the pattern's ibox
print_block_unclosed_indent(
s, blk, match_indent_unit);
s, blk, indent_unit);
}
_ => {
end(s); // close the ibox for the pattern
@ -1286,10 +1285,10 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
}
} else {
// the block will close the pattern's ibox
print_block_unclosed_indent(s, &arm.body, match_indent_unit);
print_block_unclosed_indent(s, &arm.body, indent_unit);
}
}
bclose_(s, expr.span, match_indent_unit);
bclose_(s, expr.span, indent_unit);
}
ast::expr_fn_block(ref decl, ref body) => {
// in do/for blocks we don't want to show an empty