about summary refs log tree commit diff
diff options
context:
space:
mode:
authorErick Tryzelaar <erick.tryzelaar@gmail.com>2012-12-10 20:37:21 -0800
committerErick Tryzelaar <erick.tryzelaar@gmail.com>2012-12-13 18:16:31 -0800
commit786c143a70ac40e5e028eed6b8efaa54076ce41f (patch)
tree7b591cf45dc738ff78d99528f94883179cf4e4bd
parentc3f0aa973e9391c15bdfef92f72c410d3c32bc75 (diff)
downloadrust-786c143a70ac40e5e028eed6b8efaa54076ce41f.tar.gz
rust-786c143a70ac40e5e028eed6b8efaa54076ce41f.zip
Begin renaming serialization to std::serialize. (snapshot)
-rw-r--r--src/libstd/serialize.rs585
-rw-r--r--src/libstd/std.rc4
-rw-r--r--src/libsyntax/ext/auto_encode.rs1161
-rw-r--r--src/libsyntax/ext/auto_serialize.rs133
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/syntax.rc3
6 files changed, 1759 insertions, 135 deletions
diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs
new file mode 100644
index 00000000000..a2c80914fd6
--- /dev/null
+++ b/src/libstd/serialize.rs
@@ -0,0 +1,585 @@
+// Copyright 2012 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.
+
+//! Support code for encoding and decoding types.
+
+/*
+Core encoding and decoding interfaces.
+*/
+
+#[forbid(deprecated_mode)];
+#[forbid(non_camel_case_types)];
+
+pub trait Encoder {
+    // Primitive types:
+    fn emit_nil(&self);
+    fn emit_uint(&self, v: uint);
+    fn emit_u64(&self, v: u64);
+    fn emit_u32(&self, v: u32);
+    fn emit_u16(&self, v: u16);
+    fn emit_u8(&self, v: u8);
+    fn emit_int(&self, v: int);
+    fn emit_i64(&self, v: i64);
+    fn emit_i32(&self, v: i32);
+    fn emit_i16(&self, v: i16);
+    fn emit_i8(&self, v: i8);
+    fn emit_bool(&self, v: bool);
+    fn emit_float(&self, v: float);
+    fn emit_f64(&self, v: f64);
+    fn emit_f32(&self, v: f32);
+    fn emit_char(&self, v: char);
+    fn emit_borrowed_str(&self, v: &str);
+    fn emit_owned_str(&self, v: &str);
+    fn emit_managed_str(&self, v: &str);
+
+    // Compound types:
+    fn emit_borrowed(&self, f: fn());
+    fn emit_owned(&self, f: fn());
+    fn emit_managed(&self, f: fn());
+
+    fn emit_enum(&self, name: &str, f: fn());
+    fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: fn());
+    fn emit_enum_variant_arg(&self, idx: uint, f: fn());
+
+    fn emit_borrowed_vec(&self, len: uint, f: fn());
+    fn emit_owned_vec(&self, len: uint, f: fn());
+    fn emit_managed_vec(&self, len: uint, f: fn());
+    fn emit_vec_elt(&self, idx: uint, f: fn());
+
+    fn emit_rec(&self, f: fn());
+    fn emit_struct(&self, name: &str, f: fn());
+    fn emit_field(&self, f_name: &str, f_idx: uint, f: fn());
+
+    fn emit_tup(&self, len: uint, f: fn());
+    fn emit_tup_elt(&self, idx: uint, f: fn());
+}
+
+pub trait Decoder {
+    // Primitive types:
+    fn read_nil(&self) -> ();
+    fn read_uint(&self) -> uint;
+    fn read_u64(&self) -> u64;
+    fn read_u32(&self) -> u32;
+    fn read_u16(&self) -> u16;
+    fn read_u8(&self) -> u8;
+    fn read_int(&self) -> int;
+    fn read_i64(&self) -> i64;
+    fn read_i32(&self) -> i32;
+    fn read_i16(&self) -> i16;
+    fn read_i8(&self) -> i8;
+    fn read_bool(&self) -> bool;
+    fn read_f64(&self) -> f64;
+    fn read_f32(&self) -> f32;
+    fn read_float(&self) -> float;
+    fn read_char(&self) -> char;
+    fn read_owned_str(&self) -> ~str;
+    fn read_managed_str(&self) -> @str;
+
+    // Compound types:
+    fn read_enum<T>(&self, name: &str, f: fn() -> T) -> T;
+    fn read_enum_variant<T>(&self, f: fn(uint) -> T) -> T;
+    fn read_enum_variant_arg<T>(&self, idx: uint, f: fn() -> T) -> T;
+
+    fn read_owned<T>(&self, f: fn() -> T) -> T;
+    fn read_managed<T>(&self, f: fn() -> T) -> T;
+
+    fn read_owned_vec<T>(&self, f: fn(uint) -> T) -> T;
+    fn read_managed_vec<T>(&self, f: fn(uint) -> T) -> T;
+    fn read_vec_elt<T>(&self, idx: uint, f: fn() -> T) -> T;
+
+    fn read_rec<T>(&self, f: fn() -> T) -> T;
+    fn read_struct<T>(&self, name: &str, f: fn() -> T) -> T;
+    fn read_field<T>(&self, name: &str, idx: uint, f: fn() -> T) -> T;
+
+    fn read_tup<T>(&self, sz: uint, f: fn() -> T) -> T;
+    fn read_tup_elt<T>(&self, idx: uint, f: fn() -> T) -> T;
+}
+
+pub mod traits {
+pub trait Encodable<S: Encoder> {
+    fn encode(&self, s: &S);
+}
+
+pub trait Decodable<D: Decoder> {
+    static fn decode(&self, d: &D) -> self;
+}
+
+pub impl<S: Encoder> uint: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_uint(*self) }
+}
+
+pub impl<D: Decoder> uint: Decodable<D> {
+    static fn decode(&self, d: &D) -> uint {
+        d.read_uint()
+    }
+}
+
+pub impl<S: Encoder> u8: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_u8(*self) }
+}
+
+pub impl<D: Decoder> u8: Decodable<D> {
+    static fn decode(&self, d: &D) -> u8 {
+        d.read_u8()
+    }
+}
+
+pub impl<S: Encoder> u16: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_u16(*self) }
+}
+
+pub impl<D: Decoder> u16: Decodable<D> {
+    static fn decode(&self, d: &D) -> u16 {
+        d.read_u16()
+    }
+}
+
+pub impl<S: Encoder> u32: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_u32(*self) }
+}
+
+pub impl<D: Decoder> u32: Decodable<D> {
+    static fn decode(&self, d: &D) -> u32 {
+        d.read_u32()
+    }
+}
+
+pub impl<S: Encoder> u64: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_u64(*self) }
+}
+
+pub impl<D: Decoder> u64: Decodable<D> {
+    static fn decode(&self, d: &D) -> u64 {
+        d.read_u64()
+    }
+}
+
+pub impl<S: Encoder> int: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_int(*self) }
+}
+
+pub impl<D: Decoder> int: Decodable<D> {
+    static fn decode(&self, d: &D) -> int {
+        d.read_int()
+    }
+}
+
+pub impl<S: Encoder> i8: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_i8(*self) }
+}
+
+pub impl<D: Decoder> i8: Decodable<D> {
+    static fn decode(&self, d: &D) -> i8 {
+        d.read_i8()
+    }
+}
+
+pub impl<S: Encoder> i16: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_i16(*self) }
+}
+
+pub impl<D: Decoder> i16: Decodable<D> {
+    static fn decode(&self, d: &D) -> i16 {
+        d.read_i16()
+    }
+}
+
+pub impl<S: Encoder> i32: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_i32(*self) }
+}
+
+pub impl<D: Decoder> i32: Decodable<D> {
+    static fn decode(&self, d: &D) -> i32 {
+        d.read_i32()
+    }
+}
+
+pub impl<S: Encoder> i64: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_i64(*self) }
+}
+
+pub impl<D: Decoder> i64: Decodable<D> {
+    static fn decode(&self, d: &D) -> i64 {
+        d.read_i64()
+    }
+}
+
+pub impl<S: Encoder> &str: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_borrowed_str(*self) }
+}
+
+pub impl<S: Encoder> ~str: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_owned_str(*self) }
+}
+
+pub impl<D: Decoder> ~str: Decodable<D> {
+    static fn decode(&self, d: &D) -> ~str {
+        d.read_owned_str()
+    }
+}
+
+pub impl<S: Encoder> @str: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_managed_str(*self) }
+}
+
+pub impl<D: Decoder> @str: Decodable<D> {
+    static fn decode(&self, d: &D) -> @str {
+        d.read_managed_str()
+    }
+}
+
+pub impl<S: Encoder> float: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_float(*self) }
+}
+
+pub impl<D: Decoder> float: Decodable<D> {
+    static fn decode(&self, d: &D) -> float {
+        d.read_float()
+    }
+}
+
+pub impl<S: Encoder> f32: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_f32(*self) }
+}
+
+pub impl<D: Decoder> f32: Decodable<D> {
+    static fn decode(&self, d: &D) -> f32 {
+        d.read_f32() }
+}
+
+pub impl<S: Encoder> f64: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_f64(*self) }
+}
+
+pub impl<D: Decoder> f64: Decodable<D> {
+    static fn decode(&self, d: &D) -> f64 {
+        d.read_f64()
+    }
+}
+
+pub impl<S: Encoder> bool: Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_bool(*self) }
+}
+
+pub impl<D: Decoder> bool: Decodable<D> {
+    static fn decode(&self, d: &D) -> bool {
+        d.read_bool()
+    }
+}
+
+pub impl<S: Encoder> (): Encodable<S> {
+    fn encode(&self, s: &S) { s.emit_nil() }
+}
+
+pub impl<D: Decoder> (): Decodable<D> {
+    static fn decode(&self, d: &D) -> () {
+        d.read_nil()
+    }
+}
+
+pub impl<S: Encoder, T: Encodable<S>> &T: Encodable<S> {
+    fn encode(&self, s: &S) {
+        s.emit_borrowed(|| (**self).encode(s))
+    }
+}
+
+pub impl<S: Encoder, T: Encodable<S>> ~T: Encodable<S> {
+    fn encode(&self, s: &S) {
+        s.emit_owned(|| (**self).encode(s))
+    }
+}
+
+pub impl<D: Decoder, T: Decodable<D>> ~T: Decodable<D> {
+    static fn decode(&self, d: &D) -> ~T {
+        d.read_owned(|| ~decode(d))
+    }
+}
+
+pub impl<S: Encoder, T: Encodable<S>> @T: Encodable<S> {
+    fn encode(&self, s: &S) {
+        s.emit_managed(|| (**self).encode(s))
+    }
+}
+
+pub impl<D: Decoder, T: Decodable<D>> @T: Decodable<D> {
+    static fn decode(&self, d: &D) -> @T {
+        d.read_managed(|| @decode(d))
+    }
+}
+
+pub impl<S: Encoder, T: Encodable<S>> &[T]: Encodable<S> {
+    fn encode(&self, s: &S) {
+        do s.emit_borrowed_vec(self.len()) {
+            for self.eachi |i, e| {
+                s.emit_vec_elt(i, || e.encode(s))
+            }
+        }
+    }
+}
+
+pub impl<S: Encoder, T: Encodable<S>> ~[T]: Encodable<S> {
+    fn encode(&self, s: &S) {
+        do s.emit_owned_vec(self.len()) {
+            for self.eachi |i, e| {
+                s.emit_vec_elt(i, || e.encode(s))
+            }
+        }
+    }
+}
+
+pub impl<D: Decoder, T: Decodable<D>> ~[T]: Decodable<D> {
+    static fn decode(&self, d: &D) -> ~[T] {
+        do d.read_owned_vec |len| {
+            do vec::from_fn(len) |i| {
+                d.read_vec_elt(i, || decode(d))
+            }
+        }
+    }
+}
+
+pub impl<S: Encoder, T: Encodable<S>> @[T]: Encodable<S> {
+    fn encode(&self, s: &S) {
+        do s.emit_managed_vec(self.len()) {
+            for self.eachi |i, e| {
+                s.emit_vec_elt(i, || e.encode(s))
+            }
+        }
+    }
+}
+
+pub impl<D: Decoder, T: Decodable<D>> @[T]: Decodable<D> {
+    static fn decode(&self, d: &D) -> @[T] {
+        do d.read_managed_vec |len| {
+            do at_vec::from_fn(len) |i| {
+                d.read_vec_elt(i, || decode(d))
+            }
+        }
+    }
+}
+
+pub impl<S: Encoder, T: Encodable<S>> Option<T>: Encodable<S> {
+    fn encode(&self, s: &S) {
+        do s.emit_enum(~"option") {
+            match *self {
+              None => do s.emit_enum_variant(~"none", 0u, 0u) {
+              },
+
+              Some(ref v) => do s.emit_enum_variant(~"some", 1u, 1u) {
+                s.emit_enum_variant_arg(0u, || v.encode(s))
+              }
+            }
+        }
+    }
+}
+
+pub impl<D: Decoder, T: Decodable<D>> Option<T>: Decodable<D> {
+    static fn decode(&self, d: &D) -> Option<T> {
+        do d.read_enum(~"option") {
+            do d.read_enum_variant |i| {
+                match i {
+                  0 => None,
+                  1 => Some(d.read_enum_variant_arg(0u, || decode(d))),
+                  _ => fail(fmt!("Bad variant for option: %u", i))
+                }
+            }
+        }
+    }
+}
+
+pub impl<
+    S: Encoder,
+    T0: Encodable<S>,
+    T1: Encodable<S>
+> (T0, T1): Encodable<S> {
+    fn encode(&self, s: &S) {
+        match *self {
+            (ref t0, ref t1) => {
+                do s.emit_tup(2) {
+                    s.emit_tup_elt(0, || t0.encode(s));
+                    s.emit_tup_elt(1, || t1.encode(s));
+                }
+            }
+        }
+    }
+}
+
+pub impl<
+    D: Decoder,
+    T0: Decodable<D>,
+    T1: Decodable<D>
+> (T0, T1): Decodable<D> {
+    static fn decode(&self, d: &D) -> (T0, T1) {
+        do d.read_tup(2) {
+            (
+                d.read_tup_elt(0, || decode(d)),
+                d.read_tup_elt(1, || decode(d))
+            )
+        }
+    }
+}
+
+pub impl<
+    S: Encoder,
+    T0: Encodable<S>,
+    T1: Encodable<S>,
+    T2: Encodable<S>
+> (T0, T1, T2): Encodable<S> {
+    fn encode(&self, s: &S) {
+        match *self {
+            (ref t0, ref t1, ref t2) => {
+                do s.emit_tup(3) {
+                    s.emit_tup_elt(0, || t0.encode(s));
+                    s.emit_tup_elt(1, || t1.encode(s));
+                    s.emit_tup_elt(2, || t2.encode(s));
+                }
+            }
+        }
+    }
+}
+
+pub impl<
+    D: Decoder,
+    T0: Decodable<D>,
+    T1: Decodable<D>,
+    T2: Decodable<D>
+> (T0, T1, T2): Decodable<D> {
+    static fn decode(&self, d: &D) -> (T0, T1, T2) {
+        do d.read_tup(3) {
+            (
+                d.read_tup_elt(0, || decode(d)),
+                d.read_tup_elt(1, || decode(d)),
+                d.read_tup_elt(2, || decode(d))
+            )
+        }
+    }
+}
+
+pub impl<
+    S: Encoder,
+    T0: Encodable<S>,
+    T1: Encodable<S>,
+    T2: Encodable<S>,
+    T3: Encodable<S>
+> (T0, T1, T2, T3): Encodable<S> {
+    fn encode(&self, s: &S) {
+        match *self {
+            (ref t0, ref t1, ref t2, ref t3) => {
+                do s.emit_tup(4) {
+                    s.emit_tup_elt(0, || t0.encode(s));
+                    s.emit_tup_elt(1, || t1.encode(s));
+                    s.emit_tup_elt(2, || t2.encode(s));
+                    s.emit_tup_elt(3, || t3.encode(s));
+                }
+            }
+        }
+    }
+}
+
+pub impl<
+    D: Decoder,
+    T0: Decodable<D>,
+    T1: Decodable<D>,
+    T2: Decodable<D>,
+    T3: Decodable<D>
+> (T0, T1, T2, T3): Decodable<D> {
+    static fn decode(&self, d: &D) -> (T0, T1, T2, T3) {
+        do d.read_tup(4) {
+            (
+                d.read_tup_elt(0, || decode(d)),
+                d.read_tup_elt(1, || decode(d)),
+                d.read_tup_elt(2, || decode(d)),
+                d.read_tup_elt(3, || decode(d))
+            )
+        }
+    }
+}
+
+pub impl<
+    S: Encoder,
+    T0: Encodable<S>,
+    T1: Encodable<S>,
+    T2: Encodable<S>,
+    T3: Encodable<S>,
+    T4: Encodable<S>
+> (T0, T1, T2, T3, T4): Encodable<S> {
+    fn encode(&self, s: &S) {
+        match *self {
+            (ref t0, ref t1, ref t2, ref t3, ref t4) => {
+                do s.emit_tup(5) {
+                    s.emit_tup_elt(0, || t0.encode(s));
+                    s.emit_tup_elt(1, || t1.encode(s));
+                    s.emit_tup_elt(2, || t2.encode(s));
+                    s.emit_tup_elt(3, || t3.encode(s));
+                    s.emit_tup_elt(4, || t4.encode(s));
+                }
+            }
+        }
+    }
+}
+
+pub impl<
+    D: Decoder,
+    T0: Decodable<D>,
+    T1: Decodable<D>,
+    T2: Decodable<D>,
+    T3: Decodable<D>,
+    T4: Decodable<D>
+> (T0, T1, T2, T3, T4): Decodable<D> {
+    static fn decode(&self, d: &D)
+      -> (T0, T1, T2, T3, T4) {
+        do d.read_tup(5) {
+            (
+                d.read_tup_elt(0, || decode(d)),
+                d.read_tup_elt(1, || decode(d)),
+                d.read_tup_elt(2, || decode(d)),
+                d.read_tup_elt(3, || decode(d)),
+                d.read_tup_elt(4, || decode(d))
+            )
+        }
+    }
+}
+
+// ___________________________________________________________________________
+// Helper routines
+//
+// In some cases, these should eventually be coded as traits.
+
+pub trait EncoderHelpers {
+    fn emit_from_vec<T>(&self, v: ~[T], f: fn(v: &T));
+}
+
+pub impl<S: Encoder> S: EncoderHelpers {
+    fn emit_from_vec<T>(&self, v: ~[T], f: fn(v: &T)) {
+        do self.emit_owned_vec(v.len()) {
+            for v.eachi |i, e| {
+                do self.emit_vec_elt(i) {
+                    f(e)
+                }
+            }
+        }
+    }
+}
+
+pub trait DecoderHelpers {
+    fn read_to_vec<T>(&self, f: fn() -> T) -> ~[T];
+}
+
+pub impl<D: Decoder> D: DecoderHelpers {
+    fn read_to_vec<T>(&self, f: fn() -> T) -> ~[T] {
+        do self.read_owned_vec |len| {
+            do vec::from_fn(len) |i| {
+                self.read_vec_elt(i, || f())
+            }
+        }
+    }
+}
+}
+
+pub use serialize::traits::*;
diff --git a/src/libstd/std.rc b/src/libstd/std.rc
index 7a1fdf49954..65916aa5992 100644
--- a/src/libstd/std.rc
+++ b/src/libstd/std.rc
@@ -104,13 +104,15 @@ mod unicode;
 // Compiler support modules
 
 pub mod test;
