about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-04-11 06:55:01 -0700
committerbors <bors@rust-lang.org>2013-04-11 06:55:01 -0700
commit2f8b36fc16178b298b23dfa199067ec2dd91df93 (patch)
tree685ecf6bd64a084a1827134c9f5966026763b2d3 /src/libsyntax
parente0defb8466e624ded66ef00f092a86b638e01152 (diff)
parent26ecb30f550a46d52528a7d45d9327ebce938e81 (diff)
downloadrust-2f8b36fc16178b298b23dfa199067ec2dd91df93.tar.gz
rust-2f8b36fc16178b298b23dfa199067ec2dd91df93.zip
auto merge of #5819 : erickt/rust/incoming, r=erickt
Good morning,

This first patch series adds support for `#[deriving(Decodable, Encodable)]`, but does not yet remove `#[auto_encode]` and `#[auto_decode]`. I need a snapshot to remove the old code. Along the way it also extends support for tuple structs and struct enum variants.

Also, it includes a minor fix to the pretty printer. We decided a while ago to use 4 spaces to indent a match arm instead of 2. This updates the pretty printer to reflect that. 
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/auto_encode.rs40
-rw-r--r--src/libsyntax/ext/build.rs124
-rw-r--r--src/libsyntax/ext/deriving/clone.rs10
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs454
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs388
-rw-r--r--src/libsyntax/ext/deriving/eq.rs8
-rw-r--r--src/libsyntax/ext/deriving/iter_bytes.rs8
-rw-r--r--src/libsyntax/ext/deriving/mod.rs50
-rw-r--r--src/libsyntax/print/pprust.rs15
9 files changed, 1030 insertions, 67 deletions
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
index f9dadb560e3..e53a8f361b5 100644
--- a/src/libsyntax/ext/auto_encode.rs
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -732,12 +732,12 @@ fn mk_struct_ser_impl(
             )
         );
 
-        // ast for `__s.emit_field($(name), $(idx), $(expr_lambda))`
+        // ast for `__s.emit_struct_field($(name), $(idx), $(expr_lambda))`
         cx.stmt(
             cx.expr_method_call(
                 span,
                 cx.expr_var(span, ~"__s"),
-                cx.ident_of(~"emit_field"),
+                cx.ident_of(~"emit_struct_field"),
                 ~[
                     cx.lit_str(span, @cx.str_of(field.ident)),
                     cx.lit_uint(span, idx),
@@ -786,11 +786,11 @@ fn mk_struct_deser_impl(
             )
         );
 
-        // ast for `__d.read_field($(name), $(idx), $(expr_lambda))`
+        // ast for `__d.read_struct_field($(name), $(idx), $(expr_lambda))`
         let expr: @ast::expr = cx.expr_method_call(
             span,
             cx.expr_var(span, ~"__d"),
-            cx.ident_of(~"read_field"),
+            cx.ident_of(~"read_struct_field"),
             ~[
                 cx.lit_str(span, @cx.str_of(field.ident)),
                 cx.lit_uint(span, idx),
@@ -1253,20 +1253,35 @@ mod test {
             self.add_to_log(CallToEmitEnumVariantArg (idx)); f();
         }
 
-        fn emit_seq(&self, +_len: uint, f: &fn()) {
-            self.add_unknown_to_log(); f();
+        fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) {
+            self.emit_enum_variant(name, id, cnt, f)
         }
-        fn emit_seq_elt(&self, +_idx: uint, f: &fn()) {
-            self.add_unknown_to_log(); f();
+
+        fn emit_enum_struct_variant_field(&self, _name: &str, idx: uint, f: &fn()) {
+            self.emit_enum_variant_arg(idx, f)
         }
 
         fn emit_struct(&self, name: &str, +len: uint, f: &fn()) {
             self.add_to_log(CallToEmitStruct (name.to_str(),len)); f();
         }
-        fn emit_field(&self, name: &str, +idx: uint, f: &fn()) {
+        fn emit_struct_field(&self, name: &str, +idx: uint, f: &fn()) {
             self.add_to_log(CallToEmitField (name.to_str(),idx)); f();
         }
 
+        fn emit_tuple(&self, _len: uint, f: &fn()) {
+            self.add_unknown_to_log(); f();
+        }
+        fn emit_tuple_arg(&self, _idx: uint, f: &fn()) {
+            self.add_unknown_to_log(); f();
+        }
+
+        fn emit_tuple_struct(&self, _name: &str, _len: uint, f: &fn()) {
+            self.add_unknown_to_log(); f();
+        }
+        fn emit_tuple_struct_arg(&self, _idx: uint, f: &fn()) {
+            self.add_unknown_to_log(); f();
+        }
+
         fn emit_option(&self, f: &fn()) {
             self.add_to_log(CallToEmitOption);
             f();
@@ -1279,6 +1294,13 @@ mod test {
             f();
         }
 
+        fn emit_seq(&self, +_len: uint, f: &fn()) {
+            self.add_unknown_to_log(); f();
+        }
+        fn emit_seq_elt(&self, +_idx: uint, f: &fn()) {
+            self.add_unknown_to_log(); f();
+        }
+
         fn emit_map(&self, _len: uint, f: &fn()) {
             self.add_unknown_to_log(); f();
         }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 0f84ac41532..b375adef926 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -64,12 +64,7 @@ pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr)
     mk_expr(cx, sp, ast::expr_unary(op, e))
 }
 pub fn mk_raw_path(sp: span, +idents: ~[ast::ident]) -> @ast::Path {
-    let p = @ast::Path { span: sp,
-                         global: false,
-                         idents: idents,
-                         rp: None,
-                         types: ~[] };
-    return p;
+    mk_raw_path_(sp, idents, ~[])
 }
 pub fn mk_raw_path_(sp: span,
                     +idents: ~[ast::ident],
@@ -82,11 +77,16 @@ pub fn mk_raw_path_(sp: span,
                  types: types }
 }
 pub fn mk_raw_path_global(sp: span, +idents: ~[ast::ident]) -> @ast::Path {
+    mk_raw_path_global_(sp, idents, ~[])
+}
+pub fn mk_raw_path_global_(sp: span,
+                           +idents: ~[ast::ident],
+                           +types: ~[@ast::Ty]) -> @ast::Path {
     @ast::Path { span: sp,
                  global: true,
                  idents: idents,
                  rp: None,
-                 types: ~[] }
+                 types: types }
 }
 pub fn mk_path(cx: @ext_ctxt, sp: span, +idents: ~[ast::ident])
             -> @ast::expr {
@@ -271,6 +271,36 @@ pub fn mk_simple_block(cx: @ext_ctxt,
         span: span,
     }
 }
+pub fn mk_lambda_(cx: @ext_ctxt,
+                 span: span,
+                 fn_decl: ast::fn_decl,
+                 blk: ast::blk)
+              -> @ast::expr {
+    mk_expr(cx, span, ast::expr_fn_block(fn_decl, blk))
+}
+pub fn mk_lambda(cx: @ext_ctxt,
+                 span: span,
+                 fn_decl: ast::fn_decl,
+                 expr: @ast::expr)
+              -> @ast::expr {
+    let blk = mk_simple_block(cx, span, expr);
+    mk_lambda_(cx, span, fn_decl, blk)
+}
+pub fn mk_lambda_stmts(cx: @ext_ctxt,
+                       span: span,
+                       fn_decl: ast::fn_decl,
+                       stmts: ~[@ast::stmt])
+                    -> @ast::expr {
+    let blk = mk_block(cx, span, ~[], stmts, None);
+    mk_lambda(cx, span, fn_decl, blk)
+}
+pub fn mk_lambda_no_args(cx: @ext_ctxt,
+                         span: span,
+                         expr: @ast::expr)
+                      -> @ast::expr {
+    let fn_decl = mk_fn_decl(~[], mk_ty_infer(cx, span));
+    mk_lambda(cx, span, fn_decl, expr)
+}
 pub fn mk_copy(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
     mk_expr(cx, sp, ast::expr_copy(e))
 }
@@ -280,11 +310,20 @@ pub fn mk_managed(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
 pub fn mk_pat(cx: @ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat {
     @ast::pat { id: cx.next_id(), node: pat, span: span }
 }
+pub fn mk_pat_wild(cx: @ext_ctxt, span: span) -> @ast::pat {
+    mk_pat(cx, span, ast::pat_wild)
+}
+pub fn mk_pat_lit(cx: @ext_ctxt,
+                  span: span,
+                  expr: @ast::expr) -> @ast::pat {
+    mk_pat(cx, span, ast::pat_lit(expr))
+}
 pub fn mk_pat_ident(cx: @ext_ctxt,
                     span: span,
                     ident: ast::ident) -> @ast::pat {
     mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_copy)
 }
+
 pub fn mk_pat_ident_with_binding_mode(cx: @ext_ctxt,
                                       span: span,
                                       ident: ast::ident,
@@ -337,12 +376,35 @@ pub fn mk_ty_path_global(cx: @ext_ctxt,
     let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
     ty
 }
+pub fn mk_ty_rptr(cx: @ext_ctxt,
+                  span: span,
+                  ty: @ast::Ty,
+                  mutbl: ast::mutability)
+               -> @ast::Ty {
+    @ast::Ty {
+        id: cx.next_id(),
+        span: span,
+        node: ast::ty_rptr(
+            None,
+            ast::mt { ty: ty, mutbl: 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,
+    }
+}
 pub fn mk_trait_ref_global(cx: @ext_ctxt,
                            span: span,
                            +idents: ~[ ast::ident ])
     -> @ast::trait_ref
 {
-    let path = build::mk_raw_path_global(span, idents);
+    mk_trait_ref_(cx, build::mk_raw_path_global(span, idents))
+}
+pub fn mk_trait_ref_(cx: @ext_ctxt, path: @ast::Path) -> @ast::trait_ref {
     @ast::trait_ref {
         path: path,
         ref_id: cx.next_id()
@@ -371,6 +433,16 @@ pub fn mk_arg(cx: @ext_ctxt,
 pub fn mk_fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl {
     ast::fn_decl { inputs: inputs, output: output, cf: ast::return_val }
 }
+pub fn mk_trait_ty_param_bound_global(cx: @ext_ctxt,
+                                      span: span,
+                                      +idents: ~[ast::ident])
+                                   -> ast::TyParamBound {
+    ast::TraitTyParamBound(mk_trait_ref_global(cx, span, idents))
+}
+pub fn mk_trait_ty_param_bound_(cx: @ext_ctxt,
+                                path: @ast::Path) -> ast::TyParamBound {
+    ast::TraitTyParamBound(mk_trait_ref_(cx, path))
+}
 pub fn mk_ty_param(cx: @ext_ctxt,
                    ident: ast::ident,
                    bounds: @OptVec<ast::TyParamBound>)
@@ -379,8 +451,38 @@ pub fn mk_ty_param(cx: @ext_ctxt,
 }
 pub fn mk_lifetime(cx: @ext_ctxt,
                    span: span,
-                   ident: ast::ident) -> ast::Lifetime
-{
+                   ident: ast::ident)
+                -> ast::Lifetime {
     ast::Lifetime { id: cx.next_id(), span: span, ident: ident }
 }
-
+pub fn mk_arm(cx: @ext_ctxt,
+              span: span,
+              pats: ~[@ast::pat],
+              expr: @ast::expr)
+           -> ast::arm {
+    ast::arm {
+        pats: pats,
+        guard: None,
+        body: mk_simple_block(cx, span, expr)
+    }
+}
+pub fn mk_unreachable(cx: @ext_ctxt, span: span) -> @ast::expr {
+    let loc = cx.codemap().lookup_char_pos(span.lo);
+    mk_call_global(
+        cx,
+        span,
+        ~[
+            cx.ident_of(~"core"),
+            cx.ident_of(~"sys"),
+            cx.ident_of(~"begin_unwind"),
+        ],
+        ~[
+            mk_uniq_str(cx, span, ~"internal error: entered unreachable code"),
+            mk_uniq_str(cx, span, loc.file.name),
+            mk_uint(cx, span, loc.line),
+        ]
+    )
+}
+pub fn mk_unreachable_arm(cx: @ext_ctxt, span: span) -> ast::arm {
+    mk_arm(cx, span, ~[mk_pat_wild(cx, span)], mk_unreachable(cx, span))
+}
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index c9e17715999..c8ba6b990e4 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -17,6 +17,7 @@ use ext::build;
 use ext::deriving::*;
 use codemap::{span, spanned};
 use ast_util;
+use opt_vec;
 
 use core::uint;
 
@@ -48,12 +49,13 @@ fn create_derived_clone_impl(cx: @ext_ctxt,
                              method: @method)
                           -> @item {
     let methods = [ method ];
-    let trait_path = [
+    let trait_path = ~[
         cx.ident_of(~"core"),
         cx.ident_of(~"clone"),
         cx.ident_of(~"Clone"),
     ];
-    create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
+    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)
 }
 // Creates a method from the given expression conforming to the signature of
 // the `clone` method.
@@ -188,9 +190,7 @@ fn expand_deriving_clone_struct_method(cx: @ext_ctxt,
                 fields.push(field);
             }
             unnamed_field => {
-                cx.span_bug(span,
-                            ~"unnamed fields in \
-                              expand_deriving_clone_struct_method");
+                cx.span_bug(span, ~"unnamed fields in `deriving(Clone)`");
             }
         }
     }
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
new file mode 100644
index 00000000000..11f492316e2
--- /dev/null
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -0,0 +1,454 @@
+// 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 core::prelude::*;
+
+use ast;
+use ast::*;
+use ext::base::ext_ctxt;
+use ext::build;
+use ext::deriving::*;
+use codemap::{span, spanned};
+use ast_util;
+use opt_vec;
+
+use core::uint;
+
+pub fn expand_deriving_decodable(
+    cx: @ext_ctxt,
+    span: span,
+    _mitem: @meta_item,
+    in_items: ~[@item]
+) -> ~[@item] {
+    expand_deriving(
+        cx,
+        span,
+        in_items,
+        expand_deriving_decodable_struct_def,
+        expand_deriving_decodable_enum_def
+    )
+}
+
+fn create_derived_decodable_impl(
+    cx: @ext_ctxt,
+    span: span,
+    type_ident: ident,
+    generics: &Generics,
+    method: @method
+) -> @item {
+    let decoder_ty_param = build::mk_ty_param(
+        cx,
+        cx.ident_of(~"__D"),
+        @opt_vec::with(
+            build::mk_trait_ty_param_bound_global(
+                cx,
+                span,
+                ~[
+                    cx.ident_of(~"std"),
+                    cx.ident_of(~"serialize"),
+                    cx.ident_of(~"Decoder"),
+                ]
+            )
+        )
+    );
+
+    // All the type parameters need to bound to the trait.
+    let generic_ty_params = opt_vec::with(decoder_ty_param);
+
+    let methods = [method];
+    let trait_path = build::mk_raw_path_global_(
+        span,
+        ~[
+            cx.ident_of(~"std"),
+            cx.ident_of(~"serialize"),
+            cx.ident_of(~"Decodable")
+        ],
+        ~[
+            build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D"))
+        ]
+    );
+    create_derived_impl(
+        cx,
+        span,
+        type_ident,
+        generics,
+        methods,
+        trait_path,
+        generic_ty_params
+    )
+}
+
+// Creates a method from the given set of statements conforming to the
+// signature of the `decodable` method.
+fn create_decode_method(
+    cx: @ext_ctxt,
+    span: span,
+    type_ident: ast::ident,
+    generics: &Generics,
+    expr: @ast::expr
+) -> @method {
+    // Create the `e` parameter.
+    let d_arg_type = build::mk_ty_rptr(
+        cx,
+        span,
+        build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")),
+        ast::m_imm
+    );
+    let d_ident = cx.ident_of(~"__d");
+    let d_arg = build::mk_arg(cx, span, d_ident, d_arg_type);
+
+    // Create the type of the return value.
+    let output_type = create_self_type_with_params(
+        cx,
+        span,
+        type_ident,
+        generics
+    );
+
+    // Create the function declaration.
+    let inputs = ~[d_arg];
+    let fn_decl = build::mk_fn_decl(inputs, output_type);
+
+    // Create the body block.
+    let body_block = build::mk_simple_block(cx, span, expr);
+
+    // Create the method.
+    let self_ty = spanned { node: sty_static, span: span };
+    let method_ident = cx.ident_of(~"decode");
+    @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_decode_method(
+    cx: @ext_ctxt,
+    span: span
+) -> @ast::expr {
+    // Call the substructure method.
+    build::mk_call_(
+        cx,
+        span,
+        build::mk_path_global(
+            cx,
+            span,
+            ~[
+                cx.ident_of(~"std"),
+                cx.ident_of(~"serialize"),
+                cx.ident_of(~"Decodable"),
+                cx.ident_of(~"decode"),
+            ]
+        ),
+        ~[
+            build::mk_path(cx, span, ~[cx.ident_of(~"__d")])
+        ]
+    )
+}
+
+fn expand_deriving_decodable_struct_def(
+    cx: @ext_ctxt,
+    span: span,
+    struct_def: &struct_def,
+    type_ident: ident,
+    generics: &Generics
+) -> @item {
+    // Create the method.
+    let method = expand_deriving_decodable_struct_method(
+        cx,
+        span,
+        struct_def,
+        type_ident,
+        generics
+    );
+
+    // Create the implementation.
+    create_derived_decodable_impl(
+        cx,
+        span,
+        type_ident,
+        generics,
+        method
+    )
+}
+
+fn expand_deriving_decodable_enum_def(
+    cx: @ext_ctxt,
+    span: span,
+    enum_definition: &enum_def,
+    type_ident: ident,
+    generics: &Generics
+) -> @item {
+    // Create the method.
+    let method = expand_deriving_decodable_enum_method(
+        cx,
+        span,
+        enum_definition,
+        type_ident,
+        generics
+    );
+
+    // Create the implementation.
+    create_derived_decodable_impl(
+        cx,
+        span,
+        type_ident,
+        generics,
+        method
+    )
+}
+
+fn create_read_struct_field(
+    cx: @ext_ctxt,
+    span: span,
+    idx: uint,
+    ident: ident
+) -> build::Field {
+    // Call the substructure method.
+    let decode_expr = call_substructure_decode_method(cx, span);
+
+    let call_expr = build::mk_method_call(
+        cx,
+        span,
+        build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+        cx.ident_of(~"read_struct_field"),
+        ~[
+            build::mk_base_str(cx, span, cx.str_of(ident)),
+            build::mk_uint(cx, span, idx),
+            build::mk_lambda_no_args(cx, span, decode_expr),
+        ]
+    );
+
+    build::Field { ident: ident, ex: call_expr }
+}
+
+fn create_read_struct_arg(
+    cx: @ext_ctxt,
+    span: span,
+    idx: uint,
+    ident: ident
+) -> build::Field {
+    // Call the substructure method.
+    let decode_expr = call_substructure_decode_method(cx, span);
+
+    let call_expr = build::mk_method_call(
+        cx,
+        span,
+        build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+        cx.ident_of(~"read_struct_arg"),
+        ~[
+            build::mk_uint(cx, span, idx),
+            build::mk_lambda_no_args(cx, span, decode_expr),
+        ]
+    );
+
+    build::Field { ident: ident, ex: call_expr }
+}
+
+fn expand_deriving_decodable_struct_method(
+    cx: @ext_ctxt,
+    span: span,
+    struct_def: &struct_def,
+    type_ident: ident,
+    generics: &Generics
+) -> @method {
+    // Create the body of the method.
+    let mut i = 0;
+    let mut fields = ~[];
+    for struct_def.fields.each |struct_field| {
+        match struct_field.node.kind {
+            named_field(ident, _, _) => {
+                fields.push(create_read_struct_field(cx, span, i, ident));
+            }
+            unnamed_field => {
+                cx.span_unimpl(
+                    span,
+                    ~"unnamed fields with `deriving(Decodable)`"
+                );
+            }
+        }
+        i += 1;
+    }
+
+    let read_struct_expr = build::mk_method_call(
+        cx,
+        span,
+        build::mk_path(
+            cx,
+            span,
+            ~[cx.ident_of(~"__d")]
+        ),
+        cx.ident_of(~"read_struct"),
+        ~[
+            build::mk_base_str(cx, span, cx.str_of(type_ident)),
+            build::mk_uint(cx, span, fields.len()),
+            build::mk_lambda_no_args(
+                cx,
+                span,
+                build::mk_struct_e(
+                    cx,
+                    span,
+                    ~[type_ident],
+                    fields
+                )
+            ),
+        ]
+    );
+
+    // Create the method itself.
+    create_decode_method(cx, span, type_ident, generics, read_struct_expr)
+}
+
+fn create_read_variant_arg(
+    cx: @ext_ctxt,
+    span: span,
+    idx: uint,
+    variant: &ast::variant
+) -> ast::arm {
+    // Create the matching pattern.
+    let pat = build::mk_pat_lit(cx, span, build::mk_uint(cx, span, idx));
+
+    // Feed each argument in this variant to the decode function
+    // as well.
+    let variant_arg_len = variant_arg_count(cx, span, variant);
+
+    let expr = if variant_arg_len == 0 {
+        build::mk_path(cx, span, ~[variant.node.name])
+    } else {
+        // Feed the discriminant to the decode function.
+        let mut args = ~[];
+
+        for uint::range(0, variant_arg_len) |j| {
+            // Call the substructure method.
+            let expr = call_substructure_decode_method(cx, span);
+
+            let call_expr = build::mk_method_call(
+                cx,
+                span,
+                build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+                cx.ident_of(~"read_enum_variant_arg"),
+                ~[
+                    build::mk_uint(cx, span, j),
+                    build::mk_lambda_no_args(cx, span, expr),
+                ]
+            );
+
+            args.push(call_expr);
+        }
+
+        build::mk_call(
+            cx,
+            span,
+            ~[variant.node.name],
+            args
+        )
+    };
+
+    // Create the arm.
+    build::mk_arm(cx, span, ~[pat], expr)
+}
+
+fn create_read_enum_variant(
+    cx: @ext_ctxt,
+    span: span,
+    enum_definition: &enum_def
+) -> @expr {
+    // Create a vector that contains all the variant names.
+    let expr_arm_names = build::mk_base_vec_e(
+        cx,
+        span,
+        do enum_definition.variants.map |variant| {
+            build::mk_base_str(
+                cx,
+                span,
+                cx.str_of(variant.node.name)
+            )
+        }
+    );
+
+    // Create the arms of the match in the method body.
+    let mut arms = do enum_definition.variants.mapi |i, variant| {
+        create_read_variant_arg(cx, span, i, variant)
+    };
+
+    // Add the impossible case arm.
+    arms.push(build::mk_unreachable_arm(cx, span));
+
+    // Create the read_enum_variant expression.
+    build::mk_method_call(
+        cx,
+        span,
+        build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+        cx.ident_of(~"read_enum_variant"),
+        ~[
+            expr_arm_names,
+            build::mk_lambda(
+                cx,
+                span,
+                build::mk_fn_decl(
+                    ~[
+                        build::mk_arg(
+                            cx,
+                            span,
+                            cx.ident_of(~"__i"),
+                            build::mk_ty_infer(cx, span)
+                        )
+                    ],
+                    build::mk_ty_infer(cx, span)
+                ),
+                build::mk_expr(
+                    cx,
+                    span,
+                    ast::expr_match(
+                        build::mk_path(cx, span, ~[cx.ident_of(~"__i")]),
+                        arms
+                    )
+                )
+            )
+        ]
+    )
+}
+
+fn expand_deriving_decodable_enum_method(
+    cx: @ext_ctxt,
+    span: span,
+    enum_definition: &enum_def,
+    type_ident: ast::ident,
+    generics: &Generics
+) -> @method {
+    let read_enum_variant_expr = create_read_enum_variant(
+        cx,
+        span,
+        enum_definition
+    );
+
+    // Create the read_enum expression
+    let read_enum_expr = build::mk_method_call(
+        cx,
+        span,
+        build::mk_path(cx, span, ~[cx.ident_of(~"__d")]),
+        cx.ident_of(~"read_enum"),
+        ~[
+            build::mk_base_str(cx, span, cx.str_of(type_ident)),
+            build::mk_lambda_no_args(cx, span, read_enum_variant_expr),
+        ]
+    );
+
+    // Create the method.
+    create_decode_method(cx, span, type_ident, generics, read_enum_expr)
+}
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
new file mode 100644
index 00000000000..81bfb03724f
--- /dev/null
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -0,0 +1,388 @@
+// 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 core::prelude::*;
+
+use ast;
+use ast::*;
+use ext::base::ext_ctxt;
+use ext::build;
+use ext::deriving::*;
+use codemap::{span, spanned};
+use ast_util;
+use opt_vec;
+
+use core::uint;
+
+pub fn expand_deriving_encodable(
+    cx: @ext_ctxt,
+    span: span,
+    _mitem: @meta_item,
+    in_items: ~[@item]
+) -> ~[@item] {
+    expand_deriving(
+        cx,
+        span,
+        in_items,
+        expand_deriving_encodable_struct_def,
+        expand_deriving_encodable_enum_def
+    )
+}
+
+fn create_derived_encodable_impl(
+    cx: @ext_ctxt,
+    span: span,
+    type_ident: ident,
+    generics: &Generics,
+    method: @method
+) -> @item {
+    let encoder_ty_param = build::mk_ty_param(
+        cx,
+        cx.ident_of(~"__E"),
+        @opt_vec::with(
+            build::mk_trait_ty_param_bound_global(
+                cx,
+                span,
+                ~[
+                    cx.ident_of(~"std"),
+                    cx.ident_of(~"serialize"),
+                    cx.ident_of(~"Encoder"),
+                ]
+            )
+        )
+    );
+
+    // All the type parameters need to bound to the trait.
+    let generic_ty_params = opt_vec::with(encoder_ty_param);
+
+    let methods = [method];
+    let trait_path = build::mk_raw_path_global_(
+        span,
+        ~[
+            cx.ident_of(~"std"),
+            cx.ident_of(~"serialize"),
+            cx.ident_of(~"Encodable")
+        ],
+        ~[
+            build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E"))
+        ]
+    );
+    create_derived_impl(
+        cx,
+        span,
+        type_ident,
+        generics,
+        methods,
+        trait_path,
+        generic_ty_params
+    )
+}
+
+// Creates a method from the given set of statements conforming to the
+// signature of the `encodable` method.
+fn create_encode_method(
+    cx: @ext_ctxt,
+    span: span,
+    +statements: ~[@stmt]
+) -> @method {
+    // Create the `e` parameter.
+    let e_arg_type = build::mk_ty_rptr(
+        cx,
+        span,
+        build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")),
+        ast::m_imm
+    );
+    let e_ident = cx.ident_of(~"__e");
+    let e_arg = build::mk_arg(cx, span, e_ident, e_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 = ~[e_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(~"encode");
+    @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_encode_method(
+    cx: @ext_ctxt,
+    span: span,
+    self_field: @expr
+) -> @ast::expr {
+    // Gather up the parameters we want to chain along.
+    let e_ident = cx.ident_of(~"__e");
+    let e_expr = build::mk_path(cx, span, ~[e_ident]);
+
+    // Call the substructure method.
+    let encode_ident = cx.ident_of(~"encode");
+    build::mk_method_call(
+        cx,
+        span,
+        self_field,
+        encode_ident,
+        ~[e_expr]
+    )
+}
+
+fn expand_deriving_encodable_struct_def(
+    cx: @ext_ctxt,
+    span: span,
+    struct_def: &struct_def,
+    type_ident: ident,
+    generics: &Generics
+) -> @item {
+    // Create the method.
+    let method = expand_deriving_encodable_struct_method(
+        cx,
+        span,
+        type_ident,
+        struct_def
+    );
+
+    // Create the implementation.
+    create_derived_encodable_impl(
+        cx,
+        span,
+        type_ident,
+        generics,
+        method
+    )
+}
+
+fn expand_deriving_encodable_enum_def(
+    cx: @ext_ctxt,
+    span: span,
+    enum_definition: &enum_def,
+    type_ident: ident,
+    generics: &Generics
+) -> @item {
+    // Create the method.
+    let method = expand_deriving_encodable_enum_method(
+        cx,
+        span,
+        type_ident,
+        enum_definition
+    );
+
+    // Create the implementation.
+    create_derived_encodable_impl(
+        cx,
+        span,
+        type_ident,
+        generics,
+        method
+    )
+}
+
+fn expand_deriving_encodable_struct_method(
+    cx: @ext_ctxt,
+    span: span,
+    type_ident: ident,
+    struct_def: &struct_def
+) -> @method {
+    let self_ident = cx.ident_of(~"self");
+
+    // Create the body of the method.
+    let mut idx = 0;
+    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 encode_expr = call_substructure_encode_method(
+                    cx,
+                    span,
+                    self_field
+                );
+
+                let blk_expr = build::mk_lambda(
+                    cx,
+                    span,
+                    build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
+                    encode_expr
+                );
+
+                let call_expr = build::mk_method_call(
+                    cx,
+                    span,
+                    build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
+                    cx.ident_of(~"emit_struct_field"),
+                    ~[
+                        build::mk_base_str(cx, span, cx.str_of(ident)),
+                        build::mk_uint(cx, span, idx),
+                        blk_expr
+                    ]
+                );
+
+                statements.push(build::mk_stmt(cx, span, call_expr));
+            }
+            unnamed_field => {
+                cx.span_unimpl(
+                    span,
+                    ~"unnamed fields with `deriving(Encodable)`"
+                );
+            }
+        }
+        idx += 1;
+    }
+
+    let emit_struct_stmt = build::mk_method_call(
+        cx,
+        span,
+        build::mk_path(
+            cx,
+            span,
+            ~[cx.ident_of(~"__e")]
+        ),
+        cx.ident_of(~"emit_struct"),
+        ~[
+            build::mk_base_str(cx, span, cx.str_of(type_ident)),
+            build::mk_uint(cx, span, statements.len()),
+            build::mk_lambda_stmts(
+                cx,
+                span,
+                build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
+                statements
+            ),
+        ]
+    );
+
+    let statements = ~[build::mk_stmt(cx, span, emit_struct_stmt)];
+
+    // Create the method itself.
+    return create_encode_method(cx, span, statements);
+}
+
+fn expand_deriving_encodable_enum_method(
+    cx: @ext_ctxt,
+    span: span,
+    type_ident: ast::ident,
+    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");
+
+        // Feed the discriminant to the encode function.
+        let mut stmts = ~[];
+
+        // 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 ]);
+
+            // Call the substructure method.
+            let expr = call_substructure_encode_method(cx, span, field);
+
+            let blk_expr = build::mk_lambda(
+                cx,
+                span,
+                build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
+                expr
+            );
+
+            let call_expr = build::mk_method_call(
+                cx,
+                span,
+                build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
+                cx.ident_of(~"emit_enum_variant_arg"),
+                ~[
+                    build::mk_uint(cx, span, j),
+                    blk_expr,
+                ]
+            );
+
+            stmts.push(build::mk_stmt(cx, span, call_expr));
+        }
+
+        // Create the pattern body.
+        let call_expr = build::mk_method_call(
+            cx,
+            span,
+            build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
+            cx.ident_of(~"emit_enum_variant"),
+            ~[
+                build::mk_base_str(cx, span, cx.str_of(variant.node.name)),
+                build::mk_uint(cx, span, i),
+                build::mk_uint(cx, span, variant_arg_len),
+                build::mk_lambda_stmts(
+                    cx,
+                    span,
+                    build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
+                    stmts
+                )
+            ]
+        );
+
+        let match_body_block = build::mk_simple_block(cx, span, call_expr);
+
+        // Create the arm.
+        ast::arm {
+            pats: ~[pat],
+            guard: None,
+            body: match_body_block,
+        }
+    };
+
+    // Create the method body.
+    let lambda_expr = build::mk_lambda(
+        cx,
+        span,
+        build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)),
+        expand_enum_or_struct_match(cx, span, arms)
+    );
+
+    let call_expr = build::mk_method_call(
+        cx,
+        span,
+        build::mk_path(cx, span, ~[cx.ident_of(~"__e")]),
+        cx.ident_of(~"emit_enum"),
+        ~[
+            build::mk_base_str(cx, span, cx.str_of(type_ident)),
+            lambda_expr,
+        ]
+    );
+
+    let stmt = build::mk_stmt(cx, span, call_expr);
+
+    // Create the method.
+    create_encode_method(cx, span, ~[stmt])
+}
diff --git a/src/libsyntax/ext/deriving/eq.rs b/src/libsyntax/ext/deriving/eq.rs
index 07b2835d44c..c427a206c2e 100644
--- a/src/libsyntax/ext/deriving/eq.rs
+++ b/src/libsyntax/ext/deriving/eq.rs
@@ -17,6 +17,7 @@ use ext::build;
 use ext::deriving::*;
 use codemap::{span, spanned};
 use ast_util;
+use opt_vec;
 
 use core::uint;
 
@@ -124,12 +125,13 @@ fn create_derived_eq_impl(cx: @ext_ctxt,
                           ne_method: @method)
                        -> @item {
     let methods = [ eq_method, ne_method ];
-    let trait_path = [
+    let trait_path = ~[
         cx.ident_of(~"core"),
         cx.ident_of(~"cmp"),
         cx.ident_of(~"Eq")
     ];
-    create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
+    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)
 }
 
 fn call_substructure_eq_method(cx: @ext_ctxt,
@@ -289,7 +291,7 @@ fn expand_deriving_eq_struct_method(cx: @ext_ctxt,
                                             &mut outer_expr);
             }
             unnamed_field => {
-                cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`");
+                cx.span_unimpl(span, ~"unnamed fields with `deriving(Eq)`");
             }
         }
     }
diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs
index e2a43591ef0..4124e6ee6c1 100644
--- a/src/libsyntax/ext/deriving/iter_bytes.rs
+++ b/src/libsyntax/ext/deriving/iter_bytes.rs
@@ -17,6 +17,7 @@ use ext::build;
 use ext::deriving::*;
 use codemap::{span, spanned};
 use ast_util;
+use opt_vec;
 
 use core::uint;
 
@@ -49,12 +50,13 @@ fn create_derived_iter_bytes_impl(cx: @ext_ctxt,
                                   method: @method)
                                -> @item {
     let methods = [ method ];
-    let trait_path = [
+    let trait_path = ~[
         cx.ident_of(~"core"),
         cx.ident_of(~"to_bytes"),
         cx.ident_of(~"IterBytes")
     ];
-    create_derived_impl(cx, span, type_ident, generics, methods, trait_path)
+    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)
 }
 
 // Creates a method from the given set of statements conforming to the
@@ -191,7 +193,7 @@ fn expand_deriving_iter_bytes_struct_method(cx: @ext_ctxt,
             }
             unnamed_field => {
                 cx.span_unimpl(span,
-                               ~"unnamed fields with `deriving_iter_bytes`");
+                               ~"unnamed fields with `deriving(IterBytes)`");
             }
         }
     }
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index 4337546930f..63106eae48a 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -14,7 +14,7 @@
 use core::prelude::*;
 
 use ast;
-use ast::{TraitTyParamBound, Ty, bind_by_ref, deref, enum_def};
+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};
@@ -33,6 +33,8 @@ use core::uint;
 pub mod clone;
 pub mod eq;
 pub mod iter_bytes;
+pub mod encodable;
+pub mod decodable;
 
 type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt,
                                                   span,
@@ -76,6 +78,10 @@ pub fn expand_meta_deriving(cx: @ext_ctxt,
                                 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),
                             tname => {
                                 cx.span_err(titem.span, fmt!("unknown \
                                     `deriving` trait: `%s`", tname));
@@ -153,12 +159,13 @@ pub fn create_self_type_with_params(cx: @ext_ctxt,
 }
 
 pub fn create_derived_impl(cx: @ext_ctxt,
-                       span: span,
-                       type_ident: ident,
-                       generics: &Generics,
-                       methods: &[@method],
-                       trait_path: &[ident])
-                    -> @item {
+                           span: span,
+                           type_ident: ident,
+                           generics: &Generics,
+                           methods: &[@method],
+                           trait_path: @ast::Path,
+                           mut impl_ty_params: opt_vec::OptVec<ast::TyParam>)
+                        -> @item {
     /*!
      *
      * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
@@ -175,29 +182,16 @@ pub fn create_derived_impl(cx: @ext_ctxt,
         build::mk_lifetime(cx, l.span, l.ident)
     });
 
-    // Create the type parameters.
-    let impl_ty_params = generics.ty_params.map(|ty_param| {
-        let bound = build::mk_trait_ref_global(cx,
-                                               span,
-                                               trait_path.map(|x| *x));
-        let bounds = @opt_vec::with(TraitTyParamBound(bound));
-        build::mk_ty_param(cx, ty_param.ident, bounds)
-    });
-
     // Create the reference to the trait.
-    let trait_path = ast::Path {
-        span: span,
-        global: true,
-        idents: trait_path.map(|x| *x),
-        rp: None,
-        types: ~[]
-    };
-    let trait_path = @trait_path;
-    let trait_ref = ast::trait_ref {
-        path: trait_path,
-        ref_id: cx.next_id()
+    let trait_ref = build::mk_trait_ref_(cx, trait_path);
+
+    // Create the type parameters.
+    for generics.ty_params.each |ty_param| {
+        let bounds = @opt_vec::with(
+            build::mk_trait_ty_param_bound_(cx, trait_path)
+        );
+        impl_ty_params.push(build::mk_ty_param(cx, ty_param.ident, bounds));
     };
-    let trait_ref = @trait_ref;
 
     // Create the type of `self`.
     let self_type = create_self_type_with_params(cx,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index fa1b9727566..4e7e5144a7d 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -95,7 +95,6 @@ pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps {
 }
 
 pub static indent_unit: uint = 4u;
-pub static match_indent_unit: uint = 2u;
 
 pub static default_columns: uint = 78u;
 
@@ -1227,16 +1226,16 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
         print_block(s, blk);
       }
       ast::expr_match(expr, ref arms) => {
-        cbox(s, match_indent_unit);
+        cbox(s, indent_unit);
         ibox(s, 4);
         word_nbsp(s, ~"match");
         print_expr(s, expr);
         space(s.s);
         bopen(s);
-        let len = (*arms).len();
-        for (*arms).eachi |i, arm| {
+        let len = arms.len();
+        for arms.eachi |i, arm| {
             space(s.s);
-            cbox(s, match_indent_unit);
+            cbox(s, indent_unit);
             ibox(s, 0u);
             let mut first = true;
             for arm.pats.each |p| {
@@ -1269,7 +1268,7 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
                             ast::expr_block(ref blk) => {
                                 // the block will close the pattern's ibox
                                 print_block_unclosed_indent(
-                                    s, blk, match_indent_unit);
+                                    s, blk, indent_unit);
                             }
                             _ => {
                                 end(s); // close the ibox for the pattern
@@ -1286,10 +1285,10 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
                 }
             } else {
                 // the block will close the pattern's ibox
-                print_block_unclosed_indent(s, &arm.body, match_indent_unit);
+                print_block_unclosed_indent(s, &arm.body, indent_unit);
             }
         }
-        bclose_(s, expr.span, match_indent_unit);
+        bclose_(s, expr.span, indent_unit);
       }
       ast::expr_fn_block(ref decl, ref body) => {
         // in do/for blocks we don't want to show an empty