first (functional) version of the auto_serialize syntax ext

This commit is contained in:
Niko Matsakis 2012-03-12 10:19:35 -07:00
parent 06c8acdd31
commit d91742294f
19 changed files with 851 additions and 536 deletions

View File

@ -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, io, run, rand, sys, unsafe, logging;
export libc, os, ctypes, io, run, rand, sys, unsafe, logging, serialization;
export comm, task, future;
export extfmt;
export tuple;
@ -88,6 +88,7 @@ mod cmath;
mod sys;
mod unsafe;
mod logging;
mod serialization;
// Concurrency
mod comm;

View File

@ -0,0 +1,116 @@
export serializer;
export serializer_helpers;
export deserializer;
export deserializer_helpers;
/*
Core serialization interfaces.
*/
iface serializer {
// Primitive types:
fn emit_nil();
fn emit_uint(v: uint);
fn emit_u64(v: u64);
fn emit_u32(v: u32);
fn emit_u16(v: u16);
fn emit_u8(v: u8);
fn emit_int(v: int);
fn emit_i64(v: i64);
fn emit_i32(v: i32);
fn emit_i16(v: i16);
fn emit_i8(v: i8);
fn emit_bool(v: bool);
fn emit_float(v: float);
fn emit_f64(v: f64);
fn emit_f32(v: f32);
fn emit_str(v: str);
// Compound types:
fn emit_enum(name: str, f: fn());
fn emit_enum_variant(v_name: str, v_id: uint, sz: uint, f: fn());
fn emit_enum_variant_arg(idx: uint, f: fn());
fn emit_vec(len: uint, f: fn());
fn emit_vec_elt(idx: uint, f: fn());
fn emit_box(f: fn());
fn emit_uniq(f: fn());
fn emit_rec(f: fn());
fn emit_rec_field(f_name: str, f_idx: uint, f: fn());
fn emit_tup(sz: uint, f: fn());
fn emit_tup_elt(idx: uint, f: fn());
}
iface deserializer {
// Primitive types:
fn read_nil() -> ();
fn read_uint() -> uint;
fn read_u64() -> u64;
fn read_u32() -> u32;
fn read_u16() -> u16;
fn read_u8() -> u8;
fn read_int() -> int;
fn read_i64() -> i64;
fn read_i32() -> i32;
fn read_i16() -> i16;
fn read_i8() -> i8;
fn read_bool() -> bool;
fn read_str() -> str;
fn read_f64() -> f64;
fn read_f32() -> f32;
fn read_float() -> float;
// Compound types:
fn read_enum<T:copy>(name: str, f: fn() -> T) -> T;
fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T;
fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T;
fn read_vec<T:copy>(f: fn(uint) -> T) -> T;
fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
fn read_box<T:copy>(f: fn() -> T) -> T;
fn read_uniq<T:copy>(f: fn() -> T) -> T;
fn read_rec<T:copy>(f: fn() -> T) -> T;
fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T;
fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T;
fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
}
// ___________________________________________________________________________
// Helper routines
//
// These should eventually be coded as traits.
fn emit_from_vec<S: serializer, T>(s: S, v: [T], f: fn(T)) {
s.emit_vec(vec::len(v)) {||
vec::iteri(v) {|i,e|
s.emit_vec_elt(i) {||
f(e)
}
}
}
}
fn read_to_vec<D: deserializer, T>(d: D, f: fn() -> T) -> [T] {
d.read_vec {|len|
vec::init_fn(len) {|i|
d.read_vec_elt(i) {|| f() }
}
}
}
impl serializer_helpers<S: serializer> for S {
fn emit_from_vec<T>(v: [T], f: fn(T)) {
emit_from_vec(self, v, f)
}
}
impl deserializer_helpers<D: deserializer> for D {
fn read_to_vec<T>(f: fn() -> T) -> [T] {
read_to_vec(self, f)
}
}

View File

