about summary refs log tree commit diff
path: root/src/libsyntax/ext/deriving/iter_bytes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax/ext/deriving/iter_bytes.rs')
-rw-r--r--src/libsyntax/ext/deriving/iter_bytes.rs282
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)
 }