libsyntax: convert #[deriving(IterBytes)] to generic deriving
This commit is contained in:
parent
b20eb970e1
commit
1cf2108a2b
1 changed files with 64 additions and 226 deletions
|
|
@ -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)
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
// 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,
|
||||
}
|
||||
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
|
||||
}
|
||||
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 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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue