From 74807b15944205beb2b86ea5422927c47cac3ecc Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sat, 6 Apr 2013 22:29:37 -0700 Subject: [PATCH 01/10] syntax: match variants use 4 space indent by default --- src/libsyntax/print/pprust.rs | 15 +++++++-------- src/test/pretty/alt-naked-expr-long.rs | 8 ++++---- src/test/pretty/alt-naked-expr-medium.rs | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index fa1b97275660c..4e7e5144a7df2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -95,7 +95,6 @@ pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { } pub static indent_unit: uint = 4u; -pub static match_indent_unit: uint = 2u; pub static default_columns: uint = 78u; @@ -1227,16 +1226,16 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) { print_block(s, blk); } ast::expr_match(expr, ref arms) => { - cbox(s, match_indent_unit); + cbox(s, indent_unit); ibox(s, 4); word_nbsp(s, ~"match"); print_expr(s, expr); space(s.s); bopen(s); - let len = (*arms).len(); - for (*arms).eachi |i, arm| { + let len = arms.len(); + for arms.eachi |i, arm| { space(s.s); - cbox(s, match_indent_unit); + cbox(s, indent_unit); ibox(s, 0u); let mut first = true; for arm.pats.each |p| { @@ -1269,7 +1268,7 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) { ast::expr_block(ref blk) => { // the block will close the pattern's ibox print_block_unclosed_indent( - s, blk, match_indent_unit); + s, blk, indent_unit); } _ => { end(s); // close the ibox for the pattern @@ -1286,10 +1285,10 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) { } } else { // the block will close the pattern's ibox - print_block_unclosed_indent(s, &arm.body, match_indent_unit); + print_block_unclosed_indent(s, &arm.body, indent_unit); } } - bclose_(s, expr.span, match_indent_unit); + bclose_(s, expr.span, indent_unit); } ast::expr_fn_block(ref decl, ref body) => { // in do/for blocks we don't want to show an empty diff --git a/src/test/pretty/alt-naked-expr-long.rs b/src/test/pretty/alt-naked-expr-long.rs index 67253c9753ede..66ad3d558201d 100644 --- a/src/test/pretty/alt-naked-expr-long.rs +++ b/src/test/pretty/alt-naked-expr-long.rs @@ -17,9 +17,9 @@ fn main() { let x = Some(3); let y = match x { - Some(_) => - ~"some" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" - + ~"very" + ~"very" + ~"long" + ~"string", - None => ~"none" + Some(_) => + ~"some" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" + + ~"very" + ~"very" + ~"very" + ~"long" + ~"string", + None => ~"none" }; } diff --git a/src/test/pretty/alt-naked-expr-medium.rs b/src/test/pretty/alt-naked-expr-medium.rs index 6c6398c3e52c2..4ae129c7b7307 100644 --- a/src/test/pretty/alt-naked-expr-medium.rs +++ b/src/test/pretty/alt-naked-expr-medium.rs @@ -14,7 +14,7 @@ fn main() { let x = Some(3); let _y = match x { - Some(_) => ~[~"some(_)", ~"not", ~"SO", ~"long", ~"string"], - None => ~[~"none"] + Some(_) => ~[~"some(_)", ~"not", ~"SO", ~"long", ~"string"], + None => ~[~"none"] }; } From 4464e447500c98242b536ee4a461fcd8c5d9adc5 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sat, 6 Apr 2013 22:34:09 -0700 Subject: [PATCH 02/10] syntax: update a deriving error message to use the new syntax --- src/libsyntax/ext/deriving/clone.rs | 4 +--- src/libsyntax/ext/deriving/eq.rs | 2 +- src/libsyntax/ext/deriving/iter_bytes.rs | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index c9e1771599939..6d598c95e3a53 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -188,9 +188,7 @@ fn expand_deriving_clone_struct_method(cx: @ext_ctxt, fields.push(field); } unnamed_field => { - cx.span_bug(span, - ~"unnamed fields in \ - expand_deriving_clone_struct_method"); + cx.span_bug(span, ~"unnamed fields in `deriving(Clone)`"); } } } diff --git a/src/libsyntax/ext/deriving/eq.rs b/src/libsyntax/ext/deriving/eq.rs index 07b2835d44cdf..46eec2ede68a9 100644 --- a/src/libsyntax/ext/deriving/eq.rs +++ b/src/libsyntax/ext/deriving/eq.rs @@ -289,7 +289,7 @@ fn expand_deriving_eq_struct_method(cx: @ext_ctxt, &mut outer_expr); } unnamed_field => { - cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`"); + cx.span_unimpl(span, ~"unnamed fields with `deriving(Eq)`"); } } } diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index e2a43591ef026..e832408dd2b1d 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -191,7 +191,7 @@ fn expand_deriving_iter_bytes_struct_method(cx: @ext_ctxt, } unnamed_field => { cx.span_unimpl(span, - ~"unnamed fields with `deriving_iter_bytes`"); + ~"unnamed fields with `deriving(IterBytes)`"); } } } From 97cc571358c3ac1bc3d562ac60c39c67cda3678d Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 9 Apr 2013 18:56:34 -0700 Subject: [PATCH 03/10] std: clean up the order of {De,En}codable methods --- src/libstd/ebml.rs | 50 ++++++++-------- src/libstd/json.rs | 98 ++++++++++++++++---------------- src/libstd/serialize.rs | 13 ++--- src/libsyntax/ext/auto_encode.rs | 14 ++--- 4 files changed, 87 insertions(+), 88 deletions(-) diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index b117c8d9882ba..3afc49d40addc 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -335,20 +335,6 @@ pub mod reader { f() } - fn read_seq(&self, f: &fn(uint) -> T) -> T { - debug!("read_seq()"); - do self.push_doc(self.next_doc(EsVec)) { - let len = self._next_uint(EsVecLen); - debug!(" len=%u", len); - f(len) - } - } - - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_seq_elt(idx=%u)", idx); - self.push_doc(self.next_doc(EsVecElt), f) - } - fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T { debug!("read_struct(name=%s)", name); f() @@ -373,6 +359,20 @@ pub mod reader { } } + fn read_seq(&self, f: &fn(uint) -> T) -> T { + debug!("read_seq()"); + do self.push_doc(self.next_doc(EsVec)) { + let len = self._next_uint(EsVecLen); + debug!(" len=%u", len); + f(len) + } + } + + fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_seq_elt(idx=%u)", idx); + self.push_doc(self.next_doc(EsVecElt), f) + } + fn read_map(&self, _f: &fn(uint) -> T) -> T { debug!("read_map()"); fail!(~"read_map is unimplemented"); @@ -613,17 +613,6 @@ pub mod writer { } fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) { f() } - fn emit_seq(&self, len: uint, f: &fn()) { - do self.wr_tag(EsVec as uint) { - self._emit_tagged_uint(EsVecLen, len); - f() - } - } - - fn emit_seq_elt(&self, _idx: uint, f: &fn()) { - self.wr_tag(EsVecElt as uint, f) - } - fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { f() } fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { self._emit_label(name); @@ -640,6 +629,17 @@ pub mod writer { self.emit_enum_variant("Some", 1, 1, f) } + fn emit_seq(&self, len: uint, f: &fn()) { + do self.wr_tag(EsVec as uint) { + self._emit_tagged_uint(EsVecLen, len); + f() + } + } + + fn emit_seq_elt(&self, _idx: uint, f: &fn()) { + self.wr_tag(EsVecElt as uint, f) + } + fn emit_map(&self, _len: uint, _f: &fn()) { fail!(~"emit_map is unimplemented"); } diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 90a745aaeb9b7..3714adb305561 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -130,17 +130,6 @@ impl serialize::Encoder for Encoder { f(); } - fn emit_seq(&self, _len: uint, f: &fn()) { - self.wr.write_char('['); - f(); - self.wr.write_char(']'); - } - - fn emit_seq_elt(&self, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - f() - } - fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { self.wr.write_char('{'); f(); @@ -157,6 +146,17 @@ impl serialize::Encoder for Encoder { fn emit_option_none(&self) { self.emit_nil(); } fn emit_option_some(&self, f: &fn()) { f(); } + fn emit_seq(&self, _len: uint, f: &fn()) { + self.wr.write_char('['); + f(); + self.wr.write_char(']'); + } + + fn emit_seq_elt(&self, idx: uint, f: &fn()) { + if idx != 0 { self.wr.write_char(','); } + f() + } + fn emit_map(&self, _len: uint, f: &fn()) { self.wr.write_char('{'); f(); @@ -241,58 +241,58 @@ impl serialize::Encoder for PrettyEncoder { f() } - fn emit_seq(&self, len: uint, f: &fn()) { + fn emit_struct(&self, _name: &str, len: uint, f: &fn()) { if len == 0 { - self.wr.write_str("[]"); + self.wr.write_str("{}"); } else { - self.wr.write_char('['); + self.wr.write_char('{'); self.indent += 2; f(); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); + self.wr.write_char('}'); } } - fn emit_seq_elt(&self, idx: uint, f: &fn()) { + fn emit_field(&self, name: &str, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); } else { self.wr.write_str(",\n"); } self.wr.write_str(spaces(self.indent)); - f() + self.wr.write_str(escape_str(name)); + self.wr.write_str(": "); + f(); } - fn emit_struct(&self, _name: &str, len: uint, f: &fn()) { + fn emit_option(&self, f: &fn()) { f(); } + fn emit_option_none(&self) { self.emit_nil(); } + fn emit_option_some(&self, f: &fn()) { f(); } + + fn emit_seq(&self, len: uint, f: &fn()) { if len == 0 { - self.wr.write_str("{}"); + self.wr.write_str("[]"); } else { - self.wr.write_char('{'); + self.wr.write_char('['); self.indent += 2; f(); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); + self.wr.write_char(']'); } } - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { + fn emit_seq_elt(&self, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); } else { self.wr.write_str(",\n"); } self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); - f(); + f() } - fn emit_option(&self, f: &fn()) { f(); } - fn emit_option_none(&self) { self.emit_nil(); } - fn emit_option_some(&self, f: &fn()) { f(); } - fn emit_map(&self, len: uint, f: &fn()) { if len == 0 { self.wr.write_str("{}"); @@ -827,26 +827,6 @@ impl serialize::Decoder for Decoder { f() } - fn read_seq(&self, f: &fn(uint) -> T) -> T { - debug!("read_seq()"); - let len = match self.stack.pop() { - List(list) => { - let len = list.len(); - do vec::consume_reverse(list) |_i, v| { - self.stack.push(v); - } - len - } - _ => fail!(~"not a list"), - }; - f(len) - } - - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_seq_elt(idx=%u)", idx); - f() - } - fn read_struct(&self, name: &str, len: uint, f: &fn() -> T) -> T { debug!("read_struct(name=%s, len=%u)", name, len); let value = f(); @@ -880,6 +860,26 @@ impl serialize::Decoder for Decoder { } } + fn read_seq(&self, f: &fn(uint) -> T) -> T { + debug!("read_seq()"); + let len = match self.stack.pop() { + List(list) => { + let len = list.len(); + do vec::consume_reverse(list) |_i, v| { + self.stack.push(v); + } + len + } + _ => fail!(~"not a list"), + }; + f(len) + } + + fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_seq_elt(idx=%u)", idx); + f() + } + fn read_map(&self, f: &fn(uint) -> T) -> T { debug!("read_map()"); let len = match self.stack.pop() { diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index c2f0d9cb43f09..a49f43d485b1f 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -44,14 +44,10 @@ pub trait Encoder { fn emit_str(&self, v: &str); // Compound types: - fn emit_enum(&self, name: &str, f: &fn()); fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: &fn()); fn emit_enum_variant_arg(&self, idx: uint, f: &fn()); - fn emit_seq(&self, len: uint, f: &fn()); - fn emit_seq_elt(&self, idx: uint, f: &fn()); - fn emit_struct(&self, name: &str, _len: uint, f: &fn()); fn emit_field(&self, f_name: &str, f_idx: uint, f: &fn()); @@ -60,6 +56,9 @@ pub trait Encoder { fn emit_option_none(&self); fn emit_option_some(&self, f: &fn()); + fn emit_seq(&self, len: uint, f: &fn()); + fn emit_seq_elt(&self, idx: uint, f: &fn()); + fn emit_map(&self, len: uint, f: &fn()); fn emit_map_elt_key(&self, idx: uint, f: &fn()); fn emit_map_elt_val(&self, idx: uint, f: &fn()); @@ -90,15 +89,15 @@ pub trait Decoder { fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T; - fn read_seq(&self, f: &fn(uint) -> T) -> T; - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T; - fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T; fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T; // Specialized types: fn read_option(&self, f: &fn(bool) -> T) -> T; + fn read_seq(&self, f: &fn(uint) -> T) -> T; + fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T; + fn read_map(&self, f: &fn(uint) -> T) -> T; fn read_map_elt_key(&self, idx: uint, f: &fn() -> T) -> T; fn read_map_elt_val(&self, idx: uint, f: &fn() -> T) -> T; diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index f9dadb560e3d0..932c3477cf5bc 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -1253,13 +1253,6 @@ mod test { self.add_to_log(CallToEmitEnumVariantArg (idx)); f(); } - fn emit_seq(&self, +_len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); - } - fn emit_seq_elt(&self, +_idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); - } - fn emit_struct(&self, name: &str, +len: uint, f: &fn()) { self.add_to_log(CallToEmitStruct (name.to_str(),len)); f(); } @@ -1279,6 +1272,13 @@ mod test { f(); } + fn emit_seq(&self, +_len: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_seq_elt(&self, +_idx: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_map(&self, _len: uint, f: &fn()) { self.add_unknown_to_log(); f(); } From 419f6acf0e609c18c6df5ee2ca8ed9cb6206bbfe Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 9 Apr 2013 19:41:20 -0700 Subject: [PATCH 04/10] std: rename {read,emit}_field to {read,emit}_struct_field --- src/librustc/middle/astencode.rs | 97 ++++++++++++++++++++++++++++++++ src/libstd/ebml.rs | 20 ++++++- src/libstd/json.rs | 50 +++++++++++++++- src/libstd/serialize.rs | 16 +++++- src/libsyntax/ext/auto_encode.rs | 10 ++-- 5 files changed, 183 insertions(+), 10 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 68989b3142566..f5a31879855ef 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -556,6 +556,7 @@ trait read_method_map_entry_helper { -> method_map_entry; } +#[cfg(stage0)] fn encode_method_map_entry(ecx: @e::EncodeContext, ebml_w: writer::Encoder, mme: method_map_entry) { @@ -572,7 +573,27 @@ fn encode_method_map_entry(ecx: @e::EncodeContext, } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +fn encode_method_map_entry(ecx: @e::EncodeContext, + ebml_w: writer::Encoder, + mme: method_map_entry) { + do ebml_w.emit_struct("method_map_entry", 3) { + do ebml_w.emit_struct_field("self_arg", 0u) { + ebml_w.emit_arg(ecx, mme.self_arg); + } + do ebml_w.emit_struct_field("explicit_self", 2u) { + mme.explicit_self.encode(&ebml_w); + } + do ebml_w.emit_struct_field("origin", 1u) { + mme.origin.encode(&ebml_w); + } + } +} + impl read_method_map_entry_helper for reader::Decoder { + #[cfg(stage0)] fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) -> method_map_entry { do self.read_struct("method_map_entry", 3) { @@ -592,6 +613,29 @@ impl read_method_map_entry_helper for reader::Decoder { } } } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) + -> method_map_entry { + do self.read_struct("method_map_entry", 3) { + method_map_entry { + self_arg: self.read_struct_field("self_arg", 0u, || { + self.read_arg(xcx) + }), + explicit_self: self.read_struct_field("explicit_self", 2u, || { + let self_type: ast::self_ty_ = Decodable::decode(self); + self_type + }), + origin: self.read_struct_field("origin", 1u, || { + let method_origin: method_origin = + Decodable::decode(self); + method_origin.tr(xcx) + }), + } + } + } } impl tr for method_origin { @@ -782,6 +826,7 @@ impl ebml_writer_helpers for writer::Encoder { } } + #[cfg(stage0)] fn emit_tpbt(&self, ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { do self.emit_struct("ty_param_bounds_and_ty", 2) { @@ -804,6 +849,32 @@ impl ebml_writer_helpers for writer::Encoder { } } } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_tpbt(&self, ecx: @e::EncodeContext, + tpbt: ty::ty_param_bounds_and_ty) { + do self.emit_struct("ty_param_bounds_and_ty", 2) { + do self.emit_struct_field("generics", 0) { + do self.emit_struct("Generics", 2) { + do self.emit_struct_field("type_param_defs", 0) { + do self.emit_from_vec(*tpbt.generics.type_param_defs) + |type_param_def| + { + self.emit_type_param_def(ecx, type_param_def); + } + } + do self.emit_struct_field("region_param", 1) { + tpbt.generics.region_param.encode(self); + } + } + } + do self.emit_struct_field("ty", 1) { + self.emit_ty(ecx, tpbt.ty); + } + } + } } trait write_tag_and_id { @@ -1053,6 +1124,7 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } + #[cfg(stage0)] fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty { @@ -1075,6 +1147,31 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) + -> ty::ty_param_bounds_and_ty + { + do self.read_struct("ty_param_bounds_and_ty", 2) { + ty::ty_param_bounds_and_ty { + generics: do self.read_struct("Generics", 2) { + ty::Generics { + type_param_defs: self.read_struct_field("type_param_defs", 0, || { + @self.read_to_vec(|| self.read_type_param_def(xcx)) + }), + region_param: self.read_struct_field(~"region_param", 1, || { + Decodable::decode(self) + }) + } + }, + ty: self.read_struct_field("ty", 1, || { + self.read_ty(xcx) + }) + } + } + } + fn convert_def_id(&self, xcx: @ExtendedDecodeContext, source: tydecode::DefIdSource, did: ast::def_id) -> ast::def_id { diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 3afc49d40addc..28933d553e6ef 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -340,8 +340,18 @@ pub mod reader { f() } + #[cfg(stage0)] fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%s, idx=%u)", name, idx); + debug!("read_field(name=%?, idx=%u)", name, idx); + self._check_label(name); + f() + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_struct_field(name=%?, idx=%u)", name, idx); self._check_label(name); f() } @@ -614,10 +624,18 @@ pub mod writer { fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) { f() } fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { f() } + #[cfg(stage0)] fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { self._emit_label(name); f() } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, name: &str, _idx: uint, f: &fn()) { + self._emit_label(name); + f() + } fn emit_option(&self, f: &fn()) { self.emit_enum("Option", f); diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 3714adb305561..4b5e1f1422990 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -135,12 +135,22 @@ impl serialize::Encoder for Encoder { f(); self.wr.write_char('}'); } + #[cfg(stage0)] fn emit_field(&self, name: &str, idx: uint, f: &fn()) { if idx != 0 { self.wr.write_char(','); } self.wr.write_str(escape_str(name)); self.wr.write_char(':'); f(); } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { + if idx != 0 { self.wr.write_char(','); } + self.wr.write_str(escape_str(name)); + self.wr.write_char(':'); + f(); + } fn emit_option(&self, f: &fn()) { f(); } fn emit_option_none(&self) { self.emit_nil(); } @@ -254,6 +264,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_char('}'); } } + #[cfg(stage0)] fn emit_field(&self, name: &str, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); @@ -265,6 +276,20 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_str(": "); f(); } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { + if idx == 0 { + self.wr.write_char('\n'); + } else { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + self.wr.write_str(escape_str(name)); + self.wr.write_str(": "); + f(); + } fn emit_option(&self, f: &fn()) { f(); } fn emit_option_none(&self) { self.emit_nil(); } @@ -834,8 +859,31 @@ impl serialize::Decoder for Decoder { value } + #[cfg(stage0)] fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(%s, idx=%u)", name, idx); + debug!("read_field(name=%?, idx=%u)", name, idx); + match self.stack.pop() { + Object(obj) => { + let mut obj = obj; + let value = match obj.pop(&name.to_owned()) { + None => fail!(fmt!("no such field: %s", name)), + Some(json) => { + self.stack.push(json); + f() + } + }; + self.stack.push(Object(obj)); + value + } + value => fail!(fmt!("not an object: %?", value)) + } + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_struct_field(name=%?, idx=%u)", name, idx); match self.stack.pop() { Object(obj) => { let mut obj = obj; diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index a49f43d485b1f..cc3a1ec028983 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -48,8 +48,13 @@ pub trait Encoder { fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: &fn()); fn emit_enum_variant_arg(&self, idx: uint, f: &fn()); - fn emit_struct(&self, name: &str, _len: uint, f: &fn()); + fn emit_struct(&self, name: &str, len: uint, f: &fn()); + #[cfg(stage0)] fn emit_field(&self, f_name: &str, f_idx: uint, f: &fn()); + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, f_name: &str, f_idx: uint, f: &fn()); // Specialized types: fn emit_option(&self, f: &fn()); @@ -89,8 +94,13 @@ pub trait Decoder { fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T; - fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T; - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T; + fn read_struct(&self, s_name: &str, len: uint, f: &fn() -> T) -> T; + #[cfg(stage0)] + fn read_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; // Specialized types: fn read_option(&self, f: &fn(bool) -> T) -> T; diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 932c3477cf5bc..38bac6b1f438d 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -732,12 +732,12 @@ fn mk_struct_ser_impl( ) ); - // ast for `__s.emit_field($(name), $(idx), $(expr_lambda))` + // ast for `__s.emit_struct_field($(name), $(idx), $(expr_lambda))` cx.stmt( cx.expr_method_call( span, cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_field"), + cx.ident_of(~"emit_struct_field"), ~[ cx.lit_str(span, @cx.str_of(field.ident)), cx.lit_uint(span, idx), @@ -786,11 +786,11 @@ fn mk_struct_deser_impl( ) ); - // ast for `__d.read_field($(name), $(idx), $(expr_lambda))` + // ast for `__d.read_struct_field($(name), $(idx), $(expr_lambda))` let expr: @ast::expr = cx.expr_method_call( span, cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_field"), + cx.ident_of(~"read_struct_field"), ~[ cx.lit_str(span, @cx.str_of(field.ident)), cx.lit_uint(span, idx), @@ -1256,7 +1256,7 @@ mod test { fn emit_struct(&self, name: &str, +len: uint, f: &fn()) { self.add_to_log(CallToEmitStruct (name.to_str(),len)); f(); } - fn emit_field(&self, name: &str, +idx: uint, f: &fn()) { + fn emit_struct_field(&self, name: &str, +idx: uint, f: &fn()) { self.add_to_log(CallToEmitField (name.to_str(),idx)); f(); } From f50a8e283398a8857425e80053db8db845980fa8 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 8 Apr 2013 09:02:36 -0700 Subject: [PATCH 05/10] syntax: Simplify deriving to handle classes that take generics, like Encodable --- src/libsyntax/ext/deriving/clone.rs | 6 ++-- src/libsyntax/ext/deriving/eq.rs | 6 ++-- src/libsyntax/ext/deriving/iter_bytes.rs | 6 ++-- src/libsyntax/ext/deriving/mod.rs | 44 +++++++++--------------- 4 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 6d598c95e3a53..c8ba6b990e47a 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -17,6 +17,7 @@ use ext::build; use ext::deriving::*; use codemap::{span, spanned}; use ast_util; +use opt_vec; use core::uint; @@ -48,12 +49,13 @@ fn create_derived_clone_impl(cx: @ext_ctxt, method: @method) -> @item { let methods = [ method ]; - let trait_path = [ + let trait_path = ~[ cx.ident_of(~"core"), cx.ident_of(~"clone"), cx.ident_of(~"Clone"), ]; - create_derived_impl(cx, span, type_ident, generics, methods, trait_path) + let trait_path = build::mk_raw_path_global(span, trait_path); + create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty) } // Creates a method from the given expression conforming to the signature of // the `clone` method. diff --git a/src/libsyntax/ext/deriving/eq.rs b/src/libsyntax/ext/deriving/eq.rs index 46eec2ede68a9..c427a206c2e32 100644 --- a/src/libsyntax/ext/deriving/eq.rs +++ b/src/libsyntax/ext/deriving/eq.rs @@ -17,6 +17,7 @@ use ext::build; use ext::deriving::*; use codemap::{span, spanned}; use ast_util; +use opt_vec; use core::uint; @@ -124,12 +125,13 @@ fn create_derived_eq_impl(cx: @ext_ctxt, ne_method: @method) -> @item { let methods = [ eq_method, ne_method ]; - let trait_path = [ + let trait_path = ~[ cx.ident_of(~"core"), cx.ident_of(~"cmp"), cx.ident_of(~"Eq") ]; - create_derived_impl(cx, span, type_ident, generics, methods, trait_path) + let trait_path = build::mk_raw_path_global(span, trait_path); + create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty) } fn call_substructure_eq_method(cx: @ext_ctxt, diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index e832408dd2b1d..4124e6ee6c165 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -17,6 +17,7 @@ use ext::build; use ext::deriving::*; use codemap::{span, spanned}; use ast_util; +use opt_vec; use core::uint; @@ -49,12 +50,13 @@ fn create_derived_iter_bytes_impl(cx: @ext_ctxt, method: @method) -> @item { let methods = [ method ]; - let trait_path = [ + let trait_path = ~[ cx.ident_of(~"core"), cx.ident_of(~"to_bytes"), cx.ident_of(~"IterBytes") ]; - create_derived_impl(cx, span, type_ident, generics, methods, trait_path) + let trait_path = build::mk_raw_path_global(span, trait_path); + create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty) } // Creates a method from the given set of statements conforming to the diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 4337546930ff9..95bca7ff230c7 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -14,7 +14,7 @@ use core::prelude::*; use ast; -use ast::{TraitTyParamBound, Ty, bind_by_ref, deref, enum_def}; +use ast::{Ty, bind_by_ref, deref, enum_def}; use ast::{expr, expr_match, ident, item, item_}; use ast::{item_enum, item_impl, item_struct, Generics}; use ast::{m_imm, meta_item, method}; @@ -153,12 +153,13 @@ pub fn create_self_type_with_params(cx: @ext_ctxt, } pub fn create_derived_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - methods: &[@method], - trait_path: &[ident]) - -> @item { + span: span, + type_ident: ident, + generics: &Generics, + methods: &[@method], + trait_path: @ast::Path, + mut impl_ty_params: opt_vec::OptVec) + -> @item { /*! * * Given that we are deriving a trait `Tr` for a type `T<'a, ..., @@ -175,29 +176,16 @@ pub fn create_derived_impl(cx: @ext_ctxt, build::mk_lifetime(cx, l.span, l.ident) }); - // Create the type parameters. - let impl_ty_params = generics.ty_params.map(|ty_param| { - let bound = build::mk_trait_ref_global(cx, - span, - trait_path.map(|x| *x)); - let bounds = @opt_vec::with(TraitTyParamBound(bound)); - build::mk_ty_param(cx, ty_param.ident, bounds) - }); - // Create the reference to the trait. - let trait_path = ast::Path { - span: span, - global: true, - idents: trait_path.map(|x| *x), - rp: None, - types: ~[] - }; - let trait_path = @trait_path; - let trait_ref = ast::trait_ref { - path: trait_path, - ref_id: cx.next_id() + let trait_ref = build::mk_trait_ref_(cx, trait_path); + + // Create the type parameters. + for generics.ty_params.each |ty_param| { + let bounds = @opt_vec::with( + build::mk_trait_ty_param_bound_(cx, trait_path) + ); + impl_ty_params.push(build::mk_ty_param(cx, ty_param.ident, bounds)); }; - let trait_ref = @trait_ref; // Create the type of `self`. let self_type = create_self_type_with_params(cx, From 5841564bf9a9db012fc17d53da514ddf223dfaf5 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 10 Apr 2013 16:31:51 -0700 Subject: [PATCH 06/10] syntax: add support for #[deriving(Encodable)] --- src/libsyntax/ext/build.rs | 72 ++++- src/libsyntax/ext/deriving/encodable.rs | 388 ++++++++++++++++++++++++ src/libsyntax/ext/deriving/mod.rs | 3 + 3 files changed, 455 insertions(+), 8 deletions(-) create mode 100644 src/libsyntax/ext/deriving/encodable.rs diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 0f84ac4153272..530bb8f15417a 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -64,12 +64,7 @@ pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr) mk_expr(cx, sp, ast::expr_unary(op, e)) } pub fn mk_raw_path(sp: span, +idents: ~[ast::ident]) -> @ast::Path { - let p = @ast::Path { span: sp, - global: false, - idents: idents, - rp: None, - types: ~[] }; - return p; + mk_raw_path_(sp, idents, ~[]) } pub fn mk_raw_path_(sp: span, +idents: ~[ast::ident], @@ -82,11 +77,16 @@ pub fn mk_raw_path_(sp: span, types: types } } pub fn mk_raw_path_global(sp: span, +idents: ~[ast::ident]) -> @ast::Path { + mk_raw_path_global_(sp, idents, ~[]) +} +pub fn mk_raw_path_global_(sp: span, + +idents: ~[ast::ident], + +types: ~[@ast::Ty]) -> @ast::Path { @ast::Path { span: sp, global: true, idents: idents, rp: None, - types: ~[] } + types: types } } pub fn mk_path(cx: @ext_ctxt, sp: span, +idents: ~[ast::ident]) -> @ast::expr { @@ -271,6 +271,29 @@ pub fn mk_simple_block(cx: @ext_ctxt, span: span, } } +pub fn mk_lambda_(cx: @ext_ctxt, + span: span, + fn_decl: ast::fn_decl, + blk: ast::blk) + -> @ast::expr { + mk_expr(cx, span, ast::expr_fn_block(fn_decl, blk)) +} +pub fn mk_lambda(cx: @ext_ctxt, + span: span, + fn_decl: ast::fn_decl, + expr: @ast::expr) + -> @ast::expr { + let blk = mk_simple_block(cx, span, expr); + mk_lambda_(cx, span, fn_decl, blk) +} +pub fn mk_lambda_stmts(cx: @ext_ctxt, + span: span, + fn_decl: ast::fn_decl, + stmts: ~[@ast::stmt]) + -> @ast::expr { + let blk = mk_block(cx, span, ~[], stmts, None); + mk_lambda(cx, span, fn_decl, blk) +} pub fn mk_copy(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { mk_expr(cx, sp, ast::expr_copy(e)) } @@ -337,12 +360,35 @@ pub fn mk_ty_path_global(cx: @ext_ctxt, let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span }; ty } +pub fn mk_ty_rptr(cx: @ext_ctxt, + span: span, + ty: @ast::Ty, + mutbl: ast::mutability) + -> @ast::Ty { + @ast::Ty { + id: cx.next_id(), + span: span, + node: ast::ty_rptr( + None, + ast::mt { ty: ty, mutbl: mutbl } + ), + } +} +pub fn mk_ty_infer(cx: @ext_ctxt, span: span) -> @ast::Ty { + @ast::Ty { + id: cx.next_id(), + node: ast::ty_infer, + span: span, + } +} pub fn mk_trait_ref_global(cx: @ext_ctxt, span: span, +idents: ~[ ast::ident ]) -> @ast::trait_ref { - let path = build::mk_raw_path_global(span, idents); + mk_trait_ref_(cx, build::mk_raw_path_global(span, idents)) +} +pub fn mk_trait_ref_(cx: @ext_ctxt, path: @ast::Path) -> @ast::trait_ref { @ast::trait_ref { path: path, ref_id: cx.next_id() @@ -371,6 +417,16 @@ pub fn mk_arg(cx: @ext_ctxt, pub fn mk_fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl { ast::fn_decl { inputs: inputs, output: output, cf: ast::return_val } } +pub fn mk_trait_ty_param_bound_global(cx: @ext_ctxt, + span: span, + +idents: ~[ast::ident]) + -> ast::TyParamBound { + ast::TraitTyParamBound(mk_trait_ref_global(cx, span, idents)) +} +pub fn mk_trait_ty_param_bound_(cx: @ext_ctxt, + path: @ast::Path) -> ast::TyParamBound { + ast::TraitTyParamBound(mk_trait_ref_(cx, path)) +} pub fn mk_ty_param(cx: @ext_ctxt, ident: ast::ident, bounds: @OptVec) diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs new file mode 100644 index 0000000000000..81bfb03724f30 --- /dev/null +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -0,0 +1,388 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::prelude::*; + +use ast; +use ast::*; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span, spanned}; +use ast_util; +use opt_vec; + +use core::uint; + +pub fn expand_deriving_encodable( + cx: @ext_ctxt, + span: span, + _mitem: @meta_item, + in_items: ~[@item] +) -> ~[@item] { + expand_deriving( + cx, + span, + in_items, + expand_deriving_encodable_struct_def, + expand_deriving_encodable_enum_def + ) +} + +fn create_derived_encodable_impl( + cx: @ext_ctxt, + span: span, + type_ident: ident, + generics: &Generics, + method: @method +) -> @item { + let encoder_ty_param = build::mk_ty_param( + cx, + cx.ident_of(~"__E"), + @opt_vec::with( + build::mk_trait_ty_param_bound_global( + cx, + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Encoder"), + ] + ) + ) + ); + + // All the type parameters need to bound to the trait. + let generic_ty_params = opt_vec::with(encoder_ty_param); + + let methods = [method]; + let trait_path = build::mk_raw_path_global_( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Encodable") + ], + ~[ + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")) + ] + ); + create_derived_impl( + cx, + span, + type_ident, + generics, + methods, + trait_path, + generic_ty_params + ) +} + +// Creates a method from the given set of statements conforming to the +// signature of the `encodable` method. +fn create_encode_method( + cx: @ext_ctxt, + span: span, + +statements: ~[@stmt] +) -> @method { + // Create the `e` parameter. + let e_arg_type = build::mk_ty_rptr( + cx, + span, + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")), + ast::m_imm + ); + let e_ident = cx.ident_of(~"__e"); + let e_arg = build::mk_arg(cx, span, e_ident, e_arg_type); + + // Create the type of the return value. + let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span }; + + // Create the function declaration. + let inputs = ~[e_arg]; + let fn_decl = build::mk_fn_decl(inputs, output_type); + + // Create the body block. + let body_block = build::mk_block_(cx, span, statements); + + // Create the method. + let self_ty = spanned { node: sty_region(None, m_imm), span: span }; + let method_ident = cx.ident_of(~"encode"); + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } +} + +fn call_substructure_encode_method( + cx: @ext_ctxt, + span: span, + self_field: @expr +) -> @ast::expr { + // Gather up the parameters we want to chain along. + let e_ident = cx.ident_of(~"__e"); + let e_expr = build::mk_path(cx, span, ~[e_ident]); + + // Call the substructure method. + let encode_ident = cx.ident_of(~"encode"); + build::mk_method_call( + cx, + span, + self_field, + encode_ident, + ~[e_expr] + ) +} + +fn expand_deriving_encodable_struct_def( + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_encodable_struct_method( + cx, + span, + type_ident, + struct_def + ); + + // Create the implementation. + create_derived_encodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn expand_deriving_encodable_enum_def( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_encodable_enum_method( + cx, + span, + type_ident, + enum_definition + ); + + // Create the implementation. + create_derived_encodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn expand_deriving_encodable_struct_method( + cx: @ext_ctxt, + span: span, + type_ident: ident, + struct_def: &struct_def +) -> @method { + let self_ident = cx.ident_of(~"self"); + + // Create the body of the method. + let mut idx = 0; + let mut statements = ~[]; + for struct_def.fields.each |struct_field| { + match struct_field.node.kind { + named_field(ident, _, _) => { + // Create the accessor for this field. + let self_field = build::mk_access( + cx, + span, + ~[self_ident], + ident + ); + + // Call the substructure method. + let encode_expr = call_substructure_encode_method( + cx, + span, + self_field + ); + + let blk_expr = build::mk_lambda( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + encode_expr + ); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_struct_field"), + ~[ + build::mk_base_str(cx, span, cx.str_of(ident)), + build::mk_uint(cx, span, idx), + blk_expr + ] + ); + + statements.push(build::mk_stmt(cx, span, call_expr)); + } + unnamed_field => { + cx.span_unimpl( + span, + ~"unnamed fields with `deriving(Encodable)`" + ); + } + } + idx += 1; + } + + let emit_struct_stmt = build::mk_method_call( + cx, + span, + build::mk_path( + cx, + span, + ~[cx.ident_of(~"__e")] + ), + cx.ident_of(~"emit_struct"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + build::mk_uint(cx, span, statements.len()), + build::mk_lambda_stmts( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + statements + ), + ] + ); + + let statements = ~[build::mk_stmt(cx, span, emit_struct_stmt)]; + + // Create the method itself. + return create_encode_method(cx, span, statements); +} + +fn expand_deriving_encodable_enum_method( + cx: @ext_ctxt, + span: span, + type_ident: ast::ident, + enum_definition: &enum_def +) -> @method { + // Create the arms of the match in the method body. + let arms = do enum_definition.variants.mapi |i, variant| { + // Create the matching pattern. + let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); + + // Feed the discriminant to the encode function. + let mut stmts = ~[]; + + // Feed each argument in this variant to the encode function + // as well. + let variant_arg_len = variant_arg_count(cx, span, variant); + for uint::range(0, variant_arg_len) |j| { + // Create the expression for this field. + let field_ident = cx.ident_of(~"__self" + j.to_str()); + let field = build::mk_path(cx, span, ~[ field_ident ]); + + // Call the substructure method. + let expr = call_substructure_encode_method(cx, span, field); + + let blk_expr = build::mk_lambda( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + expr + ); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_enum_variant_arg"), + ~[ + build::mk_uint(cx, span, j), + blk_expr, + ] + ); + + stmts.push(build::mk_stmt(cx, span, call_expr)); + } + + // Create the pattern body. + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_enum_variant"), + ~[ + build::mk_base_str(cx, span, cx.str_of(variant.node.name)), + build::mk_uint(cx, span, i), + build::mk_uint(cx, span, variant_arg_len), + build::mk_lambda_stmts( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + stmts + ) + ] + ); + + let match_body_block = build::mk_simple_block(cx, span, call_expr); + + // Create the arm. + ast::arm { + pats: ~[pat], + guard: None, + body: match_body_block, + } + }; + + // Create the method body. + let lambda_expr = build::mk_lambda( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + expand_enum_or_struct_match(cx, span, arms) + ); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_enum"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + lambda_expr, + ] + ); + + let stmt = build::mk_stmt(cx, span, call_expr); + + // Create the method. + create_encode_method(cx, span, ~[stmt]) +} diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 95bca7ff230c7..5242d54208758 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -33,6 +33,7 @@ use core::uint; pub mod clone; pub mod eq; pub mod iter_bytes; +pub mod encodable; type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt, span, @@ -76,6 +77,8 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, titem, in_items), ~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx, titem.span, titem, in_items), + ~"Encodable" => encodable::expand_deriving_encodable(cx, + titem.span, titem, in_items), tname => { cx.span_err(titem.span, fmt!("unknown \ `deriving` trait: `%s`", tname)); From 441df26f5a1f76ed0ea185cca22c6b2c6e1307b1 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 8 Apr 2013 18:53:39 -0700 Subject: [PATCH 07/10] syntax: add support for #[deriving(Decodable)] --- src/libsyntax/ext/build.rs | 60 +++- src/libsyntax/ext/deriving/decodable.rs | 454 ++++++++++++++++++++++++ src/libsyntax/ext/deriving/mod.rs | 3 + 3 files changed, 510 insertions(+), 7 deletions(-) create mode 100644 src/libsyntax/ext/deriving/decodable.rs diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 530bb8f15417a..b375adef9263d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -279,10 +279,10 @@ pub fn mk_lambda_(cx: @ext_ctxt, mk_expr(cx, span, ast::expr_fn_block(fn_decl, blk)) } pub fn mk_lambda(cx: @ext_ctxt, - span: span, - fn_decl: ast::fn_decl, - expr: @ast::expr) - -> @ast::expr { + span: span, + fn_decl: ast::fn_decl, + expr: @ast::expr) + -> @ast::expr { let blk = mk_simple_block(cx, span, expr); mk_lambda_(cx, span, fn_decl, blk) } @@ -294,6 +294,13 @@ pub fn mk_lambda_stmts(cx: @ext_ctxt, let blk = mk_block(cx, span, ~[], stmts, None); mk_lambda(cx, span, fn_decl, blk) } +pub fn mk_lambda_no_args(cx: @ext_ctxt, + span: span, + expr: @ast::expr) + -> @ast::expr { + let fn_decl = mk_fn_decl(~[], mk_ty_infer(cx, span)); + mk_lambda(cx, span, fn_decl, expr) +} pub fn mk_copy(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { mk_expr(cx, sp, ast::expr_copy(e)) } @@ -303,11 +310,20 @@ pub fn mk_managed(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { pub fn mk_pat(cx: @ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat { @ast::pat { id: cx.next_id(), node: pat, span: span } } +pub fn mk_pat_wild(cx: @ext_ctxt, span: span) -> @ast::pat { + mk_pat(cx, span, ast::pat_wild) +} +pub fn mk_pat_lit(cx: @ext_ctxt, + span: span, + expr: @ast::expr) -> @ast::pat { + mk_pat(cx, span, ast::pat_lit(expr)) +} pub fn mk_pat_ident(cx: @ext_ctxt, span: span, ident: ast::ident) -> @ast::pat { mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_copy) } + pub fn mk_pat_ident_with_binding_mode(cx: @ext_ctxt, span: span, ident: ast::ident, @@ -435,8 +451,38 @@ pub fn mk_ty_param(cx: @ext_ctxt, } pub fn mk_lifetime(cx: @ext_ctxt, span: span, - ident: ast::ident) -> ast::Lifetime -{ + ident: ast::ident) + -> ast::Lifetime { ast::Lifetime { id: cx.next_id(), span: span, ident: ident } } - +pub fn mk_arm(cx: @ext_ctxt, + span: span, + pats: ~[@ast::pat], + expr: @ast::expr) + -> ast::arm { + ast::arm { + pats: pats, + guard: None, + body: mk_simple_block(cx, span, expr) + } +} +pub fn mk_unreachable(cx: @ext_ctxt, span: span) -> @ast::expr { + let loc = cx.codemap().lookup_char_pos(span.lo); + mk_call_global( + cx, + span, + ~[ + cx.ident_of(~"core"), + cx.ident_of(~"sys"), + cx.ident_of(~"begin_unwind"), + ], + ~[ + mk_uniq_str(cx, span, ~"internal error: entered unreachable code"), + mk_uniq_str(cx, span, loc.file.name), + mk_uint(cx, span, loc.line), + ] + ) +} +pub fn mk_unreachable_arm(cx: @ext_ctxt, span: span) -> ast::arm { + mk_arm(cx, span, ~[mk_pat_wild(cx, span)], mk_unreachable(cx, span)) +} diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs new file mode 100644 index 0000000000000..11f492316e281 --- /dev/null +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -0,0 +1,454 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::prelude::*; + +use ast; +use ast::*; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span, spanned}; +use ast_util; +use opt_vec; + +use core::uint; + +pub fn expand_deriving_decodable( + cx: @ext_ctxt, + span: span, + _mitem: @meta_item, + in_items: ~[@item] +) -> ~[@item] { + expand_deriving( + cx, + span, + in_items, + expand_deriving_decodable_struct_def, + expand_deriving_decodable_enum_def + ) +} + +fn create_derived_decodable_impl( + cx: @ext_ctxt, + span: span, + type_ident: ident, + generics: &Generics, + method: @method +) -> @item { + let decoder_ty_param = build::mk_ty_param( + cx, + cx.ident_of(~"__D"), + @opt_vec::with( + build::mk_trait_ty_param_bound_global( + cx, + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decoder"), + ] + ) + ) + ); + + // All the type parameters need to bound to the trait. + let generic_ty_params = opt_vec::with(decoder_ty_param); + + let methods = [method]; + let trait_path = build::mk_raw_path_global_( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decodable") + ], + ~[ + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")) + ] + ); + create_derived_impl( + cx, + span, + type_ident, + generics, + methods, + trait_path, + generic_ty_params + ) +} + +// Creates a method from the given set of statements conforming to the +// signature of the `decodable` method. +fn create_decode_method( + cx: @ext_ctxt, + span: span, + type_ident: ast::ident, + generics: &Generics, + expr: @ast::expr +) -> @method { + // Create the `e` parameter. + let d_arg_type = build::mk_ty_rptr( + cx, + span, + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")), + ast::m_imm + ); + let d_ident = cx.ident_of(~"__d"); + let d_arg = build::mk_arg(cx, span, d_ident, d_arg_type); + + // Create the type of the return value. + let output_type = create_self_type_with_params( + cx, + span, + type_ident, + generics + ); + + // Create the function declaration. + let inputs = ~[d_arg]; + let fn_decl = build::mk_fn_decl(inputs, output_type); + + // Create the body block. + let body_block = build::mk_simple_block(cx, span, expr); + + // Create the method. + let self_ty = spanned { node: sty_static, span: span }; + let method_ident = cx.ident_of(~"decode"); + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } +} + +fn call_substructure_decode_method( + cx: @ext_ctxt, + span: span +) -> @ast::expr { + // Call the substructure method. + build::mk_call_( + cx, + span, + build::mk_path_global( + cx, + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decodable"), + cx.ident_of(~"decode"), + ] + ), + ~[ + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]) + ] + ) +} + +fn expand_deriving_decodable_struct_def( + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_decodable_struct_method( + cx, + span, + struct_def, + type_ident, + generics + ); + + // Create the implementation. + create_derived_decodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn expand_deriving_decodable_enum_def( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_decodable_enum_method( + cx, + span, + enum_definition, + type_ident, + generics + ); + + // Create the implementation. + create_derived_decodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn create_read_struct_field( + cx: @ext_ctxt, + span: span, + idx: uint, + ident: ident +) -> build::Field { + // Call the substructure method. + let decode_expr = call_substructure_decode_method(cx, span); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_struct_field"), + ~[ + build::mk_base_str(cx, span, cx.str_of(ident)), + build::mk_uint(cx, span, idx), + build::mk_lambda_no_args(cx, span, decode_expr), + ] + ); + + build::Field { ident: ident, ex: call_expr } +} + +fn create_read_struct_arg( + cx: @ext_ctxt, + span: span, + idx: uint, + ident: ident +) -> build::Field { + // Call the substructure method. + let decode_expr = call_substructure_decode_method(cx, span); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_struct_arg"), + ~[ + build::mk_uint(cx, span, idx), + build::mk_lambda_no_args(cx, span, decode_expr), + ] + ); + + build::Field { ident: ident, ex: call_expr } +} + +fn expand_deriving_decodable_struct_method( + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics +) -> @method { + // Create the body of the method. + let mut i = 0; + let mut fields = ~[]; + for struct_def.fields.each |struct_field| { + match struct_field.node.kind { + named_field(ident, _, _) => { + fields.push(create_read_struct_field(cx, span, i, ident)); + } + unnamed_field => { + cx.span_unimpl( + span, + ~"unnamed fields with `deriving(Decodable)`" + ); + } + } + i += 1; + } + + let read_struct_expr = build::mk_method_call( + cx, + span, + build::mk_path( + cx, + span, + ~[cx.ident_of(~"__d")] + ), + cx.ident_of(~"read_struct"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + build::mk_uint(cx, span, fields.len()), + build::mk_lambda_no_args( + cx, + span, + build::mk_struct_e( + cx, + span, + ~[type_ident], + fields + ) + ), + ] + ); + + // Create the method itself. + create_decode_method(cx, span, type_ident, generics, read_struct_expr) +} + +fn create_read_variant_arg( + cx: @ext_ctxt, + span: span, + idx: uint, + variant: &ast::variant +) -> ast::arm { + // Create the matching pattern. + let pat = build::mk_pat_lit(cx, span, build::mk_uint(cx, span, idx)); + + // Feed each argument in this variant to the decode function + // as well. + let variant_arg_len = variant_arg_count(cx, span, variant); + + let expr = if variant_arg_len == 0 { + build::mk_path(cx, span, ~[variant.node.name]) + } else { + // Feed the discriminant to the decode function. + let mut args = ~[]; + + for uint::range(0, variant_arg_len) |j| { + // Call the substructure method. + let expr = call_substructure_decode_method(cx, span); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_enum_variant_arg"), + ~[ + build::mk_uint(cx, span, j), + build::mk_lambda_no_args(cx, span, expr), + ] + ); + + args.push(call_expr); + } + + build::mk_call( + cx, + span, + ~[variant.node.name], + args + ) + }; + + // Create the arm. + build::mk_arm(cx, span, ~[pat], expr) +} + +fn create_read_enum_variant( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def +) -> @expr { + // Create a vector that contains all the variant names. + let expr_arm_names = build::mk_base_vec_e( + cx, + span, + do enum_definition.variants.map |variant| { + build::mk_base_str( + cx, + span, + cx.str_of(variant.node.name) + ) + } + ); + + // Create the arms of the match in the method body. + let mut arms = do enum_definition.variants.mapi |i, variant| { + create_read_variant_arg(cx, span, i, variant) + }; + + // Add the impossible case arm. + arms.push(build::mk_unreachable_arm(cx, span)); + + // Create the read_enum_variant expression. + build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_enum_variant"), + ~[ + expr_arm_names, + build::mk_lambda( + cx, + span, + build::mk_fn_decl( + ~[ + build::mk_arg( + cx, + span, + cx.ident_of(~"__i"), + build::mk_ty_infer(cx, span) + ) + ], + build::mk_ty_infer(cx, span) + ), + build::mk_expr( + cx, + span, + ast::expr_match( + build::mk_path(cx, span, ~[cx.ident_of(~"__i")]), + arms + ) + ) + ) + ] + ) +} + +fn expand_deriving_decodable_enum_method( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ast::ident, + generics: &Generics +) -> @method { + let read_enum_variant_expr = create_read_enum_variant( + cx, + span, + enum_definition + ); + + // Create the read_enum expression + let read_enum_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_enum"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + build::mk_lambda_no_args(cx, span, read_enum_variant_expr), + ] + ); + + // Create the method. + create_decode_method(cx, span, type_ident, generics, read_enum_expr) +} diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 5242d54208758..63106eae48ae8 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -34,6 +34,7 @@ pub mod clone; pub mod eq; pub mod iter_bytes; pub mod encodable; +pub mod decodable; type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt, span, @@ -79,6 +80,8 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, titem.span, titem, in_items), ~"Encodable" => encodable::expand_deriving_encodable(cx, titem.span, titem, in_items), + ~"Decodable" => decodable::expand_deriving_decodable(cx, + titem.span, titem, in_items), tname => { cx.span_err(titem.span, fmt!("unknown \ `deriving` trait: `%s`", tname)); From e31f7b7c74f54cc80f908dc074f3efb95e5b36d5 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 9 Apr 2013 19:44:12 -0700 Subject: [PATCH 08/10] std: add serialize {read,emit}_tuple{,_arg,_struct,_struct_arg} --- src/libstd/ebml.rs | 26 ++++++++++++++++++++++++++ src/libstd/json.rs | 32 ++++++++++++++++++++++++++++++++ src/libstd/serialize.rs | 12 ++++++++++++ src/libsyntax/ext/auto_encode.rs | 14 ++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 28933d553e6ef..a7a6e827febe0 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -356,6 +356,26 @@ pub mod reader { f() } + fn read_tuple(&self, f: &fn(uint) -> T) -> T { + debug!("read_tuple()"); + self.read_seq(f) + } + + fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_arg(idx=%u)", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { + debug!("read_tuple_struct(name=%?)", name); + self.read_tuple(f) + } + + fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_struct_arg(idx=%u)", idx); + self.read_tuple_arg(idx, f) + } + fn read_option(&self, f: &fn(bool) -> T) -> T { debug!("read_option()"); do self.read_enum("Option") || { @@ -637,6 +657,12 @@ pub mod writer { f() } + fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_option(&self, f: &fn()) { self.emit_enum("Option", f); } diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 4b5e1f1422990..658a6ce281f20 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -152,6 +152,12 @@ impl serialize::Encoder for Encoder { f(); } + fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_option(&self, f: &fn()) { f(); } fn emit_option_none(&self) { self.emit_nil(); } fn emit_option_some(&self, f: &fn()) { f(); } @@ -291,6 +297,12 @@ impl serialize::Encoder for PrettyEncoder { f(); } + fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_option(&self, f: &fn()) { f(); } fn emit_option_none(&self) { self.emit_nil(); } fn emit_option_some(&self, f: &fn()) { f(); } @@ -901,6 +913,26 @@ impl serialize::Decoder for Decoder { } } + fn read_tuple(&self, f: &fn(uint) -> T) -> T { + debug!("read_tuple()"); + self.read_seq(f) + } + + fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_arg(idx=%u)", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { + debug!("read_tuple_struct(name=%?)", name); + self.read_tuple(f) + } + + fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_struct_arg(idx=%u)", idx); + self.read_tuple_arg(idx, f) + } + fn read_option(&self, f: &fn(bool) -> T) -> T { match self.stack.pop() { Null => f(false), diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index cc3a1ec028983..2a685b2f1d62b 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -56,6 +56,12 @@ pub trait Encoder { #[cfg(stage3)] fn emit_struct_field(&self, f_name: &str, f_idx: uint, f: &fn()); + fn emit_tuple(&self, len: uint, f: &fn()); + fn emit_tuple_arg(&self, idx: uint, f: &fn()); + + fn emit_tuple_struct(&self, name: &str, len: uint, f: &fn()); + fn emit_tuple_struct_arg(&self, f_idx: uint, f: &fn()); + // Specialized types: fn emit_option(&self, f: &fn()); fn emit_option_none(&self); @@ -102,6 +108,12 @@ pub trait Decoder { #[cfg(stage3)] fn read_struct_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; + fn read_tuple(&self, f: &fn(uint) -> T) -> T; + fn read_tuple_arg(&self, a_idx: uint, f: &fn() -> T) -> T; + + fn read_tuple_struct(&self, s_name: &str, f: &fn(uint) -> T) -> T; + fn read_tuple_struct_arg(&self, a_idx: uint, f: &fn() -> T) -> T; + // Specialized types: fn read_option(&self, f: &fn(bool) -> T) -> T; diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 38bac6b1f438d..287c2d7ba84f8 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -1260,6 +1260,20 @@ mod test { self.add_to_log(CallToEmitField (name.to_str(),idx)); f(); } + fn emit_tuple(&self, _len: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_tuple_arg(&self, _idx: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + + fn emit_tuple_struct(&self, _name: &str, _len: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_tuple_struct_arg(&self, _idx: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_option(&self, f: &fn()) { self.add_to_log(CallToEmitOption); f(); From f3ab67ec5f75fc3376e5647dfb7e5b46a535dea7 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 9 Apr 2013 19:45:10 -0700 Subject: [PATCH 09/10] syntax: add {read,emit}_enum_struct_variant{,_field} --- src/libstd/ebml.rs | 24 +++++++++++++++++++++++ src/libstd/json.rs | 33 +++++++++++++++++++++++++++++++- src/libstd/serialize.rs | 14 +++++++++++--- src/libsyntax/ext/auto_encode.rs | 8 ++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index a7a6e827febe0..4a3447700bc8f 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -335,6 +335,20 @@ pub mod reader { f() } + fn read_enum_struct_variant(&self, _names: &[&str], f: &fn(uint) -> T) -> T { + debug!("read_enum_struct_variant()"); + let idx = self._next_uint(EsEnumVid); + debug!(" idx=%u", idx); + do self.push_doc(self.next_doc(EsEnumBody)) { + f(idx) + } + } + + fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_enum_struct_variant_arg(name=%?, idx=%u)", name, idx); + f() + } + fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T { debug!("read_struct(name=%s)", name); f() @@ -636,13 +650,23 @@ pub mod writer { self._emit_label(name); self.wr_tag(EsEnum as uint, f) } + fn emit_enum_variant(&self, _v_name: &str, v_id: uint, _cnt: uint, f: &fn()) { self._emit_tagged_uint(EsEnumVid, v_id); self.wr_tag(EsEnumBody as uint, f) } + fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) { f() } + fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(v_name, v_id, cnt, f) + } + + fn emit_enum_struct_variant_field(&self, _f_name: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) + } + fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { f() } #[cfg(stage0)] fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 658a6ce281f20..f5cd8b4bd6830 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -109,6 +109,7 @@ impl serialize::Encoder for Encoder { fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)) } fn emit_enum(&self, _name: &str, f: &fn()) { f() } + fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { // enums are encoded as strings or vectors: // Bunny => "Bunny" @@ -126,10 +127,18 @@ impl serialize::Encoder for Encoder { } fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { - if (idx != 0) {self.wr.write_char(',');} + if idx != 0 {self.wr.write_char(',');} f(); } + fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) + } + fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { self.wr.write_char('{'); f(); @@ -232,6 +241,7 @@ impl serialize::Encoder for PrettyEncoder { fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)); } fn emit_enum(&self, _name: &str, f: &fn()) { f() } + fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { if cnt == 0 { self.wr.write_str(escape_str(name)); @@ -249,6 +259,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_char(']'); } } + fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { if idx != 0 { self.wr.write_str(",\n"); @@ -257,6 +268,15 @@ impl serialize::Encoder for PrettyEncoder { f() } + fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&self, _name: &str, len: uint, f: &fn()) { if len == 0 { self.wr.write_str("{}"); @@ -864,6 +884,17 @@ impl serialize::Decoder for Decoder { f() } + fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T { + debug!("read_enum_struct_variant(names=%?)", names); + self.read_enum_variant(names, f) + } + + + fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_enum_struct_variant_field(name=%?, idx=%u)", name, idx); + self.read_enum_variant_arg(idx, f) + } + fn read_struct(&self, name: &str, len: uint, f: &fn() -> T) -> T { debug!("read_struct(name=%s, len=%u)", name, len); let value = f(); diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 2a685b2f1d62b..68ae9a6641726 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -45,8 +45,12 @@ pub trait Encoder { // Compound types: fn emit_enum(&self, name: &str, f: &fn()); - fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: &fn()); - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()); + + fn emit_enum_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); + fn emit_enum_variant_arg(&self, a_idx: uint, f: &fn()); + + fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); + fn emit_enum_struct_variant_field(&self, f_name: &str, f_idx: uint, f: &fn()); fn emit_struct(&self, name: &str, len: uint, f: &fn()); #[cfg(stage0)] @@ -97,8 +101,12 @@ pub trait Decoder { // Compound types: fn read_enum(&self, name: &str, f: &fn() -> T) -> T; + fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; - fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T; + fn read_enum_variant_arg(&self, a_idx: uint, f: &fn() -> T) -> T; + + fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; + fn read_enum_struct_variant_field(&self, &f_name: &str, f_idx: uint, f: &fn() -> T) -> T; fn read_struct(&self, s_name: &str, len: uint, f: &fn() -> T) -> T; #[cfg(stage0)] diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 287c2d7ba84f8..e53a8f361b5fe 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -1253,6 +1253,14 @@ mod test { self.add_to_log(CallToEmitEnumVariantArg (idx)); f(); } + fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&self, _name: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) + } + fn emit_struct(&self, name: &str, +len: uint, f: &fn()) { self.add_to_log(CallToEmitStruct (name.to_str(),len)); f(); } From 26ecb30f550a46d52528a7d45d9327ebce938e81 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 9 Apr 2013 08:36:38 -0700 Subject: [PATCH 10/10] test: update serialization tests to use new macro --- src/test/run-pass/auto-encode.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index e0720876900ff..bfc15acaa763c 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -22,7 +22,7 @@ use EBWriter = std::ebml::writer; use core::cmp::Eq; use core::io::Writer; use std::ebml; -use std::serialize::{Encodable, Decodable}; +use std::serialize::{Decodable, Encodable}; use std::time; fn test_ebml bool { !self.eq(other) } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Decodable, Encodable, Eq)] struct Spanned { lo: uint, hi: uint, node: T, } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] struct SomeStruct { v: ~[uint] } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] struct Point {x: uint, y: uint} -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] enum Quark { Top(T), Bottom(T) } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] enum CLike { A, B, C } pub fn main() {