Split auto_serialize2 into two macros
This commit is contained in:
parent
372c7de201
commit
2569adc5ea
3 changed files with 134 additions and 74 deletions
|
@ -1,13 +1,14 @@
|
||||||
/*
|
/*
|
||||||
|
|
||||||
The compiler code necessary to implement the #[auto_serialize2]
|
The compiler code necessary to implement the #[auto_serialize2] and
|
||||||
extension. The idea here is that type-defining items may be tagged
|
#[auto_deserialize2] extension. The idea here is that type-defining items may
|
||||||
with #[auto_serialize2], which will cause us to generate a little
|
be tagged with #[auto_serialize2] and #[auto_deserialize2], which will cause
|
||||||
companion module with the same name as the item.
|
us to generate a little companion module with the same name as the item.
|
||||||
|
|
||||||
For example, a type like:
|
For example, a type like:
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
struct Node {id: uint}
|
struct Node {id: uint}
|
||||||
|
|
||||||
would generate two implementations like:
|
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:
|
references other non-built-in types. A type definition like:
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
type spanned<T> = {node: T, span: span};
|
type spanned<T> = {node: T, span: span};
|
||||||
|
|
||||||
would yield functions like:
|
would yield functions like:
|
||||||
|
@ -75,7 +77,8 @@ use codemap::span;
|
||||||
use std::map;
|
use std::map;
|
||||||
use std::map::HashMap;
|
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
|
// Transitional reexports so qquote can find the paths it is looking for
|
||||||
mod syntax {
|
mod syntax {
|
||||||
|
@ -83,84 +86,130 @@ mod syntax {
|
||||||
pub use parse;
|
pub use parse;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand(cx: ext_ctxt,
|
fn expand_auto_serialize(
|
||||||
span: span,
|
cx: ext_ctxt,
|
||||||
_mitem: ast::meta_item,
|
span: span,
|
||||||
in_items: ~[@ast::item]) -> ~[@ast::item] {
|
_mitem: ast::meta_item,
|
||||||
fn not_auto_serialize2(a: &ast::attribute) -> bool {
|
in_items: ~[@ast::item]
|
||||||
attr::get_attr_name(*a) != ~"auto_serialize2"
|
) -> ~[@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 {
|
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}
|
.. *item}
|
||||||
}
|
}
|
||||||
|
|
||||||
do vec::flat_map(in_items) |item| {
|
do vec::flat_map(in_items) |item| {
|
||||||
match item.node {
|
if item.attrs.any(is_auto_serialize2) {
|
||||||
ast::item_ty(@{node: ast::ty_rec(fields), _}, tps) => {
|
match item.node {
|
||||||
let ser_impl = mk_rec_ser_impl(
|
ast::item_ty(@{node: ast::ty_rec(fields), _}, tps) => {
|
||||||
cx,
|
let ser_impl = mk_rec_ser_impl(
|
||||||
item.span,
|
cx,
|
||||||
item.ident,
|
item.span,
|
||||||
fields,
|
item.ident,
|
||||||
tps
|
fields,
|
||||||
);
|
tps
|
||||||
|
);
|
||||||
|
|
||||||
let deser_impl = mk_rec_deser_impl(
|
~[filter_attrs(*item), ser_impl]
|
||||||
cx,
|
},
|
||||||
item.span,
|
ast::item_class(@{ fields, _}, tps) => {
|
||||||
item.ident,
|
let ser_impl = mk_struct_ser_impl(
|
||||||
fields,
|
cx,
|
||||||
tps
|
item.span,
|
||||||
);
|
item.ident,
|
||||||
|
fields,
|
||||||
|
tps
|
||||||
|
);
|
||||||
|
|
||||||
~[filter_attrs(*item), ser_impl, deser_impl]
|
~[filter_attrs(*item), ser_impl]
|
||||||
},
|
},
|
||||||
ast::item_class(@{ fields, _}, tps) => {
|
ast::item_enum(enum_def, tps) => {
|
||||||
let ser_impl = mk_struct_ser_impl(
|
let ser_impl = mk_enum_ser_impl(
|
||||||
cx,
|
cx,
|
||||||
item.span,
|
item.span,
|
||||||
item.ident,
|
item.ident,
|
||||||
fields,
|
enum_def,
|
||||||
tps
|
tps
|
||||||
);
|
);
|
||||||
|
|
||||||
let deser_impl = mk_struct_deser_impl(
|
~[filter_attrs(*item), ser_impl]
|
||||||
cx,
|
},
|
||||||
item.span,
|
_ => {
|
||||||
item.ident,
|
cx.span_err(span, ~"#[auto_serialize2] can only be \
|
||||||
fields,
|
applied to structs, record types, \
|
||||||
tps
|
and enum definitions");
|
||||||
);
|
~[*item]
|
||||||
|
}
|
||||||
~[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]
|
|
||||||
}
|
}
|
||||||
|
} 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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(~"fmt", builtin(ext::fmt::expand_syntax_ext));
|
||||||
syntax_expanders.insert(~"auto_serialize",
|
syntax_expanders.insert(~"auto_serialize",
|
||||||
item_decorator(ext::auto_serialize::expand));
|
item_decorator(ext::auto_serialize::expand));
|
||||||
syntax_expanders.insert(~"auto_serialize2",
|
syntax_expanders.insert(
|
||||||
item_decorator(ext::auto_serialize2::expand));
|
~"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(~"env", builtin(ext::env::expand_syntax_ext));
|
||||||
syntax_expanders.insert(~"concat_idents",
|
syntax_expanders.insert(~"concat_idents",
|
||||||
builtin(ext::concat_idents::expand_syntax_ext));
|
builtin(ext::concat_idents::expand_syntax_ext));
|
||||||
|
|
|
@ -31,6 +31,7 @@ fn test_ser_and_deser<A:Eq Serializable Deserializable>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
enum Expr {
|
enum Expr {
|
||||||
Val(uint),
|
Val(uint),
|
||||||
Plus(@Expr, @Expr),
|
Plus(@Expr, @Expr),
|
||||||
|
@ -105,6 +106,7 @@ impl CLike : cmp::Eq {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
type Spanned<T> = {lo: uint, hi: uint, node: T};
|
type Spanned<T> = {lo: uint, hi: uint, node: T};
|
||||||
|
|
||||||
impl<T:cmp::Eq> Spanned<T> : cmp::Eq {
|
impl<T:cmp::Eq> Spanned<T> : cmp::Eq {
|
||||||
|
@ -115,21 +117,26 @@ impl<T:cmp::Eq> Spanned<T> : cmp::Eq {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
type SomeRec = {v: ~[uint]};
|
type SomeRec = {v: ~[uint]};
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
enum AnEnum = SomeRec;
|
enum AnEnum = SomeRec;
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
struct Point {x: uint, y: uint}
|
struct Point {x: uint, y: uint}
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
enum Quark<T> {
|
enum Quark<T> {
|
||||||
Top(T),
|
Top(T),
|
||||||
Bottom(T)
|
Bottom(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[auto_serialize2]
|
#[auto_serialize2]
|
||||||
|
#[auto_deserialize2]
|
||||||
enum CLike { A, B, C }
|
enum CLike { A, B, C }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue