summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-03-12 10:19:35 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-03-13 21:30:07 -0400
commitd91742294f282a07b1e26d8da02f7ecec4e0b952 (patch)
treee9a1adbbe9b13706fbe4682a9ed55d8ac0ec3a5d /src
parent06c8acdd3167127170bc7024849d5f89bd9ac70e (diff)
downloadrust-d91742294f282a07b1e26d8da02f7ecec4e0b952.tar.gz
rust-d91742294f282a07b1e26d8da02f7ecec4e0b952.zip
first (functional) version of the auto_serialize syntax ext
Diffstat (limited to 'src')
-rw-r--r--src/libcore/core.rc3
-rw-r--r--src/libcore/serialization.rs116
-rw-r--r--src/libcore/uint.rs8
-rw-r--r--src/libcore/vec.rs2
-rw-r--r--src/libstd/ebml.rs314
-rw-r--r--src/libstd/prettyprint.rs130
-rw-r--r--src/libstd/serialization.rs417
-rw-r--r--src/libstd/std.rc3
-rw-r--r--src/rustc/driver/driver.rs13
-rw-r--r--src/rustc/metadata/astencode.rs29
-rw-r--r--src/rustc/middle/typeck.rs3
-rw-r--r--src/rustc/syntax/ext/auto_serialize.rs269
-rw-r--r--src/rustc/syntax/ext/base.rs2
-rw-r--r--src/rustc/syntax/ext/qquote.rs1
-rw-r--r--src/test/run-pass/auto_serialize_enum.rs19
-rw-r--r--src/test/run-pass/auto_serialize_gen.rs19
-rw-r--r--src/test/run-pass/auto_serialize_link.rs22
-rw-r--r--src/test/run-pass/auto_serialize_rec.rs12
-rw-r--r--src/test/run-pass/auto_serialize_vec.rs13
19 files changed, 855 insertions, 540 deletions
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index c28ad0a0282..e790c55d11f 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -31,7 +31,7 @@ export uint, u8, u16, u32, u64;
 export float, f32, f64;
 export box, char, str, ptr, vec, bool;
 export either, option, result, iter;
-export libc, os, io, run, rand, sys, unsafe, logging;
+export libc, os, ctypes, io, run, rand, sys, unsafe, logging, serialization;
 export comm, task, future;
 export extfmt;
 export tuple;
@@ -88,6 +88,7 @@ mod cmath;
 mod sys;
 mod unsafe;
 mod logging;
+mod serialization;
 
 // Concurrency
 mod comm;
diff --git a/src/libcore/serialization.rs b/src/libcore/serialization.rs
new file mode 100644
index 00000000000..40e468a99db
--- /dev/null
+++ b/src/libcore/serialization.rs
@@ -0,0 +1,116 @@
+export serializer;
+export serializer_helpers;
+export deserializer;
+export deserializer_helpers;
+
+/*
+Core serialization interfaces.
+*/
+
+iface serializer {
+    // Primitive types:
+    fn emit_nil();
+    fn emit_uint(v: uint);
+    fn emit_u64(v: u64);
+    fn emit_u32(v: u32);
+    fn emit_u16(v: u16);
+    fn emit_u8(v: u8);
+    fn emit_int(v: int);
+    fn emit_i64(v: i64);
+    fn emit_i32(v: i32);
+    fn emit_i16(v: i16);
+    fn emit_i8(v: i8);
+    fn emit_bool(v: bool);
+    fn emit_float(v: float);
+    fn emit_f64(v: f64);
+    fn emit_f32(v: f32);
+    fn emit_str(v: str);
+
+    // Compound types:
+    fn emit_enum(name: str, f: fn());
+    fn emit_enum_variant(v_name: str, v_id: uint, sz: uint, f: fn());
+    fn emit_enum_variant_arg(idx: uint, f: fn());
+    fn emit_vec(len: uint, f: fn());
+    fn emit_vec_elt(idx: uint, f: fn());
+    fn emit_box(f: fn());
+    fn emit_uniq(f: fn());
+    fn emit_rec(f: fn());
+    fn emit_rec_field(f_name: str, f_idx: uint, f: fn());
+    fn emit_tup(sz: uint, f: fn());
+    fn emit_tup_elt(idx: uint, f: fn());
+}
+
+iface deserializer {
+    // Primitive types:
+    fn read_nil() -> ();
+
+    fn read_uint() -> uint;
+    fn read_u64() -> u64;
+    fn read_u32() -> u32;
+    fn read_u16() -> u16;
+    fn read_u8() -> u8;
+
+    fn read_int() -> int;
+    fn read_i64() -> i64;
+    fn read_i32() -> i32;
+    fn read_i16() -> i16;
+    fn read_i8() -> i8;
+
+
+    fn read_bool() -> bool;
+
+    fn read_str() -> str;
+
+    fn read_f64() -> f64;
+    fn read_f32() -> f32;
+    fn read_float() -> float;
+
+    // Compound types:
+    fn read_enum<T:copy>(name: str, f: fn() -> T) -> T;
+    fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T;
+    fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T;
+    fn read_vec<T:copy>(f: fn(uint) -> T) -> T;
+    fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
+    fn read_box<T:copy>(f: fn() -> T) -> T;
+    fn read_uniq<T:copy>(f: fn() -> T) -> T;
+    fn read_rec<T:copy>(f: fn() -> T) -> T;
+    fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T;
+    fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T;
+    fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
+}
+
+// ___________________________________________________________________________
+// Helper routines
+//
+// These should eventually be coded as traits.
+
+fn emit_from_vec<S: serializer, T>(s: S, v: [T], f: fn(T)) {
+    s.emit_vec(vec::len(v)) {||
+        vec::iteri(v) {|i,e|
+            s.emit_vec_elt(i) {||
+                f(e)
+            }
+        }
+    }
+}
+
+fn read_to_vec<D: deserializer, T>(d: D, f: fn() -> T) -> [T] {
+    d.read_vec {|len|
+        vec::init_fn(len) {|i|
+            d.read_vec_elt(i) {|| f() }
+        }
+    }
+}
+
+impl serializer_helpers<S: serializer> for S {
+    fn emit_from_vec<T>(v: [T], f: fn(T)) {
+        emit_from_vec(self, v, f)
+    }
+}
+
+impl deserializer_helpers<D: deserializer> for D {
+    fn read_to_vec<T>(f: fn() -> T) -> [T] {
+        read_to_vec(self, f)
+    }
+}
+
diff --git a/src/libcore/uint.rs b/src/libcore/uint.rs
index 88230bea094..e466717657d 100644
--- a/src/libcore/uint.rs
+++ b/src/libcore/uint.rs
@@ -192,6 +192,14 @@ fn compl(i: uint) -> uint {
     max_value ^ i
 }
 
+fn serialize<S: serialization::serializer>(s: S, v: uint) {
+    s.emit_uint(v);
+}
+
+fn deserialize<D: serialization::deserializer>(d: D) -> uint {
+    d.read_uint()
+}
+
 #[cfg(test)]
 mod tests {
 
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 663bc20001b..72ae981d36b 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -406,7 +406,7 @@ fn map<T, U>(v: [T], f: fn(T) -> U) -> [U] {
 }
 
 fn flat_map<T, U>(v: [T], f: fn(T) -> [U]) -> [U] {
-    let result = [];
+    let mut result = [];
     for elem: T in v { result += f(elem); }
     ret result;
 }
diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs
index 931ad32551f..203e7e12ad0 100644
--- a/src/libstd/ebml.rs
+++ b/src/libstd/ebml.rs
@@ -25,6 +25,9 @@ export doc_as_i16;
 export doc_as_i32;
 export doc_as_i64;
 export writer;
+export serializer;
+export ebml_deserializer;
+export deserializer;
 
 type ebml_tag = {id: uint, size: uint};
 
@@ -273,3 +276,314 @@ impl writer for writer {
 
 // TODO: optionally perform "relaxations" on end_tag to more efficiently
 // encode sizes; this is a fixed point iteration
+
+// Set to true to generate more debugging in EBML serialization.
+// Totally lame approach.
+const debug: bool = true;
+
+enum ebml_serializer_tag {
+    es_uint, es_u64, es_u32, es_u16, es_u8,
+    es_int, es_i64, es_i32, es_i16, es_i8,
+    es_bool,
+    es_str,
+    es_f64, es_f32, es_float,
+    es_enum, es_enum_vid, es_enum_body,
+    es_vec, es_vec_len, es_vec_elt,
+
+    es_label // Used only when debugging
+}
+
+impl serializer of core::serialization::serializer for ebml::writer {
+    fn emit_nil() {}
+
+    // used internally to emit things like the vector length and so on
+    fn _emit_tagged_uint(t: ebml_serializer_tag, v: uint) {
+        assert v <= 0xFFFF_FFFF_u;
+        self.wr_tagged_u32(t as uint, v as u32);
+    }
+
+    fn _emit_label(label: str) {
+        // There are various strings that we have access to, such as
+        // the name of a record field, which do not actually appear in
+        // the serialized EBML (normally).  This is just for
+        // efficiency.  When debugging, though, we can emit such
+        // labels and then they will be checked by deserializer to
+        // try and check failures more quickly.
+        if debug { self.wr_tagged_str(es_label as uint, label) }
+    }
+
+    fn emit_uint(v: uint) { self.wr_tagged_u64(es_uint as uint, v as u64); }
+    fn emit_u64(v: u64) { self.wr_tagged_u64(es_u64 as uint, v); }
+    fn emit_u32(v: u32) { self.wr_tagged_u32(es_u32 as uint, v); }
+    fn emit_u16(v: u16) { self.wr_tagged_u16(es_u16 as uint, v); }
+    fn emit_u8(v: u8)   { self.wr_tagged_u8 (es_u8  as uint, v); }
+
+    fn emit_int(v: int) { self.wr_tagged_i64(es_int as uint, v as i64); }
+    fn emit_i64(v: i64) { self.wr_tagged_i64(es_i64 as uint, v); }
+    fn emit_i32(v: i32) { self.wr_tagged_i32(es_i32 as uint, v); }
+    fn emit_i16(v: i16) { self.wr_tagged_i16(es_i16 as uint, v); }
+    fn emit_i8(v: i8)   { self.wr_tagged_i8 (es_i8  as uint, v); }
+
+    fn emit_bool(v: bool) { self.wr_tagged_u8(es_bool as uint, v as u8) }
+
+    fn emit_f64(_v: f64) { fail "TODO"; }
+    fn emit_f32(_v: f32) { fail "TODO"; }
+    fn emit_float(_v: float) { fail "TODO"; }
+
+    fn emit_str(v: str) { self.wr_tagged_str(es_str as uint, v) }
+
+    fn emit_enum(name: str, f: fn()) {
+        self._emit_label(name);
+        self.wr_tag(es_enum as uint, f)
+    }
+    fn emit_enum_variant(_v_name: str, v_id: uint, _cnt: uint, f: fn()) {
+        self._emit_tagged_uint(es_enum_vid, v_id);
+        self.wr_tag(es_enum_body as uint, f)
+    }
+    fn emit_enum_variant_arg(_idx: uint, f: fn()) { f() }
+
+    fn emit_vec(len: uint, f: fn()) {
+        self.wr_tag(es_vec as uint) {||
+            self._emit_tagged_uint(es_vec_len, len);
+            f()
+        }
+    }
+
+    fn emit_vec_elt(_idx: uint, f: fn()) {
+        self.wr_tag(es_vec_elt as uint, f)
+    }
+
+    fn emit_box(f: fn()) { f() }
+    fn emit_uniq(f: fn()) { f() }
+    fn emit_rec(f: fn()) { f() }
+    fn emit_rec_field(f_name: str, _f_idx: uint, f: fn()) {
+        self._emit_label(f_name);
+        f()
+    }
+    fn emit_tup(_sz: uint, f: fn()) { f() }
+    fn emit_tup_elt(_idx: uint, f: fn()) { f() }
+}
+
+type ebml_deserializer = {mutable parent: ebml::doc,
+                          mutable pos: uint};
+
+fn ebml_deserializer(d: ebml::doc) -> ebml_deserializer {
+    {mutable parent: d, mutable pos: d.start}
+}
+
+impl deserializer of core::serialization::deserializer for ebml_deserializer {
+    fn _check_label(lbl: str) {
+        if self.pos < self.parent.end {
+            let {tag: r_tag, doc: r_doc} =
+                ebml::doc_at(self.parent.data, self.pos);
+            if r_tag == (es_label as uint) {
+                self.pos = r_doc.end;
+                let str = ebml::doc_as_str(r_doc);
+                if lbl != str {
+                    fail #fmt["Expected label %s but found %s", lbl, str];
+                }
+            }
+        }
+    }
+
+    fn next_doc(exp_tag: ebml_serializer_tag) -> ebml::doc {
+        #debug[". next_doc(exp_tag=%?)", exp_tag];
+        if self.pos >= self.parent.end {
+            fail "no more documents in current node!";
+        }
+        let {tag: r_tag, doc: r_doc} =
+            ebml::doc_at(self.parent.data, self.pos);
+        #debug["self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?",
+               self.parent.start, self.parent.end, self.pos,
+               r_tag, r_doc.start, r_doc.end];
+        if r_tag != (exp_tag as uint) {
+            fail #fmt["expected EMBL doc with tag %? but found tag %?",
+                      exp_tag, r_tag];
+        }
+        if r_doc.end > self.parent.end {
+            fail #fmt["invalid EBML, child extends to 0x%x, parent to 0x%x",
+                      r_doc.end, self.parent.end];
+        }
+        self.pos = r_doc.end;
+        ret r_doc;
+    }
+
+    fn push_doc<T: copy>(d: ebml::doc, f: fn() -> T) -> T{
+        let old_parent = self.parent;
+        let old_pos = self.pos;
+        self.parent = d;
+        self.pos = d.start;
+        let r = f();
+        self.parent = old_parent;
+        self.pos = old_pos;
+        ret r;
+    }
+
+    fn _next_uint(exp_tag: ebml_serializer_tag) -> uint {
+        let r = ebml::doc_as_u32(self.next_doc(exp_tag));
+        #debug["_next_uint exp_tag=%? result=%?", exp_tag, r];
+        ret r as uint;
+    }
+
+    fn read_nil() -> () { () }
+
+    fn read_u64() -> u64 { ebml::doc_as_u64(self.next_doc(es_u64)) }
+    fn read_u32() -> u32 { ebml::doc_as_u32(self.next_doc(es_u32)) }
+    fn read_u16() -> u16 { ebml::doc_as_u16(self.next_doc(es_u16)) }
+    fn read_u8 () -> u8  { ebml::doc_as_u8 (self.next_doc(es_u8 )) }
+    fn read_uint() -> uint {
+        let v = ebml::doc_as_u64(self.next_doc(es_uint));
+        if v > (core::uint::max_value as u64) {
+            fail #fmt["uint %? too large for this architecture", v];
+        }
+        ret v as uint;
+    }
+
+    fn read_i64() -> i64 { ebml::doc_as_u64(self.next_doc(es_i64)) as i64 }
+    fn read_i32() -> i32 { ebml::doc_as_u32(self.next_doc(es_i32)) as i32 }
+    fn read_i16() -> i16 { ebml::doc_as_u16(self.next_doc(es_i16)) as i16 }
+    fn read_i8 () -> i8  { ebml::doc_as_u8 (self.next_doc(es_i8 )) as i8  }
+    fn read_int() -> int {
+        let v = ebml::doc_as_u64(self.next_doc(es_int)) as i64;
+        if v > (int::max_value as i64) || v < (int::min_value as i64) {
+            fail #fmt["int %? out of range for this architecture", v];
+        }
+        ret v as int;
+    }
+
+    fn read_bool() -> bool { ebml::doc_as_u8(self.next_doc(es_bool)) as bool }
+
+    fn read_f64() -> f64 { fail "read_f64()"; }
+    fn read_f32() -> f32 { fail "read_f32()"; }
+    fn read_float() -> float { fail "read_float()"; }
+
+    fn read_str() -> str { ebml::doc_as_str(self.next_doc(es_str)) }
+
+    // Compound types:
+    fn read_enum<T:copy>(name: str, f: fn() -> T) -> T {
+        #debug["read_enum(%s)", name];
+        self._check_label(name);
+        self.push_doc(self.next_doc(es_enum), f)
+    }
+
+    fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T {
+        #debug["read_enum_variant()"];
+        let idx = self._next_uint(es_enum_vid);
+        #debug["  idx=%u", idx];
+        self.push_doc(self.next_doc(es_enum_body)) {||
+            f(idx)
+        }
+    }
+
+    fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T {
+        #debug["read_enum_variant_arg(idx=%u)", idx];
+        f()
+    }
+
+    fn read_vec<T:copy>(f: fn(uint) -> T) -> T {
+        #debug["read_vec()"];
+        self.push_doc(self.next_doc(es_vec)) {||
+            let len = self._next_uint(es_vec_len);
+            #debug["  len=%u", len];
+            f(len)
+        }
+    }
+
+    fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
+        #debug["read_vec_elt(idx=%u)", idx];
+        self.push_doc(self.next_doc(es_vec_elt), f)
+    }
+
+    fn read_box<T:copy>(f: fn() -> T) -> T {
+        #debug["read_box()"];
+        f()
+    }
+
+    fn read_uniq<T:copy>(f: fn() -> T) -> T {
+        #debug["read_uniq()"];
+        f()
+    }
+
+    fn read_rec<T:copy>(f: fn() -> T) -> T {
+        #debug["read_rec()"];
+        f()
+    }
+
+    fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T {
+        #debug["read_rec_field(%s, idx=%u)", f_name, f_idx];
+        self._check_label(f_name);
+        f()
+    }
+
+    fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T {
+        #debug["read_tup(sz=%u)", sz];
+        f()
+    }
+
+    fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
+        #debug["read_tup_elt(idx=%u)", idx];
+        f()
+    }
+}
+
+
+// ___________________________________________________________________________
+// Testing
+
+#[test]
+fn test_option_int() {
+    fn serialize_1<S: serialization::serializer>(s: S, v: int) {
+        s.emit_i64(v as i64);
+    }
+
+    fn serialize_0<S: serialization::serializer>(s: S, v: option<int>) {
+        s.emit_enum("core::option::t") {||
+            alt v {
+              none {
+                s.emit_enum_variant("core::option::none", 0u, 0u) {||}
+              }
+              some(v0) {
+                s.emit_enum_variant("core::option::some", 1u, 1u) {||
+                    s.emit_enum_variant_arg(0u) {|| serialize_1(s, v0) }
+                }
+              }
+            }
+        }
+    }
+
+    fn deserialize_1<S: serialization::deserializer>(s: S) -> int {
+        s.read_i64() as int
+    }
+
+    fn deserialize_0<S: serialization::deserializer>(s: S) -> option<int> {
+        s.read_enum("core::option::t") {||
+            s.read_enum_variant {|i|
+                alt check i {
+                  0u { none }
+                  1u {
+                    let v0 = s.read_enum_variant_arg(0u) {||
+                        deserialize_1(s)
+                    };
+                    some(v0)
+                  }
+                }
+            }
+        }
+    }
+
+    fn test_v(v: option<int>) {
+        #debug["v == %?", v];
+        let mbuf = io::mem_buffer();
+        let ebml_w = ebml::writer(io::mem_buffer_writer(mbuf));
+        serialize_0(ebml_w, v);
+        let ebml_doc = ebml::new_doc(@io::mem_buffer_buf(mbuf));
+        let deser = ebml_deserializer(ebml_doc);
+        let v1 = deserialize_0(deser);
+        #debug["v1 == %?", v1];
+        assert v == v1;
+    }
+
+    test_v(some(22));
+    test_v(none);
+    test_v(some(3));
+}
diff --git a/src/libstd/prettyprint.rs b/src/libstd/prettyprint.rs
new file mode 100644
index 00000000000..10d971ff0f2
--- /dev/null
+++ b/src/libstd/prettyprint.rs
@@ -0,0 +1,130 @@
+import io::writer;
+import io::writer_util;
+import serialization::serializer;
+
+impl of serializer for writer {
+    fn emit_nil() {
+        self.write_str("()")
+    }
+
+    fn emit_uint(v: uint) {
+        self.write_str(#fmt["%?u", v]);
+    }
+
+    fn emit_u64(v: u64) {
+        self.write_str(#fmt["%?_u64", v]);
+    }
+
+    fn emit_u32(v: u32) {
+        self.write_str(#fmt["%?_u32", v]);
+    }
+
+    fn emit_u16(v: u16) {
+        self.write_str(#fmt["%?_u16", v]);
+    }
+
+    fn emit_u8(v: u8) {
+        self.write_str(#fmt["%?_u8", v]);
+    }
+
+    fn emit_int(v: int) {
+        self.write_str(#fmt["%?", v]);
+    }
+
+    fn emit_i64(v: i64) {
+        self.write_str(#fmt["%?_i64", v]);
+    }
+
+    fn emit_i32(v: i32) {
+        self.write_str(#fmt["%?_i32", v]);
+    }
+
+    fn emit_i16(v: i16) {
+        self.write_str(#fmt["%?_i16", v]);
+    }
+
+    fn emit_i8(v: i8) {
+        self.write_str(#fmt["%?_i8", v]);
+    }
+
+    fn emit_bool(v: bool) {
+        self.write_str(#fmt["%b", v]);
+    }
+
+    fn emit_float(v: float) {
+        self.write_str(#fmt["%?_f", v]);
+    }
+
+    fn emit_f64(v: f64) {
+        self.write_str(#fmt["%?_f64", v]);
+    }
+
+    fn emit_f32(v: f32) {
+        self.write_str(#fmt["%?_f32", v]);
+    }
+
+    fn emit_str(v: str) {
+        self.write_str(#fmt["%?", v]);
+    }
+
+    fn emit_enum(_name: str, f: fn()) {
+        f();
+    }
+
+    fn emit_enum_variant(v_name: str, _v_id: uint, _sz: uint, f: fn()) {
+        self.write_str(v_name);
+        self.write_str("(");
+        f();
+        self.write_str(")");
+    }
+
+    fn emit_enum_variant_arg(idx: uint, f: fn()) {
+        if idx > 0u { self.write_str(", "); }
+        f();
+    }
+
+    fn emit_vec(_len: uint, f: fn()) {
+        self.write_str("[");
+        f();
+        self.write_str("]");
+    }
+
+    fn emit_vec_elt(idx: uint, f: fn()) {
+        if idx > 0u { self.write_str(", "); }
+        f();
+    }
+
+    fn emit_box(f: fn()) {
+        self.write_str("@");
+        f();
+    }
+
+    fn emit_uniq(f: fn()) {
+        self.write_str("~");
+        f();
+    }
+
+    fn emit_rec(f: fn()) {
+        self.write_str("{");
+        f();
+        self.write_str("}");
+    }
+
+    fn emit_rec_field(f_name: str, f_idx: uint, f: fn()) {
+        if f_idx > 0u { self.write_str(", "); }
+        self.write_str(f_name);
+        self.write_str(": ");
+        f();
+    }
+
+    fn emit_tup(_sz: uint, f: fn()) {
+        self.write_str("(");
+        f();
+        self.write_str(")");
+    }
+
+    fn emit_tup_elt(idx: uint, f: fn()) {
+        if idx > 0u { self.write_str(", "); }
+        f();
+    }
+}
\ No newline at end of file
diff --git a/src/libstd/serialization.rs b/src/libstd/serialization.rs
index c446d10b88e..fe70247e01b 100644
--- a/src/libstd/serialization.rs
+++ b/src/libstd/serialization.rs
@@ -1,416 +1,7 @@
-#[doc = "Support code for serialization."];
+#[doc = "Support code for serialization.
 
+Deprecated in favor of core::serialization."];
+
+use core;
 import list::list;
 import ebml::writer;
-
-// Set to true to generate more debugging in EBML serialization.
-// Totally lame approach.
-const debug: bool = true;
-
-iface serializer {
-    // Primitive types:
-    fn emit_nil();
-    fn emit_uint(v: uint);
-    fn emit_u64(v: u64);
-    fn emit_u32(v: u32);
-    fn emit_u16(v: u16);
-    fn emit_u8(v: u8);
-    fn emit_int(v: int);
-    fn emit_i64(v: i64);
-    fn emit_i32(v: i32);
-    fn emit_i16(v: i16);
-    fn emit_i8(v: i8);
-    fn emit_bool(v: bool);
-    fn emit_float(v: float);
-    fn emit_f64(v: f64);
-    fn emit_f32(v: f32);
-    fn emit_str(v: str);
-
-    // Compound types:
-    fn emit_enum(name: str, f: fn());
-    fn emit_enum_variant(v_name: str, v_id: uint, sz: uint, f: fn());
-    fn emit_enum_variant_arg(idx: uint, f: fn());
-    fn emit_vec(len: uint, f: fn());
-    fn emit_vec_elt(idx: uint, f: fn());
-    fn emit_box(f: fn());
-    fn emit_uniq(f: fn());
-    fn emit_rec(f: fn());
-    fn emit_rec_field(f_name: str, f_idx: uint, f: fn());
-    fn emit_tup(sz: uint, f: fn());
-    fn emit_tup_elt(idx: uint, f: fn());
-}
-
-iface deserializer {
-    // Primitive types:
-    fn read_nil() -> ();
-
-    fn read_uint() -> uint;
-    fn read_u64() -> u64;
-    fn read_u32() -> u32;
-    fn read_u16() -> u16;
-    fn read_u8() -> u8;
-
-    fn read_int() -> int;
-    fn read_i64() -> i64;
-    fn read_i32() -> i32;
-    fn read_i16() -> i16;
-    fn read_i8() -> i8;
-
-
-    fn read_bool() -> bool;
-
-    fn read_str() -> str;
-
-    fn read_f64() -> f64;
-    fn read_f32() -> f32;
-    fn read_float() -> float;
-
-    // Compound types:
-    fn read_enum<T:copy>(name: str, f: fn() -> T) -> T;
-    fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T;
-    fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T;
-    fn read_vec<T:copy>(f: fn(uint) -> T) -> T;
-    fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
-    fn read_box<T:copy>(f: fn() -> T) -> T;
-    fn read_uniq<T:copy>(f: fn() -> T) -> T;
-    fn read_rec<T:copy>(f: fn() -> T) -> T;
-    fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T;
-    fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T;
-    fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
-}
-
-enum ebml_serializer_tag {
-    es_uint, es_u64, es_u32, es_u16, es_u8,
-    es_int, es_i64, es_i32, es_i16, es_i8,
-    es_bool,
-    es_str,
-    es_f64, es_f32, es_float,
-    es_enum, es_enum_vid, es_enum_body,
-    es_vec, es_vec_len, es_vec_elt,
-
-    es_label // Used only when debugging
-}
-
-impl of serializer for ebml::writer {
-    fn emit_nil() {}
-
-    // used internally to emit things like the vector length and so on
-    fn _emit_tagged_uint(t: ebml_serializer_tag, v: uint) {
-        assert v <= 0xFFFF_FFFF_u;
-        self.wr_tagged_u32(t as uint, v as u32);
-    }
-
-    fn _emit_label(label: str) {
-        // There are various strings that we have access to, such as
-        // the name of a record field, which do not actually appear in
-        // the serialized EBML (normally).  This is just for
-        // efficiency.  When debugging, though, we can emit such
-        // labels and then they will be checked by deserializer to
-        // try and check failures more quickly.
-        if debug { self.wr_tagged_str(es_label as uint, label) }
-    }
-
-    fn emit_uint(v: uint) { self.wr_tagged_u64(es_uint as uint, v as u64); }
-    fn emit_u64(v: u64) { self.wr_tagged_u64(es_u64 as uint, v); }
-    fn emit_u32(v: u32) { self.wr_tagged_u32(es_u32 as uint, v); }
-    fn emit_u16(v: u16) { self.wr_tagged_u16(es_u16 as uint, v); }
-    fn emit_u8(v: u8)   { self.wr_tagged_u8 (es_u8  as uint, v); }
-
-    fn emit_int(v: int) { self.wr_tagged_i64(es_int as uint, v as i64); }
-    fn emit_i64(v: i64) { self.wr_tagged_i64(es_i64 as uint, v); }
-    fn emit_i32(v: i32) { self.wr_tagged_i32(es_i32 as uint, v); }
-    fn emit_i16(v: i16) { self.wr_tagged_i16(es_i16 as uint, v); }
-    fn emit_i8(v: i8)   { self.wr_tagged_i8 (es_i8  as uint, v); }
-
-    fn emit_bool(v: bool) { self.wr_tagged_u8(es_bool as uint, v as u8) }
-
-    fn emit_f64(_v: f64) { fail "TODO"; }
-    fn emit_f32(_v: f32) { fail "TODO"; }
-    fn emit_float(_v: float) { fail "TODO"; }
-
-    fn emit_str(v: str) { self.wr_tagged_str(es_str as uint, v) }
-
-    fn emit_enum(name: str, f: fn()) {
-        self._emit_label(name);
-        self.wr_tag(es_enum as uint, f)
-    }
-    fn emit_enum_variant(_v_name: str, v_id: uint, _cnt: uint, f: fn()) {
-        self._emit_tagged_uint(es_enum_vid, v_id);
-        self.wr_tag(es_enum_body as uint, f)
-    }
-    fn emit_enum_variant_arg(_idx: uint, f: fn()) { f() }
-
-    fn emit_vec(len: uint, f: fn()) {
-        self.wr_tag(es_vec as uint) {||
-            self._emit_tagged_uint(es_vec_len, len);
-            f()
-        }
-    }
-
-    fn emit_vec_elt(_idx: uint, f: fn()) {
-        self.wr_tag(es_vec_elt as uint, f)
-    }
-
-    fn emit_box(f: fn()) { f() }
-    fn emit_uniq(f: fn()) { f() }
-    fn emit_rec(f: fn()) { f() }
-    fn emit_rec_field(f_name: str, _f_idx: uint, f: fn()) {
-        self._emit_label(f_name);
-        f()
-    }
-    fn emit_tup(_sz: uint, f: fn()) { f() }
-    fn emit_tup_elt(_idx: uint, f: fn()) { f() }
-}
-
-type ebml_deserializer = {mutable parent: ebml::doc,
-                          mutable pos: uint};
-
-fn ebml_deserializer(d: ebml::doc) -> ebml_deserializer {
-    {mutable parent: d, mutable pos: d.start}
-}
-
-impl of deserializer for ebml_deserializer {
-    fn _check_label(lbl: str) {
-        if self.pos < self.parent.end {
-            let {tag: r_tag, doc: r_doc} =
-                ebml::doc_at(self.parent.data, self.pos);
-            if r_tag == (es_label as uint) {
-                self.pos = r_doc.end;
-                let str = ebml::doc_as_str(r_doc);
-                if lbl != str {
-                    fail #fmt["Expected label %s but found %s", lbl, str];
-                }
-            }
-        }
-    }
-
-    fn next_doc(exp_tag: ebml_serializer_tag) -> ebml::doc {
-        #debug[". next_doc(exp_tag=%?)", exp_tag];
-        if self.pos >= self.parent.end {
-            fail "no more documents in current node!";
-        }
-        let {tag: r_tag, doc: r_doc} =
-            ebml::doc_at(self.parent.data, self.pos);
-        #debug["self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?",
-               self.parent.start, self.parent.end, self.pos,
-               r_tag, r_doc.start, r_doc.end];
-        if r_tag != (exp_tag as uint) {
-            fail #fmt["expected EMBL doc with tag %? but found tag %?",
-                      exp_tag, r_tag];
-        }
-        if r_doc.end > self.parent.end {
-            fail #fmt["invalid EBML, child extends to 0x%x, parent to 0x%x",
-                      r_doc.end, self.parent.end];
-        }
-        self.pos = r_doc.end;
-        ret r_doc;
-    }
-
-    fn push_doc<T: copy>(d: ebml::doc, f: fn() -> T) -> T{
-        let old_parent = self.parent;
-        let old_pos = self.pos;
-        self.parent = d;
-        self.pos = d.start;
-        let r = f();
-        self.parent = old_parent;
-        self.pos = old_pos;
-        ret r;
-    }
-
-    fn _next_uint(exp_tag: ebml_serializer_tag) -> uint {
-        let r = ebml::doc_as_u32(self.next_doc(exp_tag));
-        #debug["_next_uint exp_tag=%? result=%?", exp_tag, r];
-        ret r as uint;
-    }
-
-    fn read_nil() -> () { () }
-
-    fn read_u64() -> u64 { ebml::doc_as_u64(self.next_doc(es_u64)) }
-    fn read_u32() -> u32 { ebml::doc_as_u32(self.next_doc(es_u32)) }
-    fn read_u16() -> u16 { ebml::doc_as_u16(self.next_doc(es_u16)) }
-    fn read_u8 () -> u8  { ebml::doc_as_u8 (self.next_doc(es_u8 )) }
-    fn read_uint() -> uint {
-        let v = ebml::doc_as_u64(self.next_doc(es_uint));
-        if v > (uint::max_value as u64) {
-            fail #fmt["uint %? too large for this architecture", v];
-        }
-        ret v as uint;
-    }
-
-    fn read_i64() -> i64 { ebml::doc_as_u64(self.next_doc(es_i64)) as i64 }
-    fn read_i32() -> i32 { ebml::doc_as_u32(self.next_doc(es_i32)) as i32 }
-    fn read_i16() -> i16 { ebml::doc_as_u16(self.next_doc(es_i16)) as i16 }
-    fn read_i8 () -> i8  { ebml::doc_as_u8 (self.next_doc(es_i8 )) as i8  }
-    fn read_int() -> int {
-        let v = ebml::doc_as_u64(self.next_doc(es_int)) as i64;
-        if v > (int::max_value as i64) || v < (int::min_value as i64) {
-            fail #fmt["int %? out of range for this architecture", v];
-        }
-        ret v as int;
-    }
-
-    fn read_bool() -> bool { ebml::doc_as_u8(self.next_doc(es_bool)) as bool }
-
-    fn read_f64() -> f64 { fail "read_f64()"; }
-    fn read_f32() -> f32 { fail "read_f32()"; }
-    fn read_float() -> float { fail "read_float()"; }
-
-    fn read_str() -> str { ebml::doc_as_str(self.next_doc(es_str)) }
-
-    // Compound types:
-    fn read_enum<T:copy>(name: str, f: fn() -> T) -> T {
-        #debug["read_enum(%s)", name];
-        self._check_label(name);
-        self.push_doc(self.next_doc(es_enum), f)
-    }
-
-    fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T {
-        #debug["read_enum_variant()"];
-        let idx = self._next_uint(es_enum_vid);
-        #debug["  idx=%u", idx];
-        self.push_doc(self.next_doc(es_enum_body)) {||
-            f(idx)
-        }
-    }
-
-    fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T {
-        #debug["read_enum_variant_arg(idx=%u)", idx];
-        f()
-    }
-
-    fn read_vec<T:copy>(f: fn(uint) -> T) -> T {
-        #debug["read_vec()"];
-        self.push_doc(self.next_doc(es_vec)) {||
-            let len = self._next_uint(es_vec_len);
-            #debug["  len=%u", len];
-            f(len)
-        }
-    }
-
-    fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
-        #debug["read_vec_elt(idx=%u)", idx];
-        self.push_doc(self.next_doc(es_vec_elt), f)
-    }
-
-    fn read_box<T:copy>(f: fn() -> T) -> T {
-        #debug["read_box()"];
-        f()
-    }
-
-    fn read_uniq<T:copy>(f: fn() -> T) -> T {
-        #debug["read_uniq()"];
-        f()
-    }
-
-    fn read_rec<T:copy>(f: fn() -> T) -> T {
-        #debug["read_rec()"];
-        f()
-    }
-
-    fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T {
-        #debug["read_rec_field(%s, idx=%u)", f_name, f_idx];
-        self._check_label(f_name);
-        f()
-    }
-
-    fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T {
-        #debug["read_tup(sz=%u)", sz];
-        f()
-    }
-
-    fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
-        #debug["read_tup_elt(idx=%u)", idx];
-        f()
-    }
-}
-
-// ___________________________________________________________________________
-// Helper routines
-//
-// These should eventually be coded as traits.
-
-impl serializer_helpers<S: serializer> for S {
-    fn emit_from_vec<T>(v: [T], f: fn(T)) {
-        self.emit_vec(vec::len(v)) {||
-            vec::iteri(v) {|i,e|
-                self.emit_vec_elt(i) {||
-                    f(e)
-                }
-            }
-        }
-    }
-}
-
-impl deserializer_helpers<D: deserializer> for D {
-    fn read_to_vec<T>(f: fn() -> T) -> [T] {
-        self.read_vec {|len|
-            let v = [];
-            vec::reserve(v, len);
-            uint::range(0u, len) {|i|
-                self.read_vec_elt(i) {|| v += [f()] }
-            }
-            v
-        }
-    }
-}
-
-// ___________________________________________________________________________
-// Testing
-
-#[test]
-fn test_option_int() {
-    fn serialize_1<S: serializer>(s: S, v: int) {
-        s.emit_i64(v as i64);
-    }
-
-    fn serialize_0<S: serializer>(s: S, v: option<int>) {
-        s.emit_enum("core::option::t") {||
-            alt v {
-              none {
-                s.emit_enum_variant("core::option::none", 0u, 0u) {||}
-              }
-              some(v0) {
-                s.emit_enum_variant("core::option::some", 1u, 1u) {||
-                    s.emit_enum_variant_arg(0u) {|| serialize_1(s, v0) }
-                }
-              }
-            }
-        }
-    }
-
-    fn deserialize_1<S: deserializer>(s: S) -> int {
-        s.read_i64() as int
-    }
-
-    fn deserialize_0<S: deserializer>(s: S) -> option<int> {
-        s.read_enum("core::option::t") {||
-            s.read_enum_variant {|i|
-                alt check i {
-                  0u { none }
-                  1u {
-                    let v0 = s.read_enum_variant_arg(0u) {||
-                        deserialize_1(s)
-                    };
-                    some(v0)
-                  }
-                }
-            }
-        }
-    }
-
-    fn test_v(v: option<int>) {
-        #debug["v == %?", v];
-        let mbuf = io::mk_mem_buffer();
-        let ebml_w = ebml::writer(io::mem_buffer_writer(mbuf));
-        serialize_0(ebml_w, v);
-        let ebml_doc = ebml::new_doc(@io::mem_buffer_buf(mbuf));
-        let deser = ebml_deserializer(ebml_doc);
-        let v1 = deserialize_0(deser);
-        #debug["v1 == %?", v1];
-        assert v == v1;
-    }
-
-    test_v(some(22));
-    test_v(none);
-    test_v(some(3));
-}
diff --git a/src/libstd/std.rc b/src/libstd/std.rc
index a06cca77f75..0f11b8533d2 100644
--- a/src/libstd/std.rc
+++ b/src/libstd/std.rc
@@ -12,7 +12,7 @@ export net, uv;
 export c_vec, four, tri, util;
 export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap, ufind;
 export rope;
-export ebml, dbg, getopts, json, rand, sha1, term, time;
+export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint;
 export test, tempfile, serialization;
 
 
@@ -55,6 +55,7 @@ mod md4;
 mod tempfile;
 mod term;
 mod time;
+mod prettyprint;
 
 #[cfg(unicode)]
 mod unicode;
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs
index dbdd5325e1a..71f39a77e36 100644
--- a/src/rustc/driver/driver.rs
+++ b/src/rustc/driver/driver.rs
@@ -15,7 +15,8 @@ import io::{reader_util, writer_util};
 import getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
 import back::{x86, x86_64};
 
-enum pp_mode { ppm_normal, ppm_expanded, ppm_typed, ppm_identified, }
+enum pp_mode {ppm_normal, ppm_expanded, ppm_typed, ppm_identified,
+              ppm_expanded_identified }
 
 fn default_configuration(sess: session, argv0: str, input: str) ->
    ast::crate_cfg {
@@ -253,7 +254,7 @@ fn pretty_print_input(sess: session, cfg: ast::crate_cfg, input: str,
     // from stdin, we're going to just suck the source into a string
     // so both the parser and pretty-printer can use it.
     let upto = alt ppm {
-      ppm_expanded { cu_expand }
+      ppm_expanded | ppm_expanded_identified { cu_expand }
       ppm_typed { cu_typeck }
       _ { cu_parse }
     };
@@ -265,7 +266,7 @@ fn pretty_print_input(sess: session, cfg: ast::crate_cfg, input: str,
         ann = {pre: ann_paren_for_expr,
                post: bind ann_typed_post(option::get(tcx), _)};
       }
-      ppm_identified {
+      ppm_identified | ppm_expanded_identified {
         ann = {pre: ann_paren_for_expr, post: ann_identified_post};
       }
       ppm_expanded | ppm_normal {}
@@ -498,7 +499,11 @@ fn parse_pretty(sess: session, &&name: str) -> pp_mode {
         ret ppm_expanded;
     } else if str::eq(name, "typed") {
         ret ppm_typed;
-    } else if str::eq(name, "identified") { ret ppm_identified; }
+    } else if str::eq(name, "expanded,identified") {
+        ret ppm_expanded_identified;
+    } else if str::eq(name, "identified") {
+        ret ppm_identified;
+    }
     sess.fatal("argument to `pretty` must be one of `normal`, `typed`, or " +
                    "`identified`");
 }
diff --git a/src/rustc/metadata/astencode.rs b/src/rustc/metadata/astencode.rs
index d9469184d6b..f09b4f902fd 100644
--- a/src/rustc/metadata/astencode.rs
+++ b/src/rustc/metadata/astencode.rs
@@ -6,12 +6,13 @@ import syntax::ast_util::inlined_item_methods;
 import syntax::codemap::span;
 import std::ebml;
 import std::ebml::writer;
+import std::ebml::serializer;
+import std::ebml::deserializer;
 import std::map::hashmap;
-import std::serialization;
-import std::serialization::serializer;
-import std::serialization::deserializer;
-import std::serialization::serializer_helpers;
-import std::serialization::deserializer_helpers;
+import serialization::serializer;
+import serialization::deserializer;
+import serialization::serializer_helpers;
+import serialization::deserializer_helpers;
 import std::smallintmap::map;
 import middle::trans::common::maps;
 import middle::{ty, typeck, last_use, ast_map};
@@ -243,7 +244,7 @@ fn encode_id_range(ebml_w: ebml::writer, id_range: id_range) {
 
 fn decode_id_range(par_doc: ebml::doc) -> id_range {
     let range_doc = par_doc[c::tag_id_range];
-    let dsr = serialization::ebml_deserializer(range_doc);
+    let dsr = ebml::ebml_deserializer(range_doc);
     dsr.read_tup(2u) {||
         {min: dsr.read_tup_elt(0u) {|| dsr.read_int() },
          max: dsr.read_tup_elt(1u) {|| dsr.read_int() }}
@@ -368,7 +369,7 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item {
 
 fn decode_ast(par_doc: ebml::doc) -> ast::inlined_item {
     let chi_doc = par_doc[c::tag_tree];
-    let d = serialization::ebml_deserializer(chi_doc);
+    let d = ebml::ebml_deserializer(chi_doc);
     astencode_gen::deserialize_syntax_ast_inlined_item(d)
 }
 
@@ -398,7 +399,7 @@ fn encode_def(ebml_w: ebml::writer, def: ast::def) {
 }
 
 fn decode_def(xcx: extended_decode_ctxt, doc: ebml::doc) -> ast::def {
-    let dsr = serialization::ebml_deserializer(doc);
+    let dsr = ebml::ebml_deserializer(doc);
     let def = astencode_gen::deserialize_syntax_ast_def(dsr);
     def.tr(xcx)
 }
@@ -445,7 +446,7 @@ fn encode_freevar_entry(ebml_w: ebml::writer, fv: freevar_entry) {
     astencode_gen::serialize_middle_freevars_freevar_entry(ebml_w, fv)
 }
 
-impl helper for serialization::ebml_deserializer {
+impl helper for ebml::ebml_deserializer {
     fn read_freevar_entry(xcx: extended_decode_ctxt) -> freevar_entry {
         let fv =
             astencode_gen::deserialize_middle_freevars_freevar_entry(self);
@@ -466,7 +467,7 @@ fn encode_method_origin(ebml_w: ebml::writer, mo: method_origin) {
     astencode_gen::serialize_middle_typeck_method_origin(ebml_w, mo)
 }
 
-impl helper for serialization::ebml_deserializer {
+impl helper for ebml::ebml_deserializer {
     fn read_method_origin(xcx: extended_decode_ctxt) -> method_origin {
         let fv = astencode_gen::deserialize_middle_typeck_method_origin(self);
         fv.tr(xcx)
@@ -559,7 +560,7 @@ fn encode_dict_origin(ecx: @e::encode_ctxt,
 
 }
 
-impl helpers for serialization::ebml_deserializer {
+impl helpers for ebml::ebml_deserializer {
     fn read_dict_res(xcx: extended_decode_ctxt) -> typeck::dict_res {
         @self.read_to_vec {|| self.read_dict_origin(xcx) }
     }
@@ -800,7 +801,7 @@ impl decoder for ebml::doc {
     }
 }
 
-impl decoder for serialization::ebml_deserializer {
+impl decoder for ebml::ebml_deserializer {
     fn read_ty(xcx: extended_decode_ctxt) -> ty::t {
         tydecode::parse_ty_data(
             self.parent.data, xcx.dcx.cdata.cnum, self.pos, xcx.dcx.tcx,
@@ -850,7 +851,7 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
             dcx.maps.copy_map.insert(id, ());
         } else {
             let val_doc = entry_doc[c::tag_table_val];
-            let val_dsr = serialization::ebml_deserializer(val_doc);
+            let val_dsr = ebml::ebml_deserializer(val_doc);
             if tag == (c::tag_table_def as uint) {
                 let def = decode_def(xcx, val_doc);
                 dcx.tcx.def_map.insert(id, def);
@@ -903,7 +904,7 @@ fn encode_item_ast(ebml_w: ebml::writer, item: @ast::item) {
 #[cfg(test)]
 fn decode_item_ast(par_doc: ebml::doc) -> @ast::item {
     let chi_doc = par_doc[c::tag_tree];
-    let d = serialization::ebml_deserializer(chi_doc);
+    let d = ebml::ebml_deserializer(chi_doc);
     @astencode_gen::deserialize_syntax_ast_item(d)
 }
 
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 1a6953d2d93..a61c88cad4a 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -306,6 +306,9 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
         for ast_ty: @ast::ty in args {
             param_bindings += [do_ast_ty_to_ty(tcx, use_site, mode, ast_ty)];
         }
+        #debug("substituting(%s into %s)",
+               str::concat(vec::map(param_bindings, {|t| ty_to_str(tcx, t)})),
+               ty_to_str(tcx, ty_param_bounds_and_ty.ty));
         let typ =
             ty::substitute_type_params(tcx, param_bindings,
                                        ty_param_bounds_and_ty.ty);
diff --git a/src/rustc/syntax/ext/auto_serialize.rs b/src/rustc/syntax/ext/auto_serialize.rs
index 5f1fa8cb379..b06bf81e5a7 100644
--- a/src/rustc/syntax/ext/auto_serialize.rs
+++ b/src/rustc/syntax/ext/auto_serialize.rs
@@ -82,26 +82,39 @@ import base::*;
 import driver::session::session;
 import codemap::span;
 import std::map;
+import std::map::hashmap;
+import front::attr;
 
-export expand_auto_serialize;
+export expand;
 
-enum ser_cx = {
+enum ser_cx = @{
     ext_cx: ext_ctxt,
-    tps: map::map<str, fn@(@ast::expr) -> [@ast::stmt]>
+    tps: map::hashmap<str, fn@(@ast::expr) -> [@ast::stmt]>
 };
 
-fn expand_auto_serialize(cx: ext_ctxt,
-                         span: span,
-                         _mitem: ast::meta_item,
-                         in_items: [@ast::item]) -> [@ast::item] {
+fn expand(cx: ext_ctxt,
+          span: span,
+          _mitem: ast::meta_item,
+          in_items: [@ast::item]) -> [@ast::item] {
+    fn not_auto_serialize(a: ast::attribute) -> bool {
+        attr::get_attr_name(a) != "auto_serialize"
+    }
+
+    fn filter_attrs(item: @ast::item) -> @ast::item {
+        @{attrs: vec::filter(item.attrs, not_auto_serialize)
+          with *item}
+    }
+
     vec::flat_map(in_items) {|in_item|
         alt in_item.node {
           ast::item_ty(ty, tps) {
-            [in_item, ty_module(cx, in_item.ident, copy ty, tps)]
+            [filter_attrs(in_item),
+             ty_module(cx, in_item.ident, ty, tps)]
           }
 
           ast::item_enum(variants, tps) {
-            [in_item, enum_module(cx, in_item.ident, variants, tps)]
+            [filter_attrs(in_item),
+             enum_module(cx, in_item.ident, in_item.span, variants, tps)]
           }
 
           _ {
@@ -118,9 +131,7 @@ impl helpers for ext_ctxt {
     fn next_id() -> ast::node_id { self.session().next_node_id() }
 
     fn path(span: span, strs: [str]) -> @ast::path {
-        @{node: {global: false,
-                 idents: strs + ["serialize"],
-                 types: []},
+        @{node: {global: false, idents: strs, types: []},
           span: span}
     }
 
@@ -140,6 +151,28 @@ impl helpers for ser_cx {
         self.ext_cx.ty_path(span, strs)
     }
 
+    fn ty_fn(span: span,
+             -input_tys: [@ast::ty],
+             -output: @ast::ty) -> @ast::ty {
+        let args = vec::map(input_tys) {|ty|
+            {mode: ast::expl(ast::by_ref),
+             ty: ty,
+             ident: "",
+             id: self.next_id()}
+        };
+
+        @{node: ast::ty_fn(ast::proto_any, {inputs: args,
+                                            output: output,
+                                            purity: ast::impure_fn,
+                                            cf: ast::return_val,
+                                            constraints: []}),
+          span: span}
+    }
+
+    fn ty_nil(span: span) -> @ast::ty {
+        @{node: ast::ty_nil, span: span}
+    }
+
     fn expr(span: span, node: ast::expr_) -> @ast::expr {
         @{id: self.next_id(), node: node, span: span}
     }
@@ -195,8 +228,9 @@ impl helpers for ser_cx {
                   span: span}))
     }
 
-    fn lambda(-blk: @ast::blk) -> @ast::expr {
-        let blk_e = cx.expr(blk.span, expr_block(blk));
+    fn lambda(blk: ast::blk) -> @ast::expr {
+        let ext_cx = self;
+        let blk_e = self.expr(blk.span, ast::expr_block(blk));
         #ast(expr){{|| $(blk_e) }}
     }
 
@@ -208,6 +242,14 @@ impl helpers for ser_cx {
         fld.fold_expr(v)
     }
 
+    fn clone_ty(v: @ast::ty) -> @ast::ty {
+        let fld = fold::make_fold({
+            new_id: {|_id| self.next_id()}
+            with *fold::default_ast_fold()
+        });
+        fld.fold_ty(v)
+    }
+
     fn clone_ty_param(v: ast::ty_param) -> ast::ty_param {
         let fld = fold::make_fold({
             new_id: {|_id| self.next_id()}
@@ -249,14 +291,17 @@ fn serialize_path(cx: ser_cx, path: @ast::path,
                 cx.path(path.span, path.node.idents + ["serialize"])));
 
     let ty_args = vec::map(path.node.types) {|ty|
-        let sv = serialize_ty(cx, ty, s, #ast(expr){"__v"});
-        cx.at(ty.span, #ast(expr){"{|__v| $(sv)}"})
+        let sv_stmts = serialize_ty(cx, ty, cx.clone(s), #ast(expr){__v});
+        let sv = cx.expr(path.span,
+                         ast::expr_block(cx.blk(path.span,
+                                                sv_stmts)));
+        cx.at(ty.span, #ast(expr){{|__v| $(sv)}})
     };
 
     [cx.stmt(
         cx.expr(
             path.span,
-            ast::expr_call(callee, [s] + ty_args + [v], false)))]
+            ast::expr_call(callee, [s, v] + ty_args, false)))]
 }
 
 fn serialize_variant(cx: ser_cx,
@@ -264,8 +309,8 @@ fn serialize_variant(cx: ser_cx,
                      span: span,
                      -s: @ast::expr,
                      pfn: fn([@ast::pat]) -> ast::pat_,
-                     bodyfn: fn(-@ast::expr, @ast::blk) -> @ast::expr,
-                     argfn: fn(-@ast::expr, uint, @ast::blk) -> @ast::expr)
+                     bodyfn: fn(-@ast::expr, ast::blk) -> @ast::expr,
+                     argfn: fn(-@ast::expr, uint, ast::blk) -> @ast::expr)
     -> ast::arm {
     let vnames = vec::init_fn(vec::len(tys)) {|i| #fmt["__v%u", i]};
     let pats = vec::init_fn(vec::len(tys)) {|i|
@@ -281,7 +326,7 @@ fn serialize_variant(cx: ser_cx,
         cx.stmt(argfn(cx.clone(s), i, arg_blk))
     };
 
-    let body_blk = cx.blk(span, vec::concat(stmts));
+    let body_blk = cx.blk(span, stmts);
     let body = cx.blk(span, [cx.stmt(bodyfn(s, body_blk))]);
 
     {pats: [pat], guard: none, body: body}
@@ -289,6 +334,13 @@ fn serialize_variant(cx: ser_cx,
 
 fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
     -> [@ast::stmt] {
+
+    fn ty_lambda(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
+        -> @ast::expr {
+        cx.lambda(cx.blk(ty.span, serialize_ty(cx, ty, s, v)))
+    }
+
+
     let ext_cx = cx.ext_cx;
 
     alt ty.node {
@@ -296,19 +348,37 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
         []
       }
 
-      ast::ty_box(mt) |
-      ast::ty_uniq(mt) |
-      ast::ty_ptr(mt) {
-        serialize_ty(cx, mt.ty, s, #ast(expr){"*$(v)"})
+      ast::ty_box(mt) {
+        let l = ty_lambda(cx, mt.ty, cx.clone(s), #ast(expr){*$(v)});
+        [#ast(stmt){$(s).emit_box($(l));}]
+      }
+
+      ast::ty_uniq(mt) {
+        let l = ty_lambda(cx, mt.ty, cx.clone(s), #ast(expr){*$(v)});
+        [#ast(stmt){$(s).emit_uniq($(l));}]
+      }
+
+      ast::ty_ptr(_) | ast::ty_rptr(_, _) {
+        cx.session().span_err(
+            ty.span, #fmt["Cannot serialize pointer types"]);
+        []
       }
 
       ast::ty_rec(flds) {
-        vec::flat_map(flds) {|fld|
-            let vf = cx.expr(
-                fld.span,
-                ast::expr_field(cx.clone(v), fld.node.ident, []));
-            serialize_ty(cx, fld.node.mt.ty, cx.clone(s), vf)
-        }
+        let fld_stmts = vec::init_fn(vec::len(flds)) {|fidx|
+            let fld = flds[fidx];
+            let vf = cx.expr(fld.span,
+                             ast::expr_field(cx.clone(v),
+                                             fld.node.ident,
+                                             []));
+            let s = cx.clone(s);
+            let f = cx.lit_str(fld.span, fld.node.ident);
+            let i = cx.lit_uint(fld.span, fidx);
+            let l = ty_lambda(cx, fld.node.mt.ty, cx.clone(s), vf);
+            #ast(stmt){$(s).emit_rec_field($(f), $(i), $(l));}
+        };
+        let fld_lambda = cx.lambda(cx.blk(ty.span, fld_stmts));
+        [#ast(stmt){$(s).emit_rec($(fld_lambda));}]
       }
 
       ast::ty_fn(_, _) {
@@ -335,7 +405,7 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
                 {|pats| ast::pat_tup(pats)},
 
                 // Generate body s.emit_tup(3, {|| blk })
-                {|-s, -blk|
+                {|-s, blk|
                     let sz = cx.lit_uint(ty.span, vec::len(tys));
                     let body = cx.lambda(blk);
                     #ast[expr]{
@@ -344,7 +414,7 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
                 },
 
                 // Generate s.emit_tup_elt(i, {|| blk })
-                {|-s, i, -blk|
+                {|-s, i, blk|
                     let idx = cx.lit_uint(ty.span, i);
                     let body = cx.lambda(blk);
                     #ast[expr]{
@@ -399,57 +469,55 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
                                 ty.span,
                                 #ast(expr){__e})))));
 
-        [cx.stmt(
-            cx.expr(
-                ty.span,
-                ast::expr_call(
-                    #ast(expr){$(s).emit_from_vec},
-                    [#ast(expr){{|__e| $(ser_e)}}],
-                    false)))]
+        [#ast(stmt){
+            core::serialization::emit_from_vec($(s), $(v), {|__e| $(ser_e) })
+        }]
       }
     }
 }
 
 fn mk_ser_fn(ext_cx: ext_ctxt, span: span,
-             -v_ty: @ast::ty, tps: [ast::ty_param],
+             v_ty: @ast::ty, tps: [ast::ty_param],
              f: fn(ser_cx, @ast::ty, -@ast::expr, -@ast::expr) -> [@ast::stmt])
     -> @ast::item {
 
-    let cx = ser_cx({ext_cx: ext_cx, tps: map::new_str_hash()});
+    let cx = ser_cx(@{ext_cx: ext_cx, tps: map::new_str_hash()});
 
     let tp_inputs =
         vec::map(tps, {|tp|
             {mode: ast::expl(ast::by_ref),
-             ty: cx.ty_path(span, [tp.ident]),
+             ty: cx.ty_fn(span,
+                          [cx.ty_path(span, [tp.ident])],
+                          cx.ty_nil(span)),
              ident: "__s" + tp.ident,
              id: cx.next_id()}});
 
+    #debug["tp_inputs = %?", tp_inputs];
+
     let ser_inputs: [ast::arg] =
         [{mode: ast::expl(ast::by_ref),
           ty: cx.ty_path(span, ["__S"]),
           ident: "__s",
           id: cx.next_id()},
          {mode: ast::expl(ast::by_ref),
-          ty: v_ty,
+          ty: cx.clone_ty(v_ty),
           ident: "__v",
           id: cx.next_id()}]
         + tp_inputs;
 
-    vec::iter2(tps, ser_inputs) {|tp, arg|
+    vec::iter2(tps, tp_inputs) {|tp, arg|
         let arg_ident = arg.ident;
         cx.tps.insert(
             tp.ident,
             fn@(v: @ast::expr) -> [@ast::stmt] {
                 let f = cx.var_ref(span, arg_ident);
-                [cx.stmt(
-                    cx.expr(
-                        span,
-                        ast::expr_call(f, [v], false)))]
+                #debug["serializing type arg %s", arg_ident];
+                [#ast(stmt){$(f)($(v));}]
             });
     }
 
     let ser_bnds = @[ast::bound_iface(cx.ty_path(span,
-                                                 ["__std", "serialization",
+                                                 ["serialization",
                                                   "serializer"]))];
 
     let ser_tps: [ast::ty_param] =
@@ -462,7 +530,7 @@ fn mk_ser_fn(ext_cx: ext_ctxt, span: span,
                                  span: span};
 
     let ser_blk = cx.blk(span,
-                         f(cx, v_ty, #ast(expr){"__s"}, #ast(expr){"__v"}));
+                         f(cx, v_ty, #ast(expr){__s}, #ast(expr){__v}));
 
     @{ident: "serialize",
       attrs: [],
@@ -477,7 +545,7 @@ fn mk_ser_fn(ext_cx: ext_ctxt, span: span,
       span: span}
 }
 
-fn ty_module(ext_cx: ext_ctxt, name: str, -ty: @ast::ty, tps: [ast::ty_param])
+fn ty_module(ext_cx: ext_ctxt, name: str, ty: @ast::ty, tps: [ast::ty_param])
     -> @ast::item {
 
     let span = ty.span;
@@ -497,62 +565,51 @@ fn enum_module(ext_cx: ext_ctxt, name: str, span: span,
                variants: [ast::variant], tps: [ast::ty_param])
     -> @ast::item {
 
-    let span = ty.span;
     let ty = ext_cx.ty_path(span, [name]);
-    let ser_fn = mk_ser_fn(ext_cx, span, ty, tps) {|cx, ty, s, v|
-        let arms = vec::init_fn(vec::len(variants)) {|vidx|
-            let variant = variants[vidx];
-
-            if vec::is_empty(variant.args) {
-                // degenerate case.
-                let pat = {id: cx.next_id(),
-                           node: ast::pat_ident(cx.path(variant.ident), none),
-                           Span: variant.span};
-                //#ast(expr){
-                //    $(s).emit_enum_variant(X, Y, SZ) {||
-                //    };
-                //}
-            }
-
-            let variant_tys = vec::map(variant.args) {|a| a.ty };
-
-            serialize_variant(
-                cx, variant_tys, variant.span, cx.clone(s),
-
-                // Generate pattern var(v1, v2, v3)
-                {|pats|
-                    let pat = {id: cx.next_id(),
-                               node: ast::pat_enum(cx.path(variant.ident)),
-                               span: variant.span};
-
-                    {id: cx.next_id(),
-                     node: expr_call(s, [v_name,
-                                         v_id,
-                                         sz,
-                                         f], false),
-                     span: variant.span}
-                },
-
-                // Generate body s.emit_enum_variant("foo", 0u, 3u, {|| blk })
-                {|-s, -blk|
-                    let v_name = cx.lit_str(variant.span, variant.ident);
-                    let v_id = cx.lit_uint(variant.span, vidx);
-                    let sz = cx.lit_uint(variant.span, vec::len(variant_tys));
-                    let body = cx.lambda(blk);
-                    #ast[expr]{
-                        $(s).emit_enum_variant($(v_name), $(v_id), $(sz), $(body))
-                    }
-                },
-
-                // Generate s.emit_enum_variant_arg(i, {|| blk })
-                {|-s, i, -blk|
-                    let idx = cx.lit_uint(i);
-                    let body = cx.lambda(blk);
-                    #ast[expr]{
-                        $(s).emit_enum_variant_arg($(idx), $(body))
-                    }
-                })
-        };
+    let ser_fn = mk_ser_fn(ext_cx, span, ty, tps) {|cx, _ty, s, v|
+        let arms = vec::init_fn(
+            vec::len(variants),
+            fn&(vidx: uint) -> ast::arm {
+                let variant = variants[vidx];
+                let span = variant.span;
+                let name = variant.node.name;
+                let variant_tys = vec::map(variant.node.args) {|a| a.ty };
+
+                serialize_variant(
+                    cx, variant_tys, span, cx.clone(s),
+
+                    // Generate pattern var(v1, v2, v3)
+                    {|pats|
+                        if vec::is_empty(pats) {
+                            ast::pat_ident(cx.path(span, [name]), none)
+                        } else {
+                            ast::pat_enum(cx.path(span, [name]), pats)
+                        }
+                    },
+
+                    // Generate body s.emit_enum_variant("foo", 0u,
+                    //                                   3u, {|| blk })
+                    {|-s, blk|
+                        let v_name = cx.lit_str(span, name);
+                        let v_id = cx.lit_uint(span, vidx);
+                        let sz = cx.lit_uint(span, vec::len(variant_tys));
+                        let body = cx.lambda(blk);
+                        #ast[expr]{
+                            $(s).emit_enum_variant($(v_name), $(v_id),
+                                                   $(sz), $(body))
+                        }
+                    },
+
+                    // Generate s.emit_enum_variant_arg(i, {|| blk })
+                    {|-s, i, blk|
+                        let idx = cx.lit_uint(span, i);
+                        let body = cx.lambda(blk);
+                        #ast[expr]{
+                            $(s).emit_enum_variant_arg($(idx), $(body))
+                        }
+                    })
+            });
+        [cx.alt_stmt(arms, span, v)]
     };
 
     @{ident: name,
diff --git a/src/rustc/syntax/ext/base.rs b/src/rustc/syntax/ext/base.rs
index 721f059ee35..014cc17b5d5 100644
--- a/src/rustc/syntax/ext/base.rs
+++ b/src/rustc/syntax/ext/base.rs
@@ -27,6 +27,8 @@ fn syntax_expander_table() -> hashmap<str, syntax_extension> {
         {normal({expander: f, span: none})}
     let syntax_expanders = new_str_hash::<syntax_extension>();
     syntax_expanders.insert("fmt", builtin(ext::fmt::expand_syntax_ext));
+    syntax_expanders.insert("auto_serialize",
+                            item_decorator(ext::auto_serialize::expand));
     syntax_expanders.insert("env", builtin(ext::env::expand_syntax_ext));
     syntax_expanders.insert("macro",
                             macro_defining(ext::simplext::add_new_extension));
diff --git a/src/rustc/syntax/ext/qquote.rs b/src/rustc/syntax/ext/qquote.rs
index f93a4019c31..742e7ce45d9 100644
--- a/src/rustc/syntax/ext/qquote.rs
+++ b/src/rustc/syntax/ext/qquote.rs
@@ -193,6 +193,7 @@ fn finish<T: qq_helper>
 {
     let cm = ecx.session().parse_sess.cm;
     let str = @codemap::span_to_snippet(body.span, cm);
+    #debug["qquote--str==%?", str];
     let fname = codemap::mk_substr_filename(cm, body.span);
     let node = parse_from_source_str
         (f, fname, codemap::fss_internal(body.span), str,
diff --git a/src/test/run-pass/auto_serialize_enum.rs b/src/test/run-pass/auto_serialize_enum.rs
new file mode 100644
index 00000000000..19861d0fff6
--- /dev/null
+++ b/src/test/run-pass/auto_serialize_enum.rs
@@ -0,0 +1,19 @@
+use std;
+import std::prettyprint::serializer;
+import std::io;
+
+#[auto_serialize]
+enum expr {
+    val(uint),
+    plus(@expr, @expr),
+    minus(@expr, @expr)
+}
+
+fn main() {
+    let ex = @plus(@minus(@val(3u), @val(10u)),
+                   @plus(@val(22u), @val(5u)));
+    let s = io::with_str_writer {|w| expr::serialize(w, *ex)};
+    #debug["s == %?", s];
+    assert s == "plus(@minus(@val(3u), @val(10u)), \
+                 @plus(@val(22u), @val(5u)))";
+}
\ No newline at end of file
diff --git a/src/test/run-pass/auto_serialize_gen.rs b/src/test/run-pass/auto_serialize_gen.rs
new file mode 100644
index 00000000000..21155e509f5
--- /dev/null
+++ b/src/test/run-pass/auto_serialize_gen.rs
@@ -0,0 +1,19 @@
+use std;
+import std::prettyprint::serializer;
+import std::io;
+
+// Test where we link various types used by name.
+
+#[auto_serialize]
+type spanned<T> = {lo: uint, hi: uint, node: T};
+
+#[auto_serialize]
+type spanned_uint = spanned<uint>;
+
+fn main() {
+    let x: spanned_uint = {lo: 0u, hi: 5u, node: 22u};
+    spanned_uint::serialize(io::stdout(), x);
+    let s = io::with_str_writer {|w| spanned_uint::serialize(w, x)};
+    #debug["s == %?", s];
+    assert s == "{lo: 0u, hi: 5u, node: 22u}";
+}
\ No newline at end of file
diff --git a/src/test/run-pass/auto_serialize_link.rs b/src/test/run-pass/auto_serialize_link.rs
new file mode 100644
index 00000000000..b146b956e8e
--- /dev/null
+++ b/src/test/run-pass/auto_serialize_link.rs
@@ -0,0 +1,22 @@
+use std;
+import std::prettyprint::serializer;
+import std::io;
+
+// Test where we link various types used by name.
+
+#[auto_serialize]
+type uint_vec = [uint];
+
+#[auto_serialize]
+type some_rec = {v: uint_vec};
+
+#[auto_serialize]
+enum an_enum = some_rec;
+
+fn main() {
+    let x = an_enum({v: [1u, 2u, 3u]});
+    an_enum::serialize(io::stdout(), x);
+    let s = io::with_str_writer {|w| an_enum::serialize(w, x)};
+    #debug["s == %?", s];
+    assert s == "an_enum({v: [1u, 2u, 3u]})";
+}
\ No newline at end of file
diff --git a/src/test/run-pass/auto_serialize_rec.rs b/src/test/run-pass/auto_serialize_rec.rs
new file mode 100644
index 00000000000..d1043c8278d
--- /dev/null
+++ b/src/test/run-pass/auto_serialize_rec.rs
@@ -0,0 +1,12 @@
+use std;
+import std::prettyprint::serializer;
+import std::io;
+
+#[auto_serialize]
+type point = {x: uint, y: uint};
+
+fn main() {
+    let s = io::with_str_writer {|w| point::serialize(w, {x: 3u, y: 5u}) };
+    #debug["s == %?", s];
+    assert s == "{x: 3u, y: 5u}";
+}
\ No newline at end of file
diff --git a/src/test/run-pass/auto_serialize_vec.rs b/src/test/run-pass/auto_serialize_vec.rs
new file mode 100644
index 00000000000..103340b7b2a
--- /dev/null
+++ b/src/test/run-pass/auto_serialize_vec.rs
@@ -0,0 +1,13 @@
+use std;
+import std::prettyprint::serializer;
+import std::io;
+
+#[auto_serialize]
+type uint_vec = [uint];
+
+fn main() {
+    let ex = [1u, 2u, 3u];
+    let s = io::with_str_writer {|w| uint_vec::serialize(w, ex)};
+    #debug["s == %?", s];
+    assert s == "[1u, 2u, 3u]";
+}
\ No newline at end of file