2012-03-02 14:36:22 -08:00
|
|
|
/*
|
|
|
|
|
|
|
|
The compiler code necessary to implement the #[auto_serialize]
|
|
|
|
extension. The idea here is that type-defining items may be tagged
|
|
|
|
with #[auto_serialize], which will cause us to generate a little
|
|
|
|
companion module with the same name as the item.
|
|
|
|
|
|
|
|
For example, a type like:
|
|
|
|
|
|
|
|
type node_id = uint;
|
|
|
|
|
2012-03-14 11:49:28 -04:00
|
|
|
would generate two functions like:
|
|
|
|
|
|
|
|
fn serialize_node_id<S: serializer>(s: S, v: node_id) {
|
|
|
|
s.emit_uint(v);
|
|
|
|
}
|
|
|
|
fn deserialize_node_id<D: deserializer>(d: D) -> node_id {
|
|
|
|
d.read_uint()
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Other interesting scenarios are whe the item has type parameters or
|
|
|
|
references other non-built-in types. A type definition like:
|
|
|
|
|
|
|
|
type spanned<T> = {node: T, span: span};
|
|
|
|
|
2012-03-14 11:49:28 -04:00
|
|
|
would yield functions like:
|
|
|
|
|
|
|
|
fn serialize_spanned<S: serializer,T>(s: S, v: spanned<T>, t: fn(T)) {
|
|
|
|
s.emit_rec(2u) {||
|
|
|
|
s.emit_rec_field("node", 0u) {||
|
|
|
|
t(s.node);
|
|
|
|
};
|
|
|
|
s.emit_rec_field("span", 1u) {||
|
|
|
|
serialize_span(s, s.span);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn deserialize_spanned<D: deserializer>(d: D, t: fn() -> T) -> node_id {
|
|
|
|
d.read_rec(2u) {||
|
|
|
|
{node: d.read_rec_field("node", 0u, t),
|
|
|
|
span: d.read_rec_field("span", 1u) {||deserialize_span(d)}}
|
|
|
|
}
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
In general, the code to serialize an instance `v` of a non-built-in
|
|
|
|
type a::b::c<T0,...,Tn> looks like:
|
|
|
|
|
2012-03-14 11:49:28 -04:00
|
|
|
a::b::serialize_c(s, {|v| c_T0}, ..., {|v| c_Tn}, v)
|
2012-03-02 14:36:22 -08:00
|
|
|
|
|
|
|
where `c_Ti` is the code to serialize an instance `v` of the type
|
|
|
|
`Ti`.
|
|
|
|
|
|
|
|
Similarly, the code to deserialize an instance of a non-built-in type
|
|
|
|
`a::b::c<T0,...,Tn>` using the deserializer `d` looks like:
|
|
|
|
|
2012-03-14 11:49:28 -04:00
|
|
|
a::b::deserialize_c(d, {|| c_T0}, ..., {|| c_Tn})
|
2012-03-02 14:36:22 -08:00
|
|
|
|
|
|
|
where `c_Ti` is the code to deserialize an instance of `Ti` using the
|
|
|
|
deserializer `d`.
|
|
|
|
|
2012-03-14 11:49:28 -04:00
|
|
|
TODO--Hygiene. Search for "__" strings. We also assume "std" is the
|
|
|
|
standard library.
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-03-08 12:53:35 -08:00
|
|
|
Misc notes:
|
|
|
|
-----------
|
|
|
|
|
|
|
|
I use move mode arguments for ast nodes that will get inserted as is
|
|
|
|
into the tree. This is intended to prevent us from inserting the same
|
|
|
|
node twice.
|
|
|
|
|
2012-03-02 14:36:22 -08:00
|
|
|
*/
|
|
|
|
import base::*;
|
|
|
|
import codemap::span;
|
|
|
|
import std::map;
|
2012-03-12 10:19:35 -07:00
|
|
|
import std::map::hashmap;
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
export expand;
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-03-29 13:48:05 -07:00
|
|
|
// Transitional reexports so qquote can find the paths it is looking for
|
|
|
|
mod syntax {
|
|
|
|
import ext;
|
|
|
|
export ext;
|
|
|
|
import parse;
|
|
|
|
export parse;
|
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
type ser_tps_map = map::hashmap<str, fn@(@ast::expr) -> [@ast::stmt]/~>;
|
2012-03-13 10:55:45 -04:00
|
|
|
type deser_tps_map = map::hashmap<str, fn@() -> @ast::expr>;
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
fn expand(cx: ext_ctxt,
|
|
|
|
span: span,
|
|
|
|
_mitem: ast::meta_item,
|
2012-06-25 20:00:46 -07:00
|
|
|
in_items: [@ast::item]/~) -> [@ast::item]/~ {
|
2012-03-12 10:19:35 -07:00
|
|
|
fn not_auto_serialize(a: ast::attribute) -> bool {
|
2012-06-10 00:49:59 -07:00
|
|
|
attr::get_attr_name(a) != @"auto_serialize"
|
2012-03-12 10:19:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn filter_attrs(item: @ast::item) -> @ast::item {
|
|
|
|
@{attrs: vec::filter(item.attrs, not_auto_serialize)
|
|
|
|
with *item}
|
|
|
|
}
|
|
|
|
|
2012-03-02 14:36:22 -08:00
|
|
|
vec::flat_map(in_items) {|in_item|
|
|
|
|
alt in_item.node {
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_ty(ty, tps, _) {
|
2012-06-27 23:09:51 -07:00
|
|
|
vec::append([filter_attrs(in_item)]/~,
|
|
|
|
ty_fns(cx, in_item.ident, ty, tps))
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_enum(variants, tps, _) {
|
2012-06-27 23:09:51 -07:00
|
|
|
vec::append([filter_attrs(in_item)]/~,
|
|
|
|
enum_fns(cx, in_item.ident,
|
|
|
|
in_item.span, variants, tps))
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
_ {
|
2012-03-22 18:53:30 -07:00
|
|
|
cx.span_err(span, "#[auto_serialize] can only be \
|
|
|
|
applied to type and enum \
|
|
|
|
definitions");
|
2012-06-25 20:00:46 -07:00
|
|
|
[in_item]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-08 12:53:35 -08:00
|
|
|
impl helpers for ext_ctxt {
|
2012-03-14 11:49:28 -04:00
|
|
|
fn helper_path(base_path: @ast::path,
|
|
|
|
helper_name: str) -> @ast::path {
|
2012-04-23 13:04:46 +02:00
|
|
|
let head = vec::init(base_path.idents);
|
|
|
|
let tail = vec::last(base_path.idents);
|
2012-06-27 23:09:51 -07:00
|
|
|
self.path(base_path.span,
|
|
|
|
vec::append(head, [@(helper_name + "_" + *tail)]/~))
|
2012-03-14 11:49:28 -04:00
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
fn path(span: span, strs: [ast::ident]/~) -> @ast::path {
|
|
|
|
@{span: span, global: false, idents: strs, rp: none, types: []/~}
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
fn path_tps(span: span, strs: [ast::ident]/~,
|
|
|
|
tps: [@ast::ty]/~) -> @ast::path {
|
2012-04-24 15:52:52 -07:00
|
|
|
@{span: span, global: false, idents: strs, rp: none, types: tps}
|
2012-03-14 17:18:53 -04:00
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
fn ty_path(span: span, strs: [ast::ident]/~,
|
|
|
|
tps: [@ast::ty]/~) -> @ast::ty {
|
2012-03-13 10:55:45 -04:00
|
|
|
@{id: self.next_id(),
|
2012-03-14 17:18:53 -04:00
|
|
|
node: ast::ty_path(self.path_tps(span, strs, tps), self.next_id()),
|
2012-03-02 14:36:22 -08:00
|
|
|
span: span}
|
|
|
|
}
|
2012-03-08 12:53:35 -08:00
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
fn ty_fn(span: span,
|
2012-06-25 20:00:46 -07:00
|
|
|
-input_tys: [@ast::ty]/~,
|
2012-03-12 10:19:35 -07:00
|
|
|
-output: @ast::ty) -> @ast::ty {
|
|
|
|
let args = vec::map(input_tys) {|ty|
|
|
|
|
{mode: ast::expl(ast::by_ref),
|
|
|
|
ty: ty,
|
2012-06-10 00:49:59 -07:00
|
|
|
ident: @"",
|
2012-03-12 10:19:35 -07:00
|
|
|
id: self.next_id()}
|
|
|
|
};
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
@{id: self.next_id(),
|
|
|
|
node: ast::ty_fn(ast::proto_any, {inputs: args,
|
2012-03-12 10:19:35 -07:00
|
|
|
output: output,
|
|
|
|
purity: ast::impure_fn,
|
|
|
|
cf: ast::return_val,
|
2012-06-25 20:00:46 -07:00
|
|
|
constraints: []/~}),
|
2012-03-12 10:19:35 -07:00
|
|
|
span: span}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ty_nil(span: span) -> @ast::ty {
|
2012-03-13 10:55:45 -04:00
|
|
|
@{id: self.next_id(), node: ast::ty_nil, span: span}
|
2012-03-12 10:19:35 -07:00
|
|
|
}
|
|
|
|
|
2012-03-08 12:53:35 -08:00
|
|
|
fn expr(span: span, node: ast::expr_) -> @ast::expr {
|
|
|
|
@{id: self.next_id(), node: node, span: span}
|
|
|
|
}
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
fn var_ref(span: span, name: ast::ident) -> @ast::expr {
|
2012-06-25 20:00:46 -07:00
|
|
|
self.expr(span, ast::expr_path(self.path(span, [name]/~)))
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
fn blk(span: span, stmts: [@ast::stmt]/~) -> ast::blk {
|
|
|
|
{node: {view_items: []/~,
|
2012-03-02 14:36:22 -08:00
|
|
|
stmts: stmts,
|
|
|
|
expr: none,
|
|
|
|
id: self.next_id(),
|
|
|
|
rules: ast::default_blk},
|
|
|
|
span: span}
|
|
|
|
}
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
fn expr_blk(expr: @ast::expr) -> ast::blk {
|
2012-06-25 20:00:46 -07:00
|
|
|
{node: {view_items: []/~,
|
|
|
|
stmts: []/~,
|
2012-03-13 10:55:45 -04:00
|
|
|
expr: some(expr),
|
|
|
|
id: self.next_id(),
|
|
|
|
rules: ast::default_blk},
|
|
|
|
span: expr.span}
|
|
|
|
}
|
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
fn binder_pat(span: span, nm: ast::ident) -> @ast::pat {
|
2012-06-25 20:00:46 -07:00
|
|
|
let path = @{span: span, global: false, idents: [nm]/~,
|
|
|
|
rp: none, types: []/~};
|
2012-03-02 14:36:22 -08:00
|
|
|
@{id: self.next_id(),
|
|
|
|
node: ast::pat_ident(path, none),
|
|
|
|
span: span}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stmt(expr: @ast::expr) -> @ast::stmt {
|
|
|
|
@{node: ast::stmt_semi(expr, self.next_id()),
|
|
|
|
span: expr.span}
|
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
fn alt_stmt(arms: [ast::arm]/~,
|
|
|
|
span: span, -v: @ast::expr) -> @ast::stmt {
|
2012-03-02 14:36:22 -08:00
|
|
|
self.stmt(
|
|
|
|
self.expr(
|
|
|
|
span,
|
|
|
|
ast::expr_alt(v, arms, ast::alt_exhaustive)))
|
|
|
|
}
|
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
fn lit_str(span: span, s: @str) -> @ast::expr {
|
2012-03-08 12:53:35 -08:00
|
|
|
self.expr(
|
|
|
|
span,
|
|
|
|
ast::expr_lit(
|
|
|
|
@{node: ast::lit_str(s),
|
|
|
|
span: span}))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lit_uint(span: span, i: uint) -> @ast::expr {
|
|
|
|
self.expr(
|
|
|
|
span,
|
|
|
|
ast::expr_lit(
|
|
|
|
@{node: ast::lit_uint(i as u64, ast::ty_u),
|
|
|
|
span: span}))
|
|
|
|
}
|
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
fn lambda(blk: ast::blk) -> @ast::expr {
|
|
|
|
let ext_cx = self;
|
|
|
|
let blk_e = self.expr(blk.span, ast::expr_block(blk));
|
2012-03-13 10:55:45 -04:00
|
|
|
#ast{ {|| $(blk_e) } }
|
2012-03-08 12:53:35 -08:00
|
|
|
}
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
fn clone_folder() -> fold::ast_fold {
|
2012-05-21 18:28:39 -07:00
|
|
|
fold::make_fold(@{
|
2012-03-02 14:36:22 -08:00
|
|
|
new_id: {|_id| self.next_id()}
|
|
|
|
with *fold::default_ast_fold()
|
2012-03-13 10:55:45 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clone(v: @ast::expr) -> @ast::expr {
|
|
|
|
let fld = self.clone_folder();
|
2012-03-02 14:36:22 -08:00
|
|
|
fld.fold_expr(v)
|
|
|
|
}
|
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
fn clone_ty(v: @ast::ty) -> @ast::ty {
|
2012-03-13 10:55:45 -04:00
|
|
|
let fld = self.clone_folder();
|
2012-03-12 10:19:35 -07:00
|
|
|
fld.fold_ty(v)
|
|
|
|
}
|
|
|
|
|
2012-03-02 14:36:22 -08:00
|
|
|
fn clone_ty_param(v: ast::ty_param) -> ast::ty_param {
|
2012-03-13 10:55:45 -04:00
|
|
|
let fld = self.clone_folder();
|
2012-03-02 14:36:22 -08:00
|
|
|
fold::fold_ty_param(v, fld)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn at(span: span, expr: @ast::expr) -> @ast::expr {
|
|
|
|
fn repl_sp(old_span: span, repl_span: span, with_span: span) -> span {
|
|
|
|
if old_span == repl_span {
|
|
|
|
with_span
|
|
|
|
} else {
|
|
|
|
old_span
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-21 18:28:39 -07:00
|
|
|
let fld = fold::make_fold(@{
|
2012-06-19 19:34:01 -07:00
|
|
|
new_span: {|a|repl_sp(a, ast_util::dummy_sp(), span)}
|
2012-03-02 14:36:22 -08:00
|
|
|
with *fold::default_ast_fold()
|
|
|
|
});
|
|
|
|
|
|
|
|
fld.fold_expr(expr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
fn ser_path(cx: ext_ctxt, tps: ser_tps_map, path: @ast::path,
|
2012-03-08 12:53:35 -08:00
|
|
|
-s: @ast::expr, -v: @ast::expr)
|
2012-06-25 20:00:46 -07:00
|
|
|
-> [@ast::stmt]/~ {
|
2012-03-13 10:55:45 -04:00
|
|
|
let ext_cx = cx; // required for #ast{}
|
2012-03-02 14:36:22 -08:00
|
|
|
|
|
|
|
// We want to take a path like a::b::c<...> and generate a call
|
|
|
|
// like a::b::c::serialize(s, ...), as described above.
|
|
|
|
|
|
|
|
let callee =
|
|
|
|
cx.expr(
|
|
|
|
path.span,
|
|
|
|
ast::expr_path(
|
2012-03-14 11:49:28 -04:00
|
|
|
cx.helper_path(path, "serialize")));
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-04-23 13:04:46 +02:00
|
|
|
let ty_args = vec::map(path.types) {|ty|
|
2012-03-13 10:55:45 -04:00
|
|
|
let sv_stmts = ser_ty(cx, tps, ty, cx.clone(s), #ast{ __v });
|
2012-03-12 10:19:35 -07:00
|
|
|
let sv = cx.expr(path.span,
|
2012-03-13 10:55:45 -04:00
|
|
|
ast::expr_block(cx.blk(path.span, sv_stmts)));
|
|
|
|
cx.at(ty.span, #ast{ {|__v| $(sv)} })
|
2012-03-02 14:36:22 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
[cx.stmt(
|
|
|
|
cx.expr(
|
|
|
|
path.span,
|
2012-06-27 23:09:51 -07:00
|
|
|
ast::expr_call(callee, vec::append([s, v]/~, ty_args), false)))]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
fn ser_variant(cx: ext_ctxt,
|
|
|
|
tps: ser_tps_map,
|
2012-06-25 20:00:46 -07:00
|
|
|
tys: [@ast::ty]/~,
|
2012-03-13 10:55:45 -04:00
|
|
|
span: span,
|
|
|
|
-s: @ast::expr,
|
2012-06-25 20:00:46 -07:00
|
|
|
pfn: fn([@ast::pat]/~) -> ast::pat_,
|
2012-03-13 10:55:45 -04:00
|
|
|
bodyfn: fn(-@ast::expr, ast::blk) -> @ast::expr,
|
|
|
|
argfn: fn(-@ast::expr, uint, ast::blk) -> @ast::expr)
|
2012-03-08 12:53:35 -08:00
|
|
|
-> ast::arm {
|
2012-06-10 00:49:59 -07:00
|
|
|
let vnames = vec::from_fn(vec::len(tys)) {|i| @#fmt["__v%u", i]};
|
2012-03-13 10:55:45 -04:00
|
|
|
let pats = vec::from_fn(vec::len(tys)) {|i|
|
2012-03-02 14:36:22 -08:00
|
|
|
cx.binder_pat(tys[i].span, vnames[i])
|
|
|
|
};
|
|
|
|
let pat: @ast::pat = @{id: cx.next_id(), node: pfn(pats), span: span};
|
2012-03-13 10:55:45 -04:00
|
|
|
let stmts = vec::from_fn(vec::len(tys)) {|i|
|
2012-03-02 14:36:22 -08:00
|
|
|
let v = cx.var_ref(span, vnames[i]);
|
2012-03-08 12:53:35 -08:00
|
|
|
let arg_blk =
|
|
|
|
cx.blk(
|
|
|
|
span,
|
2012-03-13 10:55:45 -04:00
|
|
|
ser_ty(cx, tps, tys[i], cx.clone(s), v));
|
2012-03-08 12:53:35 -08:00
|
|
|
cx.stmt(argfn(cx.clone(s), i, arg_blk))
|
2012-03-02 14:36:22 -08:00
|
|
|
};
|
2012-03-08 12:53:35 -08:00
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
let body_blk = cx.blk(span, stmts);
|
2012-06-25 20:00:46 -07:00
|
|
|
let body = cx.blk(span, [cx.stmt(bodyfn(s, body_blk))]/~);
|
2012-03-08 12:53:35 -08:00
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
{pats: [pat]/~, guard: none, body: body}
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
fn ser_lambda(cx: ext_ctxt, tps: ser_tps_map, ty: @ast::ty,
|
|
|
|
-s: @ast::expr, -v: @ast::expr) -> @ast::expr {
|
|
|
|
cx.lambda(cx.blk(ty.span, ser_ty(cx, tps, ty, s, v)))
|
|
|
|
}
|
2012-03-12 10:19:35 -07:00
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
fn ser_ty(cx: ext_ctxt, tps: ser_tps_map,
|
|
|
|
ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
|
2012-06-25 20:00:46 -07:00
|
|
|
-> [@ast::stmt]/~ {
|
2012-03-12 10:19:35 -07:00
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
let ext_cx = cx; // required for #ast{}
|
2012-03-02 14:36:22 -08:00
|
|
|
|
|
|
|
alt ty.node {
|
2012-03-13 10:55:45 -04:00
|
|
|
ast::ty_nil {
|
2012-06-25 20:00:46 -07:00
|
|
|
[#ast[stmt]{$(s).emit_nil()}]/~
|
2012-03-13 10:55:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_bot {
|
2012-03-22 18:53:30 -07:00
|
|
|
cx.span_err(
|
2012-03-13 10:55:45 -04:00
|
|
|
ty.span, #fmt["Cannot serialize bottom type"]);
|
2012-06-25 20:00:46 -07:00
|
|
|
[]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
ast::ty_box(mt) {
|
2012-03-13 10:55:45 -04:00
|
|
|
let l = ser_lambda(cx, tps, mt.ty, cx.clone(s), #ast{ *$(v) });
|
2012-06-25 20:00:46 -07:00
|
|
|
[#ast(stmt){$(s).emit_box($(l));}]/~
|
2012-03-12 10:19:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_uniq(mt) {
|
2012-03-13 10:55:45 -04:00
|
|
|
let l = ser_lambda(cx, tps, mt.ty, cx.clone(s), #ast{ *$(v) });
|
2012-06-25 20:00:46 -07:00
|
|
|
[#ast(stmt){$(s).emit_uniq($(l));}]/~
|
2012-03-12 10:19:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_ptr(_) | ast::ty_rptr(_, _) {
|
2012-04-09 17:32:49 -07:00
|
|
|
cx.span_err(ty.span, "cannot serialize pointer types");
|
2012-06-25 20:00:46 -07:00
|
|
|
[]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_rec(flds) {
|
2012-03-13 10:55:45 -04:00
|
|
|
let fld_stmts = vec::from_fn(vec::len(flds)) {|fidx|
|
2012-03-12 10:19:35 -07:00
|
|
|
let fld = flds[fidx];
|
|
|
|
let vf = cx.expr(fld.span,
|
|
|
|
ast::expr_field(cx.clone(v),
|
|
|
|
fld.node.ident,
|
2012-06-25 20:00:46 -07:00
|
|
|
[]/~));
|
2012-03-12 10:19:35 -07:00
|
|
|
let s = cx.clone(s);
|
|
|
|
let f = cx.lit_str(fld.span, fld.node.ident);
|
|
|
|
let i = cx.lit_uint(fld.span, fidx);
|
2012-03-13 10:55:45 -04:00
|
|
|
let l = ser_lambda(cx, tps, fld.node.mt.ty, cx.clone(s), vf);
|
2012-03-12 10:19:35 -07:00
|
|
|
#ast(stmt){$(s).emit_rec_field($(f), $(i), $(l));}
|
|
|
|
};
|
|
|
|
let fld_lambda = cx.lambda(cx.blk(ty.span, fld_stmts));
|
2012-06-25 20:00:46 -07:00
|
|
|
[#ast(stmt){$(s).emit_rec($(fld_lambda));}]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_fn(_, _) {
|
2012-04-09 17:32:49 -07:00
|
|
|
cx.span_err(ty.span, "cannot serialize function types");
|
2012-06-25 20:00:46 -07:00
|
|
|
[]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_tup(tys) {
|
|
|
|
// Generate code like
|
|
|
|
//
|
|
|
|
// alt v {
|
|
|
|
// (v1, v2, v3) {
|
|
|
|
// .. serialize v1, v2, v3 ..
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
|
|
|
|
let arms = [
|
2012-03-13 10:55:45 -04:00
|
|
|
ser_variant(
|
2012-03-08 12:53:35 -08:00
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
cx, tps, tys, ty.span, s,
|
2012-03-08 12:53:35 -08:00
|
|
|
|
|
|
|
// Generate pattern (v1, v2, v3)
|
|
|
|
{|pats| ast::pat_tup(pats)},
|
|
|
|
|
|
|
|
// Generate body s.emit_tup(3, {|| blk })
|
2012-03-12 10:19:35 -07:00
|
|
|
{|-s, blk|
|
2012-03-08 12:53:35 -08:00
|
|
|
let sz = cx.lit_uint(ty.span, vec::len(tys));
|
|
|
|
let body = cx.lambda(blk);
|
2012-03-13 10:55:45 -04:00
|
|
|
#ast{ $(s).emit_tup($(sz), $(body)) }
|
2012-03-08 12:53:35 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
// Generate s.emit_tup_elt(i, {|| blk })
|
2012-03-12 10:19:35 -07:00
|
|
|
{|-s, i, blk|
|
2012-03-08 12:53:35 -08:00
|
|
|
let idx = cx.lit_uint(ty.span, i);
|
|
|
|
let body = cx.lambda(blk);
|
2012-03-13 10:55:45 -04:00
|
|
|
#ast{ $(s).emit_tup_elt($(idx), $(body)) }
|
2012-03-08 12:53:35 -08:00
|
|
|
})
|
2012-06-25 20:00:46 -07:00
|
|
|
]/~;
|
|
|
|
[cx.alt_stmt(arms, ty.span, v)]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_path(path, _) {
|
2012-04-23 13:04:46 +02:00
|
|
|
if vec::len(path.idents) == 1u &&
|
|
|
|
vec::is_empty(path.types) {
|
|
|
|
let ident = path.idents[0];
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
alt tps.find(*ident) {
|
2012-03-02 14:36:22 -08:00
|
|
|
some(f) { f(v) }
|
2012-03-13 10:55:45 -04:00
|
|
|
none { ser_path(cx, tps, path, s, v) }
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
} else {
|
2012-03-13 10:55:45 -04:00
|
|
|
ser_path(cx, tps, path, s, v)
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_constr(ty, _) {
|
2012-03-13 10:55:45 -04:00
|
|
|
ser_ty(cx, tps, ty, s, v)
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_mac(_) {
|
2012-04-09 17:32:49 -07:00
|
|
|
cx.span_err(ty.span, "cannot serialize macro types");
|
2012-06-25 20:00:46 -07:00
|
|
|
[]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_infer {
|
2012-04-09 17:32:49 -07:00
|
|
|
cx.span_err(ty.span, "cannot serialize inferred types");
|
2012-06-25 20:00:46 -07:00
|
|
|
[]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-06-22 11:58:07 -07:00
|
|
|
ast::ty_vstore(@{node: ast::ty_vec(mt),_}, ast::vstore_uniq) |
|
2012-03-02 14:36:22 -08:00
|
|
|
ast::ty_vec(mt) {
|
|
|
|
let ser_e =
|
|
|
|
cx.expr(
|
|
|
|
ty.span,
|
2012-03-08 12:53:35 -08:00
|
|
|
ast::expr_block(
|
2012-03-02 14:36:22 -08:00
|
|
|
cx.blk(
|
|
|
|
ty.span,
|
2012-03-13 10:55:45 -04:00
|
|
|
ser_ty(
|
|
|
|
cx, tps, mt.ty,
|
2012-03-02 14:36:22 -08:00
|
|
|
cx.clone(s),
|
2012-03-13 10:55:45 -04:00
|
|
|
cx.at(ty.span, #ast{ __e })))));
|
2012-03-08 12:53:35 -08:00
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
[#ast(stmt){
|
2012-03-14 11:49:28 -04:00
|
|
|
std::serialization::emit_from_vec($(s), $(v), {|__e| $(ser_e) })
|
2012-06-25 20:00:46 -07:00
|
|
|
}]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
2012-06-22 11:58:07 -07:00
|
|
|
|
|
|
|
ast::ty_vstore(_, _) {
|
|
|
|
cx.span_unimpl(ty.span, "serialization for vstore types");
|
|
|
|
}
|
|
|
|
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
fn mk_ser_fn(cx: ext_ctxt, span: span, name: ast::ident,
|
|
|
|
tps: [ast::ty_param]/~,
|
2012-03-14 17:18:53 -04:00
|
|
|
f: fn(ext_ctxt, ser_tps_map,
|
2012-06-25 20:00:46 -07:00
|
|
|
-@ast::expr, -@ast::expr) -> [@ast::stmt]/~)
|
2012-03-02 14:36:22 -08:00
|
|
|
-> @ast::item {
|
2012-03-13 10:55:45 -04:00
|
|
|
let ext_cx = cx; // required for #ast
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
let tp_types = vec::map(tps, {|tp| cx.ty_path(span, [tp.ident]/~, []/~)});
|
|
|
|
let v_ty = cx.ty_path(span, [name]/~, tp_types);
|
2012-03-14 17:18:53 -04:00
|
|
|
|
2012-03-08 12:53:35 -08:00
|
|
|
let tp_inputs =
|
|
|
|
vec::map(tps, {|tp|
|
|
|
|
{mode: ast::expl(ast::by_ref),
|
2012-03-12 10:19:35 -07:00
|
|
|
ty: cx.ty_fn(span,
|
2012-06-25 20:00:46 -07:00
|
|
|
[cx.ty_path(span, [tp.ident]/~, []/~)]/~,
|
2012-03-12 10:19:35 -07:00
|
|
|
cx.ty_nil(span)),
|
2012-06-10 00:49:59 -07:00
|
|
|
ident: @("__s" + *tp.ident),
|
2012-03-08 12:53:35 -08:00
|
|
|
id: cx.next_id()}});
|
|
|
|
|
2012-03-12 10:19:35 -07:00
|
|
|
#debug["tp_inputs = %?", tp_inputs];
|
|
|
|
|
2012-03-14 17:18:53 -04:00
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
let ser_inputs: [ast::arg]/~ =
|
2012-06-27 23:09:51 -07:00
|
|
|
vec::append([{mode: ast::expl(ast::by_ref),
|
|
|
|
ty: cx.ty_path(span, [@"__S"]/~, []/~),
|
|
|
|
ident: @"__s",
|
|
|
|
id: cx.next_id()},
|
|
|
|
{mode: ast::expl(ast::by_ref),
|
|
|
|
ty: v_ty,
|
|
|
|
ident: @"__v",
|
|
|
|
id: cx.next_id()}]/~,
|
|
|
|
tp_inputs);
|
2012-03-08 12:53:35 -08:00
|
|
|
|
2012-03-14 12:07:23 -07:00
|
|
|
let tps_map = map::str_hash();
|
2012-03-12 10:19:35 -07:00
|
|
|
vec::iter2(tps, tp_inputs) {|tp, arg|
|
2012-03-08 12:53:35 -08:00
|
|
|
let arg_ident = arg.ident;
|
2012-03-13 10:55:45 -04:00
|
|
|
tps_map.insert(
|
2012-06-10 00:49:59 -07:00
|
|
|
*tp.ident,
|
2012-06-25 20:00:46 -07:00
|
|
|
fn@(v: @ast::expr) -> [@ast::stmt]/~ {
|
2012-03-08 12:53:35 -08:00
|
|
|
let f = cx.var_ref(span, arg_ident);
|
2012-06-10 00:49:59 -07:00
|
|
|
#debug["serializing type arg %s", *arg_ident];
|
2012-06-25 20:00:46 -07:00
|
|
|
[#ast(stmt){$(f)($(v));}]/~
|
2012-03-08 12:53:35 -08:00
|
|
|
});
|
|
|
|
}
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-03-14 17:18:53 -04:00
|
|
|
let ser_bnds = @[
|
|
|
|
ast::bound_iface(cx.ty_path(span,
|
2012-06-25 20:00:46 -07:00
|
|
|
[@"std", @"serialization",
|
|
|
|
@"serializer"]/~,
|
|
|
|
[]/~))]/~;
|
2012-03-08 12:53:35 -08:00
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
let ser_tps: [ast::ty_param]/~ =
|
2012-06-27 23:09:51 -07:00
|
|
|
vec::append([{ident: @"__S",
|
|
|
|
id: cx.next_id(),
|
|
|
|
bounds: ser_bnds}]/~,
|
|
|
|
vec::map(tps) {|tp| cx.clone_ty_param(tp) });
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
let ser_output: @ast::ty = @{id: cx.next_id(),
|
|
|
|
node: ast::ty_nil,
|
2012-03-08 12:53:35 -08:00
|
|
|
span: span};
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-03-08 12:53:35 -08:00
|
|
|
let ser_blk = cx.blk(span,
|
2012-03-14 17:18:53 -04:00
|
|
|
f(cx, tps_map, #ast{ __s }, #ast{ __v }));
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
@{ident: @("serialize_" + *name),
|
2012-06-25 20:00:46 -07:00
|
|
|
attrs: []/~,
|
2012-03-02 14:36:22 -08:00
|
|
|
id: cx.next_id(),
|
|
|
|
node: ast::item_fn({inputs: ser_inputs,
|
|
|
|
output: ser_output,
|
|
|
|
purity: ast::impure_fn,
|
|
|
|
cf: ast::return_val,
|
2012-06-25 20:00:46 -07:00
|
|
|
constraints: []/~},
|
2012-03-02 14:36:22 -08:00
|
|
|
ser_tps,
|
|
|
|
ser_blk),
|
2012-05-08 16:06:24 +02:00
|
|
|
vis: ast::public,
|
2012-03-08 12:53:35 -08:00
|
|
|
span: span}
|
|
|
|
}
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
// ______________________________________________________________________
|
|
|
|
|
|
|
|
fn deser_path(cx: ext_ctxt, tps: deser_tps_map, path: @ast::path,
|
|
|
|
-d: @ast::expr) -> @ast::expr {
|
|
|
|
// We want to take a path like a::b::c<...> and generate a call
|
|
|
|
// like a::b::c::deserialize(d, ...), as described above.
|
|
|
|
|
|
|
|
let callee =
|
|
|
|
cx.expr(
|
|
|
|
path.span,
|
|
|
|
ast::expr_path(
|
2012-03-14 11:49:28 -04:00
|
|
|
cx.helper_path(path, "deserialize")));
|
2012-03-13 10:55:45 -04:00
|
|
|
|
2012-04-23 13:04:46 +02:00
|
|
|
let ty_args = vec::map(path.types) {|ty|
|
2012-03-13 10:55:45 -04:00
|
|
|
let dv_expr = deser_ty(cx, tps, ty, cx.clone(d));
|
|
|
|
cx.lambda(cx.expr_blk(dv_expr))
|
|
|
|
};
|
|
|
|
|
2012-06-27 23:09:51 -07:00
|
|
|
cx.expr(path.span, ast::expr_call(callee, vec::append([d]/~, ty_args),
|
|
|
|
false))
|
2012-03-13 10:55:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn deser_lambda(cx: ext_ctxt, tps: deser_tps_map, ty: @ast::ty,
|
|
|
|
-d: @ast::expr) -> @ast::expr {
|
|
|
|
cx.lambda(cx.expr_blk(deser_ty(cx, tps, ty, d)))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn deser_ty(cx: ext_ctxt, tps: deser_tps_map,
|
|
|
|
ty: @ast::ty, -d: @ast::expr) -> @ast::expr {
|
|
|
|
|
|
|
|
let ext_cx = cx; // required for #ast{}
|
|
|
|
|
|
|
|
alt ty.node {
|
|
|
|
ast::ty_nil {
|
|
|
|
#ast{ $(d).read_nil() }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_bot {
|
|
|
|
#ast{ fail }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_box(mt) {
|
|
|
|
let l = deser_lambda(cx, tps, mt.ty, cx.clone(d));
|
|
|
|
#ast{ @$(d).read_box($(l)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_uniq(mt) {
|
|
|
|
let l = deser_lambda(cx, tps, mt.ty, cx.clone(d));
|
|
|
|
#ast{ ~$(d).read_uniq($(l)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_ptr(_) | ast::ty_rptr(_, _) {
|
|
|
|
#ast{ fail }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_rec(flds) {
|
|
|
|
let fields = vec::from_fn(vec::len(flds)) {|fidx|
|
|
|
|
let fld = flds[fidx];
|
|
|
|
let d = cx.clone(d);
|
|
|
|
let f = cx.lit_str(fld.span, fld.node.ident);
|
|
|
|
let i = cx.lit_uint(fld.span, fidx);
|
|
|
|
let l = deser_lambda(cx, tps, fld.node.mt.ty, cx.clone(d));
|
|
|
|
{node: {mutbl: fld.node.mt.mutbl,
|
|
|
|
ident: fld.node.ident,
|
|
|
|
expr: #ast{ $(d).read_rec_field($(f), $(i), $(l))} },
|
|
|
|
span: fld.span}
|
|
|
|
};
|
|
|
|
let fld_expr = cx.expr(ty.span, ast::expr_rec(fields, none));
|
|
|
|
let fld_lambda = cx.lambda(cx.expr_blk(fld_expr));
|
|
|
|
#ast{ $(d).read_rec($(fld_lambda)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_fn(_, _) {
|
|
|
|
#ast{ fail }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_tup(tys) {
|
|
|
|
// Generate code like
|
|
|
|
//
|
|
|
|
// d.read_tup(3u) {||
|
|
|
|
// (d.read_tup_elt(0u, {||...}),
|
|
|
|
// d.read_tup_elt(1u, {||...}),
|
|
|
|
// d.read_tup_elt(2u, {||...}))
|
|
|
|
// }
|
|
|
|
|
|
|
|
let arg_exprs = vec::from_fn(vec::len(tys)) {|i|
|
|
|
|
let idx = cx.lit_uint(ty.span, i);
|
|
|
|
let body = deser_lambda(cx, tps, tys[i], cx.clone(d));
|
|
|
|
#ast{ $(d).read_tup_elt($(idx), $(body)) }
|
|
|
|
};
|
|
|
|
let body =
|
|
|
|
cx.lambda(cx.expr_blk(
|
|
|
|
cx.expr(ty.span, ast::expr_tup(arg_exprs))));
|
|
|
|
let sz = cx.lit_uint(ty.span, vec::len(tys));
|
|
|
|
#ast{ $(d).read_tup($(sz), $(body)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_path(path, _) {
|
2012-04-23 13:04:46 +02:00
|
|
|
if vec::len(path.idents) == 1u &&
|
|
|
|
vec::is_empty(path.types) {
|
|
|
|
let ident = path.idents[0];
|
2012-03-13 10:55:45 -04:00
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
alt tps.find(*ident) {
|
2012-03-13 10:55:45 -04:00
|
|
|
some(f) { f() }
|
|
|
|
none { deser_path(cx, tps, path, d) }
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
deser_path(cx, tps, path, d)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_constr(ty, constrs) {
|
|
|
|
deser_ty(cx, tps, ty, d)
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_mac(_) {
|
|
|
|
#ast{ fail }
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ty_infer {
|
|
|
|
#ast{ fail }
|
|
|
|
}
|
|
|
|
|
2012-06-22 11:58:07 -07:00
|
|
|
ast::ty_vstore(@{node: ast::ty_vec(mt),_}, ast::vstore_uniq) |
|
2012-03-13 10:55:45 -04:00
|
|
|
ast::ty_vec(mt) {
|
|
|
|
let l = deser_lambda(cx, tps, mt.ty, cx.clone(d));
|
2012-03-14 11:49:28 -04:00
|
|
|
#ast{ std::serialization::read_to_vec($(d), $(l)) }
|
2012-03-13 10:55:45 -04:00
|
|
|
}
|
2012-06-22 11:58:07 -07:00
|
|
|
|
|
|
|
ast::ty_vstore(_, _) {
|
|
|
|
cx.span_unimpl(ty.span, "deserialization for vstore types");
|
|
|
|
}
|
2012-03-13 10:55:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
fn mk_deser_fn(cx: ext_ctxt, span: span,
|
2012-06-25 20:00:46 -07:00
|
|
|
name: ast::ident, tps: [ast::ty_param]/~,
|
2012-03-14 17:18:53 -04:00
|
|
|
f: fn(ext_ctxt, deser_tps_map, -@ast::expr) -> @ast::expr)
|
2012-03-13 10:55:45 -04:00
|
|
|
-> @ast::item {
|
|
|
|
let ext_cx = cx; // required for #ast
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
let tp_types = vec::map(tps, {|tp| cx.ty_path(span, [tp.ident]/~, []/~)});
|
|
|
|
let v_ty = cx.ty_path(span, [name]/~, tp_types);
|
2012-03-14 17:18:53 -04:00
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
let tp_inputs =
|
|
|
|
vec::map(tps, {|tp|
|
|
|
|
{mode: ast::expl(ast::by_ref),
|
|
|
|
ty: cx.ty_fn(span,
|
2012-06-25 20:00:46 -07:00
|
|
|
[]/~,
|
|
|
|
cx.ty_path(span, [tp.ident]/~, []/~)),
|
2012-06-10 00:49:59 -07:00
|
|
|
ident: @("__d" + *tp.ident),
|
2012-03-13 10:55:45 -04:00
|
|
|
id: cx.next_id()}});
|
|
|
|
|
|
|
|
#debug["tp_inputs = %?", tp_inputs];
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
let deser_inputs: [ast::arg]/~ =
|
2012-06-27 23:09:51 -07:00
|
|
|
vec::append([{mode: ast::expl(ast::by_ref),
|
|
|
|
ty: cx.ty_path(span, [@"__D"]/~, []/~),
|
|
|
|
ident: @"__d",
|
|
|
|
id: cx.next_id()}]/~,
|
|
|
|
tp_inputs);
|
2012-03-13 10:55:45 -04:00
|
|
|
|
2012-03-14 12:07:23 -07:00
|
|
|
let tps_map = map::str_hash();
|
2012-03-13 10:55:45 -04:00
|
|
|
vec::iter2(tps, tp_inputs) {|tp, arg|
|
|
|
|
let arg_ident = arg.ident;
|
|
|
|
tps_map.insert(
|
2012-06-10 00:49:59 -07:00
|
|
|
*tp.ident,
|
2012-03-13 10:55:45 -04:00
|
|
|
fn@() -> @ast::expr {
|
|
|
|
let f = cx.var_ref(span, arg_ident);
|
|
|
|
#ast{ $(f)() }
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:18:53 -04:00
|
|
|
let deser_bnds = @[
|
2012-06-10 00:49:59 -07:00
|
|
|
ast::bound_iface(cx.ty_path(
|
|
|
|
span,
|
2012-06-25 20:00:46 -07:00
|
|
|
[@"std", @"serialization", @"deserializer"]/~,
|
|
|
|
[]/~))]/~;
|
2012-03-13 10:55:45 -04:00
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
let deser_tps: [ast::ty_param]/~ =
|
2012-06-28 13:52:13 -07:00
|
|
|
vec::append([{ident: @"__D",
|
|
|
|
id: cx.next_id(),
|
|
|
|
bounds: deser_bnds}]/~,
|
|
|
|
vec::map(tps) {|tp|
|
|
|
|
let cloned = cx.clone_ty_param(tp);
|
|
|
|
{bounds: @(vec::append(*cloned.bounds,
|
|
|
|
[ast::bound_copy]/~))
|
|
|
|
with cloned}
|
|
|
|
});
|
2012-03-13 10:55:45 -04:00
|
|
|
|
2012-03-14 17:18:53 -04:00
|
|
|
let deser_blk = cx.expr_blk(f(cx, tps_map, #ast(expr){__d}));
|
2012-03-13 10:55:45 -04:00
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
@{ident: @("deserialize_" + *name),
|
2012-06-25 20:00:46 -07:00
|
|
|
attrs: []/~,
|
2012-03-13 10:55:45 -04:00
|
|
|
id: cx.next_id(),
|
|
|
|
node: ast::item_fn({inputs: deser_inputs,
|
|
|
|
output: v_ty,
|
|
|
|
purity: ast::impure_fn,
|
|
|
|
cf: ast::return_val,
|
2012-06-25 20:00:46 -07:00
|
|
|
constraints: []/~},
|
2012-03-13 10:55:45 -04:00
|
|
|
deser_tps,
|
|
|
|
deser_blk),
|
2012-05-08 16:06:24 +02:00
|
|
|
vis: ast::public,
|
2012-03-13 10:55:45 -04:00
|
|
|
span: span}
|
|
|
|
}
|
|
|
|
|
2012-06-25 20:00:46 -07:00
|
|
|
fn ty_fns(cx: ext_ctxt, name: ast::ident,
|
|
|
|
ty: @ast::ty, tps: [ast::ty_param]/~)
|
|
|
|
-> [@ast::item]/~ {
|
2012-03-08 12:53:35 -08:00
|
|
|
|
|
|
|
let span = ty.span;
|
2012-03-14 11:49:28 -04:00
|
|
|
[
|
2012-06-19 19:34:01 -07:00
|
|
|
mk_ser_fn(cx, span, name, tps, {|a,b,c,d|ser_ty(a, b, ty, c, d)}),
|
|
|
|
mk_deser_fn(cx, span, name, tps, {|a,b,c|deser_ty(a, b, ty, c)})
|
2012-06-25 20:00:46 -07:00
|
|
|
]/~
|
2012-03-02 14:36:22 -08:00
|
|
|
}
|
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: ast::ident,
|
2012-06-25 20:00:46 -07:00
|
|
|
e_span: span, variants: [ast::variant]/~,
|
|
|
|
-s: @ast::expr, -v: @ast::expr) -> [@ast::stmt]/~ {
|
2012-03-13 10:55:45 -04:00
|
|
|
let ext_cx = cx;
|
|
|
|
let arms = vec::from_fn(vec::len(variants)) {|vidx|
|
|
|
|
let variant = variants[vidx];
|
|
|
|
let v_span = variant.span;
|
|
|
|
let v_name = variant.node.name;
|
|
|
|
let variant_tys = vec::map(variant.node.args) {|a| a.ty };
|
|
|
|
|
|
|
|
ser_variant(
|
|
|
|
cx, tps, variant_tys, v_span, cx.clone(s),
|
|
|
|
|
|
|
|
// Generate pattern var(v1, v2, v3)
|
|
|
|
{|pats|
|
|
|
|
if vec::is_empty(pats) {
|
2012-06-25 20:00:46 -07:00
|
|
|
ast::pat_ident(cx.path(v_span, [v_name]/~), none)
|
2012-03-13 10:55:45 -04:00
|
|
|
} else {
|
2012-06-25 20:00:46 -07:00
|
|
|
ast::pat_enum(cx.path(v_span, [v_name]/~), some(pats))
|
2012-03-13 10:55:45 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// Generate body s.emit_enum_variant("foo", 0u,
|
|
|
|
// 3u, {|| blk })
|
|
|
|
{|-s, blk|
|
|
|
|
let v_name = cx.lit_str(v_span, v_name);
|
|
|
|
let v_id = cx.lit_uint(v_span, vidx);
|
|
|
|
let sz = cx.lit_uint(v_span, vec::len(variant_tys));
|
|
|
|
let body = cx.lambda(blk);
|
|
|
|
#ast[expr]{
|
|
|
|
$(s).emit_enum_variant($(v_name), $(v_id),
|
|
|
|
$(sz), $(body))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// Generate s.emit_enum_variant_arg(i, {|| blk })
|
|
|
|
{|-s, i, blk|
|
|
|
|
let idx = cx.lit_uint(v_span, i);
|
|
|
|
let body = cx.lambda(blk);
|
|
|
|
#ast[expr]{
|
|
|
|
$(s).emit_enum_variant_arg($(idx), $(body))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
};
|
2012-06-25 20:00:46 -07:00
|
|
|
let lam = cx.lambda(cx.blk(e_span, [cx.alt_stmt(arms, e_span, v)]/~));
|
2012-03-13 10:55:45 -04:00
|
|
|
let e_name = cx.lit_str(e_span, e_name);
|
2012-06-25 20:00:46 -07:00
|
|
|
[#ast(stmt){ $(s).emit_enum($(e_name), $(lam)) }]/~
|
2012-03-13 10:55:45 -04:00
|
|
|
}
|
2012-03-02 14:36:22 -08:00
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
fn deser_enum(cx: ext_ctxt, tps: deser_tps_map, e_name: ast::ident,
|
2012-06-25 20:00:46 -07:00
|
|
|
e_span: span, variants: [ast::variant]/~,
|
2012-03-14 17:18:53 -04:00
|
|
|
-d: @ast::expr) -> @ast::expr {
|
2012-03-13 10:55:45 -04:00
|
|
|
let ext_cx = cx;
|
2012-06-25 20:00:46 -07:00
|
|
|
let arms: [ast::arm]/~ = vec::from_fn(vec::len(variants)) {|vidx|
|
2012-03-13 10:55:45 -04:00
|
|
|
let variant = variants[vidx];
|
|
|
|
let v_span = variant.span;
|
|
|
|
let v_name = variant.node.name;
|
|
|
|
let tys = vec::map(variant.node.args) {|a| a.ty };
|
|
|
|
|
|
|
|
let arg_exprs = vec::from_fn(vec::len(tys)) {|i|
|
|
|
|
let idx = cx.lit_uint(v_span, i);
|
|
|
|
let body = deser_lambda(cx, tps, tys[i], cx.clone(d));
|
|
|
|
#ast{ $(d).read_enum_variant_arg($(idx), $(body)) }
|
|
|
|
};
|
|
|
|
|
2012-03-14 20:54:17 -04:00
|
|
|
let body = {
|
|
|
|
if vec::is_empty(tys) {
|
|
|
|
// for a nullary variant v, do "v"
|
|
|
|
cx.var_ref(v_span, v_name)
|
|
|
|
} else {
|
|
|
|
// for an n-ary variant v, do "v(a_1, ..., a_n)"
|
|
|
|
cx.expr(v_span, ast::expr_call(
|
|
|
|
cx.var_ref(v_span, v_name), arg_exprs, false))
|
|
|
|
}
|
|
|
|
};
|
2012-03-13 10:55:45 -04:00
|
|
|
|
|
|
|
{pats: [@{id: cx.next_id(),
|
|
|
|
node: ast::pat_lit(cx.lit_uint(v_span, vidx)),
|
2012-06-25 20:00:46 -07:00
|
|
|
span: v_span}]/~,
|
2012-03-13 10:55:45 -04:00
|
|
|
guard: none,
|
|
|
|
body: cx.expr_blk(body)}
|
2012-03-08 12:53:35 -08:00
|
|
|
};
|
|
|
|
|
2012-03-13 10:55:45 -04:00
|
|
|
// Generate code like:
|
|
|
|
let e_name = cx.lit_str(e_span, e_name);
|
|
|
|
let alt_expr = cx.expr(e_span,
|
|
|
|
ast::expr_alt(#ast{__i}, arms, ast::alt_check));
|
|
|
|
let var_lambda = #ast{ {|__i| $(alt_expr)} };
|
|
|
|
let read_var = #ast{ $(cx.clone(d)).read_enum_variant($(var_lambda)) };
|
|
|
|
let read_lambda = cx.lambda(cx.expr_blk(read_var));
|
|
|
|
#ast{ $(d).read_enum($(e_name), $(read_lambda)) }
|
|
|
|
}
|
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
fn enum_fns(cx: ext_ctxt, e_name: ast::ident, e_span: span,
|
2012-06-25 20:00:46 -07:00
|
|
|
variants: [ast::variant]/~, tps: [ast::ty_param]/~)
|
|
|
|
-> [@ast::item]/~ {
|
2012-03-14 11:49:28 -04:00
|
|
|
[
|
2012-03-14 17:18:53 -04:00
|
|
|
mk_ser_fn(cx, e_span, e_name, tps,
|
2012-06-19 19:34:01 -07:00
|
|
|
{|a,b,c,d|ser_enum(a, b, e_name, e_span, variants, c, d)}),
|
2012-03-14 17:18:53 -04:00
|
|
|
mk_deser_fn(cx, e_span, e_name, tps,
|
2012-06-19 19:34:01 -07:00
|
|
|
{|a,b,c|deser_enum(a, b, e_name, e_span, variants, c)})
|
2012-06-25 20:00:46 -07:00
|
|
|
]/~
|
2012-03-08 12:53:35 -08:00
|
|
|
}
|