diff options
Diffstat (limited to 'src/libsyntax/ext/deriving/iter_bytes.rs')
| -rw-r--r-- | src/libsyntax/ext/deriving/iter_bytes.rs | 282 |
1 files changed, 60 insertions, 222 deletions
diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index f03306ea07a..3d66506d6ca 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -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); +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 pattern body. - let match_body_block = build::mk_block_(cx, span, stmts); + stmts.push(call_iterbytes(discriminant)); - // Create the arm. - ast::arm { - pats: ~[ pat ], - guard: None, - body: match_body_block, + fields = fs; } - }; + _ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`") + } - // 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); + for fields.each |&(_, field, _)| { + stmts.push(call_iterbytes(field)); + } - // Create the method. - create_iter_bytes_method(cx, span, ~[ self_match_stmt ]) + build::mk_block(cx, span, ~[], stmts, None) } |