+pub mod serialize;
 pub mod serialization;
 
 // A curious inner-module that's not exported that contains the binding
-// 'std' so that macro-expanded references to std::serialization and such
+// 'std' so that macro-expanded references to std::code and such
 // can be resolved within libcore.
 #[doc(hidden)] // FIXME #3538
 mod std {
+    pub use serialize;
     pub use serialization;
 }
 
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
new file mode 100644
index 00000000000..0ff3dbe1506
--- /dev/null
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -0,0 +1,1161 @@
+// Copyright 2012 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.
+
+/*
+
+The compiler code necessary to implement the #[auto_encode] and
+#[auto_decode] extension.  The idea here is that type-defining items may
+be tagged with #[auto_encode] and #[auto_decode], which will cause
+us to generate a little companion module with the same name as the item.
+
+For example, a type like:
+
+    #[auto_encode]
+    #[auto_decode]
+    struct Node {id: uint}
+
+would generate two implementations like:
+
+    impl<S: Encoder> node_id: Encodable<S> {
+        fn encode(s: &S) {
+            do s.emit_struct("Node") {
+                s.emit_field("id", 0, || s.emit_uint(self))
+            }
+        }
+    }
+
+    impl<D: Decoder> node_id: Decodable {
+        static fn decode(d: &D) -> Node {
+            do d.read_struct("Node") {
+                Node {
+                    id: d.read_field(~"x", 0, || decode(d))
+                }
+            }
+        }
+    }
+
+Other interesting scenarios are whe the item has type parameters or
+references other non-built-in types.  A type definition like:
+
+    #[auto_encode]
+    #[auto_decode]
+    type spanned<T> = {node: T, span: span};
+
+would yield functions like:
+
+    impl<
+        S: Encoder,
+        T: Encodable<S>
+    > spanned<T>: Encodable<S> {
+        fn encode<S: Encoder>(s: &S) {
+            do s.emit_rec {
+                s.emit_field("node", 0, || self.node.encode(s));
+                s.emit_field("span", 1, || self.span.encode(s));
+            }
+        }
+    }
+
+    impl<
+        D: Decoder,
+        T: Decodable<D>
+    > spanned<T>: Decodable<D> {
+        static fn decode(d: &D) -> spanned<T> {
+            do d.read_rec {
+                {
+                    node: d.read_field(~"node", 0, || decode(d)),
+                    span: d.read_field(~"span", 1, || decode(d)),
+                }
+            }
+        }
+    }
+
+FIXME (#2810)--Hygiene. Search for "__" strings.  We also assume "std" is the
+standard library.
+
+Misc notes:
+-----------
+
+I use move mode arguments for ast nodes that will get inserted as is
+into the tree.  This is intended to prevent us from inserting the same
+node twice.
+
+*/
+
+use ext::base::*;
+use codemap::span;
+use std::map;
+use std::map::HashMap;
+
+export expand_auto_encode;
+export expand_auto_decode;
+
+// Transitional reexports so qquote can find the paths it is looking for
+mod syntax {
+    pub use ext;
+    pub use parse;
+}
+
+fn expand_auto_encode(
+    cx: ext_ctxt,
+    span: span,
+    _mitem: ast::meta_item,
+    in_items: ~[@ast::item]
+) -> ~[@ast::item] {
+    fn is_auto_encode(a: &ast::attribute) -> bool {
+        attr::get_attr_name(*a) == ~"auto_encode"
+    }
+
+    fn filter_attrs(item: @ast::item) -> @ast::item {
+        @{attrs: vec::filter(item.attrs, |a| !is_auto_encode(a)),
+          .. *item}
+    }
+
+    do vec::flat_map(in_items) |item| {
+        if item.attrs.any(is_auto_encode) {
+            match item.node {
+                ast::item_ty(@{node: ast::ty_rec(ref fields), _}, tps) => {
+                    let ser_impl = mk_rec_ser_impl(
+                        cx,
+                        item.span,
+                        item.ident,
+                        (*fields),
+                        tps
+                    );
+
+                    ~[filter_attrs(*item), ser_impl]
+                },
+                ast::item_struct(@{ fields, _}, tps) => {
+                    let ser_impl = mk_struct_ser_impl(
+                        cx,
+                        item.span,
+                        item.ident,
+                        fields,
+                        tps
+                    );
+
+                    ~[filter_attrs(*item), ser_impl]
+                },
+                ast::item_enum(ref enum_def, tps) => {
+                    let ser_impl = mk_enum_ser_impl(
+                        cx,
+                        item.span,
+                        item.ident,
+                        (*enum_def),
+                        tps
+                    );
+
+                    ~[filter_attrs(*item), ser_impl]
+                },
+                _ => {
+                    cx.span_err(span, ~"#[auto_encode] can only be \
+                                        applied to structs, record types, \
+                                        and enum definitions");
+                    ~[*item]
+                }
+            }
+        } else {
+            ~[*item]
+        }
+    }
+}
+
+fn expand_auto_decode(
+    cx: ext_ctxt,
+    span: span,
+    _mitem: ast::meta_item,
+    in_items: ~[@ast::item]
+) -> ~[@ast::item] {
+    fn is_auto_decode(a: &ast::attribute) -> bool {
+        attr::get_attr_name(*a) == ~"auto_decode"
+    }
+
+    fn filter_attrs(item: @ast::item) -> @ast::item {
+        @{attrs: vec::filter(item.attrs, |a| !is_auto_decode(a)),
+          .. *item}
+    }
+
+    do vec::flat_map(in_items) |item| {
+        if item.attrs.any(is_auto_decode) {
+            match item.node {
+                ast::item_ty(@{node: ast::ty_rec(ref fields), _}, tps) => {
+                    let deser_impl = mk_rec_deser_impl(
+                        cx,
+                        item.span,
+                        item.ident,
+                        (*fields),
+                        tps
+                    );
+
+                    ~[filter_attrs(*item), deser_impl]
+                },
+                ast::item_struct(@{ fields, _}, tps) => {
+                    let deser_impl = mk_struct_deser_impl(
+                        cx,
+                        item.span,
+                        item.ident,
+                        fields,
+                        tps
+                    );
+
+                    ~[filter_attrs(*item), deser_impl]
+                },
+                ast::item_enum(ref enum_def, tps) => {
+                    let deser_impl = mk_enum_deser_impl(
+                        cx,
+                        item.span,
+                        item.ident,
+                        (*enum_def),
+                        tps
+                    );
+
+                    ~[filter_attrs(*item), deser_impl]
+                },
+                _ => {
+                    cx.span_err(span, ~"#[auto_decode] can only be \
+                                        applied to structs, record types, \
+                                        and enum definitions");
+                    ~[*item]
+                }
+            }
+        } else {
+            ~[*item]
+        }
+    }
+}
+
+priv impl ext_ctxt {
+    fn bind_path(
+        span: span,
+        ident: ast::ident,
+        path: @ast::path,
+        bounds: @~[ast::ty_param_bound]
+    ) -> ast::ty_param {
+        let bound = ast::ty_param_bound(@{
+            id: self.next_id(),
+            node: ast::ty_path(path, self.next_id()),
+            span: span,
+        });
+
+        {
+            ident: ident,
+            id: self.next_id(),
+            bounds: @vec::append(~[bound], *bounds)
+        }
+    }
+
+    fn expr(span: span, node: ast::expr_) -> @ast::expr {
+        @{id: self.next_id(), callee_id: self.next_id(),
+          node: node, span: span}
+    }
+
+    fn path(span: span, strs: ~[ast::ident]) -> @ast::path {
+        @{span: span, global: false, idents: strs, rp: None, types: ~[]}
+    }
+
+    fn path_tps(span: span, strs: ~[ast::ident],
+                tps: ~[@ast::Ty]) -> @ast::path {
+        @{span: span, global: false, idents: strs, rp: None, types: tps}
+    }
+
+    fn ty_path(span: span, strs: ~[ast::ident],
+               tps: ~[@ast::Ty]) -> @ast::Ty {
+        @{id: self.next_id(),
+          node: ast::ty_path(self.path_tps(span, strs, tps), self.next_id()),
+          span: span}
+    }
+
+    fn binder_pat(span: span, nm: ast::ident) -> @ast::pat {
+        let path = @{span: span, global: false, idents: ~[nm],
+                     rp: None, types: ~[]};
+        @{id: self.next_id(),
+          node: ast::pat_ident(ast::bind_by_ref(ast::m_imm),
+                               path,
+                               None),
+          span: span}
+    }
+
+    fn stmt(expr: @ast::expr) -> @ast::stmt {
+        @{node: ast::stmt_semi(expr, self.next_id()),
+          span: expr.span}
+    }
+
+    fn lit_str(span: span, s: @~str) -> @ast::expr {
+        self.expr(
+            span,
+            ast::expr_vstore(
+                self.expr(
+                    span,
+                    ast::expr_lit(
+                        @{node: ast::lit_str(s),
+                          span: span})),
+                ast::expr_vstore_uniq))
+    }
+
+    fn lit_uint(span: span, i: uint) -> @ast::expr {
+        self.expr(
+            span,
+            ast::expr_lit(
+                @{node: ast::lit_uint(i as u64, ast::ty_u),
+                  span: span}))
+    }
+
+    fn lambda(blk: ast::blk) -> @ast::expr {
+        let ext_cx = self;
+        let blk_e = self.expr(blk.span, ast::expr_block(blk));
+        quote_expr!( || $blk_e )
+    }
+
+    fn blk(span: span, stmts: ~[@ast::stmt]) -> ast::blk {
+        {node: {view_items: ~[],
+                stmts: stmts,
+                expr: None,
+                id: self.next_id(),
+                rules: ast::default_blk},
+         span: span}
+    }
+
+    fn expr_blk(expr: @ast::expr) -> ast::blk {
+        {node: {view_items: ~[],
+                stmts: ~[],
+                expr: Some(expr),
+                id: self.next_id(),
+                rules: ast::default_blk},
+         span: expr.span}
+    }
+
+    fn expr_path(span: span, strs: ~[ast::ident]) -> @ast::expr {
+        self.expr(span, ast::expr_path(self.path(span, strs)))
+    }
+
+    fn expr_var(span: span, var: ~str) -> @ast::expr {
+        self.expr_path(span, ~[self.ident_of(var)])
+    }
+
+    fn expr_field(
+        span: span,
+        expr: @ast::expr,
+        ident: ast::ident
+    ) -> @ast::expr {
+        self.expr(span, ast::expr_field(expr, ident, ~[]))
+    }
+
+    fn expr_call(
+        span: span,
+        expr: @ast::expr,
+        args: ~[@ast::expr]
+    ) -> @ast::expr {
+        self.expr(span, ast::expr_call(expr, args, false))
+    }
+
+    fn lambda_expr(expr: @ast::expr) -> @ast::expr {
+        self.lambda(self.expr_blk(expr))
+    }
+
+    fn lambda_stmts(span: span, stmts: ~[@ast::stmt]) -> @ast::expr {
+        self.lambda(self.blk(span, stmts))
+    }
+}
+
+fn mk_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    ty_param: ast::ty_param,
+    path: @ast::path,
+    tps: ~[ast::ty_param],
+    f: fn(@ast::Ty) -> @ast::method
+) -> @ast::item {
+    // All the type parameters need to bound to the trait.
+    let mut trait_tps = vec::append(
+        ~[ty_param],
+         do tps.map |tp| {
+            let t_bound = ast::ty_param_bound(@{
+                id: cx.next_id(),
+                node: ast::ty_path(path, cx.next_id()),
+                span: span,
+            });
+
+            {
+                ident: tp.ident,
+                id: cx.next_id(),
+                bounds: @vec::append(~[t_bound], *tp.bounds)
+            }
+        }
+    );
+
+    let opt_trait = Some(@{
+        path: path,
+        ref_id: cx.next_id(),
+    });
+
+    let ty = cx.ty_path(
+        span,
+        ~[ident],
+        tps.map(|tp| cx.ty_path(span, ~[tp.ident], ~[]))
+    );
+
+    @{
+        // This is a new-style impl declaration.
+        // XXX: clownshoes
+        ident: ast::token::special_idents::clownshoes_extensions,
+        attrs: ~[],
+        id: cx.next_id(),
+        node: ast::item_impl(trait_tps, opt_trait, ty, ~[f(ty)]),
+        vis: ast::public,
+        span: span,
+    }
+}
+
+fn mk_ser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    tps: ~[ast::ty_param],
+    body: @ast::expr
+) -> @ast::item {
+    // Make a path to the std::serialize::Encodable typaram.
+    let ty_param = cx.bind_path(
+        span,
+        cx.ident_of(~"__S"),
+        cx.path(
+            span,
+            ~[
+                cx.ident_of(~"std"),
+                cx.ident_of(~"serialize"),
+                cx.ident_of(~"Encoder"),
+            ]
+        ),
+        @~[]
+    );
+
+    // Make a path to the std::serialize::Encodable trait.
+    let path = cx.path_tps(
+        span,
+        ~[
+            cx.ident_of(~"std"),
+            cx.ident_of(~"serialize"),
+            cx.ident_of(~"Encodable"),
+        ],
+        ~[cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[])]
+    );
+
+    mk_impl(
+        cx,
+        span,
+        ident,
+        ty_param,
+        path,
+        tps,
+        |_ty| mk_ser_method(cx, span, cx.expr_blk(body))
+    )
+}
+
+fn mk_deser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    tps: ~[ast::ty_param],
+    body: @ast::expr
+) -> @ast::item {
+    // Make a path to the std::serialize::Decodable typaram.
+    let ty_param = cx.bind_path(
+        span,
+        cx.ident_of(~"__D"),
+        cx.path(
+            span,
+            ~[
+                cx.ident_of(~"std"),
+                cx.ident_of(~"serialize"),
+                cx.ident_of(~"Decoder"),
+            ]
+        ),
+        @~[]
+    );
+
+    // Make a path to the std::serialize::Decodable trait.
+    let path = cx.path_tps(
+        span,
+        ~[
+            cx.ident_of(~"std"),
+            cx.ident_of(~"serialize"),
+            cx.ident_of(~"Decodable"),
+        ],
+        ~[cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[])]
+    );
+
+    mk_impl(
+        cx,
+        span,
+        ident,
+        ty_param,
+        path,
+        tps,
+        |ty| mk_deser_method(cx, span, ty, cx.expr_blk(body))
+    )
+}
+
+fn mk_ser_method(
+    cx: ext_ctxt,
+    span: span,
+    ser_body: ast::blk
+) -> @ast::method {
+    let ty_s = @{
+        id: cx.next_id(),
+        node: ast::ty_rptr(
+            @{
+                id: cx.next_id(),
+                node: ast::re_anon,
+            },
+            {
+                ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]),
+                mutbl: ast::m_imm
+            }
+        ),
+        span: span,
+    };
+
+    let ser_inputs = ~[{
+        mode: ast::infer(cx.next_id()),
+        ty: ty_s,
+        pat: @{id: cx.next_id(),
+               node: ast::pat_ident(
+                    ast::bind_by_value,
+                    ast_util::ident_to_path(span, cx.ident_of(~"__s")),
+                    None),
+               span: span},
+        id: cx.next_id(),
+    }];
+
+    let ser_output = @{
+        id: cx.next_id(),
+        node: ast::ty_nil,
+        span: span,
+    };
+
+    let ser_decl = {
+        inputs: ser_inputs,
+        output: ser_output,
+        cf: ast::return_val,
+    };
+
+    @{
+        ident: cx.ident_of(~"encode"),
+        attrs: ~[],
+        tps: ~[],
+        self_ty: { node: ast::sty_region(ast::m_imm), span: span },
+        purity: ast::impure_fn,
+        decl: ser_decl,
+        body: ser_body,
+        id: cx.next_id(),
+        span: span,
+        self_id: cx.next_id(),
+        vis: ast::public,
+    }
+}
+
+fn mk_deser_method(
+    cx: ext_ctxt,
+    span: span,
+    ty: @ast::Ty,
+    deser_body: ast::blk
+) -> @ast::method {
+    let ty_d = @{
+        id: cx.next_id(),
+        node: ast::ty_rptr(
+            @{
+                id: cx.next_id(),
+                node: ast::re_anon,
+            },
+            {
+                ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]),
+                mutbl: ast::m_imm
+            }
+        ),
+        span: span,
+    };
+
+    let deser_inputs = ~[{
+        mode: ast::infer(cx.next_id()),
+        ty: ty_d,
+        pat: @{id: cx.next_id(),
+               node: ast::pat_ident(
+                    ast::bind_by_value,
+                    ast_util::ident_to_path(span, cx.ident_of(~"__d")),
+                    None),
+               span: span},
+        id: cx.next_id(),
+    }];
+
+    let deser_decl = {
+        inputs: deser_inputs,
+        output: ty,
+        cf: ast::return_val,
+    };
+
+    @{
+        ident: cx.ident_of(~"decode"),
+        attrs: ~[],
+        tps: ~[],
+        self_ty: { node: ast::sty_static, span: span },
+        purity: ast::impure_fn,
+        decl: deser_decl,
+        body: deser_body,
+        id: cx.next_id(),
+        span: span,
+        self_id: cx.next_id(),
+        vis: ast::public,
+    }
+}
+
+fn mk_rec_ser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    fields: ~[ast::ty_field],
+    tps: ~[ast::ty_param]
+) -> @ast::item {
+    let fields = mk_ser_fields(cx, span, mk_rec_fields(fields));
+
+    // ast for `__s.emit_rec(|| $(fields))`
+    let body = cx.expr_call(
+        span,
+        cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__s"),
+            cx.ident_of(~"emit_rec")
+        ),
+        ~[cx.lambda_stmts(span, fields)]
+    );
+
+    mk_ser_impl(cx, span, ident, tps, body)
+}
+
+fn mk_rec_deser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    fields: ~[ast::ty_field],
+    tps: ~[ast::ty_param]
+) -> @ast::item {
+    let fields = mk_deser_fields(cx, span, mk_rec_fields(fields));
+
+    // ast for `read_rec(|| $(fields))`
+    let body = cx.expr_call(
+        span,
+        cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__d"),
+            cx.ident_of(~"read_rec")
+        ),
+        ~[
+            cx.lambda_expr(
+                cx.expr(
+                    span,
+                    ast::expr_rec(fields, None)
+                )
+            )
+        ]
+    );
+
+    mk_deser_impl(cx, span, ident, tps, body)
+}
+
+fn mk_struct_ser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    fields: ~[@ast::struct_field],
+    tps: ~[ast::ty_param]
+) -> @ast::item {
+    let fields = mk_ser_fields(cx, span, mk_struct_fields(fields));
+
+    // ast for `__s.emit_struct($(name), || $(fields))`
+    let ser_body = cx.expr_call(
+        span,
+        cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__s"),
+            cx.ident_of(~"emit_struct")
+        ),
+        ~[
+            cx.lit_str(span, @cx.str_of(ident)),
+            cx.lambda_stmts(span, fields),
+        ]
+    );
+
+    mk_ser_impl(cx, span, ident, tps, ser_body)
+}
+
+fn mk_struct_deser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    fields: ~[@ast::struct_field],
+    tps: ~[ast::ty_param]
+) -> @ast::item {
+    let fields = mk_deser_fields(cx, span, mk_struct_fields(fields));
+
+    // ast for `read_struct($(name), || $(fields))`
+    let body = cx.expr_call(
+        span,
+        cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__d"),
+            cx.ident_of(~"read_struct")
+        ),
+        ~[
+            cx.lit_str(span, @cx.str_of(ident)),
+            cx.lambda_expr(
+                cx.expr(
+                    span,
+                    ast::expr_struct(
+                        cx.path(span, ~[ident]),
+                        fields,
+                        None
+                    )
+                )
+            ),
+        ]
+    );
+
+    mk_deser_impl(cx, span, ident, tps, body)
+}
+
+// Records and structs don't have the same fields types, but they share enough
+// that if we extract the right subfields out we can share the code
+// generator code.
+type field = { span: span, ident: ast::ident, mutbl: ast::mutability };
+
+fn mk_rec_fields(fields: ~[ast::ty_field]) -> ~[field] {
+    do fields.map |field| {
+        {
+            span: field.span,
+            ident: field.node.ident,
+            mutbl: field.node.mt.mutbl,
+        }
+    }
+}
+
+fn mk_struct_fields(fields: ~[@ast::struct_field]) -> ~[field] {
+    do fields.map |field| {
+        let (ident, mutbl) = match field.node.kind {
+            ast::named_field(ident, mutbl, _) => (ident, mutbl),
+            _ => fail ~"[auto_encode] does not support \
+                        unnamed fields",
+        };
+
+        {
+            span: field.span,
+            ident: ident,
+            mutbl: match mutbl {
+                ast::struct_mutable => ast::m_mutbl,
+                ast::struct_immutable => ast::m_imm,
+            },
+        }
+    }
+}
+
+fn mk_ser_fields(
+    cx: ext_ctxt,
+    span: span,
+    fields: ~[field]
+) -> ~[@ast::stmt] {
+    do fields.mapi |idx, field| {
+        // ast for `|| self.$(name).encode(__s)`
+        let expr_lambda = cx.lambda_expr(
+            cx.expr_call(
+                span,
+                cx.expr_field(
+                    span,
+                    cx.expr_field(
+                        span,
+                        cx.expr_var(span, ~"self"),
+                        field.ident
+                    ),
+                    cx.ident_of(~"encode")
+                ),
+                ~[cx.expr_var(span, ~"__s")]
+            )
+        );
+
+        // ast for `__s.emit_field($(name), $(idx), $(expr_lambda))`
+        cx.stmt(
+            cx.expr_call(
+                span,
+                cx.expr_field(
+                    span,
+                    cx.expr_var(span, ~"__s"),
+                    cx.ident_of(~"emit_field")
+                ),
+                ~[
+                    cx.lit_str(span, @cx.str_of(field.ident)),
+                    cx.lit_uint(span, idx),
+                    expr_lambda,
+                ]
+            )
+        )
+    }
+}
+
+fn mk_deser_fields(
+    cx: ext_ctxt,
+    span: span,
+    fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }]
+) -> ~[ast::field] {
+    do fields.mapi |idx, field| {
+        // ast for `|| std::serialize::decode(__d)`
+        let expr_lambda = cx.lambda(
+            cx.expr_blk(
+                cx.expr_call(
+                    span,
+                    cx.expr_path(span, ~[
+                        cx.ident_of(~"std"),
+                        cx.ident_of(~"serialize"),
+                        cx.ident_of(~"decode"),
+                    ]),
+                    ~[cx.expr_var(span, ~"__d")]
+                )
+            )
+        );
+
+        // ast for `__d.read_field($(name), $(idx), $(expr_lambda))`
+        let expr: @ast::expr = cx.expr_call(
+            span,
+            cx.expr_field(
+                span,
+                cx.expr_var(span, ~"__d"),
+                cx.ident_of(~"read_field")
+            ),
+            ~[
+                cx.lit_str(span, @cx.str_of(field.ident)),
+                cx.lit_uint(span, idx),
+                expr_lambda,
+            ]
+        );
+
+        {
+            node: { mutbl: field.mutbl, ident: field.ident, expr: expr },
+            span: span,
+        }
+    }
+}
+
+fn mk_enum_ser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    enum_def: ast::enum_def,
+    tps: ~[ast::ty_param]
+) -> @ast::item {
+    let body = mk_enum_ser_body(
+        cx,
+        span,
+        ident,
+        enum_def.variants
+    );
+
+    mk_ser_impl(cx, span, ident, tps, body)
+}
+
+fn mk_enum_deser_impl(
+    cx: ext_ctxt,
+    span: span,
+    ident: ast::ident,
+    enum_def: ast::enum_def,
+    tps: ~[ast::ty_param]
+) -> @ast::item {
+    let body = mk_enum_deser_body(
+        cx,
+        span,
+        ident,
+        enum_def.variants
+    );
+
+    mk_deser_impl(cx, span, ident, tps, body)
+}
+
+fn ser_variant(
+    cx: ext_ctxt,
+    span: span,
+    v_name: ast::ident,
+    v_idx: uint,
+    args: ~[ast::variant_arg]
+) -> ast::arm {
+    // Name the variant arguments.
+    let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i)));
+
+    // Bind the names to the variant argument type.
+    let pats = args.mapi(|i, arg| cx.binder_pat(arg.ty.span, names[i]));
+
+    let pat_node = if pats.is_empty() {
+        ast::pat_ident(
+            ast::bind_by_ref(ast::m_imm),
+            cx.path(span, ~[v_name]),
+            None
+        )
+    } else {
+        ast::pat_enum(
+            cx.path(span, ~[v_name]),
+            Some(pats)
+        )
+    };
+
+    let pat = @{
+        id: cx.next_id(),
+        node: pat_node,
+        span: span,
+    };
+
+    let stmts = do args.mapi |a_idx, _arg| {
+        // ast for `__s.emit_enum_variant_arg`
+        let expr_emit = cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__s"),
+            cx.ident_of(~"emit_enum_variant_arg")
+        );
+
+        // ast for `|| $(v).encode(__s)`
+        let expr_encode = cx.lambda_expr(
+             cx.expr_call(
+                span,
+                cx.expr_field(
+                    span,
+                    cx.expr_path(span, ~[names[a_idx]]),
+                    cx.ident_of(~"encode")
+                ),
+                ~[cx.expr_var(span, ~"__s")]
+            )
+        );
+
+        // ast for `$(expr_emit)($(a_idx), $(expr_encode))`
+        cx.stmt(
+            cx.expr_call(
+                span,
+                expr_emit,
+                ~[cx.lit_uint(span, a_idx), expr_encode]
+            )
+        )
+    };
+
+    // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))`
+    let body = cx.expr_call(
+        span,
+        cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__s"),
+            cx.ident_of(~"emit_enum_variant")
+        ),
+        ~[
+            cx.lit_str(span, @cx.str_of(v_name)),
+            cx.lit_uint(span, v_idx),
+            cx.lit_uint(span, stmts.len()),
+            cx.lambda_stmts(span, stmts),
+        ]
+    );
+
+    { pats: ~[pat], guard: None, body: cx.expr_blk(body) }
+}
+
+fn mk_enum_ser_body(
+    cx: ext_ctxt,
+    span: span,
+    name: ast::ident,
+    variants: ~[ast::variant]
+) -> @ast::expr {
+    let arms = do variants.mapi |v_idx, variant| {
+        match variant.node.kind {
+            ast::tuple_variant_kind(args) =>
+                ser_variant(cx, span, variant.node.name, v_idx, args),
+            ast::struct_variant_kind(*) =>
+                fail ~"struct variants unimplemented",
+            ast::enum_variant_kind(*) =>
+                fail ~"enum variants unimplemented",
+        }
+    };
+
+    // ast for `match *self { $(arms) }`
+    let match_expr = cx.expr(
+        span,
+        ast::expr_match(
+            cx.expr(
+                span,
+                ast::expr_unary(ast::deref, cx.expr_var(span, ~"self"))
+            ),
+            arms
+        )
+    );
+
+    // ast for `__s.emit_enum($(name), || $(match_expr))`
+    cx.expr_call(
+        span,
+        cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__s"),
+            cx.ident_of(~"emit_enum")
+        ),
+        ~[
+            cx.lit_str(span, @cx.str_of(name)),
+            cx.lambda_expr(match_expr),
+        ]
+    )
+}
+
+fn mk_enum_deser_variant_nary(
+    cx: ext_ctxt,
+    span: span,
+    name: ast::ident,
+    args: ~[ast::variant_arg]
+) -> @ast::expr {
+    let args = do args.mapi |idx, _arg| {
+        // ast for `|| std::serialize::decode(__d)`
+        let expr_lambda = cx.lambda_expr(
+            cx.expr_call(
+                span,
+                cx.expr_path(span, ~[
+                    cx.ident_of(~"std"),
+                    cx.ident_of(~"serialize"),
+                    cx.ident_of(~"decode"),
+                ]),
+                ~[cx.expr_var(span, ~"__d")]
+            )
+        );
+
+        // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))`
+        cx.expr_call(
+            span,
+            cx.expr_field(
+                span,
+                cx.expr_var(span, ~"__d"),
+                cx.ident_of(~"read_enum_variant_arg")
+            ),
+            ~[cx.lit_uint(span, idx), expr_lambda]
+        )
+    };
+
+    // ast for `$(name)($(args))`
+    cx.expr_call(span, cx.expr_path(span, ~[name]), args)
+}
+
+fn mk_enum_deser_body(
+    cx: ext_ctxt,
+    span: span,
+    name: ast::ident,
+    variants: ~[ast::variant]
+) -> @ast::expr {
+    let mut arms = do variants.mapi |v_idx, variant| {
+        let body = match variant.node.kind {
+            ast::tuple_variant_kind(args) => {
+                if args.is_empty() {
+                    // for a nullary variant v, do "v"
+                    cx.expr_path(span, ~[variant.node.name])
+                } else {
+                    // for an n-ary variant v, do "v(a_1, ..., a_n)"
+                    mk_enum_deser_variant_nary(
+                        cx,
+                        span,
+                        variant.node.name,
+                        args
+                    )
+                }
+            },
+            ast::struct_variant_kind(*) =>
+                fail ~"struct variants unimplemented",
+            ast::enum_variant_kind(*) =>
+                fail ~"enum variants unimplemented",
+        };
+
+        let pat = @{
+            id: cx.next_id(),
+            node: ast::pat_lit(cx.lit_uint(span, v_idx)),
+            span: span,
+        };
+
+        {
+            pats: ~[pat],
+            guard: None,
+            body: cx.expr_blk(body),
+        }
+    };
+
+    let impossible_case = {
+        pats: ~[@{ id: cx.next_id(), node: ast::pat_wild, span: span}],
+        guard: None,
+
+        // FIXME(#3198): proper error message
+        body: cx.expr_blk(cx.expr(span, ast::expr_fail(None))),
+    };
+
+    arms.push(impossible_case);
+
+    // ast for `|i| { match i { $(arms) } }`
+    let expr_lambda = cx.expr(
+        span,
+        ast::expr_fn_block(
+            {
+                inputs: ~[{
+                    mode: ast::infer(cx.next_id()),
+                    ty: @{
+                        id: cx.next_id(),
+                        node: ast::ty_infer,
+                        span: span
+                    },
+                    pat: @{id: cx.next_id(),
+                           node: ast::pat_ident(
+                                ast::bind_by_value,
+                                ast_util::ident_to_path(span,
+                                                        cx.ident_of(~"i")),
+                                None),
+                           span: span},
+                    id: cx.next_id(),
+                }],
+                output: @{
+                    id: cx.next_id(),
+                    node: ast::ty_infer,
+                    span: span,
+                },
+                cf: ast::return_val,
+            },
+            cx.expr_blk(
+                cx.expr(
+                    span,
+                    ast::expr_match(cx.expr_var(span, ~"i"), arms)
+                )
+            ),
+            @~[]
+        )
+    );
+
+    // ast for `__d.read_enum_variant($(expr_lambda))`
+    let expr_lambda = cx.lambda_expr(
+        cx.expr_call(
+            span,
+            cx.expr_field(
+                span,
+                cx.expr_var(span, ~"__d"),
+                cx.ident_of(~"read_enum_variant")
+            ),
+            ~[expr_lambda]
+        )
+    );
+
+    // ast for `__d.read_enum($(e_name), $(expr_lambda))`
+    cx.expr_call(
+        span,
+        cx.expr_field(
+            span,
+            cx.expr_var(span, ~"__d"),
+            cx.ident_of(~"read_enum")
+        ),
+        ~[
+            cx.lit_str(span, @cx.str_of(name)),
+            expr_lambda
+        ]
+    )
+}
diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs
index 359414cff42..4c1725b1000 100644
--- a/src/libsyntax/ext/auto_serialize.rs
+++ b/src/libsyntax/ext/auto_serialize.rs
@@ -230,139 +230,6 @@ fn expand_auto_deserialize(
     }
 }
 
