From 2569adc5ea0b950c6e41a1c72d9eb7efdba49f05 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 1 Oct 2012 08:12:39 -0700 Subject: [PATCH] Split auto_serialize2 into two macros --- src/libsyntax/ext/auto_serialize2.rs | 193 +++++++++++++++++---------- src/libsyntax/ext/base.rs | 8 +- src/test/run-pass/auto_serialize2.rs | 7 + 3 files changed, 134 insertions(+), 74 deletions(-) diff --git a/src/libsyntax/ext/auto_serialize2.rs b/src/libsyntax/ext/auto_serialize2.rs index 426873ce347..99f837a4c84 100644 --- a/src/libsyntax/ext/auto_serialize2.rs +++ b/src/libsyntax/ext/auto_serialize2.rs @@ -1,13 +1,14 @@ /* -The compiler code necessary to implement the #[auto_serialize2] -extension. The idea here is that type-defining items may be tagged -with #[auto_serialize2], which will cause us to generate a little -companion module with the same name as the item. +The compiler code necessary to implement the #[auto_serialize2] and +#[auto_deserialize2] extension. The idea here is that type-defining items may +be tagged with #[auto_serialize2] and #[auto_deserialize2], which will cause +us to generate a little companion module with the same name as the item. For example, a type like: #[auto_serialize2] + #[auto_deserialize2] struct Node {id: uint} would generate two implementations like: @@ -34,6 +35,7 @@ Other interesting scenarios are whe the item has type parameters or references other non-built-in types. A type definition like: #[auto_serialize2] + #[auto_deserialize2] type spanned = {node: T, span: span}; would yield functions like: @@ -75,7 +77,8 @@ use codemap::span; use std::map; use std::map::HashMap; -export expand; +export expand_auto_serialize; +export expand_auto_deserialize; // Transitional reexports so qquote can find the paths it is looking for mod syntax { @@ -83,84 +86,130 @@ mod syntax { pub use parse; } -fn expand(cx: ext_ctxt, - span: span, - _mitem: ast::meta_item, - in_items: ~[@ast::item]) -> ~[@ast::item] { - fn not_auto_serialize2(a: &ast::attribute) -> bool { - attr::get_attr_name(*a) != ~"auto_serialize2" +fn expand_auto_serialize( + cx: ext_ctxt, + span: span, + _mitem: ast::meta_item, + in_items: ~[@ast::item] +) -> ~[@ast::item] { + fn is_auto_serialize2(a: &ast::attribute) -> bool { + attr::get_attr_name(*a) == ~"auto_serialize2" } fn filter_attrs(item: @ast::item) -> @ast::item { - @{attrs: vec::filter(item.attrs, not_auto_serialize2), + @{attrs: vec::filter(item.attrs, |a| !is_auto_serialize2(a)), .. *item} } do vec::flat_map(in_items) |item| { - match item.node { - ast::item_ty(@{node: ast::ty_rec(fields), _}, tps) => { - let ser_impl = mk_rec_ser_impl( - cx, - item.span, - item.ident, - fields, - tps - ); + if item.attrs.any(is_auto_serialize2) { + match item.node { + ast::item_ty(@{node: ast::ty_rec(fields), _}, tps) => { + let ser_impl = mk_rec_ser_impl( + cx, + item.span, + item.ident, + fields, + tps + ); - let deser_impl = mk_rec_deser_impl( - cx, - item.span, - item.ident, - fields, - tps - ); + ~[filter_attrs(*item), ser_impl] + }, + ast::item_class(@{ fields, _}, tps) => { + let ser_impl = mk_struct_ser_impl( + cx, + item.span, + item.ident, + fields, + tps + ); - ~[filter_attrs(*item), ser_impl, deser_impl] - }, - ast::item_class(@{ fields, _}, tps) => { - let ser_impl = mk_struct_ser_impl( - cx, - item.span, - item.ident, - fields, - tps - ); + ~[filter_attrs(*item), ser_impl] + }, + ast::item_enum(enum_def, tps) => { + let ser_impl = mk_enum_ser_impl( + cx, + item.span, + item.ident, + enum_def, + tps + ); - let deser_impl = mk_struct_deser_impl( - cx, - item.span, - item.ident, - fields, - tps - ); - - ~[filter_attrs(*item), ser_impl, deser_impl] - }, - ast::item_enum(enum_def, tps) => { - let ser_impl = mk_enum_ser_impl( - cx, - item.span, - item.ident, - enum_def, - tps - ); - - let deser_impl = mk_enum_deser_impl( - cx, - item.span, - item.ident, - enum_def, - tps - ); - - ~[filter_attrs(*item), ser_impl, deser_impl] - }, - _ => { - cx.span_err(span, ~"#[auto_serialize2] can only be applied \ - to structs, record types, and enum \ - definitions"); - ~[*item] + ~[filter_attrs(*item), ser_impl] + }, + _ => { + cx.span_err(span, ~"#[auto_serialize2] can only be \ + applied to structs, record types, \ + and enum definitions"); + ~[*item] + } } + } else { + ~[*item] + } + } +} + +fn expand_auto_deserialize( + cx: ext_ctxt, + span: span, + _mitem: ast::meta_item, + in_items: ~[@ast::item] +) -> ~[@ast::item] { + fn is_auto_deserialize2(a: &ast::attribute) -> bool { + attr::get_attr_name(*a) == ~"auto_deserialize2" + } + + fn filter_attrs(item: @ast::item) -> @ast::item { + @{attrs: vec::filter(item.attrs, |a| !is_auto_deserialize2(a)), + .. *item} + } + + do vec::flat_map(in_items) |item| { + if item.attrs.any(is_auto_deserialize2) { + match item.node { + ast::item_ty(@{node: ast::ty_rec(fields), _}, tps) => { + let deser_impl = mk_rec_deser_impl( + cx, + item.span, + item.ident, + fields, + tps + ); + + ~[filter_attrs(*item), deser_impl] + }, + ast::item_class(@{ fields, _}, tps) => { + let deser_impl = mk_struct_deser_impl( + cx, + item.span, + item.ident, + fields, + tps + ); + + ~[filter_attrs(*item), deser_impl] + }, + ast::item_enum(enum_def, tps) => { + let deser_impl = mk_enum_deser_impl( + cx, + item.span, + item.ident, + enum_def, + tps + ); + + ~[filter_attrs(*item), deser_impl] + }, + _ => { + cx.span_err(span, ~"#[auto_deserialize2] can only be \ + applied to structs, record types, \ + and enum definitions"); + ~[*item] + } + } + } else { + ~[*item] } } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6c71fd8fcbc..9a31cc1d8f6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -82,8 +82,12 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { syntax_expanders.insert(~"fmt", builtin(ext::fmt::expand_syntax_ext)); syntax_expanders.insert(~"auto_serialize", item_decorator(ext::auto_serialize::expand)); - syntax_expanders.insert(~"auto_serialize2", - item_decorator(ext::auto_serialize2::expand)); + syntax_expanders.insert( + ~"auto_serialize2", + item_decorator(ext::auto_serialize2::expand_auto_serialize)); + syntax_expanders.insert( + ~"auto_deserialize2", + item_decorator(ext::auto_serialize2::expand_auto_deserialize)); syntax_expanders.insert(~"env", builtin(ext::env::expand_syntax_ext)); syntax_expanders.insert(~"concat_idents", builtin(ext::concat_idents::expand_syntax_ext)); diff --git a/src/test/run-pass/auto_serialize2.rs b/src/test/run-pass/auto_serialize2.rs index f3f7e80e8a2..4503ea6c7e0 100644 --- a/src/test/run-pass/auto_serialize2.rs +++ b/src/test/run-pass/auto_serialize2.rs @@ -31,6 +31,7 @@ fn test_ser_and_deser( } #[auto_serialize2] +#[auto_deserialize2] enum Expr { Val(uint), Plus(@Expr, @Expr), @@ -105,6 +106,7 @@ impl CLike : cmp::Eq { } #[auto_serialize2] +#[auto_deserialize2] type Spanned = {lo: uint, hi: uint, node: T}; impl Spanned : cmp::Eq { @@ -115,21 +117,26 @@ impl Spanned : cmp::Eq { } #[auto_serialize2] +#[auto_deserialize2] type SomeRec = {v: ~[uint]}; #[auto_serialize2] +#[auto_deserialize2] enum AnEnum = SomeRec; #[auto_serialize2] +#[auto_deserialize2] struct Point {x: uint, y: uint} #[auto_serialize2] +#[auto_deserialize2] enum Quark { Top(T), Bottom(T) } #[auto_serialize2] +#[auto_deserialize2] enum CLike { A, B, C } fn main() {