@ -192,6 +192,14 @@ fn compl(i: uint) -> uint {
max_value ^ i
}
fn serialize<S: serialization::serializer>(s: S, v: uint) {
s.emit_uint(v);
}
fn deserialize<D: serialization::deserializer>(d: D) -> uint {
d.read_uint()
}
#[cfg(test)]
mod tests {

View File

@ -406,7 +406,7 @@ fn map<T, U>(v: [T], f: fn(T) -> U) -> [U] {
}
fn flat_map<T, U>(v: [T], f: fn(T) -> [U]) -> [U] {
let result = [];
let mut result = [];
for elem: T in v { result += f(elem); }
ret result;
}

View File

@ -25,6 +25,9 @@ export doc_as_i16;
export doc_as_i32;
export doc_as_i64;
export writer;
export serializer;
export ebml_deserializer;
export deserializer;
type ebml_tag = {id: uint, size: uint};
@ -273,3 +276,314 @@ impl writer for writer {
// TODO: optionally perform "relaxations" on end_tag to more efficiently
// encode sizes; this is a fixed point iteration
// Set to true to generate more debugging in EBML serialization.
// Totally lame approach.
const debug: bool = true;
enum ebml_serializer_tag {
es_uint, es_u64, es_u32, es_u16, es_u8,
es_int, es_i64, es_i32, es_i16, es_i8,
es_bool,
es_str,
es_f64, es_f32, es_float,
es_enum, es_enum_vid, es_enum_body,
es_vec, es_vec_len, es_vec_elt,
es_label // Used only when debugging
}
impl serializer of core::serialization::serializer for ebml::writer {
fn emit_nil() {}
// used internally to emit things like the vector length and so on
fn _emit_tagged_uint(t: ebml_serializer_tag, v: uint) {
assert v <= 0xFFFF_FFFF_u;
self.wr_tagged_u32(t as uint, v as u32);
}
fn _emit_label(label: str) {
// There are various strings that we have access to, such as
// the name of a record field, which do not actually appear in
// the serialized EBML (normally). This is just for
// efficiency. When debugging, though, we can emit such
// labels and then they will be checked by deserializer to
// try and check failures more quickly.
if debug { self.wr_tagged_str(es_label as uint, label) }
}
fn emit_uint(v: uint) { self.wr_tagged_u64(es_uint as uint, v as u64); }
fn emit_u64(v: u64) { self.wr_tagged_u64(es_u64 as uint, v); }
fn emit_u32(v: u32) { self.wr_tagged_u32(es_u32 as uint, v); }
fn emit_u16(v: u16) { self.wr_tagged_u16(es_u16 as uint, v); }
fn emit_u8(v: u8) { self.wr_tagged_u8 (es_u8 as uint, v); }
fn emit_int(v: int) { self.wr_tagged_i64(es_int as uint, v as i64); }
fn emit_i64(v: i64) { self.wr_tagged_i64(es_i64 as uint, v); }
fn emit_i32(v: i32) { self.wr_tagged_i32(es_i32 as uint, v); }
fn emit_i16(v: i16) { self.wr_tagged_i16(es_i16 as uint, v); }
fn emit_i8(v: i8) { self.wr_tagged_i8 (es_i8 as uint, v); }
fn emit_bool(v: bool) { self.wr_tagged_u8(es_bool as uint, v as u8) }
fn emit_f64(_v: f64) { fail "TODO"; }
fn emit_f32(_v: f32) { fail "TODO"; }
fn emit_float(_v: float) { fail "TODO"; }
fn emit_str(v: str) { self.wr_tagged_str(es_str as uint, v) }
fn emit_enum(name: str, f: fn()) {
self._emit_label(name);
self.wr_tag(es_enum as uint, f)
}
fn emit_enum_variant(_v_name: str, v_id: uint, _cnt: uint, f: fn()) {
self._emit_tagged_uint(es_enum_vid, v_id);
self.wr_tag(es_enum_body as uint, f)
}
fn emit_enum_variant_arg(_idx: uint, f: fn()) { f() }
fn emit_vec(len: uint, f: fn()) {
self.wr_tag(es_vec as uint) {||
self._emit_tagged_uint(es_vec_len, len);
f()
}
}
fn emit_vec_elt(_idx: uint, f: fn()) {
self.wr_tag(es_vec_elt as uint, f)
}
fn emit_box(f: fn()) { f() }
fn emit_uniq(f: fn()) { f() }
fn emit_rec(f: fn()) { f() }
fn emit_rec_field(f_name: str, _f_idx: uint, f: fn()) {
self._emit_label(f_name);
f()
}
fn emit_tup(_sz: uint, f: fn()) { f() }
fn emit_tup_elt(_idx: uint, f: fn()) { f() }
}
type ebml_deserializer = {mutable parent: ebml::doc,
mutable pos: uint};
fn ebml_deserializer(d: ebml::doc) -> ebml_deserializer {
{mutable parent: d, mutable pos: d.start}
}
impl deserializer of core::serialization::deserializer for ebml_deserializer {
fn _check_label(lbl: str) {
if self.pos < self.parent.end {
let {tag: r_tag, doc: r_doc} =
ebml::doc_at(self.parent.data, self.pos);
if r_tag == (es_label as uint) {
self.pos = r_doc.end;
let str = ebml::doc_as_str(r_doc);
if lbl != str {
fail #fmt["Expected label %s but found %s", lbl, str];
}
}
}
}
fn next_doc(exp_tag: ebml_serializer_tag) -> ebml::doc {
#debug[". next_doc(exp_tag=%?)", exp_tag];
if self.pos >= self.parent.end {
fail "no more documents in current node!";
}
let {tag: r_tag, doc: r_doc} =
ebml::doc_at(self.parent.data, self.pos);
#debug["self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?",
self.parent.start, self.parent.end, self.pos,
r_tag, r_doc.start, r_doc.end];
if r_tag != (exp_tag as uint) {
fail #fmt["expected EMBL doc with tag %? but found tag %?",
exp_tag, r_tag];
}
if r_doc.end > self.parent.end {
fail #fmt["invalid EBML, child extends to 0x%x, parent to 0x%x",
r_doc.end, self.parent.end];
}
self.pos = r_doc.end;
ret r_doc;
}
fn push_doc<T: copy>(d: ebml::doc, f: fn() -> T) -> T{
let old_parent = self.parent;
let old_pos = self.pos;
self.parent = d;
self.pos = d.start;
let r = f();
self.parent = old_parent;
self.pos = old_pos;
ret r;
}
fn _next_uint(exp_tag: ebml_serializer_tag) -> uint {
let r = ebml::doc_as_u32(self.next_doc(exp_tag));
#debug["_next_uint exp_tag=%? result=%?", exp_tag, r];
ret r as uint;
}
fn read_nil() -> () { () }
fn read_u64() -> u64 { ebml::doc_as_u64(self.next_doc(es_u64)) }
fn read_u32() -> u32 { ebml::doc_as_u32(self.next_doc(es_u32)) }
fn read_u16() -> u16 { ebml::doc_as_u16(self.next_doc(es_u16)) }
fn read_u8 () -> u8 { ebml::doc_as_u8 (self.next_doc(es_u8 )) }
fn read_uint() -> uint {
let v = ebml::doc_as_u64(self.next_doc(es_uint));
if v > (core::uint::max_value as u64) {
fail #fmt["uint %? too large for this architecture", v];
}
ret v as uint;
}
fn read_i64() -> i64 { ebml::doc_as_u64(self.next_doc(es_i64)) as i64 }
fn read_i32() -> i32 { ebml::doc_as_u32(self.next_doc(es_i32)) as i32 }
fn read_i16() -> i16 { ebml::doc_as_u16(self.next_doc(es_i16)) as i16 }
fn read_i8 () -> i8 { ebml::doc_as_u8 (self.next_doc(es_i8 )) as i8 }
fn read_int() -> int {
let v = ebml::doc_as_u64(self.next_doc(es_int)) as i64;
if v > (int::max_value as i64) || v < (int::min_value as i64) {
fail #fmt["int %? out of range for this architecture", v];
}
ret v as int;
}
fn read_bool() -> bool { ebml::doc_as_u8(self.next_doc(es_bool)) as bool }
fn read_f64() -> f64 { fail "read_f64()"; }
fn read_f32() -> f32 { fail "read_f32()"; }
fn read_float() -> float { fail "read_float()"; }
fn read_str() -> str { ebml::doc_as_str(self.next_doc(es_str)) }
// Compound types:
fn read_enum<T:copy>(name: str, f: fn() -> T) -> T {
#debug["read_enum(%s)", name];
self._check_label(name);
self.push_doc(self.next_doc(es_enum), f)
}
fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T {
#debug["read_enum_variant()"];
let idx = self._next_uint(es_enum_vid);
#debug[" idx=%u", idx];
self.push_doc(self.next_doc(es_enum_body)) {||
f(idx)
}
}
fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T {
#debug["read_enum_variant_arg(idx=%u)", idx];
f()
}
fn read_vec<T:copy>(f: fn(uint) -> T) -> T {
#debug["read_vec()"];
self.push_doc(self.next_doc(es_vec)) {||
let len = self._next_uint(es_vec_len);
#debug[" len=%u", len];
f(len)
}
}
fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
#debug["read_vec_elt(idx=%u)", idx];
self.push_doc(self.next_doc(es_vec_elt), f)
}
fn read_box<T:copy>(f: fn() -> T) -> T {
#debug["read_box()"];
f()
}
fn read_uniq<T:copy>(f: fn() -> T) -> T {
#debug["read_uniq()"];
f()
}
fn read_rec<T:copy>(f: fn() -> T) -> T {
#debug["read_rec()"];
f()
}
fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T {
#debug["read_rec_field(%s, idx=%u)", f_name, f_idx];
self._check_label(f_name);
f()
}
fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T {
#debug["read_tup(sz=%u)", sz];
f()
}
fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
#debug["read_tup_elt(idx=%u)", idx];
f()
}
}
// ___________________________________________________________________________
// Testing
#[test]
fn test_option_int() {
fn serialize_1<S: serialization::serializer>(s: S, v: int) {
s.emit_i64(v as i64);
}
fn serialize_0<S: serialization::serializer>(s: S, v: option<int>) {
s.emit_enum("core::option::t") {||
alt v {
none {
s.emit_enum_variant("core::option::none", 0u, 0u) {||}
}
some(v0) {
s.emit_enum_variant("core::option::some", 1u, 1u) {||
s.emit_enum_variant_arg(0u) {|| serialize_1(s, v0) }
}
}
}
}
}
fn deserialize_1<S: serialization::deserializer>(s: S) -> int {
s.read_i64() as int
}
fn deserialize_0<S: serialization::deserializer>(s: S) -> option<int> {
s.read_enum("core::option::t") {||
s.read_enum_variant {|i|
alt check i {
0u { none }
1u {
let v0 = s.read_enum_variant_arg(0u) {||
deserialize_1(s)
};
some(v0)
}
}
}
}
}
fn test_v(v: option<int>) {
#debug["v == %?", v];
let mbuf = io::mem_buffer();
let ebml_w = ebml::writer(io::mem_buffer_writer(mbuf));
serialize_0(ebml_w, v);
let ebml_doc = ebml::new_doc(@io::mem_buffer_buf(mbuf));
let deser = ebml_deserializer(ebml_doc);
let v1 = deserialize_0(deser);
#debug["v1 == %?", v1];
assert v == v1;
}
test_v(some(22));
test_v(none);
test_v(some(3));
}