-priv impl ext_ctxt {
-    fn bind_path(
-        span: span,
-        ident: ast::ident,
-        path: @ast::path,
-        bounds: @~[ast::ty_param_bound]
-    ) -> ast::ty_param {
-        let bound = ast::ty_param_bound(@{
-            id: self.next_id(),
-            node: ast::ty_path(path, self.next_id()),
-            span: span,
-        });
-
-        {
-            ident: ident,
-            id: self.next_id(),
-            bounds: @vec::append(~[bound], *bounds)
-        }
-    }
-
-    fn expr(span: span, node: ast::expr_) -> @ast::expr {
-        @{id: self.next_id(), callee_id: self.next_id(),
-          node: node, span: span}
-    }
-
-    fn path(span: span, strs: ~[ast::ident]) -> @ast::path {
-        @{span: span, global: false, idents: strs, rp: None, types: ~[]}
-    }
-
-    fn path_tps(span: span, strs: ~[ast::ident],
-                tps: ~[@ast::Ty]) -> @ast::path {
-        @{span: span, global: false, idents: strs, rp: None, types: tps}
-    }
-
-    fn ty_path(span: span, strs: ~[ast::ident],
-               tps: ~[@ast::Ty]) -> @ast::Ty {
-        @{id: self.next_id(),
-          node: ast::ty_path(self.path_tps(span, strs, tps), self.next_id()),
-          span: span}
-    }
-
-    fn binder_pat(span: span, nm: ast::ident) -> @ast::pat {
-        let path = @{span: span, global: false, idents: ~[nm],
-                     rp: None, types: ~[]};
-        @{id: self.next_id(),
-          node: ast::pat_ident(ast::bind_by_ref(ast::m_imm),
-                               path,
-                               None),
-          span: span}
-    }
-
-    fn stmt(expr: @ast::expr) -> @ast::stmt {
-        @{node: ast::stmt_semi(expr, self.next_id()),
-          span: expr.span}
-    }
-
-    fn lit_str(span: span, s: @~str) -> @ast::expr {
-        self.expr(
-            span,
-            ast::expr_vstore(
-                self.expr(
-                    span,
-                    ast::expr_lit(
-                        @{node: ast::lit_str(s),
-                          span: span})),
-                ast::expr_vstore_uniq))
-    }
-
-    fn lit_uint(span: span, i: uint) -> @ast::expr {
-        self.expr(
-            span,
-            ast::expr_lit(
-                @{node: ast::lit_uint(i as u64, ast::ty_u),
-                  span: span}))
-    }
-
-    fn lambda(blk: ast::blk) -> @ast::expr {
-        let ext_cx = self;
-        let blk_e = self.expr(blk.span, ast::expr_block(blk));
-        quote_expr!( || $blk_e )
-    }
-
-    fn blk(span: span, stmts: ~[@ast::stmt]) -> ast::blk {
-        {node: {view_items: ~[],
-                stmts: stmts,
-                expr: None,
-                id: self.next_id(),
-                rules: ast::default_blk},
-         span: span}
-    }
-
-    fn expr_blk(expr: @ast::expr) -> ast::blk {
-        {node: {view_items: ~[],
-                stmts: ~[],
-                expr: Some(expr),
-                id: self.next_id(),
-                rules: ast::default_blk},
-         span: expr.span}
-    }
-
-    fn expr_path(span: span, strs: ~[ast::ident]) -> @ast::expr {
-        self.expr(span, ast::expr_path(self.path(span, strs)))
-    }
-
-    fn expr_var(span: span, var: ~str) -> @ast::expr {
-        self.expr_path(span, ~[self.ident_of(var)])
-    }
-
-    fn expr_field(
-        span: span,
-        expr: @ast::expr,
-        ident: ast::ident
-    ) -> @ast::expr {
-        self.expr(span, ast::expr_field(expr, ident, ~[]))
-    }
-
-    fn expr_call(
-        span: span,
-        expr: @ast::expr,
-        args: ~[@ast::expr]
-    ) -> @ast::expr {
-        self.expr(span, ast::expr_call(expr, args, false))
-    }
-
-    fn lambda_expr(expr: @ast::expr) -> @ast::expr {
-        self.lambda(self.expr_blk(expr))
-    }
-
-    fn lambda_stmts(span: span, stmts: ~[@ast::stmt]) -> @ast::expr {
-        self.lambda(self.blk(span, stmts))
-    }
-}
-
 fn mk_impl(
     cx: ext_ctxt,
     span: span,
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index a5ed1f5e101..d245aa1c050 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -47,7 +47,7 @@ enum mac_result {
 
 enum syntax_extension {
 
-    // #[auto_serialize] and such
+    // #[auto_encode] and such
     item_decorator(item_decorator),
 
     // Token-tree expanders
@@ -79,6 +79,12 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
     syntax_expanders.insert(
         ~"auto_deserialize",
         item_decorator(ext::auto_serialize::expand_auto_deserialize));
+    syntax_expanders.insert(
+        ~"auto_encode",
+        item_decorator(ext::auto_encode::expand_auto_encode));
+    syntax_expanders.insert(
+        ~"auto_decode",
+        item_decorator(ext::auto_encode::expand_auto_decode));
     syntax_expanders.insert(~"env",
                             builtin_normal_tt(ext::env::expand_syntax_ext));
     syntax_expanders.insert(~"concat_idents",
diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc
index 119e1e25fb7..6013178c5ee 100644
--- a/src/libsyntax/syntax.rc
+++ b/src/libsyntax/syntax.rc
@@ -117,6 +117,9 @@ mod ext {
     #[path = "ext/log_syntax.rs"]
     mod log_syntax;
     #[legacy_exports]
+    #[path = "ext/auto_encode.rs"]
+    mod auto_encode;
+    #[legacy_exports]
     #[path = "ext/auto_serialize.rs"]
     mod auto_serialize;
     #[legacy_exports]