Split auto_serialize2 into two macros

This commit is contained in:
Erick Tryzelaar 2012-10-01 08:12:39 -07:00 committed by Niko Matsakis
parent 372c7de201
commit 2569adc5ea
3 changed files with 134 additions and 74 deletions

View File

@ -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<T> = {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]
}
}
}

View File

@ -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));

View File

@ -31,6 +31,7 @@ fn test_ser_and_deser<A:Eq Serializable Deserializable>(
}
#[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<T> = {lo: uint, hi: uint, node: T};
impl<T:cmp::Eq> Spanned<T> : cmp::Eq {
@ -115,21 +117,26 @@ impl<T:cmp::Eq> Spanned<T> : 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<T> {
Top(T),
Bottom(T)
}
#[auto_serialize2]
#[auto_deserialize2]
enum CLike { A, B, C }
fn main() {