130
src/libstd/prettyprint.rs Normal file
View File

@ -0,0 +1,130 @@
import io::writer;
import io::writer_util;
import serialization::serializer;
impl of serializer for writer {
fn emit_nil() {
self.write_str("()")
}
fn emit_uint(v: uint) {
self.write_str(#fmt["%?u", v]);
}
fn emit_u64(v: u64) {
self.write_str(#fmt["%?_u64", v]);
}
fn emit_u32(v: u32) {
self.write_str(#fmt["%?_u32", v]);
}
fn emit_u16(v: u16) {
self.write_str(#fmt["%?_u16", v]);
}
fn emit_u8(v: u8) {
self.write_str(#fmt["%?_u8", v]);
}
fn emit_int(v: int) {
self.write_str(#fmt["%?", v]);
}
fn emit_i64(v: i64) {
self.write_str(#fmt["%?_i64", v]);
}
fn emit_i32(v: i32) {
self.write_str(#fmt["%?_i32", v]);
}
fn emit_i16(v: i16) {
self.write_str(#fmt["%?_i16", v]);
}
fn emit_i8(v: i8) {
self.write_str(#fmt["%?_i8", v]);
}
fn emit_bool(v: bool) {
self.write_str(#fmt["%b", v]);
}
fn emit_float(v: float) {
self.write_str(#fmt["%?_f", v]);
}
fn emit_f64(v: f64) {
self.write_str(#fmt["%?_f64", v]);
}
fn emit_f32(v: f32) {
self.write_str(#fmt["%?_f32", v]);
}
fn emit_str(v: str) {
self.write_str(#fmt["%?", v]);
}
fn emit_enum(_name: str, f: fn()) {
f();
}
fn emit_enum_variant(v_name: str, _v_id: uint, _sz: uint, f: fn()) {
self.write_str(v_name);
self.write_str("(");
f();
self.write_str(")");
}
fn emit_enum_variant_arg(idx: uint, f: fn()) {
if idx > 0u { self.write_str(", "); }
f();
}
fn emit_vec(_len: uint, f: fn()) {
self.write_str("[");
f();
self.write_str("]");
}
fn emit_vec_elt(idx: uint, f: fn()) {
if idx > 0u { self.write_str(", "); }
f();
}
fn emit_box(f: fn()) {
self.write_str("@");
f();
}
fn emit_uniq(f: fn()) {
self.write_str("~");
f();
}
fn emit_rec(f: fn()) {
self.write_str("{");
f();
self.write_str("}");
}
fn emit_rec_field(f_name: str, f_idx: uint, f: fn()) {
if f_idx > 0u { self.write_str(", "); }
self.write_str(f_name);
self.write_str(": ");
f();
}
fn emit_tup(_sz: uint, f: fn()) {
self.write_str("(");
f();
self.write_str(")");
}
fn emit_tup_elt(idx: uint, f: fn()) {
if idx > 0u { self.write_str(", "); }
f();
}
}

View File

@ -1,416 +1,7 @@
#[doc = "Support code for serialization."];
#[doc = "Support code for serialization.
Deprecated in favor of core::serialization."];
use core;
import list::list;
import ebml::writer;
// Set to true to generate more debugging in EBML serialization.
// Totally lame approach.
const debug: bool = true;
iface serializer {
// Primitive types:
fn emit_nil();
fn emit_uint(v: uint);
fn emit_u64(v: u64);
fn emit_u32(v: u32);
fn emit_u16(v: u16);
fn emit_u8(v: u8);
fn emit_int(v: int);
fn emit_i64(v: i64);
fn emit_i32(v: i32);
fn emit_i16(v: i16);
fn emit_i8(v: i8);
fn emit_bool(v: bool);
fn emit_float(v: float);
fn emit_f64(v: f64);
fn emit_f32(v: f32);
fn emit_str(v: str);
// Compound types:
fn emit_enum(name: str, f: fn());
fn emit_enum_variant(v_name: str, v_id: uint, sz: uint, f: fn());
fn emit_enum_variant_arg(idx: uint, f: fn());
fn emit_vec(len: uint, f: fn());
fn emit_vec_elt(idx: uint, f: fn());
fn emit_box(f: fn());
fn emit_uniq(f: fn());
fn emit_rec(f: fn());
fn emit_rec_field(f_name: str, f_idx: uint, f: fn());
fn emit_tup(sz: uint, f: fn());
fn emit_tup_elt(idx: uint, f: fn());
}
iface deserializer {
// Primitive types:
fn read_nil() -> ();
fn read_uint() -> uint;
fn read_u64() -> u64;
fn read_u32() -> u32;
fn read_u16() -> u16;
fn read_u8() -> u8;
fn read_int() -> int;
fn read_i64() -> i64;
fn read_i32() -> i32;
fn read_i16() -> i16;
fn read_i8() -> i8;
fn read_bool() -> bool;
fn read_str() -> str;
fn read_f64() -> f64;
fn read_f32() -> f32;
fn read_float() -> float;
// Compound types:
fn read_enum<T:copy>(name: str, f: fn() -> T) -> T;
fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T;
fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T;
fn read_vec<T:copy>(f: fn(uint) -> T) -> T;
fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
fn read_box<T:copy>(f: fn() -> T) -> T;
fn read_uniq<T:copy>(f: fn() -> T) -> T;
fn read_rec<T:copy>(f: fn() -> T) -> T;
fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T;
fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T;
fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T;
}
enum ebml_serializer_tag {
es_uint, es_u64, es_u32, es_u16, es_u8,
es_int, es_i64, es_i32, es_i16, es_i8,
es_bool,
es_str,
es_f64, es_f32, es_float,
es_enum, es_enum_vid, es_enum_body,
es_vec, es_vec_len, es_vec_elt,
es_label // Used only when debugging
}
impl of serializer for ebml::writer {
fn emit_nil() {}
// used internally to emit things like the vector length and so on
fn _emit_tagged_uint(t: ebml_serializer_tag, v: uint) {
assert v <= 0xFFFF_FFFF_u;
self.wr_tagged_u32(t as uint, v as u32);
}
fn _emit_label(label: str) {
// There are various strings that we have access to, such as
// the name of a record field, which do not actually appear in
// the serialized EBML (normally). This is just for
// efficiency. When debugging, though, we can emit such
// labels and then they will be checked by deserializer to
// try and check failures more quickly.
if debug { self.wr_tagged_str(es_label as uint, label) }
}
fn emit_uint(v: uint) { self.wr_tagged_u64(es_uint as uint, v as u64); }
fn emit_u64(v: u64) { self.wr_tagged_u64(es_u64 as uint, v); }
fn emit_u32(v: u32) { self.wr_tagged_u32(es_u32 as uint, v); }
fn emit_u16(v: u16) { self.wr_tagged_u16(es_u16 as uint, v); }
fn emit_u8(v: u8) { self.wr_tagged_u8 (es_u8 as uint, v); }
fn emit_int(v: int) { self.wr_tagged_i64(es_int as uint, v as i64); }
fn emit_i64(v: i64) { self.wr_tagged_i64(es_i64 as uint, v); }
fn emit_i32(v: i32) { self.wr_tagged_i32(es_i32 as uint, v); }
fn emit_i16(v: i16) { self.wr_tagged_i16(es_i16 as uint, v); }
fn emit_i8(v: i8) { self.wr_tagged_i8 (es_i8 as uint, v); }
fn emit_bool(v: bool) { self.wr_tagged_u8(es_bool as uint, v as u8) }
fn emit_f64(_v: f64) { fail "TODO"; }
fn emit_f32(_v: f32) { fail "TODO"; }
fn emit_float(_v: float) { fail "TODO"; }
fn emit_str(v: str) { self.wr_tagged_str(es_str as uint, v) }
fn emit_enum(name: str, f: fn()) {
self._emit_label(name);
self.wr_tag(es_enum as uint, f)
}
fn emit_enum_variant(_v_name: str, v_id: uint, _cnt: uint, f: fn()) {
self._emit_tagged_uint(es_enum_vid, v_id);
self.wr_tag(es_enum_body as uint, f)
}
fn emit_enum_variant_arg(_idx: uint, f: fn()) { f() }
fn emit_vec(len: uint, f: fn()) {
self.wr_tag(es_vec as uint) {||
self._emit_tagged_uint(es_vec_len, len);
f()
}
}
fn emit_vec_elt(_idx: uint, f: fn()) {
self.wr_tag(es_vec_elt as uint, f)
}
fn emit_box(f: fn()) { f() }
fn emit_uniq(f: fn()) { f() }
fn emit_rec(f: fn()) { f() }
fn emit_rec_field(f_name: str, _f_idx: uint, f: fn()) {
self._emit_label(f_name);
f()
}
fn emit_tup(_sz: uint, f: fn()) { f() }
fn emit_tup_elt(_idx: uint, f: fn()) { f() }
}
type ebml_deserializer = {mutable parent: ebml::doc,
mutable pos: uint};
fn ebml_deserializer(d: ebml::doc) -> ebml_deserializer {
{mutable parent: d, mutable pos: d.start}
}
impl of deserializer for ebml_deserializer {
fn _check_label(lbl: str) {
if self.pos < self.parent.end {
let {tag: r_tag, doc: r_doc} =
ebml::doc_at(self.parent.data, self.pos);
if r_tag == (es_label as uint) {
self.pos = r_doc.end;
let str = ebml::doc_as_str(r_doc);
if lbl != str {
fail #fmt["Expected label %s but found %s", lbl, str];
}
}
}
}
fn next_doc(exp_tag: ebml_serializer_tag) -> ebml::doc {
#debug[". next_doc(exp_tag=%?)", exp_tag];
if self.pos >= self.parent.end {
fail "no more documents in current node!";
}
let {tag: r_tag, doc: r_doc} =
ebml::doc_at(self.parent.data, self.pos);
#debug["self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?",
self.parent.start, self.parent.end, self.pos,
r_tag, r_doc.start, r_doc.end];
if r_tag != (exp_tag as uint) {
fail #fmt["expected EMBL doc with tag %? but found tag %?",
exp_tag, r_tag];
}
if r_doc.end > self.parent.end {
fail #fmt["invalid EBML, child extends to 0x%x, parent to 0x%x",
r_doc.end, self.parent.end];
}
self.pos = r_doc.end;
ret r_doc;
}
fn push_doc<T: copy>(d: ebml::doc, f: fn() -> T) -> T{
let old_parent = self.parent;
let old_pos = self.pos;
self.parent = d;
self.pos = d.start;
let r = f();
self.parent = old_parent;
self.pos = old_pos;
ret r;
}
fn _next_uint(exp_tag: ebml_serializer_tag) -> uint {
let r = ebml::doc_as_u32(self.next_doc(exp_tag));
#debug["_next_uint exp_tag=%? result=%?", exp_tag, r];
ret r as uint;
}
fn read_nil() -> () { () }
fn read_u64() -> u64 { ebml::doc_as_u64(self.next_doc(es_u64)) }
fn read_u32() -> u32 { ebml::doc_as_u32(self.next_doc(es_u32)) }
fn read_u16() -> u16 { ebml::doc_as_u16(self.next_doc(es_u16)) }
fn read_u8 () -> u8 { ebml::doc_as_u8 (self.next_doc(es_u8 )) }
fn read_uint() -> uint {
let v = ebml::doc_as_u64(self.next_doc(es_uint));
if v > (uint::max_value as u64) {
fail #fmt["uint %? too large for this architecture", v];
}
ret v as uint;
}
fn read_i64() -> i64 { ebml::doc_as_u64(self.next_doc(es_i64)) as i64 }
fn read_i32() -> i32 { ebml::doc_as_u32(self.next_doc(es_i32)) as i32 }
fn read_i16() -> i16 { ebml::doc_as_u16(self.next_doc(es_i16)) as i16 }
fn read_i8 () -> i8 { ebml::doc_as_u8 (self.next_doc(es_i8 )) as i8 }
fn read_int() -> int {
let v = ebml::doc_as_u64(self.next_doc(es_int)) as i64;
if v > (int::max_value as i64) || v < (int::min_value as i64) {
fail #fmt["int %? out of range for this architecture", v];
}
ret v as int;
}
fn read_bool() -> bool { ebml::doc_as_u8(self.next_doc(es_bool)) as bool }
fn read_f64() -> f64 { fail "read_f64()"; }
fn read_f32() -> f32 { fail "read_f32()"; }
fn read_float() -> float { fail "read_float()"; }
fn read_str() -> str { ebml::doc_as_str(self.next_doc(es_str)) }
// Compound types:
fn read_enum<T:copy>(name: str, f: fn() -> T) -> T {
#debug["read_enum(%s)", name];
self._check_label(name);
self.push_doc(self.next_doc(es_enum), f)
}
fn read_enum_variant<T:copy>(f: fn(uint) -> T) -> T {
#debug["read_enum_variant()"];
let idx = self._next_uint(es_enum_vid);
#debug[" idx=%u", idx];
self.push_doc(self.next_doc(es_enum_body)) {||
f(idx)
}
}
fn read_enum_variant_arg<T:copy>(idx: uint, f: fn() -> T) -> T {
#debug["read_enum_variant_arg(idx=%u)", idx];
f()
}
fn read_vec<T:copy>(f: fn(uint) -> T) -> T {
#debug["read_vec()"];
self.push_doc(self.next_doc(es_vec)) {||
let len = self._next_uint(es_vec_len);
#debug[" len=%u", len];
f(len)
}
}
fn read_vec_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
#debug["read_vec_elt(idx=%u)", idx];
self.push_doc(self.next_doc(es_vec_elt), f)
}
fn read_box<T:copy>(f: fn() -> T) -> T {
#debug["read_box()"];
f()
}
fn read_uniq<T:copy>(f: fn() -> T) -> T {
#debug["read_uniq()"];
f()
}
fn read_rec<T:copy>(f: fn() -> T) -> T {
#debug["read_rec()"];
f()
}
fn read_rec_field<T:copy>(f_name: str, f_idx: uint, f: fn() -> T) -> T {
#debug["read_rec_field(%s, idx=%u)", f_name, f_idx];
self._check_label(f_name);
f()
}
fn read_tup<T:copy>(sz: uint, f: fn() -> T) -> T {
#debug["read_tup(sz=%u)", sz];
f()
}
fn read_tup_elt<T:copy>(idx: uint, f: fn() -> T) -> T {
#debug["read_tup_elt(idx=%u)", idx];
f()
}
}
// ___________________________________________________________________________
// Helper routines
//
// These should eventually be coded as traits.
impl serializer_helpers<S: serializer> for S {
fn emit_from_vec<T>(v: [T], f: fn(T)) {
self.emit_vec(vec::len(v)) {||
vec::iteri(v) {|i,e|
self.emit_vec_elt(i) {||
f(e)
}
}
}
}
}
impl deserializer_helpers<D: deserializer> for D {
fn read_to_vec<T>(f: fn() -> T) -> [T] {
self.read_vec {|len|
let v = [];
vec::reserve(v, len);
uint::range(0u, len) {|i|
self.read_vec_elt(i) {|| v += [f()] }
}
v
}
}
}
// ___________________________________________________________________________
// Testing
#[test]
fn test_option_int() {
fn serialize_1<S: serializer>(s: S, v: int) {
s.emit_i64(v as i64);
}
fn serialize_0<S: serializer>(s: S, v: option<int>) {
s.emit_enum("core::option::t") {||
alt v {
none {
s.emit_enum_variant("core::option::none", 0u, 0u) {||}
}
some(v0) {
s.emit_enum_variant("core::option::some", 1u, 1u) {||
s.emit_enum_variant_arg(0u) {|| serialize_1(s, v0) }
}
}
}
}
}
fn deserialize_1<S: deserializer>(s: S) -> int {
s.read_i64() as int
}
fn deserialize_0<S: deserializer>(s: S) -> option<int> {
s.read_enum("core::option::t") {||
s.read_enum_variant {|i|
alt check i {
0u { none }
1u {
let v0 = s.read_enum_variant_arg(0u) {||
deserialize_1(s)
};
some(v0)
}
}
}
}
}
fn test_v(v: option<int>) {
#debug["v == %?", v];
let mbuf = io::mk_mem_buffer();
let ebml_w = ebml::writer(io::mem_buffer_writer(mbuf));
serialize_0(ebml_w, v);
let ebml_doc = ebml::new_doc(@io::mem_buffer_buf(mbuf));
let deser = ebml_deserializer(ebml_doc);
let v1 = deserialize_0(deser);
#debug["v1 == %?", v1];
assert v == v1;
}
test_v(some(22));
test_v(none);
test_v(some(3));
}

View File

@ -12,7 +12,7 @@ export net, uv;
export c_vec, four, tri, util;
export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap, ufind;
export rope;
export ebml, dbg, getopts, json, rand, sha1, term, time;
export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint;
export test, tempfile, serialization;
@ -55,6 +55,7 @@ mod md4;
mod tempfile;
mod term;
mod time;
mod prettyprint;
#[cfg(unicode)]
mod unicode;

View File

@ -15,7 +15,8 @@ import io::{reader_util, writer_util};
import getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
import back::{x86, x86_64};
enum pp_mode { ppm_normal, ppm_expanded, ppm_typed, ppm_identified, }
enum pp_mode {ppm_normal, ppm_expanded, ppm_typed, ppm_identified,
ppm_expanded_identified }
fn default_configuration(sess: session, argv0: str, input: str) ->
ast::crate_cfg {
@ -253,7 +254,7 @@ fn pretty_print_input(sess: session, cfg: ast::crate_cfg, input: str,
// from stdin, we're going to just suck the source into a string
// so both the parser and pretty-printer can use it.
let upto = alt ppm {
ppm_expanded { cu_expand }
ppm_expanded | ppm_expanded_identified { cu_expand }
ppm_typed { cu_typeck }
_ { cu_parse }
};
@ -265,7 +266,7 @@ fn pretty_print_input(sess: session, cfg: ast::crate_cfg, input: str,
ann = {pre: ann_paren_for_expr,
post: bind ann_typed_post(option::get(tcx), _)};
}
ppm_identified {
ppm_identified | ppm_expanded_identified {
ann = {pre: ann_paren_for_expr, post: ann_identified_post};
}
ppm_expanded | ppm_normal {}
@ -498,7 +499,11 @@ fn parse_pretty(sess: session, &&name: str) -> pp_mode {
ret ppm_expanded;
} else if str::eq(name, "typed") {
ret ppm_typed;
} else if str::eq(name, "identified") { ret ppm_identified; }
} else if str::eq(name, "expanded,identified") {
ret ppm_expanded_identified;
} else if str::eq(name, "identified") {
ret ppm_identified;
}
sess.fatal("argument to `pretty` must be one of `normal`, `typed`, or " +
"`identified`");
}

View File

@ -6,12 +6,13 @@ import syntax::ast_util::inlined_item_methods;
import syntax::codemap::span;
import std::ebml;
import std::ebml::writer;
import std::ebml::serializer;
import std::ebml::deserializer;
import std::map::hashmap;
import std::serialization;
import std::serialization::serializer;
import std::serialization::deserializer;
import std::serialization::serializer_helpers;
import std::serialization::deserializer_helpers;
import serialization::serializer;
import serialization::deserializer;
import serialization::serializer_helpers;
import serialization::deserializer_helpers;
import std::smallintmap::map;
import middle::trans::common::maps;
import middle::{ty, typeck, last_use, ast_map};
@ -243,7 +244,7 @@ fn encode_id_range(ebml_w: ebml::writer, id_range: id_range) {
fn decode_id_range(par_doc: ebml::doc) -> id_range {
let range_doc = par_doc[c::tag_id_range];
let dsr = serialization::ebml_deserializer(range_doc);
let dsr = ebml::ebml_deserializer(range_doc);
dsr.read_tup(2u) {||
{min: dsr.read_tup_elt(0u) {|| dsr.read_int() },
max: dsr.read_tup_elt(1u) {|| dsr.read_int() }}
@ -368,7 +369,7 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item {
fn decode_ast(par_doc: ebml::doc) -> ast::inlined_item {
let chi_doc = par_doc[c::tag_tree];
let d = serialization::ebml_deserializer(chi_doc);
let d = ebml::ebml_deserializer(chi_doc);
astencode_gen::deserialize_syntax_ast_inlined_item(d)
}
@ -398,7 +399,7 @@ fn encode_def(ebml_w: ebml::writer, def: ast::def) {
}
fn decode_def(xcx: extended_decode_ctxt, doc: ebml::doc) -> ast::def {
let dsr = serialization::ebml_deserializer(doc);
let dsr = ebml::ebml_deserializer(doc);
let def = astencode_gen::deserialize_syntax_ast_def(dsr);
def.tr(xcx)
}
@ -445,7 +446,7 @@ fn encode_freevar_entry(ebml_w: ebml::writer, fv: freevar_entry) {
astencode_gen::serialize_middle_freevars_freevar_entry(ebml_w, fv)
}
impl helper for serialization::ebml_deserializer {
impl helper for ebml::ebml_deserializer {
fn read_freevar_entry(xcx: extended_decode_ctxt) -> freevar_entry {
let fv =
astencode_gen::deserialize_middle_freevars_freevar_entry(self);
@ -466,7 +467,7 @@ fn encode_method_origin(ebml_w: ebml::writer, mo: method_origin) {
astencode_gen::serialize_middle_typeck_method_origin(ebml_w, mo)
}
impl helper for serialization::ebml_deserializer {
impl helper for ebml::ebml_deserializer {
fn read_method_origin(xcx: extended_decode_ctxt) -> method_origin {
let fv = astencode_gen::deserialize_middle_typeck_method_origin(self);
fv.tr(xcx)
@ -559,7 +560,7 @@ fn encode_dict_origin(ecx: @e::encode_ctxt,
}
impl helpers for serialization::ebml_deserializer {
impl helpers for ebml::ebml_deserializer {
fn read_dict_res(xcx: extended_decode_ctxt) -> typeck::dict_res {
@self.read_to_vec {|| self.read_dict_origin(xcx) }
}
@ -800,7 +801,7 @@ impl decoder for ebml::doc {
}
}
impl decoder for serialization::ebml_deserializer {
impl decoder for ebml::ebml_deserializer {
fn read_ty(xcx: extended_decode_ctxt) -> ty::t {
tydecode::parse_ty_data(
self.parent.data, xcx.dcx.cdata.cnum, self.pos, xcx.dcx.tcx,
@ -850,7 +851,7 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
dcx.maps.copy_map.insert(id, ());
} else {
let val_doc = entry_doc[c::tag_table_val];
let val_dsr = serialization::ebml_deserializer(val_doc);
let val_dsr = ebml::ebml_deserializer(val_doc);
if tag == (c::tag_table_def as uint) {
let def = decode_def(xcx, val_doc);
dcx.tcx.def_map.insert(id, def);
@ -903,7 +904,7 @@ fn encode_item_ast(ebml_w: ebml::writer, item: @ast::item) {
#[cfg(test)]
fn decode_item_ast(par_doc: ebml::doc) -> @ast::item {
let chi_doc = par_doc[c::tag_tree];
let d = serialization::ebml_deserializer(chi_doc);
let d = ebml::ebml_deserializer(chi_doc);
@astencode_gen::deserialize_syntax_ast_item(d)
}

View File

@ -306,6 +306,9 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
for ast_ty: @ast::ty in args {
param_bindings += [do_ast_ty_to_ty(tcx, use_site, mode, ast_ty)];
}
#debug("substituting(%s into %s)",
str::concat(vec::map(param_bindings, {|t| ty_to_str(tcx, t)})),
ty_to_str(tcx, ty_param_bounds_and_ty.ty));
let typ =
ty::substitute_type_params(tcx, param_bindings,
ty_param_bounds_and_ty.ty);

View File

@ -82,26 +82,39 @@ import base::*;
import driver::session::session;
import codemap::span;
import std::map;
import std::map::hashmap;
import front::attr;
export expand_auto_serialize;
export expand;
enum ser_cx = {
enum ser_cx = @{
ext_cx: ext_ctxt,
tps: map::map<str, fn@(@ast::expr) -> [@ast::stmt]>
tps: map::hashmap<str, fn@(@ast::expr) -> [@ast::stmt]>
};
fn expand_auto_serialize(cx: ext_ctxt,
span: span,
_mitem: ast::meta_item,
in_items: [@ast::item]) -> [@ast::item] {
fn expand(cx: ext_ctxt,
span: span,
_mitem: ast::meta_item,
in_items: [@ast::item]) -> [@ast::item] {
fn not_auto_serialize(a: ast::attribute) -> bool {
attr::get_attr_name(a) != "auto_serialize"
}
fn filter_attrs(item: @ast::item) -> @ast::item {
@{attrs: vec::filter(item.attrs, not_auto_serialize)
with *item}
}
vec::flat_map(in_items) {|in_item|
alt in_item.node {
ast::item_ty(ty, tps) {
[in_item, ty_module(cx, in_item.ident, copy ty, tps)]
[filter_attrs(in_item),
ty_module(cx, in_item.ident, ty, tps)]
}
ast::item_enum(variants, tps) {
[in_item, enum_module(cx, in_item.ident, variants, tps)]
[filter_attrs(in_item),
enum_module(cx, in_item.ident, in_item.span, variants, tps)]
}
_ {
@ -118,9 +131,7 @@ impl helpers for ext_ctxt {
fn next_id() -> ast::node_id { self.session().next_node_id() }
fn path(span: span, strs: [str]) -> @ast::path {
@{node: {global: false,
idents: strs + ["serialize"],
types: []},
@{node: {global: false, idents: strs, types: []},
span: span}
}
@ -140,6 +151,28 @@ impl helpers for ser_cx {
self.ext_cx.ty_path(span, strs)
}
fn ty_fn(span: span,
-input_tys: [@ast::ty],
-output: @ast::ty) -> @ast::ty {
let args = vec::map(input_tys) {|ty|
{mode: ast::expl(ast::by_ref),
ty: ty,
ident: "",
id: self.next_id()}
};
@{node: ast::ty_fn(ast::proto_any, {inputs: args,
output: output,
purity: ast::impure_fn,
cf: ast::return_val,
constraints: []}),
span: span}
}
fn ty_nil(span: span) -> @ast::ty {
@{node: ast::ty_nil, span: span}
}
fn expr(span: span, node: ast::expr_) -> @ast::expr {
@{id: self.next_id(), node: node, span: span}
}
@ -195,8 +228,9 @@ impl helpers for ser_cx {
span: span}))
}
fn lambda(-blk: @ast::blk) -> @ast::expr {
let blk_e = cx.expr(blk.span, expr_block(blk));
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) }}
}
@ -208,6 +242,14 @@ impl helpers for ser_cx {
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()
});
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()}
@ -249,14 +291,17 @@ 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 = serialize_ty(cx, ty, s, #ast(expr){"__v"});
cx.at(ty.span, #ast(expr){"{|__v| $(sv)}"})
let sv_stmts = serialize_ty(cx, ty, cx.clone(s), #ast(expr){__v});
let sv = cx.expr(path.span,
ast::expr_block(cx.blk(path.span,
sv_stmts)));
cx.at(ty.span, #ast(expr){{|__v| $(sv)}})
};
[cx.stmt(
cx.expr(
path.span,
ast::expr_call(callee, [s] + ty_args + [v], false)))]
ast::expr_call(callee, [s, v] + ty_args, false)))]
}
fn serialize_variant(cx: ser_cx,
@ -264,8 +309,8 @@ fn serialize_variant(cx: ser_cx,
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)
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|
@ -281,7 +326,7 @@ fn serialize_variant(cx: ser_cx,
cx.stmt(argfn(cx.clone(s), i, arg_blk))
};
let body_blk = cx.blk(span, vec::concat(stmts));
let body_blk = cx.blk(span, stmts);
let body = cx.blk(span, [cx.stmt(bodyfn(s, body_blk))]);
{pats: [pat], guard: none, body: body}
@ -289,6 +334,13 @@ fn serialize_variant(cx: ser_cx,
fn serialize_ty(cx: ser_cx, 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;
alt ty.node {
@ -296,19 +348,37 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
[]
}
ast::ty_box(mt) |
ast::ty_uniq(mt) |
ast::ty_ptr(mt) {
serialize_ty(cx, mt.ty, s, #ast(expr){"*$(v)"})
ast::ty_box(mt) {
let l = ty_lambda(cx, mt.ty, cx.clone(s), #ast(expr){*$(v)});
[#ast(stmt){$(s).emit_box($(l));}]
}
ast::ty_uniq(mt) {
let l = ty_lambda(cx, mt.ty, cx.clone(s), #ast(expr){*$(v)});
[#ast(stmt){$(s).emit_uniq($(l));}]
}
ast::ty_ptr(_) | ast::ty_rptr(_, _) {
cx.session().span_err(
ty.span, #fmt["Cannot serialize pointer types"]);
[]
}
ast::ty_rec(flds) {
vec::flat_map(flds) {|fld|
let vf = cx.expr(
fld.span,
ast::expr_field(cx.clone(v), fld.node.ident, []));
serialize_ty(cx, fld.node.mt.ty, cx.clone(s), vf)
}
let fld_stmts = vec::init_fn(vec::len(flds)) {|fidx|
let fld = flds[fidx];
let vf = cx.expr(fld.span,
ast::expr_field(cx.clone(v),
fld.node.ident,
[]));
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);
#ast(stmt){$(s).emit_rec_field($(f), $(i), $(l));}
};
let fld_lambda = cx.lambda(cx.blk(ty.span, fld_stmts));
[#ast(stmt){$(s).emit_rec($(fld_lambda));}]
}
ast::ty_fn(_, _) {
@ -335,7 +405,7 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
{|pats| ast::pat_tup(pats)},
// Generate body s.emit_tup(3, {|| blk })
{|-s, -blk|
{|-s, blk|
let sz = cx.lit_uint(ty.span, vec::len(tys));
let body = cx.lambda(blk);
#ast[expr]{
@ -344,7 +414,7 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
},
// Generate s.emit_tup_elt(i, {|| blk })
{|-s, i, -blk|
{|-s, i, blk|
let idx = cx.lit_uint(ty.span, i);
let body = cx.lambda(blk);
#ast[expr]{
@ -399,57 +469,55 @@ fn serialize_ty(cx: ser_cx, ty: @ast::ty, -s: @ast::expr, -v: @ast::expr)
ty.span,
#ast(expr){__e})))));
[cx.stmt(
cx.expr(
ty.span,
ast::expr_call(
#ast(expr){$(s).emit_from_vec},
[#ast(expr){{|__e| $(ser_e)}}],
false)))]
[#ast(stmt){
core::serialization::emit_from_vec($(s), $(v), {|__e| $(ser_e) })
}]
}
}
}
fn mk_ser_fn(ext_cx: ext_ctxt, span: span,
-v_ty: @ast::ty, tps: [ast::ty_param],
v_ty: @ast::ty, tps: [ast::ty_param],
f: fn(ser_cx, @ast::ty, -@ast::expr, -@ast::expr) -> [@ast::stmt])
-> @ast::item {
let cx = ser_cx({ext_cx: ext_cx, tps: map::new_str_hash()});
let cx = ser_cx(@{ext_cx: ext_cx, tps: map::new_str_hash()});
let tp_inputs =
vec::map(tps, {|tp|
{mode: ast::expl(ast::by_ref),
ty: cx.ty_path(span, [tp.ident]),
ty: cx.ty_fn(span,
[cx.ty_path(span, [tp.ident])],
cx.ty_nil(span)),
ident: "__s" + tp.ident,
id: cx.next_id()}});
#debug["tp_inputs = %?", tp_inputs];
let ser_inputs: [ast::arg] =
[{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,
ty: cx.clone_ty(v_ty),
ident: "__v",
id: cx.next_id()}]
+ tp_inputs;
vec::iter2(tps, ser_inputs) {|tp, arg|
vec::iter2(tps, tp_inputs) {|tp, arg|
let arg_ident = arg.ident;
cx.tps.insert(
tp.ident,
fn@(v: @ast::expr) -> [@ast::stmt] {
let f = cx.var_ref(span, arg_ident);
[cx.stmt(
cx.expr(
span,
ast::expr_call(f, [v], false)))]
#debug["serializing type arg %s", arg_ident];
[#ast(stmt){$(f)($(v));}]
});
}
let ser_bnds = @[ast::bound_iface(cx.ty_path(span,
["__std", "serialization",
["serialization",
"serializer"]))];
let ser_tps: [ast::ty_param] =
@ -462,7 +530,7 @@ fn mk_ser_fn(ext_cx: ext_ctxt, span: span,
span: span};
let ser_blk = cx.blk(span,
f(cx, v_ty, #ast(expr){"__s"}, #ast(expr){"__v"}));
f(cx, v_ty, #ast(expr){__s}, #ast(expr){__v}));
@{ident: "serialize",
attrs: [],
@ -477,7 +545,7 @@ 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 ty_module(ext_cx: ext_ctxt, name: str, ty: @ast::ty, tps: [ast::ty_param])
-> @ast::item {
let span = ty.span;
@ -497,62 +565,51 @@ fn enum_module(ext_cx: ext_ctxt, name: str, span: span,
variants: [ast::variant], tps: [ast::ty_param])
-> @ast::item {
let span = ty.span;
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)) {|vidx|
let variant = variants[vidx];
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 };
if vec::is_empty(variant.args) {
// degenerate case.
let pat = {id: cx.next_id(),
node: ast::pat_ident(cx.path(variant.ident), none),
Span: variant.span};
//#ast(expr){
// $(s).emit_enum_variant(X, Y, SZ) {||
// };
//}
}
serialize_variant(
cx, variant_tys, span, cx.clone(s),
let variant_tys = vec::map(variant.args) {|a| a.ty };
// 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)
}
},
serialize_variant(
cx, variant_tys, variant.span, cx.clone(s),
// 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 pattern var(v1, v2, v3)
{|pats|
let pat = {id: cx.next_id(),
node: ast::pat_enum(cx.path(variant.ident)),
span: variant.span};
{id: cx.next_id(),
node: expr_call(s, [v_name,
v_id,
sz,
f], false),
span: variant.span}
},
// Generate body s.emit_enum_variant("foo", 0u, 3u, {|| blk })
{|-s, -blk|
let v_name = cx.lit_str(variant.span, variant.ident);
let v_id = cx.lit_uint(variant.span, vidx);
let sz = cx.lit_uint(variant.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(i);
let body = cx.lambda(blk);
#ast[expr]{
$(s).emit_enum_variant_arg($(idx), $(body))
}
})
};
// 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)]
};
@{ident: name,

View File

@ -27,6 +27,8 @@ fn syntax_expander_table() -> hashmap<str, syntax_extension> {
{normal({expander: f, span: none})}
let syntax_expanders = new_str_hash::<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("env", builtin(ext::env::expand_syntax_ext));
syntax_expanders.insert("macro",
macro_defining(ext::simplext::add_new_extension));

View File

@ -193,6 +193,7 @@ fn finish<T: qq_helper>
{
let cm = ecx.session().parse_sess.cm;
let str = @codemap::span_to_snippet(body.span, cm);
#debug["qquote--str==%?", str];
let fname = codemap::mk_substr_filename(cm, body.span);
let node = parse_from_source_str
(f, fname, codemap::fss_internal(body.span), str,

View File

@ -0,0 +1,19 @@
use std;
import std::prettyprint::serializer;
import std::io;
#[auto_serialize]
enum expr {
val(uint),
plus(@expr, @expr),
minus(@expr, @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)))";
}

View File

@ -0,0 +1,19 @@
use std;
import std::prettyprint::serializer;
import std::io;
// Test where we link various types used by name.
#[auto_serialize]
type spanned<T> = {lo: uint, hi: uint, node: T};
#[auto_serialize]
type spanned_uint = spanned<uint>;
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}";
}

View File

@ -0,0 +1,22 @@
use std;
import std::prettyprint::serializer;
import std::io;
// Test where we link various types used by name.
#[auto_serialize]
type uint_vec = [uint];
#[auto_serialize]
type some_rec = {v: uint_vec};
#[auto_serialize]
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]})";
}

View File

@ -0,0 +1,12 @@
use std;
import std::prettyprint::serializer;
import std::io;
#[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}";
}

View File

@ -0,0 +1,13 @@
use std;
import std::prettyprint::serializer;
import std::io;
#[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]";
}