auto merge of #6267 : huonw/rust/syntax-deriving-generaliseder, r=nikomatsakis
This "finishes" the generic deriving code (which I started in #5640), in the sense it supports everything that I can think of being useful. (Including lifetimes and type parameters on methods and traits, arguments and return values of (almost) any type, static methods.) It closes #6149, but met with #6257, so the following doesn't work: ```rust #[deriving(TotalEq)] struct Foo<'self>(&'self int); ``` (It only fails for `TotalOrd`, `TotalEq` and `Clone`, since they are the only ones that call a method directly on sub-elements of the type, which means that the auto-deref interferes with the pointer.) It also makes `Rand` (chooses a random variant, fills the fields with random values, including recursively for recursive types) and `ToStr` (`x.to_str()` is the same as `fmt!("%?", x)`) derivable, as well as converting IterBytes to the generic code (which made the code 2.5x shorter, more robust and added support for tuple structs). ({En,De}codable are trickier, so I'll convert them over later.)
This commit is contained in:
commit
8f94ac6118
@ -54,43 +54,52 @@ pub fn mk_binary(cx: @ext_ctxt, sp: span, op: ast::binop,
|
||||
cx.next_id(); // see ast_util::op_expr_callee_id
|
||||
mk_expr(cx, sp, ast::expr_binary(op, lhs, rhs))
|
||||
}
|
||||
|
||||
pub fn mk_deref(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
|
||||
mk_unary(cx, sp, ast::deref, e)
|
||||
}
|
||||
pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr)
|
||||
-> @ast::expr {
|
||||
cx.next_id(); // see ast_util::op_expr_callee_id
|
||||
mk_expr(cx, sp, ast::expr_unary(op, e))
|
||||
}
|
||||
pub fn mk_raw_path(sp: span, idents: ~[ast::ident]) -> @ast::Path {
|
||||
mk_raw_path_(sp, idents, ~[])
|
||||
mk_raw_path_(sp, idents, None, ~[])
|
||||
}
|
||||
pub fn mk_raw_path_(sp: span,
|
||||
idents: ~[ast::ident],
|
||||
rp: Option<@ast::Lifetime>,
|
||||
types: ~[@ast::Ty])
|
||||
-> @ast::Path {
|
||||
@ast::Path { span: sp,
|
||||
global: false,
|
||||
idents: idents,
|
||||
rp: None,
|
||||
rp: rp,
|
||||
types: types }
|
||||
}
|
||||
pub fn mk_raw_path_global(sp: span, idents: ~[ast::ident]) -> @ast::Path {
|
||||
mk_raw_path_global_(sp, idents, ~[])
|
||||
mk_raw_path_global_(sp, idents, None, ~[])
|
||||
}
|
||||
pub fn mk_raw_path_global_(sp: span,
|
||||
idents: ~[ast::ident],
|
||||
rp: Option<@ast::Lifetime>,
|
||||
types: ~[@ast::Ty]) -> @ast::Path {
|
||||
@ast::Path { span: sp,
|
||||
global: true,
|
||||
idents: idents,
|
||||
rp: None,
|
||||
rp: rp,
|
||||
types: types }
|
||||
}
|
||||
pub fn mk_path_raw(cx: @ext_ctxt, sp: span, path: @ast::Path)-> @ast::expr {
|
||||
mk_expr(cx, sp, ast::expr_path(path))
|
||||
}
|
||||
pub fn mk_path(cx: @ext_ctxt, sp: span, idents: ~[ast::ident])
|
||||
-> @ast::expr {
|
||||
mk_expr(cx, sp, ast::expr_path(mk_raw_path(sp, idents)))
|
||||
mk_path_raw(cx, sp, mk_raw_path(sp, idents))
|
||||
}
|
||||
pub fn mk_path_global(cx: @ext_ctxt, sp: span, idents: ~[ast::ident])
|
||||
-> @ast::expr {
|
||||
mk_expr(cx, sp, ast::expr_path(mk_raw_path_global(sp, idents)))
|
||||
mk_path_raw(cx, sp, mk_raw_path_global(sp, idents))
|
||||
}
|
||||
pub fn mk_access_(cx: @ext_ctxt, sp: span, p: @ast::expr, m: ast::ident)
|
||||
-> @ast::expr {
|
||||
@ -354,44 +363,69 @@ pub fn mk_stmt(cx: @ext_ctxt, span: span, expr: @ast::expr) -> @ast::stmt {
|
||||
let stmt_ = ast::stmt_semi(expr, cx.next_id());
|
||||
@codemap::spanned { node: stmt_, span: span }
|
||||
}
|
||||
|
||||
pub fn mk_ty_mt(ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt {
|
||||
ast::mt {
|
||||
ty: ty,
|
||||
mutbl: mutbl
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_ty(cx: @ext_ctxt,
|
||||
span: span,
|
||||
ty: ast::ty_) -> @ast::Ty {
|
||||
@ast::Ty {
|
||||
id: cx.next_id(),
|
||||
span: span,
|
||||
node: ty
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_ty_path(cx: @ext_ctxt,
|
||||
span: span,
|
||||
idents: ~[ ast::ident ])
|
||||
-> @ast::Ty {
|
||||
let ty = build::mk_raw_path(span, idents);
|
||||
let ty = ast::ty_path(ty, cx.next_id());
|
||||
let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
|
||||
ty
|
||||
mk_ty_path_path(cx, span, ty)
|
||||
}
|
||||
|
||||
pub fn mk_ty_path_global(cx: @ext_ctxt,
|
||||
span: span,
|
||||
idents: ~[ ast::ident ])
|
||||
-> @ast::Ty {
|
||||
let ty = build::mk_raw_path_global(span, idents);
|
||||
let ty = ast::ty_path(ty, cx.next_id());
|
||||
let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
|
||||
ty
|
||||
mk_ty_path_path(cx, span, ty)
|
||||
}
|
||||
|
||||
pub fn mk_ty_path_path(cx: @ext_ctxt,
|
||||
span: span,
|
||||
path: @ast::Path)
|
||||
-> @ast::Ty {
|
||||
let ty = ast::ty_path(path, cx.next_id());
|
||||
mk_ty(cx, span, ty)
|
||||
}
|
||||
|
||||
pub fn mk_ty_rptr(cx: @ext_ctxt,
|
||||
span: span,
|
||||
ty: @ast::Ty,
|
||||
lifetime: Option<@ast::Lifetime>,
|
||||
mutbl: ast::mutability)
|
||||
-> @ast::Ty {
|
||||
@ast::Ty {
|
||||
id: cx.next_id(),
|
||||
span: span,
|
||||
node: ast::ty_rptr(
|
||||
None,
|
||||
ast::mt { ty: ty, mutbl: mutbl }
|
||||
),
|
||||
mk_ty(cx, span,
|
||||
ast::ty_rptr(lifetime, mk_ty_mt(ty, mutbl)))
|
||||
}
|
||||
pub fn mk_ty_uniq(cx: @ext_ctxt, span: span, ty: @ast::Ty) -> @ast::Ty {
|
||||
mk_ty(cx, span, ast::ty_uniq(mk_ty_mt(ty, ast::m_imm)))
|
||||
}
|
||||
pub fn mk_ty_box(cx: @ext_ctxt, span: span,
|
||||
ty: @ast::Ty, mutbl: ast::mutability) -> @ast::Ty {
|
||||
mk_ty(cx, span, ast::ty_box(mk_ty_mt(ty, 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,
|
||||
}
|
||||
mk_ty(cx, span, ast::ty_infer)
|
||||
}
|
||||
pub fn mk_trait_ref_global(cx: @ext_ctxt,
|
||||
span: span,
|
||||
|
@ -13,7 +13,6 @@ use codemap::span;
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
use core::option::{None,Some};
|
||||
|
||||
|
||||
pub fn expand_deriving_clone(cx: @ext_ctxt,
|
||||
@ -22,13 +21,16 @@ pub fn expand_deriving_clone(cx: @ext_ctxt,
|
||||
in_items: ~[@item])
|
||||
-> ~[@item] {
|
||||
let trait_def = TraitDef {
|
||||
path: ~[~"core", ~"clone", ~"Clone"],
|
||||
path: Path::new(~[~"core", ~"clone", ~"Clone"]),
|
||||
additional_bounds: ~[],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"clone",
|
||||
nargs: 0,
|
||||
output_type: None, // return Self
|
||||
generics: LifetimeBounds::empty(),
|
||||
self_ty: borrowed_explicit_self(),
|
||||
args: ~[],
|
||||
ret_ty: Self,
|
||||
const_nonmatching: false,
|
||||
combine_substructure: cs_clone
|
||||
}
|
||||
@ -66,7 +68,8 @@ fn cs_clone(cx: @ext_ctxt, span: span,
|
||||
ctor_ident = ~[ variant.node.name ];
|
||||
all_fields = af;
|
||||
},
|
||||
EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`")
|
||||
EnumNonMatching(*) => cx.span_bug(span, "Non-matching enum variants in `deriving(Clone)`"),
|
||||
StaticEnum(*) | StaticStruct(*) => cx.span_bug(span, "Static method in `deriving(Clone)`")
|
||||
}
|
||||
|
||||
match all_fields {
|
||||
|
@ -8,15 +8,12 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use ast::{meta_item, item, expr};
|
||||
use codemap::span;
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
|
||||
use core::option::Some;
|
||||
|
||||
pub fn expand_deriving_eq(cx: @ext_ctxt,
|
||||
span: span,
|
||||
mitem: @meta_item,
|
||||
@ -24,28 +21,32 @@ pub fn expand_deriving_eq(cx: @ext_ctxt,
|
||||
// structures are equal if all fields are equal, and non equal, if
|
||||
// any fields are not equal or if the enum variants are different
|
||||
fn cs_eq(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
|
||||
cs_and(|cx, span, _| build::mk_bool(cx, span, false),
|
||||
cs_and(|cx, span, _, _| build::mk_bool(cx, span, false),
|
||||
cx, span, substr)
|
||||
}
|
||||
fn cs_ne(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
|
||||
cs_or(|cx, span, _| build::mk_bool(cx, span, true),
|
||||
cs_or(|cx, span, _, _| build::mk_bool(cx, span, true),
|
||||
cx, span, substr)
|
||||
}
|
||||
|
||||
macro_rules! md (
|
||||
($name:expr, $f:ident) => {
|
||||
MethodDef {
|
||||
name: $name,
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
generics: LifetimeBounds::empty(),
|
||||
self_ty: borrowed_explicit_self(),
|
||||
args: ~[borrowed_self()],
|
||||
ret_ty: Literal(Path::new(~[~"bool"])),
|
||||
const_nonmatching: true,
|
||||
combine_substructure: $f
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
let trait_def = TraitDef {
|
||||
path: ~[~"core", ~"cmp", ~"Eq"],
|
||||
path: Path::new(~[~"core", ~"cmp", ~"Eq"]),
|
||||
additional_bounds: ~[],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
md!(~"eq", cs_eq),
|
||||
md!(~"ne", cs_ne)
|
||||
|
@ -14,29 +14,33 @@ use codemap::span;
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
use core::option::Some;
|
||||
|
||||
macro_rules! md {
|
||||
($name:expr, $less:expr, $equal:expr) => {
|
||||
MethodDef {
|
||||
name: $name,
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
const_nonmatching: false,
|
||||
combine_substructure: |cx, span, substr|
|
||||
cs_ord($less, $equal, cx, span, substr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_deriving_ord(cx: @ext_ctxt,
|
||||
span: span,
|
||||
mitem: @meta_item,
|
||||
in_items: ~[@item]) -> ~[@item] {
|
||||
macro_rules! md (
|
||||
($name:expr, $less:expr, $equal:expr) => {
|
||||
MethodDef {
|
||||
name: $name,
|
||||
generics: LifetimeBounds::empty(),
|
||||
self_ty: borrowed_explicit_self(),
|
||||
args: ~[borrowed_self()],
|
||||
ret_ty: Literal(Path::new(~[~"bool"])),
|
||||
const_nonmatching: false,
|
||||
combine_substructure: |cx, span, substr|
|
||||
cs_ord($less, $equal, cx, span, substr)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
let trait_def = TraitDef {
|
||||
path: ~[~"core", ~"cmp", ~"Ord"],
|
||||
path: Path::new(~[~"core", ~"cmp", ~"Ord"]),
|
||||
// XXX: Ord doesn't imply Eq yet
|
||||
additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]],
|
||||
additional_bounds: ~[Literal(Path::new(~[~"core", ~"cmp", ~"Eq"]))],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
md!(~"lt", true, false),
|
||||
md!(~"le", true, true),
|
||||
@ -97,19 +101,19 @@ fn cs_ord(less: bool, equal: bool,
|
||||
}
|
||||
|
||||
let cmp = build::mk_method_call(cx, span,
|
||||
self_f, cx.ident_of(~"eq"), other_fs);
|
||||
self_f, cx.ident_of(~"eq"), other_fs.to_owned());
|
||||
let subexpr = build::mk_simple_block(cx, span, subexpr);
|
||||
let elseif = expr_if(cmp, subexpr, Some(false_blk_expr));
|
||||
let elseif = build::mk_expr(cx, span, elseif);
|
||||
|
||||
let cmp = build::mk_method_call(cx, span,
|
||||
self_f, binop, other_fs);
|
||||
self_f, binop, other_fs.to_owned());
|
||||
let if_ = expr_if(cmp, true_blk, Some(elseif));
|
||||
|
||||
build::mk_expr(cx, span, if_)
|
||||
},
|
||||
base,
|
||||
|cx, span, args| {
|
||||
|cx, span, args, _| {
|
||||
// nonmatching enums, order by the order the variants are
|
||||
// written
|
||||
match args {
|
||||
|
@ -15,26 +15,27 @@ use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
|
||||
use core::option::Some;
|
||||
|
||||
pub fn expand_deriving_totaleq(cx: @ext_ctxt,
|
||||
span: span,
|
||||
mitem: @meta_item,
|
||||
in_items: ~[@item]) -> ~[@item] {
|
||||
|
||||
fn cs_equals(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
|
||||
cs_and(|cx, span, _| build::mk_bool(cx, span, false),
|
||||
cs_and(|cx, span, _, _| build::mk_bool(cx, span, false),
|
||||
cx, span, substr)
|
||||
}
|
||||
|
||||
let trait_def = TraitDef {
|
||||
path: ~[~"core", ~"cmp", ~"TotalEq"],
|
||||
path: Path::new(~[~"core", ~"cmp", ~"TotalEq"]),
|
||||
additional_bounds: ~[],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"equals",
|
||||
output_type: Some(~[~"bool"]),
|
||||
nargs: 1,
|
||||
generics: LifetimeBounds::empty(),
|
||||
self_ty: borrowed_explicit_self(),
|
||||
args: ~[borrowed_self()],
|
||||
ret_ty: Literal(Path::new(~[~"bool"])),
|
||||
const_nonmatching: true,
|
||||
combine_substructure: cs_equals
|
||||
}
|
||||
|
@ -14,20 +14,22 @@ use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
use core::cmp::{Ordering, Equal, Less, Greater};
|
||||
use core::option::Some;
|
||||
|
||||
pub fn expand_deriving_totalord(cx: @ext_ctxt,
|
||||
span: span,
|
||||
mitem: @meta_item,
|
||||
in_items: ~[@item]) -> ~[@item] {
|
||||
let trait_def = TraitDef {
|
||||
path: ~[~"core", ~"cmp", ~"TotalOrd"],
|
||||
path: Path::new(~[~"core", ~"cmp", ~"TotalOrd"]),
|
||||
additional_bounds: ~[],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"cmp",
|
||||
output_type: Some(~[~"core", ~"cmp", ~"Ordering"]),
|
||||
nargs: 1,
|
||||
generics: LifetimeBounds::empty(),
|
||||
self_ty: borrowed_explicit_self(),
|
||||
args: ~[borrowed_self()],
|
||||
ret_ty: Literal(Path::new(~[~"core", ~"cmp", ~"Ordering"])),
|
||||
const_nonmatching: false,
|
||||
combine_substructure: cs_cmp
|
||||
}
|
||||
@ -64,7 +66,7 @@ pub fn cs_cmp(cx: @ext_ctxt, span: span,
|
||||
build::mk_call_global(cx, span, lexical_ord, ~[old, new])
|
||||
},
|
||||
ordering_const(cx, span, Equal),
|
||||
|cx, span, list| {
|
||||
|cx, span, list, _| {
|
||||
match list {
|
||||
// an earlier nonmatching variant is Less than a
|
||||
// later one
|
||||
|
@ -66,6 +66,7 @@ fn create_derived_decodable_impl(
|
||||
cx.ident_of(~"serialize"),
|
||||
cx.ident_of(~"Decodable")
|
||||
],
|
||||
None,
|
||||
~[
|
||||
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D"))
|
||||
]
|
||||
@ -77,7 +78,7 @@ fn create_derived_decodable_impl(
|
||||
generics,
|
||||
methods,
|
||||
trait_path,
|
||||
generic_ty_params,
|
||||
Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty },
|
||||
opt_vec::Empty
|
||||
)
|
||||
}
|
||||
@ -96,6 +97,7 @@ fn create_decode_method(
|
||||
cx,
|
||||
span,
|
||||
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")),
|
||||
None,
|
||||
ast::m_mutbl
|
||||
);
|
||||
let d_ident = cx.ident_of(~"__d");
|
||||
|
@ -66,6 +66,7 @@ fn create_derived_encodable_impl(
|
||||
cx.ident_of(~"serialize"),
|
||||
cx.ident_of(~"Encodable")
|
||||
],
|
||||
None,
|
||||
~[
|
||||
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E"))
|
||||
]
|
||||
@ -77,7 +78,7 @@ fn create_derived_encodable_impl(
|
||||
generics,
|
||||
methods,
|
||||
trait_path,
|
||||
generic_ty_params,
|
||||
Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty },
|
||||
opt_vec::Empty
|
||||
)
|
||||
}
|
||||
@ -94,6 +95,7 @@ fn create_encode_method(
|
||||
cx,
|
||||
span,
|
||||
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")),
|
||||
None,
|
||||
ast::m_mutbl
|
||||
);
|
||||
let e_arg = build::mk_arg(cx, span, cx.ident_of(~"__e"), e_arg_type);
|
||||
@ -303,7 +305,7 @@ fn expand_deriving_encodable_enum_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");
|
||||
let (pat, fields) = create_enum_variant_pattern(cx, span, variant, ~"__self", ast::m_imm);
|
||||
|
||||
// Feed the discriminant to the encode function.
|
||||
let mut stmts = ~[];
|
||||
@ -311,11 +313,7 @@ fn expand_deriving_encodable_enum_method(
|
||||
// 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 ]);
|
||||
|
||||
for fields.eachi |j, &(_, field)| {
|
||||
// Call the substructure method.
|
||||
let expr = call_substructure_encode_method(cx, span, field);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,25 +8,37 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ast;
|
||||
use ast::*;
|
||||
use ast::{meta_item, item, expr};
|
||||
use codemap::span;
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::*;
|
||||
use codemap::{span, spanned};
|
||||
use ast_util;
|
||||
use opt_vec;
|
||||
use ext::deriving::generic::*;
|
||||
|
||||
pub fn expand_deriving_iter_bytes(cx: @ext_ctxt,
|
||||
span: span,
|
||||
_mitem: @meta_item,
|
||||
in_items: ~[@item])
|
||||
-> ~[@item] {
|
||||
expand_deriving(cx,
|
||||
span,
|
||||
in_items,
|
||||
expand_deriving_iter_bytes_struct_def,
|
||||
expand_deriving_iter_bytes_enum_def)
|
||||
mitem: @meta_item,
|
||||
in_items: ~[@item]) -> ~[@item] {
|
||||
let trait_def = TraitDef {
|
||||
path: Path::new(~[~"core", ~"to_bytes", ~"IterBytes"]),
|
||||
additional_bounds: ~[],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"iter_bytes",
|
||||
generics: LifetimeBounds::empty(),
|
||||
self_ty: borrowed_explicit_self(),
|
||||
args: ~[
|
||||
Literal(Path::new(~[~"bool"])),
|
||||
Literal(Path::new(~[~"core", ~"to_bytes", ~"Cb"]))
|
||||
],
|
||||
ret_ty: nil_ty(),
|
||||
const_nonmatching: false,
|
||||
combine_substructure: iter_bytes_substructure
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expand_deriving_generic(cx, span, mitem, in_items, &trait_def)
|
||||
}
|
||||
|
||||
pub fn expand_deriving_obsolete(cx: @ext_ctxt,
|
||||
@ -39,217 +51,43 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt,
|
||||
in_items
|
||||
}
|
||||
|
||||
fn create_derived_iter_bytes_impl(cx: @ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
generics: &Generics,
|
||||
method: @method)
|
||||
-> @item {
|
||||
let methods = [ method ];
|
||||
let trait_path = ~[
|
||||
cx.ident_of(~"core"),
|
||||
cx.ident_of(~"to_bytes"),
|
||||
cx.ident_of(~"IterBytes")
|
||||
];
|
||||
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, opt_vec::Empty)
|
||||
fn iter_bytes_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
|
||||
let lsb0_f = match substr.nonself_args {
|
||||
[l, f] => ~[l, f],
|
||||
_ => cx.span_bug(span, "Incorrect number of arguments in `deriving(IterBytes)`")
|
||||
};
|
||||
let iter_bytes_ident = substr.method_ident;
|
||||
let call_iterbytes = |thing_expr| {
|
||||
build::mk_stmt(
|
||||
cx, span,
|
||||
build::mk_method_call(cx, span,
|
||||
thing_expr, iter_bytes_ident,
|
||||
copy lsb0_f))
|
||||
};
|
||||
let mut stmts = ~[];
|
||||
let fields;
|
||||
match *substr.fields {
|
||||
Struct(ref fs) => {
|
||||
fields = fs
|
||||
}
|
||||
|
||||
// Creates a method from the given set of statements conforming to the
|
||||
// signature of the `iter_bytes` method.
|
||||
fn create_iter_bytes_method(cx: @ext_ctxt,
|
||||
span: span,
|
||||
statements: ~[@stmt])
|
||||
-> @method {
|
||||
// Create the `lsb0` parameter.
|
||||
let bool_ident = cx.ident_of(~"bool");
|
||||
let lsb0_arg_type = build::mk_simple_ty_path(cx, span, bool_ident);
|
||||
let lsb0_ident = cx.ident_of(~"__lsb0");
|
||||
let lsb0_arg = build::mk_arg(cx, span, lsb0_ident, lsb0_arg_type);
|
||||
|
||||
// Create the `f` parameter.
|
||||
let core_ident = cx.ident_of(~"core");
|
||||
let to_bytes_ident = cx.ident_of(~"to_bytes");
|
||||
let cb_ident = cx.ident_of(~"Cb");
|
||||
let core_to_bytes_cb_ident = ~[ core_ident, to_bytes_ident, cb_ident ];
|
||||
let f_arg_type = build::mk_ty_path(cx, span, core_to_bytes_cb_ident);
|
||||
let f_ident = cx.ident_of(~"__f");
|
||||
let f_arg = build::mk_arg(cx, span, f_ident, f_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 = ~[ lsb0_arg, f_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(~"iter_bytes");
|
||||
@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_iter_bytes_method(cx: @ext_ctxt,
|
||||
span: span,
|
||||
self_field: @expr)
|
||||
-> @stmt {
|
||||
// Gather up the parameters we want to chain along.
|
||||
let lsb0_ident = cx.ident_of(~"__lsb0");
|
||||
let f_ident = cx.ident_of(~"__f");
|
||||
let lsb0_expr = build::mk_path(cx, span, ~[ lsb0_ident ]);
|
||||
let f_expr = build::mk_path(cx, span, ~[ f_ident ]);
|
||||
|
||||
// Call the substructure method.
|
||||
let iter_bytes_ident = cx.ident_of(~"iter_bytes");
|
||||
let self_call = build::mk_method_call(cx,
|
||||
span,
|
||||
self_field,
|
||||
iter_bytes_ident,
|
||||
~[ lsb0_expr, f_expr ]);
|
||||
|
||||
// Create a statement out of this expression.
|
||||
build::mk_stmt(cx, span, self_call)
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_struct_def(cx: @ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
type_ident: ident,
|
||||
generics: &Generics)
|
||||
-> @item {
|
||||
// Create the method.
|
||||
let method = expand_deriving_iter_bytes_struct_method(cx,
|
||||
span,
|
||||
struct_def);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_iter_bytes_impl(cx,
|
||||
span,
|
||||
type_ident,
|
||||
generics,
|
||||
method);
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_enum_def(cx: @ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
type_ident: ident,
|
||||
generics: &Generics)
|
||||
-> @item {
|
||||
// Create the method.
|
||||
let method = expand_deriving_iter_bytes_enum_method(cx,
|
||||
span,
|
||||
enum_definition);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_iter_bytes_impl(cx,
|
||||
span,
|
||||
type_ident,
|
||||
generics,
|
||||
method);
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_struct_method(cx: @ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def)
|
||||
-> @method {
|
||||
let self_ident = cx.ident_of(~"self");
|
||||
|
||||
// Create the body of the method.
|
||||
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 stmt = call_substructure_iter_bytes_method(cx,
|
||||
span,
|
||||
self_field);
|
||||
statements.push(stmt);
|
||||
}
|
||||
unnamed_field => {
|
||||
cx.span_unimpl(span,
|
||||
~"unnamed fields with `deriving(IterBytes)`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the method itself.
|
||||
return create_iter_bytes_method(cx, span, statements);
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_enum_method(cx: @ext_ctxt,
|
||||
span: span,
|
||||
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");
|
||||
|
||||
EnumMatching(copy index, ref variant, ref fs) => {
|
||||
// Determine the discriminant. We will feed this value to the byte
|
||||
// iteration function.
|
||||
let discriminant;
|
||||
match variant.node.disr_expr {
|
||||
Some(copy disr_expr) => discriminant = disr_expr,
|
||||
None => discriminant = build::mk_uint(cx, span, i),
|
||||
}
|
||||
|
||||
// Feed the discriminant to the byte iteration function.
|
||||
let mut stmts = ~[];
|
||||
let discrim_stmt = call_substructure_iter_bytes_method(cx,
|
||||
span,
|
||||
discriminant);
|
||||
stmts.push(discrim_stmt);
|
||||
|
||||
// Feed each argument in this variant to the byte iteration function
|
||||
// as well.
|
||||
for uint::range(0, variant_arg_count(cx, span, variant)) |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 stmt = call_substructure_iter_bytes_method(cx, span, field);
|
||||
stmts.push(stmt);
|
||||
}
|
||||
|
||||
// Create the pattern body.
|
||||
let match_body_block = build::mk_block_(cx, span, stmts);
|
||||
|
||||
// Create the arm.
|
||||
ast::arm {
|
||||
pats: ~[ pat ],
|
||||
guard: None,
|
||||
body: match_body_block,
|
||||
}
|
||||
let discriminant = match variant.node.disr_expr {
|
||||
Some(copy d)=> d,
|
||||
None => build::mk_uint(cx, span, index)
|
||||
};
|
||||
|
||||
// Create the method body.
|
||||
let self_match_expr = expand_enum_or_struct_match(cx, span, arms);
|
||||
let self_match_stmt = build::mk_stmt(cx, span, self_match_expr);
|
||||
stmts.push(call_iterbytes(discriminant));
|
||||
|
||||
// Create the method.
|
||||
create_iter_bytes_method(cx, span, ~[ self_match_stmt ])
|
||||
fields = fs;
|
||||
}
|
||||
_ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`")
|
||||
}
|
||||
|
||||
for fields.each |&(_, field, _)| {
|
||||
stmts.push(call_iterbytes(field));
|
||||
}
|
||||
|
||||
build::mk_block(cx, span, ~[], stmts, None)
|
||||
}
|
@ -12,14 +12,7 @@
|
||||
/// #[deriving(IterBytes)] extensions.
|
||||
|
||||
use ast;
|
||||
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};
|
||||
use ast::{named_field, pat, pat_ident, public};
|
||||
use ast::{struct_def, struct_variant_kind};
|
||||
use ast::{tuple_variant_kind};
|
||||
use ast::{ty_path, unnamed_field, variant};
|
||||
use ast::{Ty, enum_def, expr, ident, item, Generics, meta_item, struct_def};
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use codemap::{span, respan};
|
||||
@ -30,6 +23,8 @@ pub mod clone;
|
||||
pub mod iter_bytes;
|
||||
pub mod encodable;
|
||||
pub mod decodable;
|
||||
pub mod rand;
|
||||
pub mod to_str;
|
||||
|
||||
#[path="cmp/eq.rs"]
|
||||
pub mod eq;
|
||||
@ -78,23 +73,25 @@ pub fn expand_meta_deriving(cx: @ext_ctxt,
|
||||
meta_name_value(tname, _) |
|
||||
meta_list(tname, _) |
|
||||
meta_word(tname) => {
|
||||
macro_rules! expand(($func:path) => ($func(cx, titem.span,
|
||||
titem, in_items)));
|
||||
match *tname {
|
||||
~"Clone" => clone::expand_deriving_clone(cx,
|
||||
titem.span, 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),
|
||||
~"Eq" => eq::expand_deriving_eq(cx, titem.span,
|
||||
titem, in_items),
|
||||
~"TotalEq" => totaleq::expand_deriving_totaleq(cx, titem.span,
|
||||
titem, in_items),
|
||||
~"Ord" => ord::expand_deriving_ord(cx, titem.span,
|
||||
titem, in_items),
|
||||
~"TotalOrd" => totalord::expand_deriving_totalord(cx, titem.span,
|
||||
titem, in_items),
|
||||
~"Clone" => expand!(clone::expand_deriving_clone),
|
||||
|
||||
~"IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes),
|
||||
|
||||
~"Encodable" => expand!(encodable::expand_deriving_encodable),
|
||||
~"Decodable" => expand!(decodable::expand_deriving_decodable),
|
||||
|
||||
~"Eq" => expand!(eq::expand_deriving_eq),
|
||||
~"TotalEq" => expand!(totaleq::expand_deriving_totaleq),
|
||||
~"Ord" => expand!(ord::expand_deriving_ord),
|
||||
~"TotalOrd" => expand!(totalord::expand_deriving_totalord),
|
||||
|
||||
~"Rand" => expand!(rand::expand_deriving_rand),
|
||||
|
||||
~"ToStr" => expand!(to_str::expand_deriving_to_str),
|
||||
|
||||
tname => {
|
||||
cx.span_err(titem.span, fmt!("unknown \
|
||||
`deriving` trait: `%s`", tname));
|
||||
@ -118,14 +115,14 @@ pub fn expand_deriving(cx: @ext_ctxt,
|
||||
for in_items.each |item| {
|
||||
result.push(copy *item);
|
||||
match item.node {
|
||||
item_struct(struct_def, ref generics) => {
|
||||
ast::item_struct(struct_def, ref generics) => {
|
||||
result.push(expand_deriving_struct_def(cx,
|
||||
span,
|
||||
struct_def,
|
||||
item.ident,
|
||||
generics));
|
||||
}
|
||||
item_enum(ref enum_definition, ref generics) => {
|
||||
ast::item_enum(ref enum_definition, ref generics) => {
|
||||
result.push(expand_deriving_enum_def(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
@ -138,7 +135,7 @@ pub fn expand_deriving(cx: @ext_ctxt,
|
||||
result
|
||||
}
|
||||
|
||||
fn create_impl_item(cx: @ext_ctxt, span: span, item: item_) -> @item {
|
||||
fn create_impl_item(cx: @ext_ctxt, span: span, item: ast::item_) -> @item {
|
||||
let doc_attr = respan(span,
|
||||
ast::lit_str(@~"Automatically derived."));
|
||||
let doc_attr = respan(span, ast::meta_name_value(@~"doc", doc_attr));
|
||||
@ -154,7 +151,7 @@ fn create_impl_item(cx: @ext_ctxt, span: span, item: item_) -> @item {
|
||||
attrs: ~[doc_attr],
|
||||
id: cx.next_id(),
|
||||
node: item,
|
||||
vis: public,
|
||||
vis: ast::public,
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
@ -173,22 +170,29 @@ pub fn create_self_type_with_params(cx: @ext_ctxt,
|
||||
self_ty_params.push(self_ty_param);
|
||||
}
|
||||
|
||||
let lifetime = if generics.lifetimes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(@*generics.lifetimes.get(0))
|
||||
};
|
||||
|
||||
|
||||
// Create the type of `self`.
|
||||
let self_type = build::mk_raw_path_(span,
|
||||
~[ type_ident ],
|
||||
lifetime,
|
||||
self_ty_params);
|
||||
let self_type = ty_path(self_type, cx.next_id());
|
||||
@ast::Ty { id: cx.next_id(), node: self_type, span: span }
|
||||
build::mk_ty_path_path(cx, span, self_type)
|
||||
}
|
||||
|
||||
pub fn create_derived_impl(cx: @ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
generics: &Generics,
|
||||
methods: &[@method],
|
||||
methods: &[@ast::method],
|
||||
trait_path: @ast::Path,
|
||||
mut impl_ty_params: opt_vec::OptVec<ast::TyParam>,
|
||||
bounds_paths: opt_vec::OptVec<~[ident]>)
|
||||
mut impl_generics: Generics,
|
||||
bounds_paths: opt_vec::OptVec<@ast::Path>)
|
||||
-> @item {
|
||||
/*!
|
||||
*
|
||||
@ -204,21 +208,22 @@ pub fn create_derived_impl(cx: @ext_ctxt,
|
||||
*/
|
||||
|
||||
// Copy the lifetimes
|
||||
let impl_lifetimes = generics.lifetimes.map(|l| {
|
||||
build::mk_lifetime(cx, l.span, l.ident)
|
||||
});
|
||||
for generics.lifetimes.each |l| {
|
||||
impl_generics.lifetimes.push(copy *l)
|
||||
};
|
||||
|
||||
// Create the type parameters.
|
||||
for generics.ty_params.each |ty_param| {
|
||||
// extra restrictions on the generics parameters to the type being derived upon
|
||||
let mut bounds = do bounds_paths.map |&bound_path| {
|
||||
build::mk_trait_ty_param_bound_global(cx, span, bound_path)
|
||||
build::mk_trait_ty_param_bound_(cx, bound_path)
|
||||
};
|
||||
|
||||
let this_trait_bound =
|
||||
build::mk_trait_ty_param_bound_(cx, trait_path);
|
||||
bounds.push(this_trait_bound);
|
||||
|
||||
impl_ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds));
|
||||
impl_generics.ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds));
|
||||
}
|
||||
|
||||
// Create the reference to the trait.
|
||||
@ -231,8 +236,7 @@ pub fn create_derived_impl(cx: @ext_ctxt,
|
||||
generics);
|
||||
|
||||
// Create the impl item.
|
||||
let impl_item = item_impl(Generics {lifetimes: impl_lifetimes,
|
||||
ty_params: impl_ty_params},
|
||||
let impl_item = ast::item_impl(impl_generics,
|
||||
Some(trait_ref),
|
||||
self_type,
|
||||
methods.map(|x| *x));
|
||||
@ -241,113 +245,135 @@ pub fn create_derived_impl(cx: @ext_ctxt,
|
||||
|
||||
pub fn create_subpatterns(cx: @ext_ctxt,
|
||||
span: span,
|
||||
field_paths: ~[@ast::Path],
|
||||
mutbl: ast::mutability)
|
||||
-> ~[@ast::pat] {
|
||||
do field_paths.map |&path| {
|
||||
build::mk_pat(cx, span,
|
||||
ast::pat_ident(ast::bind_by_ref(mutbl), path, None))
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq)] // dogfooding!
|
||||
enum StructType {
|
||||
Unknown, Record, Tuple
|
||||
}
|
||||
|
||||
pub fn create_struct_pattern(cx: @ext_ctxt,
|
||||
span: span,
|
||||
struct_ident: ident,
|
||||
struct_def: &struct_def,
|
||||
prefix: ~str,
|
||||
n: uint)
|
||||
-> ~[@pat] {
|
||||
let mut subpats = ~[];
|
||||
for uint::range(0, n) |_i| {
|
||||
// Create the subidentifier.
|
||||
let index = subpats.len();
|
||||
let ident = cx.ident_of(fmt!("%s_%u", prefix, index));
|
||||
|
||||
// Create the subpattern.
|
||||
let subpath = build::mk_raw_path(span, ~[ ident ]);
|
||||
let subpat = pat_ident(bind_by_ref(m_imm), subpath, None);
|
||||
let subpat = build::mk_pat(cx, span, subpat);
|
||||
subpats.push(subpat);
|
||||
}
|
||||
return subpats;
|
||||
mutbl: ast::mutability)
|
||||
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
|
||||
if struct_def.fields.is_empty() {
|
||||
return (
|
||||
build::mk_pat_ident_with_binding_mode(
|
||||
cx, span, struct_ident, ast::bind_infer),
|
||||
~[]);
|
||||
}
|
||||
|
||||
pub fn is_struct_tuple(struct_def: &struct_def) -> bool {
|
||||
struct_def.fields.len() > 0 && struct_def.fields.all(|f| {
|
||||
match f.node.kind {
|
||||
named_field(*) => false,
|
||||
unnamed_field => true
|
||||
let matching_path = build::mk_raw_path(span, ~[ struct_ident ]);
|
||||
|
||||
let mut paths = ~[], ident_expr = ~[];
|
||||
|
||||
let mut struct_type = Unknown;
|
||||
|
||||
for struct_def.fields.eachi |i, struct_field| {
|
||||
let opt_id = match struct_field.node.kind {
|
||||
ast::named_field(ident, _, _) if (struct_type == Unknown ||
|
||||
struct_type == Record) => {
|
||||
struct_type = Record;
|
||||
Some(ident)
|
||||
}
|
||||
})
|
||||
ast::unnamed_field if (struct_type == Unknown ||
|
||||
struct_type == Tuple) => {
|
||||
struct_type = Tuple;
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
cx.span_bug(span, "A struct with named and unnamed fields in `deriving`");
|
||||
}
|
||||
};
|
||||
let path = build::mk_raw_path(span,
|
||||
~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]);
|
||||
paths.push(path);
|
||||
ident_expr.push((opt_id, build::mk_path_raw(cx, span, path)));
|
||||
}
|
||||
|
||||
let subpats = create_subpatterns(cx, span, paths, mutbl);
|
||||
|
||||
// struct_type is definitely not Unknown, since struct_def.fields
|
||||
// must be nonempty to reach here
|
||||
let pattern = if struct_type == Record {
|
||||
let field_pats = do vec::build |push| {
|
||||
for vec::each2(subpats, ident_expr) |&pat, &(id, _)| {
|
||||
// id is guaranteed to be Some
|
||||
push(ast::field_pat { ident: id.get(), pat: pat })
|
||||
}
|
||||
};
|
||||
build::mk_pat_struct(cx, span, matching_path, field_pats)
|
||||
} else {
|
||||
build::mk_pat_enum(cx, span, matching_path, subpats)
|
||||
};
|
||||
|
||||
(pattern, ident_expr)
|
||||
}
|
||||
|
||||
pub fn create_enum_variant_pattern(cx: @ext_ctxt,
|
||||
span: span,
|
||||
variant: &variant,
|
||||
prefix: ~str)
|
||||
-> @pat {
|
||||
variant: &ast::variant,
|
||||
prefix: ~str,
|
||||
mutbl: ast::mutability)
|
||||
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
|
||||
|
||||
let variant_ident = variant.node.name;
|
||||
match variant.node.kind {
|
||||
tuple_variant_kind(ref variant_args) => {
|
||||
if variant_args.len() == 0 {
|
||||
return build::mk_pat_ident_with_binding_mode(
|
||||
cx, span, variant_ident, ast::bind_infer);
|
||||
ast::tuple_variant_kind(ref variant_args) => {
|
||||
if variant_args.is_empty() {
|
||||
return (build::mk_pat_ident_with_binding_mode(
|
||||
cx, span, variant_ident, ast::bind_infer), ~[]);
|
||||
}
|
||||
|
||||
let matching_path = build::mk_raw_path(span, ~[ variant_ident ]);
|
||||
let subpats = create_subpatterns(cx,
|
||||
span,
|
||||
|
||||
let mut paths = ~[], ident_expr = ~[];
|
||||
for uint::range(0, variant_args.len()) |i| {
|
||||
let path = build::mk_raw_path(span,
|
||||
~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]);
|
||||
|
||||
paths.push(path);
|
||||
ident_expr.push((None, build::mk_path_raw(cx, span, path)));
|
||||
}
|
||||
|
||||
let subpats = create_subpatterns(cx, span, paths, mutbl);
|
||||
|
||||
(build::mk_pat_enum(cx, span, matching_path, subpats),
|
||||
ident_expr)
|
||||
}
|
||||
ast::struct_variant_kind(struct_def) => {
|
||||
create_struct_pattern(cx, span,
|
||||
variant_ident, struct_def,
|
||||
prefix,
|
||||
variant_args.len());
|
||||
|
||||
return build::mk_pat_enum(cx, span, matching_path, subpats);
|
||||
}
|
||||
struct_variant_kind(struct_def) => {
|
||||
let matching_path = build::mk_raw_path(span, ~[ variant_ident ]);
|
||||
let subpats = create_subpatterns(cx,
|
||||
span,
|
||||
prefix,
|
||||
struct_def.fields.len());
|
||||
|
||||
let field_pats = do struct_def.fields.mapi |i, struct_field| {
|
||||
let ident = match struct_field.node.kind {
|
||||
named_field(ident, _, _) => ident,
|
||||
unnamed_field => {
|
||||
cx.span_bug(span, ~"unexpected unnamed field");
|
||||
}
|
||||
};
|
||||
ast::field_pat { ident: ident, pat: subpats[i] }
|
||||
};
|
||||
|
||||
build::mk_pat_struct(cx, span, matching_path, field_pats)
|
||||
mutbl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &variant) -> uint {
|
||||
pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &ast::variant) -> uint {
|
||||
match variant.node.kind {
|
||||
tuple_variant_kind(ref args) => args.len(),
|
||||
struct_variant_kind(ref struct_def) => struct_def.fields.len(),
|
||||
ast::tuple_variant_kind(ref args) => args.len(),
|
||||
ast::struct_variant_kind(ref struct_def) => struct_def.fields.len(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate through the idents of the variant arguments. The field is
|
||||
/// unnamed (i.e. it's not a struct-like enum), then `None`.
|
||||
pub fn each_variant_arg_ident(_cx: @ext_ctxt, _span: span,
|
||||
variant: &variant, it: &fn(uint, Option<ident>) -> bool) {
|
||||
match variant.node.kind {
|
||||
tuple_variant_kind(ref args) => {
|
||||
for uint::range(0, args.len()) |i| {
|
||||
if !it(i, None) { break }
|
||||
}
|
||||
}
|
||||
struct_variant_kind(ref struct_def) => {
|
||||
for struct_def.fields.eachi |i, f| {
|
||||
let id = match f.node.kind {
|
||||
named_field(ident, _, _) => Some(ident),
|
||||
unnamed_field => None
|
||||
};
|
||||
if !it(i, id) { break }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn expand_enum_or_struct_match(cx: @ext_ctxt,
|
||||
span: span,
|
||||
arms: ~[ ast::arm ])
|
||||
-> @expr {
|
||||
let self_ident = cx.ident_of(~"self");
|
||||
let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
|
||||
let self_expr = build::mk_unary(cx, span, deref, self_expr);
|
||||
let self_match_expr = expr_match(self_expr, arms);
|
||||
let self_expr = build::mk_unary(cx, span, ast::deref, self_expr);
|
||||
let self_match_expr = ast::expr_match(self_expr, arms);
|
||||
build::mk_expr(cx, span, self_match_expr)
|
||||
}
|
||||
|
136
src/libsyntax/ext/deriving/rand.rs
Normal file
136
src/libsyntax/ext/deriving/rand.rs
Normal file
@ -0,0 +1,136 @@
|
||||
// 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 ast;
|
||||
use ast::{meta_item, item, expr, ident};
|
||||
use codemap::span;
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
|
||||
pub fn expand_deriving_rand(cx: @ext_ctxt,
|
||||
span: span,
|
||||
mitem: @meta_item,
|
||||
in_items: ~[@item])
|
||||
-> ~[@item] {
|
||||
let trait_def = TraitDef {
|
||||
path: Path::new(~[~"core", ~"rand", ~"Rand"]),
|
||||
additional_bounds: ~[],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"rand",
|
||||
generics: LifetimeBounds {
|
||||
lifetimes: ~[],
|
||||
bounds: ~[(~"R",
|
||||
~[ Path::new(~[~"core", ~"rand", ~"Rng"]) ])]
|
||||
},
|
||||
self_ty: None,
|
||||
args: ~[
|
||||
Ptr(~Literal(Path::new_local(~"R")),
|
||||
Borrowed(None, ast::m_imm))
|
||||
],
|
||||
ret_ty: Self,
|
||||
const_nonmatching: false,
|
||||
combine_substructure: rand_substructure
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expand_deriving_generic(cx, span, mitem, in_items, &trait_def)
|
||||
}
|
||||
|
||||
fn rand_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
|
||||
let rng = match substr.nonself_args {
|
||||
[rng] => ~[ rng ],
|
||||
_ => cx.bug("Incorrect number of arguments to `rand` in `deriving(Rand)`")
|
||||
};
|
||||
let rand_ident = ~[
|
||||
cx.ident_of(~"core"),
|
||||
cx.ident_of(~"rand"),
|
||||
cx.ident_of(~"Rand"),
|
||||
cx.ident_of(~"rand")
|
||||
];
|
||||
let rand_call = || {
|
||||
build::mk_call_global(cx, span,
|
||||
copy rand_ident, copy rng)
|
||||
};
|
||||
|
||||
return match *substr.fields {
|
||||
StaticStruct(_, ref summary) => {
|
||||
rand_thing(cx, span, substr.type_ident, summary, rand_call)
|
||||
}
|
||||
StaticEnum(_, ref variants) => {
|
||||
if variants.is_empty() {
|
||||
cx.span_fatal(span, "`Rand` cannot be derived for enums with no variants");
|
||||
}
|
||||
|
||||
let variant_count = build::mk_uint(cx, span, variants.len());
|
||||
|
||||
// need to specify the uint-ness of the random number
|
||||
let u32_ty = build::mk_ty_path(cx, span, ~[cx.ident_of(~"uint")]);
|
||||
let r_ty = build::mk_ty_path(cx, span, ~[cx.ident_of(~"R")]);
|
||||
let rand_name = build::mk_raw_path_(span, copy rand_ident, None, ~[ u32_ty, r_ty ]);
|
||||
let rand_name = build::mk_path_raw(cx, span, rand_name);
|
||||
|
||||
let rv_call = build::mk_call_(cx, span, rand_name, copy rng);
|
||||
|
||||
// rand() % variants.len()
|
||||
let rand_variant = build::mk_binary(cx, span, ast::rem,
|
||||
rv_call, variant_count);
|
||||
|
||||
let mut arms = do variants.mapi |i, id_sum| {
|
||||
let i_expr = build::mk_uint(cx, span, i);
|
||||
let pat = build::mk_pat_lit(cx, span, i_expr);
|
||||
|
||||
match *id_sum {
|
||||
(ident, ref summary) => {
|
||||
build::mk_arm(cx, span,
|
||||
~[ pat ],
|
||||
rand_thing(cx, span, ident, summary, rand_call))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// _ => {} at the end. Should never occur
|
||||
arms.push(build::mk_unreachable_arm(cx, span));
|
||||
|
||||
build::mk_expr(cx, span,
|
||||
ast::expr_match(rand_variant, arms))
|
||||
}
|
||||
_ => cx.bug("Non-static method in `deriving(Rand)`")
|
||||
};
|
||||
|
||||
fn rand_thing(cx: @ext_ctxt, span: span,
|
||||
ctor_ident: ident,
|
||||
summary: &Either<uint, ~[ident]>,
|
||||
rand_call: &fn() -> @expr) -> @expr {
|
||||
let ctor_ident = ~[ ctor_ident ];
|
||||
match *summary {
|
||||
Left(copy count) => {
|
||||
if count == 0 {
|
||||
build::mk_path(cx, span, ctor_ident)
|
||||
} else {
|
||||
let exprs = vec::from_fn(count, |_| rand_call());
|
||||
build::mk_call(cx, span, ctor_ident, exprs)
|
||||
}
|
||||
}
|
||||
Right(ref fields) => {
|
||||
let rand_fields = do fields.map |ident| {
|
||||
build::Field {
|
||||
ident: *ident,
|
||||
ex: rand_call()
|
||||
}
|
||||
};
|
||||
build::mk_struct_e(cx, span, ctor_ident, rand_fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
src/libsyntax/ext/deriving/to_str.rs
Normal file
54
src/libsyntax/ext/deriving/to_str.rs
Normal file
@ -0,0 +1,54 @@
|
||||
// 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 ast::{meta_item, item, expr};
|
||||
use codemap::span;
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use ext::deriving::generic::*;
|
||||
|
||||
pub fn expand_deriving_to_str(cx: @ext_ctxt,
|
||||
span: span,
|
||||
mitem: @meta_item,
|
||||
in_items: ~[@item])
|
||||
-> ~[@item] {
|
||||
let trait_def = TraitDef {
|
||||
path: Path::new(~[~"core", ~"to_str", ~"ToStr"]),
|
||||
additional_bounds: ~[],
|
||||
generics: LifetimeBounds::empty(),
|
||||
methods: ~[
|
||||
MethodDef {
|
||||
name: ~"to_str",
|
||||
generics: LifetimeBounds::empty(),
|
||||
self_ty: borrowed_explicit_self(),
|
||||
args: ~[],
|
||||
ret_ty: Ptr(~Literal(Path::new_local(~"str")), Owned),
|
||||
const_nonmatching: false,
|
||||
combine_substructure: to_str_substructure
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expand_deriving_generic(cx, span, mitem, in_items, &trait_def)
|
||||
}
|
||||
|
||||
fn to_str_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
|
||||
match substr.self_args {
|
||||
[self_obj] => {
|
||||
let self_addr = build::mk_addr_of(cx, span, self_obj);
|
||||
build::mk_call_global(cx, span,
|
||||
~[cx.ident_of(~"core"),
|
||||
cx.ident_of(~"sys"),
|
||||
cx.ident_of(~"log_str")],
|
||||
~[self_addr])
|
||||
}
|
||||
_ => cx.span_bug(span, ~"Invalid number of arguments in `deriving(ToStr)`")
|
||||
}
|
||||
}
|
242
src/libsyntax/ext/deriving/ty.rs
Normal file
242
src/libsyntax/ext/deriving/ty.rs
Normal file
@ -0,0 +1,242 @@
|
||||
// Copyright 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.
|
||||
|
||||
/*!
|
||||
A mini version of ast::Ty, which is easier to use, and features an
|
||||
explicit `Self` type to use when specifying impls to be derived.
|
||||
*/
|
||||
|
||||
use ast;
|
||||
use ast::{expr,Generics,ident};
|
||||
use ext::base::ext_ctxt;
|
||||
use ext::build;
|
||||
use codemap::{span,respan};
|
||||
use opt_vec;
|
||||
|
||||
/// The types of pointers
|
||||
#[deriving(Eq)]
|
||||
pub enum PtrTy {
|
||||
Owned, // ~
|
||||
Managed(ast::mutability), // @[mut]
|
||||
Borrowed(Option<~str>, ast::mutability), // &['lifetime] [mut]
|
||||
}
|
||||
|
||||
/// A path, e.g. `::core::option::Option::<int>` (global). Has support
|
||||
/// for type parameters and a lifetime.
|
||||
#[deriving(Eq)]
|
||||
pub struct Path {
|
||||
path: ~[~str],
|
||||
lifetime: Option<~str>,
|
||||
params: ~[~Ty],
|
||||
global: bool
|
||||
}
|
||||
|
||||
pub impl Path {
|
||||
fn new(path: ~[~str]) -> Path {
|
||||
Path::new_(path, None, ~[], true)
|
||||
}
|
||||
fn new_local(path: ~str) -> Path {
|
||||
Path::new_(~[ path ], None, ~[], false)
|
||||
}
|
||||
fn new_(path: ~[~str], lifetime: Option<~str>, params: ~[~Ty], global: bool) -> Path {
|
||||
Path {
|
||||
path: path,
|
||||
lifetime: lifetime,
|
||||
params: params,
|
||||
global: global
|
||||
}
|
||||
}
|
||||
|
||||
fn to_ty(&self, cx: @ext_ctxt, span: span,
|
||||
self_ty: ident, self_generics: &Generics) -> @ast::Ty {
|
||||
build::mk_ty_path_path(cx, span,
|
||||
self.to_path(cx, span,
|
||||
self_ty, self_generics))
|
||||
}
|
||||
fn to_path(&self, cx: @ext_ctxt, span: span,
|
||||
self_ty: ident, self_generics: &Generics) -> @ast::Path {
|
||||
let idents = self.path.map(|s| cx.ident_of(*s) );
|
||||
let lt = mk_lifetime(cx, span, self.lifetime);
|
||||
let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics));
|
||||
|
||||
if self.global {
|
||||
build::mk_raw_path_global_(span, idents, lt, tys)
|
||||
} else {
|
||||
build::mk_raw_path_(span, idents, lt, tys)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type. Supports pointers (except for *), Self, and literals
|
||||
#[deriving(Eq)]
|
||||
pub enum Ty {
|
||||
Self,
|
||||
// &/~/@ Ty
|
||||
Ptr(~Ty, PtrTy),
|
||||
// mod::mod::Type<[lifetime], [Params...]>, including a plain type
|
||||
// parameter, and things like `int`
|
||||
Literal(Path),
|
||||
// includes nil
|
||||
Tuple(~[Ty])
|
||||
}
|
||||
|
||||
pub fn borrowed_ptrty() -> PtrTy {
|
||||
Borrowed(None, ast::m_imm)
|
||||
}
|
||||
pub fn borrowed(ty: ~Ty) -> Ty {
|
||||
Ptr(ty, borrowed_ptrty())
|
||||
}
|
||||
|
||||
pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
|
||||
Some(Some(borrowed_ptrty()))
|
||||
}
|
||||
|
||||
pub fn borrowed_self() -> Ty {
|
||||
borrowed(~Self)
|
||||
}
|
||||
|
||||
pub fn nil_ty() -> Ty {
|
||||
Tuple(~[])
|
||||
}
|
||||
|
||||
fn mk_lifetime(cx: @ext_ctxt, span: span, lt: Option<~str>) -> Option<@ast::Lifetime> {
|
||||
match lt {
|
||||
Some(s) => Some(@build::mk_lifetime(cx, span, cx.ident_of(s))),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
pub impl Ty {
|
||||
fn to_ty(&self, cx: @ext_ctxt, span: span,
|
||||
self_ty: ident, self_generics: &Generics) -> @ast::Ty {
|
||||
match *self {
|
||||
Ptr(ref ty, ref ptr) => {
|
||||
let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
|
||||
match *ptr {
|
||||
Owned => {
|
||||
build::mk_ty_uniq(cx, span, raw_ty)
|
||||
}
|
||||
Managed(copy mutbl) => {
|
||||
build::mk_ty_box(cx, span, raw_ty, mutbl)
|
||||
}
|
||||
Borrowed(copy lt, copy mutbl) => {
|
||||
let lt = mk_lifetime(cx, span, lt);
|
||||
build::mk_ty_rptr(cx, span, raw_ty, lt, mutbl)
|
||||
}
|
||||
}
|
||||
}
|
||||
Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
|
||||
Self => {
|
||||
build::mk_ty_path_path(cx, span, self.to_path(cx, span, self_ty, self_generics))
|
||||
}
|
||||
Tuple(ref fields) => {
|
||||
let ty = if fields.is_empty() {
|
||||
ast::ty_nil
|
||||
} else {
|
||||
ast::ty_tup(fields.map(|f| f.to_ty(cx, span, self_ty, self_generics)))
|
||||
};
|
||||
|
||||
build::mk_ty(cx, span, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_path(&self, cx: @ext_ctxt, span: span,
|
||||
self_ty: ident, self_generics: &Generics) -> @ast::Path {
|
||||
match *self {
|
||||
Self => {
|
||||
let self_params = do self_generics.ty_params.map |ty_param| {
|
||||
build::mk_ty_path(cx, span, ~[ ty_param.ident ])
|
||||
};
|
||||
let lifetime = if self_generics.lifetimes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(@*self_generics.lifetimes.get(0))
|
||||
};
|
||||
|
||||
build::mk_raw_path_(span, ~[self_ty], lifetime,
|
||||
opt_vec::take_vec(self_params))
|
||||
}
|
||||
Literal(ref p) => {
|
||||
p.to_path(cx, span, self_ty, self_generics)
|
||||
}
|
||||
Ptr(*) => { cx.span_bug(span, ~"Pointer in a path in generic `deriving`") }
|
||||
Tuple(*) => { cx.span_bug(span, ~"Tuple in a path in generic `deriving`") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn mk_ty_param(cx: @ext_ctxt, span: span, name: ~str, bounds: ~[Path],
|
||||
self_ident: ident, self_generics: &Generics) -> ast::TyParam {
|
||||
let bounds = opt_vec::from(
|
||||
do bounds.map |b| {
|
||||
let path = b.to_path(cx, span, self_ident, self_generics);
|
||||
build::mk_trait_ty_param_bound_(cx, path)
|
||||
});
|
||||
build::mk_ty_param(cx, cx.ident_of(name), @bounds)
|
||||
}
|
||||
|
||||
fn mk_generics(lifetimes: ~[ast::Lifetime], ty_params: ~[ast::TyParam]) -> Generics {
|
||||
Generics {
|
||||
lifetimes: opt_vec::from(lifetimes),
|
||||
ty_params: opt_vec::from(ty_params)
|
||||
}
|
||||
}
|
||||
|
||||
/// Lifetimes and bounds on type paramers
|
||||
pub struct LifetimeBounds {
|
||||
lifetimes: ~[~str],
|
||||
bounds: ~[(~str, ~[Path])]
|
||||
}
|
||||
|
||||
pub impl LifetimeBounds {
|
||||
fn empty() -> LifetimeBounds {
|
||||
LifetimeBounds {
|
||||
lifetimes: ~[], bounds: ~[]
|
||||
}
|
||||
}
|
||||
fn to_generics(&self, cx: @ext_ctxt, span: span,
|
||||
self_ty: ident, self_generics: &Generics) -> Generics {
|
||||
let lifetimes = do self.lifetimes.map |<| {
|
||||
build::mk_lifetime(cx, span, cx.ident_of(lt))
|
||||
};
|
||||
let ty_params = do self.bounds.map |&(name, bounds)| {
|
||||
mk_ty_param(cx, span, name, bounds, self_ty, self_generics)
|
||||
};
|
||||
mk_generics(lifetimes, ty_params)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_explicit_self(cx: @ext_ctxt, span: span, self_ptr: Option<PtrTy>)
|
||||
-> (@expr, ast::self_ty) {
|
||||
let self_path = build::mk_path(cx, span, ~[cx.ident_of(~"self")]);
|
||||
match self_ptr {
|
||||
None => {
|
||||
(self_path, respan(span, ast::sty_value))
|
||||
}
|
||||
Some(ptr) => {
|
||||
let self_ty = respan(
|
||||
span,
|
||||
match ptr {
|
||||
Owned => ast::sty_uniq(ast::m_imm),
|
||||
Managed(mutbl) => ast::sty_box(mutbl),
|
||||
Borrowed(lt, mutbl) => {
|
||||
let lt = lt.map(|s| @build::mk_lifetime(cx, span,
|
||||
cx.ident_of(*s)));
|
||||
ast::sty_region(lt, mutbl)
|
||||
}
|
||||
});
|
||||
let self_expr = build::mk_deref(cx, span, self_path);
|
||||
(self_expr, self_ty)
|
||||
}
|
||||
}
|
||||
}
|
39
src/test/run-pass/deriving-rand.rs
Normal file
39
src/test/run-pass/deriving-rand.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// xfail-fast #6330
|
||||
// Copyright 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.
|
||||
|
||||
#[deriving(Rand)]
|
||||
struct A;
|
||||
|
||||
#[deriving(Rand)]
|
||||
struct B(int, int);
|
||||
|
||||
#[deriving(Rand)]
|
||||
struct C {
|
||||
x: f64,
|
||||
y: (u8, u8)
|
||||
}
|
||||
|
||||
#[deriving(Rand)]
|
||||
enum D {
|
||||
D0,
|
||||
D1(uint),
|
||||
D2 { x: (), y: () }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// check there's no segfaults
|
||||
for 20.times {
|
||||
rand::random::<A>();
|
||||
rand::random::<B>();
|
||||
rand::random::<C>();
|
||||
rand::random::<D>();
|
||||
}
|
||||
}
|
32
src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs
Normal file
32
src/test/run-pass/deriving-self-lifetime-totalord-totaleq.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// xfail-test FIXME #6257
|
||||
|
||||
// Copyright 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::cmp::{Less,Equal,Greater};
|
||||
|
||||
#[deriving(TotalEq,TotalOrd)]
|
||||
struct A<'self> {
|
||||
x: &'self int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = A { x: &1 }, b = A { x: &2 };
|
||||
|
||||
assert!(a.equals(&a));
|
||||
assert!(b.equals(&b));
|
||||
|
||||
|
||||
assert_eq!(a.cmp(&a), Equal);
|
||||
assert_eq!(b.cmp(&b), Equal);
|
||||
|
||||
assert_eq!(a.cmp(&b), Less);
|
||||
assert_eq!(b.cmp(&a), Greater);
|
||||
}
|
33
src/test/run-pass/deriving-self-lifetime.rs
Normal file
33
src/test/run-pass/deriving-self-lifetime.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 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.
|
||||
|
||||
#[deriving(Eq,Ord)]
|
||||
struct A<'self> {
|
||||
x: &'self int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = A { x: &1 }, b = A { x: &2 };
|
||||
|
||||
assert_eq!(a, a);
|
||||
assert_eq!(b, b);
|
||||
|
||||
|
||||
assert!(a < b);
|
||||
assert!(b > a);
|
||||
|
||||
assert!(a <= b);
|
||||
assert!(a <= a);
|
||||
assert!(b <= b);
|
||||
|
||||
assert!(b >= a);
|
||||
assert!(b >= b);
|
||||
assert!(a >= a);
|
||||
}
|
45
src/test/run-pass/deriving-to-str.rs
Normal file
45
src/test/run-pass/deriving-to-str.rs
Normal file
@ -0,0 +1,45 @@
|
||||
// xfail-fast #6330
|
||||
// Copyright 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.
|
||||
|
||||
#[deriving(Rand,ToStr)]
|
||||
struct A;
|
||||
|
||||
#[deriving(Rand,ToStr)]
|
||||
struct B(int, int);
|
||||
|
||||
#[deriving(Rand,ToStr)]
|
||||
struct C {
|
||||
x: f64,
|
||||
y: (u8, u8)
|
||||
}
|
||||
|
||||
#[deriving(Rand,ToStr)]
|
||||
enum D {
|
||||
D0,
|
||||
D1(uint),
|
||||
D2 { x: (), y: () }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
macro_rules! t(
|
||||
($ty:ty) => {{
|
||||
let x =rand::random::<$ty>();
|
||||
assert_eq!(x.to_str(), fmt!("%?", x));
|
||||
}}
|
||||
);
|
||||
|
||||
for 20.times {
|
||||
t!(A);
|
||||
t!(B);
|
||||
t!(C);
|
||||
t!(D);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user