libsyntax: Implement deriving via a syntax extension for the IterBytes trait. r=brson
This commit is contained in:
parent
b053f0b5e6
commit
57588edf3b
5 changed files with 442 additions and 123 deletions
|
|
@ -100,6 +100,9 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
|
|||
syntax_expanders.insert(~"deriving_eq",
|
||||
item_decorator(
|
||||
ext::deriving::expand_deriving_eq));
|
||||
syntax_expanders.insert(~"deriving_iter_bytes",
|
||||
item_decorator(
|
||||
ext::deriving::expand_deriving_iter_bytes));
|
||||
|
||||
// Quasi-quoting expanders
|
||||
syntax_expanders.insert(~"quote_tokens",
|
||||
|
|
|
|||
|
|
@ -141,6 +141,18 @@ fn mk_block(cx: ext_ctxt, sp: span,
|
|||
span: sp };
|
||||
mk_expr(cx, sp, ast::expr_block(blk))
|
||||
}
|
||||
fn mk_block_(cx: ext_ctxt, sp: span, +stmts: ~[@ast::stmt]) -> ast::blk {
|
||||
{
|
||||
node: {
|
||||
view_items: ~[],
|
||||
stmts: move stmts,
|
||||
expr: None,
|
||||
id: cx.next_id(),
|
||||
rules: ast::default_blk
|
||||
},
|
||||
span: sp
|
||||
}
|
||||
}
|
||||
fn mk_simple_block(cx: ext_ctxt, span: span, expr: @ast::expr) -> ast::blk {
|
||||
let block = {
|
||||
view_items: ~[],
|
||||
|
|
@ -177,4 +189,39 @@ fn mk_bool(cx: ext_ctxt, span: span, value: bool) -> @ast::expr {
|
|||
let lit_expr = ast::expr_lit(@{ node: ast::lit_bool(value), span: span });
|
||||
build::mk_expr(cx, span, move lit_expr)
|
||||
}
|
||||
fn mk_stmt(cx: ext_ctxt, span: span, expr: @ast::expr) -> @ast::stmt {
|
||||
let stmt_ = ast::stmt_semi(expr, cx.next_id());
|
||||
@{ node: move stmt_, span: span }
|
||||
}
|
||||
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 = @{ id: cx.next_id(), node: move ty, span: span };
|
||||
ty
|
||||
}
|
||||
fn mk_simple_ty_path(cx: ext_ctxt,
|
||||
span: span,
|
||||
ident: ast::ident)
|
||||
-> @ast::Ty {
|
||||
mk_ty_path(cx, span, ~[ ident ])
|
||||
}
|
||||
fn mk_arg(cx: ext_ctxt,
|
||||
span: span,
|
||||
ident: ast::ident,
|
||||
ty: @ast::Ty)
|
||||
-> ast::arg {
|
||||
let arg_pat = mk_pat_ident(cx, span, ident);
|
||||
{
|
||||
mode: ast::infer(cx.next_id()),
|
||||
ty: ty,
|
||||
pat: arg_pat,
|
||||
id: cx.next_id()
|
||||
}
|
||||
}
|
||||
fn mk_fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl {
|
||||
{ inputs: move inputs, output: output, cf: ast::return_val }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/// The compiler code necessary to implement the #[deriving_eq] and
|
||||
/// #[deriving_ord] extensions.
|
||||
/// #[deriving_iter_bytes] extensions.
|
||||
|
||||
use ast::{and, bind_by_ref, binop, blk, default_blk, deref, enum_def};
|
||||
use ast::{enum_variant_kind, expr};
|
||||
|
|
@ -7,9 +7,9 @@ use ast::{expr_, expr_addr_of, expr_binary, expr_call, expr_field, expr_lit};
|
|||
use ast::{expr_match, expr_path, expr_unary, ident, infer, item, item_};
|
||||
use ast::{item_class, item_enum, item_impl, lit_bool, m_imm, meta_item};
|
||||
use ast::{method, named_field, or, pat, pat_ident, pat_wild, path, public};
|
||||
use ast::{pure_fn, re_anon, return_val, struct_def, struct_variant_kind};
|
||||
use ast::{sty_region, tuple_variant_kind, ty_path};
|
||||
use ast::{ty_rptr, unnamed_field, variant};
|
||||
use ast::{pure_fn, re_anon, return_val, stmt, struct_def};
|
||||
use ast::{struct_variant_kind, sty_by_ref, sty_region, tuple_variant_kind};
|
||||
use ast::{ty_nil, ty_path, ty_rptr, unnamed_field, variant};
|
||||
use base::ext_ctxt;
|
||||
use codemap::span;
|
||||
use parse::token::special_idents::clownshoes_extensions;
|
||||
|
|
@ -28,11 +28,47 @@ impl Junction {
|
|||
}
|
||||
}
|
||||
|
||||
type ExpandDerivingStructDefFn = &fn(ext_ctxt,
|
||||
span,
|
||||
x: &struct_def,
|
||||
ident)
|
||||
-> @item;
|
||||
type ExpandDerivingEnumDefFn = &fn(ext_ctxt,
|
||||
span,
|
||||
x: &enum_def,
|
||||
ident)
|
||||
-> @item;
|
||||
|
||||
pub fn expand_deriving_eq(cx: ext_ctxt,
|
||||
span: span,
|
||||
_mitem: meta_item,
|
||||
in_items: ~[@item])
|
||||
-> ~[@item] {
|
||||
expand_deriving(cx,
|
||||
span,
|
||||
in_items,
|
||||
expand_deriving_eq_struct_def,
|
||||
expand_deriving_eq_enum_def)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fn expand_deriving(cx: ext_ctxt,
|
||||
span: span,
|
||||
in_items: ~[@item],
|
||||
expand_deriving_struct_def: ExpandDerivingStructDefFn,
|
||||
expand_deriving_enum_def: ExpandDerivingEnumDefFn)
|
||||
-> ~[@item] {
|
||||
let result = dvec::DVec();
|
||||
for in_items.each |item| {
|
||||
result.push(copy *item);
|
||||
|
|
@ -68,33 +104,21 @@ fn create_impl_item(cx: ext_ctxt, span: span, +item: item_) -> @item {
|
|||
|
||||
/// Creates a method from the given expression, the signature of which
|
||||
/// conforms to the `eq` or `ne` method.
|
||||
fn create_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
body: @expr)
|
||||
-> @method {
|
||||
fn create_eq_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
body: @expr)
|
||||
-> @method {
|
||||
// Create the type of the `other` parameter.
|
||||
let arg_path_type = build::mk_raw_path(span, ~[ type_ident ]);
|
||||
let arg_path_type = ty_path(arg_path_type, cx.next_id());
|
||||
let arg_path_type = @{
|
||||
id: cx.next_id(),
|
||||
node: move arg_path_type,
|
||||
span: span
|
||||
};
|
||||
let arg_path_type = build::mk_simple_ty_path(cx, span, type_ident);
|
||||
let arg_region = @{ id: cx.next_id(), node: re_anon };
|
||||
let arg_type = ty_rptr(arg_region, { ty: arg_path_type, mutbl: m_imm });
|
||||
let arg_type = @{ id: cx.next_id(), node: move arg_type, span: span };
|
||||
|
||||
// Create the `other` parameter.
|
||||
let other_ident = cx.ident_of(~"__other");
|
||||
let arg_pat = build::mk_pat_ident(cx, span, other_ident);
|
||||
let arg = {
|
||||
mode: infer(cx.next_id()),
|
||||
ty: arg_type,
|
||||
pat: arg_pat,
|
||||
id: cx.next_id()
|
||||
};
|
||||
let arg = build::mk_arg(cx, span, other_ident, arg_type);
|
||||
|
||||
// Create the type of the return value.
|
||||
let bool_ident = cx.ident_of(~"bool");
|
||||
|
|
@ -107,11 +131,7 @@ fn create_method(cx: ext_ctxt,
|
|||
};
|
||||
|
||||
// Create the function declaration.
|
||||
let fn_decl = {
|
||||
inputs: ~[ move arg ],
|
||||
output: output_type,
|
||||
cf: return_val
|
||||
};
|
||||
let fn_decl = build::mk_fn_decl(~[ move arg ], output_type);
|
||||
|
||||
// Create the body block.
|
||||
let body_block = build::mk_simple_block(cx, span, body);
|
||||
|
|
@ -136,28 +156,20 @@ fn create_method(cx: ext_ctxt,
|
|||
fn create_derived_impl(cx: ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
eq_method: @method,
|
||||
ne_method: @method)
|
||||
methods: &[@method],
|
||||
trait_path: &[ast::ident])
|
||||
-> @item {
|
||||
// Create the reference to the `core::cmp::Eq` trait.
|
||||
let core_ident = cx.ident_of(~"core");
|
||||
let cmp_ident = cx.ident_of(~"cmp");
|
||||
let eq_ident = cx.ident_of(~"Eq");
|
||||
let core_cmp_eq_idents = ~[
|
||||
move core_ident,
|
||||
move cmp_ident,
|
||||
move eq_ident
|
||||
];
|
||||
let core_cmp_eq_path = {
|
||||
// Create the reference to the trait.
|
||||
let trait_path = {
|
||||
span: span,
|
||||
global: false,
|
||||
idents: move core_cmp_eq_idents,
|
||||
idents: trait_path.map(|x| *x),
|
||||
rp: None,
|
||||
types: ~[]
|
||||
};
|
||||
let core_cmp_eq_path = @move core_cmp_eq_path;
|
||||
let trait_path = @move trait_path;
|
||||
let trait_ref = {
|
||||
path: core_cmp_eq_path,
|
||||
path: trait_path,
|
||||
ref_id: cx.next_id(),
|
||||
impl_id: cx.next_id(),
|
||||
};
|
||||
|
|
@ -172,10 +184,87 @@ fn create_derived_impl(cx: ext_ctxt,
|
|||
let impl_item = item_impl(~[],
|
||||
Some(trait_ref),
|
||||
self_type,
|
||||
~[ eq_method, ne_method ]);
|
||||
methods.map(|x| *x));
|
||||
return create_impl_item(cx, span, move impl_item);
|
||||
}
|
||||
|
||||
fn create_derived_eq_impl(cx: ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
eq_method: @method,
|
||||
ne_method: @method)
|
||||
-> @item {
|
||||
let methods = [ eq_method, ne_method ];
|
||||
let trait_path = [
|
||||
cx.ident_of(~"core"),
|
||||
cx.ident_of(~"cmp"),
|
||||
cx.ident_of(~"Eq")
|
||||
];
|
||||
create_derived_impl(cx, span, type_ident, methods, trait_path)
|
||||
}
|
||||
|
||||
fn create_derived_iter_bytes_impl(cx: ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
method: @method)
|
||||
-> @item {
|
||||
let trait_path = [
|
||||
cx.ident_of(~"core"),
|
||||
cx.ident_of(~"to_bytes"),
|
||||
cx.ident_of(~"IterBytes")
|
||||
];
|
||||
create_derived_impl(cx, span, type_ident, [ method ], trait_path)
|
||||
}
|
||||
|
||||
// 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 = @{ id: cx.next_id(), node: ty_nil, span: span };
|
||||
|
||||
// Create the function declaration.
|
||||
let inputs = ~[ move lsb0_arg, move f_arg ];
|
||||
let fn_decl = build::mk_fn_decl(move inputs, output_type);
|
||||
|
||||
// Create the body block.
|
||||
let body_block = build::mk_block_(cx, span, move statements);
|
||||
|
||||
// Create the method.
|
||||
let self_ty = { node: sty_by_ref, span: span };
|
||||
let method_ident = cx.ident_of(~"iter_bytes");
|
||||
return @{
|
||||
ident: method_ident,
|
||||
attrs: ~[],
|
||||
tps: ~[],
|
||||
self_ty: self_ty,
|
||||
purity: pure_fn,
|
||||
decl: move fn_decl,
|
||||
body: move body_block,
|
||||
id: cx.next_id(),
|
||||
span: span,
|
||||
self_id: cx.next_id(),
|
||||
vis: public
|
||||
}
|
||||
}
|
||||
|
||||
fn create_enum_variant_pattern(cx: ext_ctxt,
|
||||
span: span,
|
||||
variant: &ast::variant,
|
||||
|
|
@ -214,13 +303,13 @@ fn create_enum_variant_pattern(cx: ext_ctxt,
|
|||
}
|
||||
}
|
||||
|
||||
fn call_substructure_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
self_field: @expr,
|
||||
other_field_ref: @expr,
|
||||
method_ident: ident,
|
||||
junction: Junction,
|
||||
chain_expr: &mut Option<@expr>) {
|
||||
fn call_substructure_eq_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
self_field: @expr,
|
||||
other_field_ref: @expr,
|
||||
method_ident: ident,
|
||||
junction: Junction,
|
||||
chain_expr: &mut Option<@expr>) {
|
||||
// Call the substructure method.
|
||||
let self_method = build::mk_access_(cx, span, self_field, method_ident);
|
||||
let self_call = build::mk_call_(cx,
|
||||
|
|
@ -243,11 +332,11 @@ fn call_substructure_method(cx: ext_ctxt,
|
|||
};
|
||||
}
|
||||
|
||||
fn finish_chain_expr(cx: ext_ctxt,
|
||||
span: span,
|
||||
chain_expr: Option<@expr>,
|
||||
junction: Junction)
|
||||
-> @expr {
|
||||
fn finish_eq_chain_expr(cx: ext_ctxt,
|
||||
span: span,
|
||||
chain_expr: Option<@expr>,
|
||||
junction: Junction)
|
||||
-> @expr {
|
||||
match chain_expr {
|
||||
None => {
|
||||
match junction {
|
||||
|
|
@ -259,6 +348,31 @@ fn finish_chain_expr(cx: ext_ctxt,
|
|||
}
|
||||
}
|
||||
|
||||
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_method = build::mk_access_(cx,
|
||||
span,
|
||||
self_field,
|
||||
iter_bytes_ident);
|
||||
let self_call = build::mk_call_(cx,
|
||||
span,
|
||||
self_method,
|
||||
~[ lsb0_expr, f_expr ]);
|
||||
|
||||
// Create a statement out of this expression.
|
||||
build::mk_stmt(cx, span, self_call)
|
||||
}
|
||||
|
||||
fn variant_arg_count(cx: ext_ctxt, span: span, variant: &variant) -> uint {
|
||||
match variant.node.kind {
|
||||
tuple_variant_kind(args) => args.len(),
|
||||
|
|
@ -269,38 +383,66 @@ fn variant_arg_count(cx: ext_ctxt, span: span, variant: &variant) -> uint {
|
|||
}
|
||||
}
|
||||
|
||||
fn expand_deriving_struct_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
type_ident: ident)
|
||||
-> @item {
|
||||
fn expand_deriving_eq_struct_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
type_ident: ident)
|
||||
-> @item {
|
||||
// Create the methods.
|
||||
let eq_ident = cx.ident_of(~"eq");
|
||||
let ne_ident = cx.ident_of(~"ne");
|
||||
let eq_method = expand_deriving_struct_method(cx,
|
||||
span,
|
||||
struct_def,
|
||||
eq_ident,
|
||||
type_ident,
|
||||
Conjunction);
|
||||
let ne_method = expand_deriving_struct_method(cx,
|
||||
span,
|
||||
struct_def,
|
||||
ne_ident,
|
||||
type_ident,
|
||||
Disjunction);
|
||||
let eq_method = expand_deriving_eq_struct_method(cx,
|
||||
span,
|
||||
struct_def,
|
||||
eq_ident,
|
||||
type_ident,
|
||||
Conjunction);
|
||||
let ne_method = expand_deriving_eq_struct_method(cx,
|
||||
span,
|
||||
struct_def,
|
||||
ne_ident,
|
||||
type_ident,
|
||||
Disjunction);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_impl(cx, span, type_ident, eq_method, ne_method);
|
||||
return create_derived_eq_impl(cx, span, type_ident, eq_method, ne_method);
|
||||
}
|
||||
|
||||
fn expand_deriving_struct_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
junction: Junction)
|
||||
-> @method {
|
||||
fn expand_deriving_iter_bytes_struct_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
type_ident: ident)
|
||||
-> @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, method);
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_enum_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
type_ident: ident)
|
||||
-> @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, method);
|
||||
}
|
||||
|
||||
fn expand_deriving_eq_struct_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
junction: Junction)
|
||||
-> @method {
|
||||
let self_ident = cx.ident_of(~"self");
|
||||
let other_ident = cx.ident_of(~"__other");
|
||||
|
||||
|
|
@ -325,13 +467,13 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
|
|||
ident);
|
||||
|
||||
// Call the substructure method.
|
||||
call_substructure_method(cx,
|
||||
span,
|
||||
self_field,
|
||||
other_field_ref,
|
||||
method_ident,
|
||||
junction,
|
||||
&mut outer_expr);
|
||||
call_substructure_eq_method(cx,
|
||||
span,
|
||||
self_field,
|
||||
other_field_ref,
|
||||
method_ident,
|
||||
junction,
|
||||
&mut outer_expr);
|
||||
}
|
||||
unnamed_field => {
|
||||
cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`");
|
||||
|
|
@ -340,42 +482,77 @@ fn expand_deriving_struct_method(cx: ext_ctxt,
|
|||
}
|
||||
|
||||
// Create the method itself.
|
||||
let body = finish_chain_expr(cx, span, outer_expr, junction);
|
||||
return create_method(cx, span, method_ident, type_ident, body);
|
||||
let body = finish_eq_chain_expr(cx, span, outer_expr, junction);
|
||||
return create_eq_method(cx, span, method_ident, type_ident, body);
|
||||
}
|
||||
|
||||
fn expand_deriving_enum_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
type_ident: ident)
|
||||
-> @item {
|
||||
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 statements = dvec::DVec();
|
||||
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_iter_bytes`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the method itself.
|
||||
let statements = dvec::unwrap(move statements);
|
||||
return create_iter_bytes_method(cx, span, move statements);
|
||||
}
|
||||
|
||||
fn expand_deriving_eq_enum_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
type_ident: ident)
|
||||
-> @item {
|
||||
// Create the methods.
|
||||
let eq_ident = cx.ident_of(~"eq");
|
||||
let ne_ident = cx.ident_of(~"ne");
|
||||
let eq_method = expand_deriving_enum_method(cx,
|
||||
let eq_method = expand_deriving_eq_enum_method(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
eq_ident,
|
||||
type_ident,
|
||||
Conjunction);
|
||||
let ne_method = expand_deriving_enum_method(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
ne_ident,
|
||||
type_ident,
|
||||
Disjunction);
|
||||
let ne_method = expand_deriving_eq_enum_method(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
ne_ident,
|
||||
type_ident,
|
||||
Disjunction);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_impl(cx, span, type_ident, eq_method, ne_method);
|
||||
return create_derived_eq_impl(cx, span, type_ident, eq_method, ne_method);
|
||||
}
|
||||
|
||||
fn expand_deriving_enum_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
junction: Junction)
|
||||
-> @method {
|
||||
fn expand_deriving_eq_enum_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
junction: Junction)
|
||||
-> @method {
|
||||
let self_ident = cx.ident_of(~"self");
|
||||
let other_ident = cx.ident_of(~"__other");
|
||||
|
||||
|
|
@ -410,19 +587,19 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
|
|||
let self_field = build::mk_path(cx, span, ~[ self_field_ident ]);
|
||||
|
||||
// Call the substructure method.
|
||||
call_substructure_method(cx,
|
||||
span,
|
||||
self_field,
|
||||
other_field,
|
||||
method_ident,
|
||||
junction,
|
||||
&mut matching_body_expr);
|
||||
call_substructure_eq_method(cx,
|
||||
span,
|
||||
self_field,
|
||||
other_field,
|
||||
method_ident,
|
||||
junction,
|
||||
&mut matching_body_expr);
|
||||
}
|
||||
|
||||
let matching_body_expr = finish_chain_expr(cx,
|
||||
span,
|
||||
matching_body_expr,
|
||||
junction);
|
||||
let matching_body_expr = finish_eq_chain_expr(cx,
|
||||
span,
|
||||
matching_body_expr,
|
||||
junction);
|
||||
let matching_body_block = build::mk_simple_block(cx,
|
||||
span,
|
||||
matching_body_expr);
|
||||
|
|
@ -491,6 +668,72 @@ fn expand_deriving_enum_method(cx: ext_ctxt,
|
|||
let self_match_expr = build::mk_expr(cx, span, move self_match_expr);
|
||||
|
||||
// Create the method.
|
||||
return create_method(cx, span, method_ident, type_ident, self_match_expr);
|
||||
return create_eq_method(cx,
|
||||
span,
|
||||
method_ident,
|
||||
type_ident,
|
||||
self_match_expr);
|
||||
}
|
||||
|
||||
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 = dvec::DVec();
|
||||
for enum_definition.variants.eachi |i, variant| {
|
||||
// Create the matching pattern.
|
||||
let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
|
||||
|
||||
// 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 stmts = dvec::DVec();
|
||||
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 stmts = dvec::unwrap(move stmts);
|
||||
let match_body_block = build::mk_block_(cx, span, move stmts);
|
||||
|
||||
// Create the arm.
|
||||
let arm = {
|
||||
pats: ~[ pat ],
|
||||
guard: None,
|
||||
body: move match_body_block
|
||||
};
|
||||
arms.push(move arm);
|
||||
}
|
||||
|
||||
// Create the method body.
|
||||
let self_ident = cx.ident_of(~"self");
|
||||
let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
|
||||
let arms = dvec::unwrap(move arms);
|
||||
let self_match_expr = expr_match(self_expr, move arms);
|
||||
let self_match_expr = build::mk_expr(cx, span, move self_match_expr);
|
||||
let self_match_stmt = build::mk_stmt(cx, span, self_match_expr);
|
||||
|
||||
// Create the method.
|
||||
return create_iter_bytes_method(cx, span, ~[ self_match_stmt ]);
|
||||
}
|
||||
|
||||
|
|
|
|||
16
src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs
Normal file
16
src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#[deriving_iter_bytes]
|
||||
enum Foo {
|
||||
Bar(int, char),
|
||||
Baz(char, int)
|
||||
}
|
||||
|
||||
#[deriving_iter_bytes]
|
||||
enum A {
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E
|
||||
}
|
||||
|
||||
fn main(){}
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#[deriving_iter_bytes]
|
||||
struct Foo {
|
||||
x: int,
|
||||
y: int,
|
||||
z: int
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue