From b30cb8e43a57f8f16065c37a664b26db0891f134 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Mar 2012 10:55:45 -0400 Subject: [PATCH] implement deserialization, rename mk_mem_buffer() to mem_buffer() --- src/fuzzer/fuzzer.rs | 4 +- src/libcore/core.rc | 2 +- src/libcore/io.rs | 6 +- src/libcore/serialization.rs | 2 +- src/libcore/vec.rs | 1 + src/libstd/serialization.rs | 5 + src/libstd/test.rs | 2 +- src/rustc/metadata/astencode.rs | 2 +- src/rustc/metadata/encoder.rs | 4 +- src/rustc/metadata/tyencode.rs | 2 +- src/rustc/syntax/ext/auto_serialize.rs | 517 ++++++++++++++++------- src/rustc/syntax/print/pprust.rs | 8 +- src/test/auxiliary/auto_serialize_lib.rs | 32 ++ src/test/auxiliary/cci_impl_lib.rs | 2 + src/test/auxiliary/cci_iter_lib.rs | 2 + src/test/auxiliary/cci_no_inline_lib.rs | 2 + src/test/auxiliary/native_lib.rs | 2 + src/test/run-pass/auto_serialize_enum.rs | 21 +- src/test/run-pass/auto_serialize_gen.rs | 18 +- src/test/run-pass/auto_serialize_link.rs | 18 +- src/test/run-pass/auto_serialize_rec.rs | 16 +- src/test/run-pass/auto_serialize_vec.rs | 17 +- src/test/run-pass/qquote.rs | 2 +- 23 files changed, 501 insertions(+), 186 deletions(-) create mode 100644 src/test/auxiliary/auto_serialize_lib.rs diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs index b0b1d5c5f66..49aa10998db 100644 --- a/src/fuzzer/fuzzer.rs +++ b/src/fuzzer/fuzzer.rs @@ -221,10 +221,10 @@ fn under(n: uint, it: fn(uint)) { while i < n { it(i); i += 1u; } } -fn devnull() -> io::writer { io::mem_buffer_writer(io::mk_mem_buffer()) } +fn devnull() -> io::writer { io::mem_buffer_writer(io::mem_buffer()) } fn as_str(f: fn@(io::writer)) -> str { - let buf = io::mk_mem_buffer(); + let buf = io::mem_buffer(); f(io::mem_buffer_writer(buf)); io::mem_buffer_str(buf) } diff --git a/src/libcore/core.rc b/src/libcore/core.rc index e790c55d11f..72f5b528c9a 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -31,7 +31,7 @@ export uint, u8, u16, u32, u64; export float, f32, f64; export box, char, str, ptr, vec, bool; export either, option, result, iter; -export libc, os, ctypes, io, run, rand, sys, unsafe, logging, serialization; +export libc, os, io, run, rand, sys, unsafe, logging, serialization; export comm, task, future; export extfmt; export tuple; diff --git a/src/libcore/io.rs b/src/libcore/io.rs index e28876f2134..6c344ed73f6 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -543,7 +543,7 @@ impl of writer for mem_buffer { fn flush() -> int { 0 } } -fn mk_mem_buffer() -> mem_buffer { +fn mem_buffer() -> mem_buffer { @{mutable buf: [mutable], mutable pos: 0u} } fn mem_buffer_writer(b: mem_buffer) -> writer { b as writer } @@ -554,14 +554,14 @@ fn mem_buffer_str(b: mem_buffer) -> str { } fn with_str_writer(f: fn(writer)) -> str { - let buf = mk_mem_buffer(); + let buf = mem_buffer(); let wr = mem_buffer_writer(buf); f(wr); io::mem_buffer_str(buf) } fn with_buf_writer(f: fn(writer)) -> [u8] { - let buf = mk_mem_buffer(); + let buf = mem_buffer(); let wr = mem_buffer_writer(buf); f(wr); io::mem_buffer_buf(buf) diff --git a/src/libcore/serialization.rs b/src/libcore/serialization.rs index 40e468a99db..187be90c4f5 100644 --- a/src/libcore/serialization.rs +++ b/src/libcore/serialization.rs @@ -96,7 +96,7 @@ fn emit_from_vec(s: S, v: [T], f: fn(T)) { fn read_to_vec(d: D, f: fn() -> T) -> [T] { d.read_vec {|len| - vec::init_fn(len) {|i| + vec::from_fn(len) {|i| d.read_vec_elt(i) {|| f() } } } diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 72ae981d36b..795da4d7026 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -31,6 +31,7 @@ export grow_fn; export grow_set; export map; export map2; +export flat_map; export filter_map; export filter; export concat; diff --git a/src/libstd/serialization.rs b/src/libstd/serialization.rs index fe70247e01b..c0f71d067c4 100644 --- a/src/libstd/serialization.rs +++ b/src/libstd/serialization.rs @@ -5,3 +5,8 @@ Deprecated in favor of core::serialization."]; use core; import list::list; import ebml::writer; + +import core::serialization::{serializer,deserializer}; + +export serializer; +export deserializer; diff --git a/src/libstd/test.rs b/src/libstd/test.rs index d28912bae12..828f0ca85d4 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -189,7 +189,7 @@ fn print_failures(st: console_test_state) { #[test] fn should_sort_failures_before_printing_them() { - let buffer = io::mk_mem_buffer(); + let buffer = io::mem_buffer(); let writer = io::mem_buffer_writer(buffer); let test_a = { diff --git a/src/rustc/metadata/astencode.rs b/src/rustc/metadata/astencode.rs index f09b4f902fd..4aea919c40f 100644 --- a/src/rustc/metadata/astencode.rs +++ b/src/rustc/metadata/astencode.rs @@ -948,7 +948,7 @@ fn mk_ctxt() -> fake_ext_ctxt { #[cfg(test)] fn roundtrip(in_item: @ast::item) { #debug["in_item = %s", pprust::item_to_str(in_item)]; - let mbuf = io::mk_mem_buffer(); + let mbuf = io::mem_buffer(); let ebml_w = ebml::writer(io::mem_buffer_writer(mbuf)); encode_item_ast(ebml_w, in_item); let ebml_doc = ebml::new_doc(@io::mem_buffer_buf(mbuf)); diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index 27492364866..7f1359aeadc 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -745,7 +745,7 @@ fn encode_metadata(cx: crate_ctxt, crate: @crate) -> [u8] { type_abbrevs: abbrevs, reachable: reachable}; - let buf = io::mk_mem_buffer(); + let buf = io::mem_buffer(); let buf_w = io::mem_buffer_writer(buf); let ebml_w = ebml::writer(buf_w); @@ -779,7 +779,7 @@ fn encode_metadata(cx: crate_ctxt, crate: @crate) -> [u8] { // Get the encoded string for a type fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> str { let cx = @{ds: def_to_str, tcx: tcx, abbrevs: tyencode::ac_no_abbrevs}; - let buf = io::mk_mem_buffer(); + let buf = io::mem_buffer(); tyencode::enc_ty(io::mem_buffer_writer(buf), cx, t); ret io::mem_buffer_str(buf); } diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index 81e9eff4a9d..4dd229c7dd2 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -40,7 +40,7 @@ fn enc_ty(w: io::writer, cx: @ctxt, t: ty::t) { let result_str = alt cx.tcx.short_names_cache.find(t) { some(s) { *s } none { - let buf = io::mk_mem_buffer(); + let buf = io::mem_buffer(); enc_sty(io::mem_buffer_writer(buf), cx, ty::get(t).struct); cx.tcx.short_names_cache.insert(t, @io::mem_buffer_str(buf)); io::mem_buffer_str(buf) diff --git a/src/rustc/syntax/ext/auto_serialize.rs b/src/rustc/syntax/ext/auto_serialize.rs index b06bf81e5a7..1b048c26240 100644 --- a/src/rustc/syntax/ext/auto_serialize.rs +++ b/src/rustc/syntax/ext/auto_serialize.rs @@ -87,10 +87,8 @@ import front::attr; export expand; -enum ser_cx = @{ - ext_cx: ext_ctxt, - tps: map::hashmap [@ast::stmt]> -}; +type ser_tps_map = map::hashmap [@ast::stmt]>; +type deser_tps_map = map::hashmap @ast::expr>; fn expand(cx: ext_ctxt, span: span, @@ -136,20 +134,10 @@ impl helpers for ext_ctxt { } fn ty_path(span: span, strs: [str]) -> @ast::ty { - @{node: ast::ty_path(self.path(span, strs), self.next_id()), + @{id: self.next_id(), + node: ast::ty_path(self.path(span, strs), self.next_id()), span: span} } -} - -impl helpers for ser_cx { - fn session() -> session { self.ext_cx.session() } - fn next_id() -> ast::node_id { self.ext_cx.next_id() } - fn path(span: span, strs: [str]) -> @ast::path { - self.ext_cx.path(span, strs) - } - fn ty_path(span: span, strs: [str]) -> @ast::ty { - self.ext_cx.ty_path(span, strs) - } fn ty_fn(span: span, -input_tys: [@ast::ty], @@ -161,7 +149,8 @@ impl helpers for ser_cx { id: self.next_id()} }; - @{node: ast::ty_fn(ast::proto_any, {inputs: args, + @{id: self.next_id(), + node: ast::ty_fn(ast::proto_any, {inputs: args, output: output, purity: ast::impure_fn, cf: ast::return_val, @@ -170,7 +159,7 @@ impl helpers for ser_cx { } fn ty_nil(span: span) -> @ast::ty { - @{node: ast::ty_nil, span: span} + @{id: self.next_id(), node: ast::ty_nil, span: span} } fn expr(span: span, node: ast::expr_) -> @ast::expr { @@ -190,6 +179,15 @@ impl helpers for ser_cx { span: span} } + fn expr_blk(expr: @ast::expr) -> ast::blk { + {node: {view_items: [], + stmts: [], + expr: some(expr), + id: self.next_id(), + rules: ast::default_blk}, + span: expr.span} + } + fn binder_pat(span: span, nm: str) -> @ast::pat { let path = @{node: {global: false, idents: [nm], @@ -231,30 +229,28 @@ impl helpers for ser_cx { fn lambda(blk: ast::blk) -> @ast::expr { let ext_cx = self; let blk_e = self.expr(blk.span, ast::expr_block(blk)); - #ast(expr){{|| $(blk_e) }} + #ast{ {|| $(blk_e) } } + } + + fn clone_folder() -> fold::ast_fold { + fold::make_fold({ + new_id: {|_id| self.next_id()} + with *fold::default_ast_fold() + }) } fn clone(v: @ast::expr) -> @ast::expr { - let fld = fold::make_fold({ - new_id: {|_id| self.next_id()} - with *fold::default_ast_fold() - }); + let fld = self.clone_folder(); fld.fold_expr(v) } fn clone_ty(v: @ast::ty) -> @ast::ty { - let fld = fold::make_fold({ - new_id: {|_id| self.next_id()} - with *fold::default_ast_fold() - }); + let fld = self.clone_folder(); fld.fold_ty(v) } fn clone_ty_param(v: ast::ty_param) -> ast::ty_param { - let fld = fold::make_fold({ - new_id: {|_id| self.next_id()} - with *fold::default_ast_fold() - }); + let fld = self.clone_folder(); fold::fold_ty_param(v, fld) } @@ -276,10 +272,10 @@ impl helpers for ser_cx { } } -fn serialize_path(cx: ser_cx, path: @ast::path, +fn ser_path(cx: ext_ctxt, tps: ser_tps_map, path: @ast::path, -s: @ast::expr, -v: @ast::expr) -> [@ast::stmt] { - let ext_cx = cx.ext_cx; + let ext_cx = cx; // required for #ast{} // We want to take a path like a::b::c<...> and generate a call // like a::b::c::serialize(s, ...), as described above. @@ -291,11 +287,10 @@ fn serialize_path(cx: ser_cx, path: @ast::path, cx.path(path.span, path.node.idents + ["serialize"]))); let ty_args = vec::map(path.node.types) {|ty| - let sv_stmts = serialize_ty(cx, ty, cx.clone(s), #ast(expr){__v}); + let sv_stmts = ser_ty(cx, tps, ty, cx.clone(s), #ast{ __v }); let sv = cx.expr(path.span, - ast::expr_block(cx.blk(path.span, - sv_stmts))); - cx.at(ty.span, #ast(expr){{|__v| $(sv)}}) + ast::expr_block(cx.blk(path.span, sv_stmts))); + cx.at(ty.span, #ast{ {|__v| $(sv)} }) }; [cx.stmt( @@ -304,25 +299,26 @@ fn serialize_path(cx: ser_cx, path: @ast::path, ast::expr_call(callee, [s, v] + ty_args, false)))] } -fn serialize_variant(cx: ser_cx, - tys: [@ast::ty], - span: span, - -s: @ast::expr, - pfn: fn([@ast::pat]) -> ast::pat_, - bodyfn: fn(-@ast::expr, ast::blk) -> @ast::expr, - argfn: fn(-@ast::expr, uint, ast::blk) -> @ast::expr) +fn ser_variant(cx: ext_ctxt, + tps: ser_tps_map, + tys: [@ast::ty], + span: span, + -s: @ast::expr, + pfn: fn([@ast::pat]) -> ast::pat_, + bodyfn: fn(-@ast::expr, ast::blk) -> @ast::expr, + argfn: fn(-@ast::expr, uint, ast::blk) -> @ast::expr) -> ast::arm { - let vnames = vec::init_fn(vec::len(tys)) {|i| #fmt["__v%u", i]}; - let pats = vec::init_fn(vec::len(tys)) {|i| + let vnames = vec::from_fn(vec::len(tys)) {|i| #fmt["__v%u", i]}; + let pats = vec::from_fn(vec::len(tys)) {|i| cx.binder_pat(tys[i].span, vnames[i]) }; let pat: @ast::pat = @{id: cx.next_id(), node: pfn(pats), span: span}; - let stmts = vec::init_fn(vec::len(tys)) {|i| + let stmts = vec::from_fn(vec::len(tys)) {|i| let v = cx.var_ref(span, vnames[i]); let arg_blk = cx.blk( span, - serialize_ty(cx, tys[i], cx.clone(s), v)); + ser_ty(cx, tps, tys[i], cx.clone(s), v)); cx.stmt(argfn(cx.clone(s), i, arg_blk)) }; @@ -332,29 +328,35 @@ fn serialize_variant(cx: ser_cx, {pats: [pat], guard: none, body: body} } -fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) +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))) +} + +fn ser_ty(cx: ext_ctxt, tps: ser_tps_map, + ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) -> [@ast::stmt] { - fn ty_lambda(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) - -> @ast::expr { - cx.lambda(cx.blk(ty.span, serialize_ty(cx, ty, s, v))) - } - - - let ext_cx = cx.ext_cx; + let ext_cx = cx; // required for #ast{} alt ty.node { - ast::ty_nil | ast::ty_bot { + ast::ty_nil { + [#ast[stmt]{$(s).emit_nil()}] + } + + ast::ty_bot { + cx.session().span_err( + ty.span, #fmt["Cannot serialize bottom type"]); [] } ast::ty_box(mt) { - let l = ty_lambda(cx, mt.ty, cx.clone(s), #ast(expr){*$(v)}); + let l = ser_lambda(cx, tps, mt.ty, cx.clone(s), #ast{ *$(v) }); [#ast(stmt){$(s).emit_box($(l));}] } ast::ty_uniq(mt) { - let l = ty_lambda(cx, mt.ty, cx.clone(s), #ast(expr){*$(v)}); + let l = ser_lambda(cx, tps, mt.ty, cx.clone(s), #ast{ *$(v) }); [#ast(stmt){$(s).emit_uniq($(l));}] } @@ -365,7 +367,7 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) } ast::ty_rec(flds) { - let fld_stmts = vec::init_fn(vec::len(flds)) {|fidx| + let fld_stmts = vec::from_fn(vec::len(flds)) {|fidx| let fld = flds[fidx]; let vf = cx.expr(fld.span, ast::expr_field(cx.clone(v), @@ -374,7 +376,7 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) let s = cx.clone(s); let f = cx.lit_str(fld.span, fld.node.ident); let i = cx.lit_uint(fld.span, fidx); - let l = ty_lambda(cx, fld.node.mt.ty, cx.clone(s), vf); + let l = ser_lambda(cx, tps, fld.node.mt.ty, cx.clone(s), vf); #ast(stmt){$(s).emit_rec_field($(f), $(i), $(l));} }; let fld_lambda = cx.lambda(cx.blk(ty.span, fld_stmts)); @@ -397,9 +399,9 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) // }; let arms = [ - serialize_variant( + ser_variant( - cx, tys, ty.span, s, + cx, tps, tys, ty.span, s, // Generate pattern (v1, v2, v3) {|pats| ast::pat_tup(pats)}, @@ -408,18 +410,14 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) {|-s, blk| let sz = cx.lit_uint(ty.span, vec::len(tys)); let body = cx.lambda(blk); - #ast[expr]{ - $(s).emit_tup($(sz), $(body)) - } + #ast{ $(s).emit_tup($(sz), $(body)) } }, // Generate s.emit_tup_elt(i, {|| blk }) {|-s, i, blk| let idx = cx.lit_uint(ty.span, i); let body = cx.lambda(blk); - #ast[expr]{ - $(s).emit_tup_elt($(idx), $(body)) - } + #ast{ $(s).emit_tup_elt($(idx), $(body)) } }) ]; [cx.alt_stmt(arms, ty.span, v)] @@ -430,17 +428,17 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) vec::is_empty(path.node.types) { let ident = path.node.idents[0]; - alt cx.tps.find(ident) { + alt tps.find(ident) { some(f) { f(v) } - none { serialize_path(cx, path, s, v) } + none { ser_path(cx, tps, path, s, v) } } } else { - serialize_path(cx, path, s, v) + ser_path(cx, tps, path, s, v) } } ast::ty_constr(ty, _) { - serialize_ty(cx, ty, s, v) + ser_ty(cx, tps, ty, s, v) } ast::ty_mac(_) { @@ -462,12 +460,10 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) ast::expr_block( cx.blk( ty.span, - serialize_ty( - cx, mt.ty, + ser_ty( + cx, tps, mt.ty, cx.clone(s), - cx.at( - ty.span, - #ast(expr){__e}))))); + cx.at(ty.span, #ast{ __e }))))); [#ast(stmt){ core::serialization::emit_from_vec($(s), $(v), {|__e| $(ser_e) }) @@ -476,12 +472,12 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) } } -fn mk_ser_fn(ext_cx: ext_ctxt, span: span, - v_ty: @ast::ty, tps: [ast::ty_param], - f: fn(ser_cx, @ast::ty, -@ast::expr, -@ast::expr) -> [@ast::stmt]) +fn mk_ser_fn(cx: ext_ctxt, span: span, + -v_ty: @ast::ty, tps: [ast::ty_param], + f: fn(ext_ctxt, ser_tps_map, @ast::ty, + -@ast::expr, -@ast::expr) -> [@ast::stmt]) -> @ast::item { - - let cx = ser_cx(@{ext_cx: ext_cx, tps: map::new_str_hash()}); + let ext_cx = cx; // required for #ast let tp_inputs = vec::map(tps, {|tp| @@ -500,14 +496,15 @@ fn mk_ser_fn(ext_cx: ext_ctxt, span: span, ident: "__s", id: cx.next_id()}, {mode: ast::expl(ast::by_ref), - ty: cx.clone_ty(v_ty), + ty: v_ty, ident: "__v", id: cx.next_id()}] + tp_inputs; + let tps_map = map::new_str_hash(); vec::iter2(tps, tp_inputs) {|tp, arg| let arg_ident = arg.ident; - cx.tps.insert( + tps_map.insert( tp.ident, fn@(v: @ast::expr) -> [@ast::stmt] { let f = cx.var_ref(span, arg_ident); @@ -526,11 +523,12 @@ fn mk_ser_fn(ext_cx: ext_ctxt, span: span, bounds: ser_bnds}] + vec::map(tps) {|tp| cx.clone_ty_param(tp) }; - let ser_output: @ast::ty = @{node: ast::ty_nil, + let ser_output: @ast::ty = @{id: cx.next_id(), + node: ast::ty_nil, span: span}; let ser_blk = cx.blk(span, - f(cx, v_ty, #ast(expr){__s}, #ast(expr){__v})); + f(cx, tps_map, v_ty, #ast{ __s }, #ast{ __v })); @{ident: "serialize", attrs: [], @@ -545,77 +543,314 @@ fn mk_ser_fn(ext_cx: ext_ctxt, span: span, span: span} } -fn ty_module(ext_cx: ext_ctxt, name: str, ty: @ast::ty, tps: [ast::ty_param]) +// ______________________________________________________________________ + +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( + cx.path(path.span, path.node.idents + ["deserialize"]))); + + let ty_args = vec::map(path.node.types) {|ty| + let dv_expr = deser_ty(cx, tps, ty, cx.clone(d)); + cx.lambda(cx.expr_blk(dv_expr)) + }; + + cx.expr(path.span, ast::expr_call(callee, [d] + ty_args, false)) +} + +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, _) { + if vec::len(path.node.idents) == 1u && + vec::is_empty(path.node.types) { + let ident = path.node.idents[0]; + + alt tps.find(ident) { + 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 } + } + + ast::ty_vec(mt) { + let l = deser_lambda(cx, tps, mt.ty, cx.clone(d)); + #ast{ core::serialization::read_to_vec($(d), $(l)) } + } + } +} + +fn mk_deser_fn(cx: ext_ctxt, span: span, + -v_ty: @ast::ty, tps: [ast::ty_param], + f: fn(ext_ctxt, deser_tps_map, + @ast::ty, -@ast::expr) -> @ast::expr) + -> @ast::item { + let ext_cx = cx; // required for #ast + + let tp_inputs = + vec::map(tps, {|tp| + {mode: ast::expl(ast::by_ref), + ty: cx.ty_fn(span, + [], + cx.ty_path(span, [tp.ident])), + ident: "__d" + tp.ident, + id: cx.next_id()}}); + + #debug["tp_inputs = %?", tp_inputs]; + + let deser_inputs: [ast::arg] = + [{mode: ast::expl(ast::by_ref), + ty: cx.ty_path(span, ["__D"]), + ident: "__d", + id: cx.next_id()}] + + tp_inputs; + + let tps_map = map::new_str_hash(); + vec::iter2(tps, tp_inputs) {|tp, arg| + let arg_ident = arg.ident; + tps_map.insert( + tp.ident, + fn@() -> @ast::expr { + let f = cx.var_ref(span, arg_ident); + #ast{ $(f)() } + }); + } + + let deser_bnds = @[ast::bound_iface(cx.ty_path(span, + ["serialization", + "deserializer"]))]; + + let deser_tps: [ast::ty_param] = + [{ident: "__D", + id: cx.next_id(), + bounds: deser_bnds}] + + vec::map(tps) {|tp| cx.clone_ty_param(tp) }; + + let deser_blk = cx.expr_blk(f(cx, tps_map, v_ty, #ast(expr){__d})); + + @{ident: "deserialize", + attrs: [], + id: cx.next_id(), + node: ast::item_fn({inputs: deser_inputs, + output: v_ty, + purity: ast::impure_fn, + cf: ast::return_val, + constraints: []}, + deser_tps, + deser_blk), + span: span} +} + +fn ty_module(cx: ext_ctxt, name: str, ty: @ast::ty, tps: [ast::ty_param]) -> @ast::item { let span = ty.span; - let ser_fn = mk_ser_fn(ext_cx, span, ty, tps, serialize_ty); + let ser_fn = mk_ser_fn(cx, span, cx.clone_ty(ty), tps, ser_ty); + let deser_fn = mk_deser_fn(cx, span, cx.clone_ty(ty), tps, deser_ty); // Return a module containing the serialization and deserialization // functions: @{ident: name, attrs: [], - id: ext_cx.session().next_node_id(), + id: cx.next_id(), node: ast::item_mod({view_items: [], - items: [ser_fn]}), + items: [ser_fn, deser_fn]}), span: span} } -fn enum_module(ext_cx: ext_ctxt, name: str, span: span, - variants: [ast::variant], tps: [ast::ty_param]) - -> @ast::item { +fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: str, + e_span: span, variants: [ast::variant], + _ty: @ast::ty, -s: @ast::expr, -v: @ast::expr) -> [@ast::stmt] { + 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 }; - let ty = ext_cx.ty_path(span, [name]); - let ser_fn = mk_ser_fn(ext_cx, span, ty, tps) {|cx, _ty, s, v| - let arms = vec::init_fn( - vec::len(variants), - fn&(vidx: uint) -> ast::arm { - let variant = variants[vidx]; - let span = variant.span; - let 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), - serialize_variant( - cx, variant_tys, span, cx.clone(s), + // Generate pattern var(v1, v2, v3) + {|pats| + if vec::is_empty(pats) { + ast::pat_ident(cx.path(v_span, [v_name]), none) + } else { + ast::pat_enum(cx.path(v_span, [v_name]), pats) + } + }, - // Generate pattern var(v1, v2, v3) - {|pats| - if vec::is_empty(pats) { - ast::pat_ident(cx.path(span, [name]), none) - } else { - ast::pat_enum(cx.path(span, [name]), pats) - } - }, + // 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 body s.emit_enum_variant("foo", 0u, - // 3u, {|| blk }) - {|-s, blk| - let v_name = cx.lit_str(span, name); - let v_id = cx.lit_uint(span, vidx); - let sz = cx.lit_uint(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)) + } + }) + }; + let lam = cx.lambda(cx.blk(e_span, [cx.alt_stmt(arms, e_span, v)])); + let e_name = cx.lit_str(e_span, e_name); + [#ast(stmt){ $(s).emit_enum($(e_name), $(lam)) }] +} - // Generate s.emit_enum_variant_arg(i, {|| blk }) - {|-s, i, blk| - let idx = cx.lit_uint(span, i); - let body = cx.lambda(blk); - #ast[expr]{ - $(s).emit_enum_variant_arg($(idx), $(body)) - } - }) - }); - [cx.alt_stmt(arms, span, v)] +fn deser_enum(cx: ext_ctxt, tps: deser_tps_map, e_name: str, + e_span: span, variants: [ast::variant], + _ty: @ast::ty, -d: @ast::expr) -> @ast::expr { + let ext_cx = cx; + let arms: [ast::arm] = vec::from_fn(vec::len(variants)) {|vidx| + 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)) } + }; + + let body = + cx.expr(v_span, ast::expr_call( + cx.var_ref(v_span, v_name), arg_exprs, false)); + + {pats: [@{id: cx.next_id(), + node: ast::pat_lit(cx.lit_uint(v_span, vidx)), + span: v_span}], + guard: none, + body: cx.expr_blk(body)} }; - @{ident: name, - attrs: [], - id: ext_cx.session().next_node_id(), - node: ast::item_mod({view_items: [], - items: [ser_fn]}), - span: span} + // 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)) } +} + +fn enum_module(cx: ext_ctxt, e_name: str, e_span: span, + variants: [ast::variant], tps: [ast::ty_param]) + -> @ast::item { + let ty = cx.ty_path(e_span, [e_name]); + let ser_fn = + mk_ser_fn(cx, e_span, cx.clone_ty(ty), tps, + ser_enum(_, _, e_name, e_span, variants, _, _, _)); + let deser_fn = + mk_deser_fn(cx, e_span, ty, tps, + deser_enum(_, _, e_name, e_span, variants, _, _)); + + @{ident: e_name, + attrs: [], + id: cx.next_id(), + node: ast::item_mod({view_items: [], + items: [ser_fn, deser_fn]}), + span: e_span} } diff --git a/src/rustc/syntax/print/pprust.rs b/src/rustc/syntax/print/pprust.rs index ec592cda700..34d6d09b5ad 100644 --- a/src/rustc/syntax/print/pprust.rs +++ b/src/rustc/syntax/print/pprust.rs @@ -99,7 +99,7 @@ fn path_to_str(&&p: @ast::path) -> str { fn fun_to_str(decl: ast::fn_decl, name: ast::ident, params: [ast::ty_param]) -> str { - let buffer = io::mk_mem_buffer(); + let buffer = io::mem_buffer(); let s = rust_printer(io::mem_buffer_writer(buffer)); print_fn(s, decl, name, params); end(s); // Close the head box @@ -124,7 +124,7 @@ fn test_fun_to_str() { fn res_to_str(decl: ast::fn_decl, name: ast::ident, params: [ast::ty_param]) -> str { - let buffer = io::mk_mem_buffer(); + let buffer = io::mem_buffer(); let s = rust_printer(io::mem_buffer_writer(buffer)); print_res(s, decl, name, params); end(s); // Close the head box @@ -155,7 +155,7 @@ fn test_res_to_str() { } fn block_to_str(blk: ast::blk) -> str { - let buffer = io::mk_mem_buffer(); + let buffer = io::mem_buffer(); let s = rust_printer(io::mem_buffer_writer(buffer)); // containing cbox, will be closed by print-block at } cbox(s, indent_unit); @@ -1700,7 +1700,7 @@ fn escape_str(st: str, to_escape: char) -> str { } fn to_str(t: T, f: fn@(ps, T)) -> str { - let buffer = io::mk_mem_buffer(); + let buffer = io::mem_buffer(); let s = rust_printer(io::mem_buffer_writer(buffer)); f(s, t); eof(s.s); diff --git a/src/test/auxiliary/auto_serialize_lib.rs b/src/test/auxiliary/auto_serialize_lib.rs new file mode 100644 index 00000000000..419985ef731 --- /dev/null +++ b/src/test/auxiliary/auto_serialize_lib.rs @@ -0,0 +1,32 @@ +#[link(name="auto_serialize_lib", vers="0.0")]; + +use std; +import std::ebml; +import io::writer; + +fn test_ser_and_deser(a1: A, + expected: str, + ebml_ser_fn: fn(ebml::writer, A), + ebml_deser_fn: fn(ebml::ebml_deserializer) -> A, + io_ser_fn: fn(io::writer, A)) { + + // check the pretty printer: + io_ser_fn(io::stdout(), a1); + let s = io::with_str_writer {|w| io_ser_fn(w, a1) }; + #debug["s == %?", s]; + assert s == expected; + + // check the EBML serializer: + let buf = io::mem_buffer(); + let w = ebml::writer(buf as io::writer); + ebml_ser_fn(w, a1); + let d = ebml::new_doc(@io::mem_buffer_buf(buf)); + let a2 = ebml_deser_fn(ebml::ebml_deserializer(d)); + io::print("\na1 = "); + io_ser_fn(io::stdout(), a1); + io::print("\na2 = "); + io_ser_fn(io::stdout(), a2); + io::print("\n"); + assert a1 == a2; + +} diff --git a/src/test/auxiliary/cci_impl_lib.rs b/src/test/auxiliary/cci_impl_lib.rs index 47fa5a11bdf..6e58c4cecee 100644 --- a/src/test/auxiliary/cci_impl_lib.rs +++ b/src/test/auxiliary/cci_impl_lib.rs @@ -1,3 +1,5 @@ +#[link(name="cci_impl_lib", vers="0.0")]; + impl helpers for uint { #[inline] fn to(v: uint, f: fn(uint)) { diff --git a/src/test/auxiliary/cci_iter_lib.rs b/src/test/auxiliary/cci_iter_lib.rs index 9c7c1d09b2b..668030087bd 100644 --- a/src/test/auxiliary/cci_iter_lib.rs +++ b/src/test/auxiliary/cci_iter_lib.rs @@ -1,3 +1,5 @@ +#[link(name="cci_iter_lib", vers="0.0")]; + #[inline] fn iter(v: [T], f: fn(T)) { let i = 0u; diff --git a/src/test/auxiliary/cci_no_inline_lib.rs b/src/test/auxiliary/cci_no_inline_lib.rs index ff6b923035d..2755fdfa6cf 100644 --- a/src/test/auxiliary/cci_no_inline_lib.rs +++ b/src/test/auxiliary/cci_no_inline_lib.rs @@ -1,3 +1,5 @@ +#[link(name="cci_no_inline_lib", vers="0.0")]; + // same as cci_iter_lib, more-or-less, but not marked inline fn iter(v: [uint], f: fn(uint)) { let i = 0u; diff --git a/src/test/auxiliary/native_lib.rs b/src/test/auxiliary/native_lib.rs index 56d5f7f052a..35a1f613058 100644 --- a/src/test/auxiliary/native_lib.rs +++ b/src/test/auxiliary/native_lib.rs @@ -1,3 +1,5 @@ +#[link(name="native_lib", vers="0.0")]; + native mod rustrt { fn last_os_error() -> str; } \ No newline at end of file diff --git a/src/test/run-pass/auto_serialize_enum.rs b/src/test/run-pass/auto_serialize_enum.rs index 19861d0fff6..8bb9e02e0f2 100644 --- a/src/test/run-pass/auto_serialize_enum.rs +++ b/src/test/run-pass/auto_serialize_enum.rs @@ -1,6 +1,12 @@ +// aux-build:auto_serialize_lib.rs +// xfail-fast:aux-build currently incompatible + use std; +use auto_serialize_lib; import std::prettyprint::serializer; -import std::io; +import std::ebml::serializer; +import std::ebml::deserializer; +import auto_serialize_lib::*; #[auto_serialize] enum expr { @@ -10,10 +16,11 @@ enum expr { } fn main() { - let ex = @plus(@minus(@val(3u), @val(10u)), - @plus(@val(22u), @val(5u))); - let s = io::with_str_writer {|w| expr::serialize(w, *ex)}; - #debug["s == %?", s]; - assert s == "plus(@minus(@val(3u), @val(10u)), \ - @plus(@val(22u), @val(5u)))"; + test_ser_and_deser(plus(@minus(@val(3u), @val(10u)), + @plus(@val(22u), @val(5u))), + "plus(@minus(@val(3u), @val(10u)), \ + @plus(@val(22u), @val(5u)))", + expr::serialize(_, _), + expr::deserialize(_), + expr::serialize(_, _)); } \ No newline at end of file diff --git a/src/test/run-pass/auto_serialize_gen.rs b/src/test/run-pass/auto_serialize_gen.rs index 21155e509f5..b4cf5417b3b 100644 --- a/src/test/run-pass/auto_serialize_gen.rs +++ b/src/test/run-pass/auto_serialize_gen.rs @@ -1,6 +1,12 @@ +// aux-build:auto_serialize_lib.rs +// xfail-fast:aux-build currently incompatible + use std; +use auto_serialize_lib; import std::prettyprint::serializer; -import std::io; +import std::ebml::serializer; +import std::ebml::deserializer; +import auto_serialize_lib::*; // Test where we link various types used by name. @@ -11,9 +17,9 @@ type spanned = {lo: uint, hi: uint, node: T}; type spanned_uint = spanned; fn main() { - let x: spanned_uint = {lo: 0u, hi: 5u, node: 22u}; - spanned_uint::serialize(io::stdout(), x); - let s = io::with_str_writer {|w| spanned_uint::serialize(w, x)}; - #debug["s == %?", s]; - assert s == "{lo: 0u, hi: 5u, node: 22u}"; + test_ser_and_deser({lo: 0u, hi: 5u, node: 22u}, + "{lo: 0u, hi: 5u, node: 22u}", + spanned_uint::serialize(_, _), + spanned_uint::deserialize(_), + spanned_uint::serialize(_, _)); } \ No newline at end of file diff --git a/src/test/run-pass/auto_serialize_link.rs b/src/test/run-pass/auto_serialize_link.rs index b146b956e8e..5f3cd8f7aa6 100644 --- a/src/test/run-pass/auto_serialize_link.rs +++ b/src/test/run-pass/auto_serialize_link.rs @@ -1,6 +1,12 @@ +// aux-build:auto_serialize_lib.rs +// xfail-fast:aux-build currently incompatible + use std; +use auto_serialize_lib; import std::prettyprint::serializer; -import std::io; +import std::ebml::serializer; +import std::ebml::deserializer; +import auto_serialize_lib::*; // Test where we link various types used by name. @@ -14,9 +20,9 @@ type some_rec = {v: uint_vec}; enum an_enum = some_rec; fn main() { - let x = an_enum({v: [1u, 2u, 3u]}); - an_enum::serialize(io::stdout(), x); - let s = io::with_str_writer {|w| an_enum::serialize(w, x)}; - #debug["s == %?", s]; - assert s == "an_enum({v: [1u, 2u, 3u]})"; + test_ser_and_deser(an_enum({v: [1u, 2u, 3u]}), + "an_enum({v: [1u, 2u, 3u]})", + an_enum::serialize(_, _), + an_enum::deserialize(_), + an_enum::serialize(_, _)); } \ No newline at end of file diff --git a/src/test/run-pass/auto_serialize_rec.rs b/src/test/run-pass/auto_serialize_rec.rs index d1043c8278d..a16396ce3d0 100644 --- a/src/test/run-pass/auto_serialize_rec.rs +++ b/src/test/run-pass/auto_serialize_rec.rs @@ -1,12 +1,20 @@ +// aux-build:auto_serialize_lib.rs +// xfail-fast:aux-build currently incompatible + use std; +use auto_serialize_lib; import std::prettyprint::serializer; -import std::io; +import std::ebml::serializer; +import std::ebml::deserializer; +import auto_serialize_lib::*; #[auto_serialize] type point = {x: uint, y: uint}; fn main() { - let s = io::with_str_writer {|w| point::serialize(w, {x: 3u, y: 5u}) }; - #debug["s == %?", s]; - assert s == "{x: 3u, y: 5u}"; + test_ser_and_deser({x: 3u, y: 5u}, + "{x: 3u, y: 5u}", + point::serialize(_, _), + point::deserialize(_), + point::serialize(_, _)); } \ No newline at end of file diff --git a/src/test/run-pass/auto_serialize_vec.rs b/src/test/run-pass/auto_serialize_vec.rs index 103340b7b2a..24fa76d5316 100644 --- a/src/test/run-pass/auto_serialize_vec.rs +++ b/src/test/run-pass/auto_serialize_vec.rs @@ -1,13 +1,20 @@ +// aux-build:auto_serialize_lib.rs +// xfail-fast:aux-build currently incompatible + use std; +use auto_serialize_lib; import std::prettyprint::serializer; -import std::io; +import std::ebml::serializer; +import std::ebml::deserializer; +import auto_serialize_lib::*; #[auto_serialize] type uint_vec = [uint]; fn main() { - let ex = [1u, 2u, 3u]; - let s = io::with_str_writer {|w| uint_vec::serialize(w, ex)}; - #debug["s == %?", s]; - assert s == "[1u, 2u, 3u]"; + test_ser_and_deser([1u, 2u, 3u], + "[1u, 2u, 3u]", + uint_vec::serialize(_, _), + uint_vec::deserialize(_), + uint_vec::serialize(_, _)); } \ No newline at end of file diff --git a/src/test/run-pass/qquote.rs b/src/test/run-pass/qquote.rs index 8bb722706a1..74624781a30 100644 --- a/src/test/run-pass/qquote.rs +++ b/src/test/run-pass/qquote.rs @@ -100,7 +100,7 @@ fn main() { } fn check_pp(expr: T, f: fn(pprust::ps, T), expect: str) { - let buf = mk_mem_buffer(); + let buf = mem_buffer(); let pp = pprust::rust_printer(buf as io::writer); f(pp, expr); pp::eof(pp.s);