From d91742294f282a07b1e26d8da02f7ecec4e0b952 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 12 Mar 2012 10:19:35 -0700 Subject: [PATCH] first (functional) version of the auto_serialize syntax ext --- src/libcore/core.rc | 3 +- src/libcore/serialization.rs | 116 +++++++ src/libcore/uint.rs | 8 + src/libcore/vec.rs | 2 +- src/libstd/ebml.rs | 314 +++++++++++++++++ src/libstd/prettyprint.rs | 130 +++++++ src/libstd/serialization.rs | 417 +---------------------- src/libstd/std.rc | 3 +- src/rustc/driver/driver.rs | 13 +- src/rustc/metadata/astencode.rs | 29 +- src/rustc/middle/typeck.rs | 3 + src/rustc/syntax/ext/auto_serialize.rs | 261 ++++++++------ src/rustc/syntax/ext/base.rs | 2 + src/rustc/syntax/ext/qquote.rs | 1 + src/test/run-pass/auto_serialize_enum.rs | 19 ++ src/test/run-pass/auto_serialize_gen.rs | 19 ++ src/test/run-pass/auto_serialize_link.rs | 22 ++ src/test/run-pass/auto_serialize_rec.rs | 12 + src/test/run-pass/auto_serialize_vec.rs | 13 + 19 files changed, 851 insertions(+), 536 deletions(-) create mode 100644 src/libcore/serialization.rs create mode 100644 src/libstd/prettyprint.rs create mode 100644 src/test/run-pass/auto_serialize_enum.rs create mode 100644 src/test/run-pass/auto_serialize_gen.rs create mode 100644 src/test/run-pass/auto_serialize_link.rs create mode 100644 src/test/run-pass/auto_serialize_rec.rs create mode 100644 src/test/run-pass/auto_serialize_vec.rs diff --git a/src/libcore/core.rc b/src/libcore/core.rc index c28ad0a0282a..e790c55d11fe 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 000000000000..40e468a99dba --- /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(name: str, f: fn() -> T) -> T; + fn read_enum_variant(f: fn(uint) -> T) -> T; + fn read_enum_variant_arg(idx: uint, f: fn() -> T) -> T; + fn read_vec(f: fn(uint) -> T) -> T; + fn read_vec_elt(idx: uint, f: fn() -> T) -> T; + fn read_box(f: fn() -> T) -> T; + fn read_uniq(f: fn() -> T) -> T; + fn read_rec(f: fn() -> T) -> T; + fn read_rec_field(f_name: str, f_idx: uint, f: fn() -> T) -> T; + fn read_tup(sz: uint, f: fn() -> T) -> T; + fn read_tup_elt(idx: uint, f: fn() -> T) -> T; +} + +// ___________________________________________________________________________ +// Helper routines +// +// These should eventually be coded as traits. + +fn emit_from_vec(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: D, f: fn() -> T) -> [T] { + d.read_vec {|len| + vec::init_fn(len) {|i| + d.read_vec_elt(i) {|| f() } + } + } +} + +impl serializer_helpers for S { + fn emit_from_vec(v: [T], f: fn(T)) { + emit_from_vec(self, v, f) + } +} + +impl deserializer_helpers for D { + fn read_to_vec(f: fn() -> T) -> [T] { + read_to_vec(self, f) + } +} + diff --git a/src/libcore/uint.rs b/src/libcore/uint.rs index 88230bea0940..e466717657d5 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: S, v: uint) { + s.emit_uint(v); +} + +fn deserialize(d: D) -> uint { + d.read_uint() +} + #[cfg(test)] mod tests { diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 663bc20001b7..72ae981d36b3 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -406,7 +406,7 @@ fn map(v: [T], f: fn(T) -> U) -> [U] { } fn flat_map(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 931ad32551fa..203e7e12ad03 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(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(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(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(idx: uint, f: fn() -> T) -> T { + #debug["read_enum_variant_arg(idx=%u)", idx]; + f() + } + + fn read_vec(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(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(f: fn() -> T) -> T { + #debug["read_box()"]; + f() + } + + fn read_uniq(f: fn() -> T) -> T { + #debug["read_uniq()"]; + f() + } + + fn read_rec(f: fn() -> T) -> T { + #debug["read_rec()"]; + f() + } + + fn read_rec_field(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(sz: uint, f: fn() -> T) -> T { + #debug["read_tup(sz=%u)", sz]; + f() + } + + fn read_tup_elt(idx: uint, f: fn() -> T) -> T { + #debug["read_tup_elt(idx=%u)", idx]; + f() + } +} + + +// ___________________________________________________________________________ +// Testing + +#[test] +fn test_option_int() { + fn serialize_1(s: S, v: int) { + s.emit_i64(v as i64); + } + + fn serialize_0(s: S, v: option) { + 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: S) -> int { + s.read_i64() as int + } + + fn deserialize_0(s: S) -> option { + 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) { + #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 000000000000..10d971ff0f20 --- /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 c446d10b88e7..fe70247e01b1 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(name: str, f: fn() -> T) -> T; - fn read_enum_variant(f: fn(uint) -> T) -> T; - fn read_enum_variant_arg(idx: uint, f: fn() -> T) -> T; - fn read_vec(f: fn(uint) -> T) -> T; - fn read_vec_elt(idx: uint, f: fn() -> T) -> T; - fn read_box(f: fn() -> T) -> T; - fn read_uniq(f: fn() -> T) -> T; - fn read_rec(f: fn() -> T) -> T; - fn read_rec_field(f_name: str, f_idx: uint, f: fn() -> T) -> T; - fn read_tup(sz: uint, f: fn() -> T) -> T; - fn read_tup_elt(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(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(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(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(idx: uint, f: fn() -> T) -> T { - #debug["read_enum_variant_arg(idx=%u)", idx]; - f() - } - - fn read_vec(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(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(f: fn() -> T) -> T { - #debug["read_box()"]; - f() - } - - fn read_uniq(f: fn() -> T) -> T { - #debug["read_uniq()"]; - f() - } - - fn read_rec(f: fn() -> T) -> T { - #debug["read_rec()"]; - f() - } - - fn read_rec_field(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(sz: uint, f: fn() -> T) -> T { - #debug["read_tup(sz=%u)", sz]; - f() - } - - fn read_tup_elt(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 for S { - fn emit_from_vec(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 for D { - fn read_to_vec(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: S, v: int) { - s.emit_i64(v as i64); - } - - fn serialize_0(s: S, v: option) { - 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: S) -> int { - s.read_i64() as int - } - - fn deserialize_0(s: S) -> option { - 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) { - #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 a06cca77f752..0f11b8533d23 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 dbdd5325e1af..71f39a77e362 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 d9469184d6b2..f09b4f902fd3 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 1a6953d2d930..a61c88cad4a8 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 5f1fa8cb3790..b06bf81e5a7c 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 [@ast::stmt]> + tps: map::hashmap [@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]; + 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 }; - 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) {|| - // }; - //} - } + serialize_variant( + cx, variant_tys, span, cx.clone(s), - let variant_tys = vec::map(variant.args) {|a| a.ty }; + // 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) + } + }, - serialize_variant( - cx, variant_tys, variant.span, cx.clone(s), + // 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 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)) - } - }) - }; + // 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 721f059ee35e..014cc17b5d5b 100644 --- a/src/rustc/syntax/ext/base.rs +++ b/src/rustc/syntax/ext/base.rs @@ -27,6 +27,8 @@ fn syntax_expander_table() -> hashmap { {normal({expander: f, span: none})} let syntax_expanders = new_str_hash::(); 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 f93a4019c31f..742e7ce45d97 100644 --- a/src/rustc/syntax/ext/qquote.rs +++ b/src/rustc/syntax/ext/qquote.rs @@ -193,6 +193,7 @@ fn finish { 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 000000000000..19861d0fff64 --- /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 000000000000..21155e509f54 --- /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 = {lo: uint, hi: uint, node: T}; + +#[auto_serialize] +type spanned_uint = spanned; + +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 000000000000..b146b956e8eb --- /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 000000000000..d1043c8278de --- /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 000000000000..103340b7b2a1 --- /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