diff options
| author | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2012-12-10 20:37:21 -0800 |
|---|---|---|
| committer | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2012-12-13 18:16:31 -0800 |
| commit | 786c143a70ac40e5e028eed6b8efaa54076ce41f (patch) | |
| tree | 7b591cf45dc738ff78d99528f94883179cf4e4bd | |
| parent | c3f0aa973e9391c15bdfef92f72c410d3c32bc75 (diff) | |
| download | rust-786c143a70ac40e5e028eed6b8efaa54076ce41f.tar.gz rust-786c143a70ac40e5e028eed6b8efaa54076ce41f.zip | |
Begin renaming serialization to std::serialize. (snapshot)
| -rw-r--r-- | src/libstd/serialize.rs | 585 | ||||
| -rw-r--r-- | src/libstd/std.rc | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/auto_encode.rs | 1161 | ||||
| -rw-r--r-- | src/libsyntax/ext/auto_serialize.rs | 133 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/syntax.rc | 3 |
6 files changed, 1759 insertions, 135 deletions
diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs new file mode 100644 index 00000000000..a2c80914fd6 --- /dev/null +++ b/src/libstd/serialize.rs @@ -0,0 +1,585 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support code for encoding and decoding types. + +/* +Core encoding and decoding interfaces. +*/ + +#[forbid(deprecated_mode)]; +#[forbid(non_camel_case_types)]; + +pub trait Encoder { + // Primitive types: + fn emit_nil(&self); + fn emit_uint(&self, v: uint); + fn emit_u64(&self, v: u64); + fn emit_u32(&self, v: u32); + fn emit_u16(&self, v: u16); + fn emit_u8(&self, v: u8); + fn emit_int(&self, v: int); + fn emit_i64(&self, v: i64); + fn emit_i32(&self, v: i32); + fn emit_i16(&self, v: i16); + fn emit_i8(&self, v: i8); + fn emit_bool(&self, v: bool); + fn emit_float(&self, v: float); + fn emit_f64(&self, v: f64); + fn emit_f32(&self, v: f32); + fn emit_char(&self, v: char); + fn emit_borrowed_str(&self, v: &str); + fn emit_owned_str(&self, v: &str); + fn emit_managed_str(&self, v: &str); + + // Compound types: + fn emit_borrowed(&self, f: fn()); + fn emit_owned(&self, f: fn()); + fn emit_managed(&self, f: fn()); + + fn emit_enum(&self, name: &str, f: fn()); + fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: fn()); + fn emit_enum_variant_arg(&self, idx: uint, f: fn()); + + fn emit_borrowed_vec(&self, len: uint, f: fn()); + fn emit_owned_vec(&self, len: uint, f: fn()); + fn emit_managed_vec(&self, len: uint, f: fn()); + fn emit_vec_elt(&self, idx: uint, f: fn()); + + fn emit_rec(&self, f: fn()); + fn emit_struct(&self, name: &str, f: fn()); + fn emit_field(&self, f_name: &str, f_idx: uint, f: fn()); + + fn emit_tup(&self, len: uint, f: fn()); + fn emit_tup_elt(&self, idx: uint, f: fn()); +} + +pub trait Decoder { + // Primitive types: + fn read_nil(&self) -> (); + fn read_uint(&self) -> uint; + fn read_u64(&self) -> u64; + fn read_u32(&self) -> u32; + fn read_u16(&self) -> u16; + fn read_u8(&self) -> u8; + fn read_int(&self) -> int; + fn read_i64(&self) -> i64; + fn read_i32(&self) -> i32; + fn read_i16(&self) -> i16; + fn read_i8(&self) -> i8; + fn read_bool(&self) -> bool; + fn read_f64(&self) -> f64; + fn read_f32(&self) -> f32; + fn read_float(&self) -> float; + fn read_char(&self) -> char; + fn read_owned_str(&self) -> ~str; + fn read_managed_str(&self) -> @str; + + // Compound types: + fn read_enum<T>(&self, name: &str, f: fn() -> T) -> T; + fn read_enum_variant<T>(&self, f: fn(uint) -> T) -> T; + fn read_enum_variant_arg<T>(&self, idx: uint, f: fn() -> T) -> T; + + fn read_owned<T>(&self, f: fn() -> T) -> T; + fn read_managed<T>(&self, f: fn() -> T) -> T; + + fn read_owned_vec<T>(&self, f: fn(uint) -> T) -> T; + fn read_managed_vec<T>(&self, f: fn(uint) -> T) -> T; + fn read_vec_elt<T>(&self, idx: uint, f: fn() -> T) -> T; + + fn read_rec<T>(&self, f: fn() -> T) -> T; + fn read_struct<T>(&self, name: &str, f: fn() -> T) -> T; + fn read_field<T>(&self, name: &str, idx: uint, f: fn() -> T) -> T; + + fn read_tup<T>(&self, sz: uint, f: fn() -> T) -> T; + fn read_tup_elt<T>(&self, idx: uint, f: fn() -> T) -> T; +} + +pub mod traits { +pub trait Encodable<S: Encoder> { + fn encode(&self, s: &S); +} + +pub trait Decodable<D: Decoder> { + static fn decode(&self, d: &D) -> self; +} + +pub impl<S: Encoder> uint: Encodable<S> { + fn encode(&self, s: &S) { s.emit_uint(*self) } +} + +pub impl<D: Decoder> uint: Decodable<D> { + static fn decode(&self, d: &D) -> uint { + d.read_uint() + } +} + +pub impl<S: Encoder> u8: Encodable<S> { + fn encode(&self, s: &S) { s.emit_u8(*self) } +} + +pub impl<D: Decoder> u8: Decodable<D> { + static fn decode(&self, d: &D) -> u8 { + d.read_u8() + } +} + +pub impl<S: Encoder> u16: Encodable<S> { + fn encode(&self, s: &S) { s.emit_u16(*self) } +} + +pub impl<D: Decoder> u16: Decodable<D> { + static fn decode(&self, d: &D) -> u16 { + d.read_u16() + } +} + +pub impl<S: Encoder> u32: Encodable<S> { + fn encode(&self, s: &S) { s.emit_u32(*self) } +} + +pub impl<D: Decoder> u32: Decodable<D> { + static fn decode(&self, d: &D) -> u32 { + d.read_u32() + } +} + +pub impl<S: Encoder> u64: Encodable<S> { + fn encode(&self, s: &S) { s.emit_u64(*self) } +} + +pub impl<D: Decoder> u64: Decodable<D> { + static fn decode(&self, d: &D) -> u64 { + d.read_u64() + } +} + +pub impl<S: Encoder> int: Encodable<S> { + fn encode(&self, s: &S) { s.emit_int(*self) } +} + +pub impl<D: Decoder> int: Decodable<D> { + static fn decode(&self, d: &D) -> int { + d.read_int() + } +} + +pub impl<S: Encoder> i8: Encodable<S> { + fn encode(&self, s: &S) { s.emit_i8(*self) } +} + +pub impl<D: Decoder> i8: Decodable<D> { + static fn decode(&self, d: &D) -> i8 { + d.read_i8() + } +} + +pub impl<S: Encoder> i16: Encodable<S> { + fn encode(&self, s: &S) { s.emit_i16(*self) } +} + +pub impl<D: Decoder> i16: Decodable<D> { + static fn decode(&self, d: &D) -> i16 { + d.read_i16() + } +} + +pub impl<S: Encoder> i32: Encodable<S> { + fn encode(&self, s: &S) { s.emit_i32(*self) } +} + +pub impl<D: Decoder> i32: Decodable<D> { + static fn decode(&self, d: &D) -> i32 { + d.read_i32() + } +} + +pub impl<S: Encoder> i64: Encodable<S> { + fn encode(&self, s: &S) { s.emit_i64(*self) } +} + +pub impl<D: Decoder> i64: Decodable<D> { + static fn decode(&self, d: &D) -> i64 { + d.read_i64() + } +} + +pub impl<S: Encoder> &str: Encodable<S> { + fn encode(&self, s: &S) { s.emit_borrowed_str(*self) } +} + +pub impl<S: Encoder> ~str: Encodable<S> { + fn encode(&self, s: &S) { s.emit_owned_str(*self) } +} + +pub impl<D: Decoder> ~str: Decodable<D> { + static fn decode(&self, d: &D) -> ~str { + d.read_owned_str() + } +} + +pub impl<S: Encoder> @str: Encodable<S> { + fn encode(&self, s: &S) { s.emit_managed_str(*self) } +} + +pub impl<D: Decoder> @str: Decodable<D> { + static fn decode(&self, d: &D) -> @str { + d.read_managed_str() + } +} + +pub impl<S: Encoder> float: Encodable<S> { + fn encode(&self, s: &S) { s.emit_float(*self) } +} + +pub impl<D: Decoder> float: Decodable<D> { + static fn decode(&self, d: &D) -> float { + d.read_float() + } +} + +pub impl<S: Encoder> f32: Encodable<S> { + fn encode(&self, s: &S) { s.emit_f32(*self) } +} + +pub impl<D: Decoder> f32: Decodable<D> { + static fn decode(&self, d: &D) -> f32 { + d.read_f32() } +} + +pub impl<S: Encoder> f64: Encodable<S> { + fn encode(&self, s: &S) { s.emit_f64(*self) } +} + +pub impl<D: Decoder> f64: Decodable<D> { + static fn decode(&self, d: &D) -> f64 { + d.read_f64() + } +} + +pub impl<S: Encoder> bool: Encodable<S> { + fn encode(&self, s: &S) { s.emit_bool(*self) } +} + +pub impl<D: Decoder> bool: Decodable<D> { + static fn decode(&self, d: &D) -> bool { + d.read_bool() + } +} + +pub impl<S: Encoder> (): Encodable<S> { + fn encode(&self, s: &S) { s.emit_nil() } +} + +pub impl<D: Decoder> (): Decodable<D> { + static fn decode(&self, d: &D) -> () { + d.read_nil() + } +} + +pub impl<S: Encoder, T: Encodable<S>> &T: Encodable<S> { + fn encode(&self, s: &S) { + s.emit_borrowed(|| (**self).encode(s)) + } +} + +pub impl<S: Encoder, T: Encodable<S>> ~T: Encodable<S> { + fn encode(&self, s: &S) { + s.emit_owned(|| (**self).encode(s)) + } +} + +pub impl<D: Decoder, T: Decodable<D>> ~T: Decodable<D> { + static fn decode(&self, d: &D) -> ~T { + d.read_owned(|| ~decode(d)) + } +} + +pub impl<S: Encoder, T: Encodable<S>> @T: Encodable<S> { + fn encode(&self, s: &S) { + s.emit_managed(|| (**self).encode(s)) + } +} + +pub impl<D: Decoder, T: Decodable<D>> @T: Decodable<D> { + static fn decode(&self, d: &D) -> @T { + d.read_managed(|| @decode(d)) + } +} + +pub impl<S: Encoder, T: Encodable<S>> &[T]: Encodable<S> { + fn encode(&self, s: &S) { + do s.emit_borrowed_vec(self.len()) { + for self.eachi |i, e| { + s.emit_vec_elt(i, || e.encode(s)) + } + } + } +} + +pub impl<S: Encoder, T: Encodable<S>> ~[T]: Encodable<S> { + fn encode(&self, s: &S) { + do s.emit_owned_vec(self.len()) { + for self.eachi |i, e| { + s.emit_vec_elt(i, || e.encode(s)) + } + } + } +} + +pub impl<D: Decoder, T: Decodable<D>> ~[T]: Decodable<D> { + static fn decode(&self, d: &D) -> ~[T] { + do d.read_owned_vec |len| { + do vec::from_fn(len) |i| { + d.read_vec_elt(i, || decode(d)) + } + } + } +} + +pub impl<S: Encoder, T: Encodable<S>> @[T]: Encodable<S> { + fn encode(&self, s: &S) { + do s.emit_managed_vec(self.len()) { + for self.eachi |i, e| { + s.emit_vec_elt(i, || e.encode(s)) + } + } + } +} + +pub impl<D: Decoder, T: Decodable<D>> @[T]: Decodable<D> { + static fn decode(&self, d: &D) -> @[T] { + do d.read_managed_vec |len| { + do at_vec::from_fn(len) |i| { + d.read_vec_elt(i, || decode(d)) + } + } + } +} + +pub impl<S: Encoder, T: Encodable<S>> Option<T>: Encodable<S> { + fn encode(&self, s: &S) { + do s.emit_enum(~"option") { + match *self { + None => do s.emit_enum_variant(~"none", 0u, 0u) { + }, + + Some(ref v) => do s.emit_enum_variant(~"some", 1u, 1u) { + s.emit_enum_variant_arg(0u, || v.encode(s)) + } + } + } + } +} + +pub impl<D: Decoder, T: Decodable<D>> Option<T>: Decodable<D> { + static fn decode(&self, d: &D) -> Option<T> { + do d.read_enum(~"option") { + do d.read_enum_variant |i| { + match i { + 0 => None, + 1 => Some(d.read_enum_variant_arg(0u, || decode(d))), + _ => fail(fmt!("Bad variant for option: %u", i)) + } + } + } + } +} + +pub impl< + S: Encoder, + T0: Encodable<S>, + T1: Encodable<S> +> (T0, T1): Encodable<S> { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1) => { + do s.emit_tup(2) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + } + } + } + } +} + +pub impl< + D: Decoder, + T0: Decodable<D>, + T1: Decodable<D> +> (T0, T1): Decodable<D> { + static fn decode(&self, d: &D) -> (T0, T1) { + do d.read_tup(2) { + ( + d.read_tup_elt(0, || decode(d)), + d.read_tup_elt(1, || decode(d)) + ) + } + } +} + +pub impl< + S: Encoder, + T0: Encodable<S>, + T1: Encodable<S>, + T2: Encodable<S> +> (T0, T1, T2): Encodable<S> { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1, ref t2) => { + do s.emit_tup(3) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + s.emit_tup_elt(2, || t2.encode(s)); + } + } + } + } +} + +pub impl< + D: Decoder, + T0: Decodable<D>, + T1: Decodable<D>, + T2: Decodable<D> +> (T0, T1, T2): Decodable<D> { + static fn decode(&self, d: &D) -> (T0, T1, T2) { + do d.read_tup(3) { + ( + d.read_tup_elt(0, || decode(d)), + d.read_tup_elt(1, || decode(d)), + d.read_tup_elt(2, || decode(d)) + ) + } + } +} + +pub impl< + S: Encoder, + T0: Encodable<S>, + T1: Encodable<S>, + T2: Encodable<S>, + T3: Encodable<S> +> (T0, T1, T2, T3): Encodable<S> { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1, ref t2, ref t3) => { + do s.emit_tup(4) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + s.emit_tup_elt(2, || t2.encode(s)); + s.emit_tup_elt(3, || t3.encode(s)); + } + } + } + } +} + +pub impl< + D: Decoder, + T0: Decodable<D>, + T1: Decodable<D>, + T2: Decodable<D>, + T3: Decodable<D> +> (T0, T1, T2, T3): Decodable<D> { + static fn decode(&self, d: &D) -> (T0, T1, T2, T3) { + do d.read_tup(4) { + ( + d.read_tup_elt(0, || decode(d)), + d.read_tup_elt(1, || decode(d)), + d.read_tup_elt(2, || decode(d)), + d.read_tup_elt(3, || decode(d)) + ) + } + } +} + +pub impl< + S: Encoder, + T0: Encodable<S>, + T1: Encodable<S>, + T2: Encodable<S>, + T3: Encodable<S>, + T4: Encodable<S> +> (T0, T1, T2, T3, T4): Encodable<S> { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1, ref t2, ref t3, ref t4) => { + do s.emit_tup(5) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + s.emit_tup_elt(2, || t2.encode(s)); + s.emit_tup_elt(3, || t3.encode(s)); + s.emit_tup_elt(4, || t4.encode(s)); + } + } + } + } +} + +pub impl< + D: Decoder, + T0: Decodable<D>, + T1: Decodable<D>, + T2: Decodable<D>, + T3: Decodable<D>, + T4: Decodable<D> +> (T0, T1, T2, T3, T4): Decodable<D> { + static fn decode(&self, d: &D) + -> (T0, T1, T2, T3, T4) { + do d.read_tup(5) { + ( + d.read_tup_elt(0, || decode(d)), + d.read_tup_elt(1, || decode(d)), + d.read_tup_elt(2, || decode(d)), + d.read_tup_elt(3, || decode(d)), + d.read_tup_elt(4, || decode(d)) + ) + } + } +} + +// ___________________________________________________________________________ +// Helper routines +// +// In some cases, these should eventually be coded as traits. + +pub trait EncoderHelpers { + fn emit_from_vec<T>(&self, v: ~[T], f: fn(v: &T)); +} + +pub impl<S: Encoder> S: EncoderHelpers { + fn emit_from_vec<T>(&self, v: ~[T], f: fn(v: &T)) { + do self.emit_owned_vec(v.len()) { + for v.eachi |i, e| { + do self.emit_vec_elt(i) { + f(e) + } + } + } + } +} + +pub trait DecoderHelpers { + fn read_to_vec<T>(&self, f: fn() -> T) -> ~[T]; +} + +pub impl<D: Decoder> D: DecoderHelpers { + fn read_to_vec<T>(&self, f: fn() -> T) -> ~[T] { + do self.read_owned_vec |len| { + do vec::from_fn(len) |i| { + self.read_vec_elt(i, || f()) + } + } + } +} +} + +pub use serialize::traits::*; diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 7a1fdf49954..65916aa5992 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -104,13 +104,15 @@ mod unicode; // Compiler support modules pub mod test; +pub mod serialize; pub mod serialization; // A curious inner-module that's not exported that contains the binding -// 'std' so that macro-expanded references to std::serialization and such +// 'std' so that macro-expanded references to std::code and such // can be resolved within libcore. #[doc(hidden)] // FIXME #3538 mod std { + pub use serialize; pub use serialization; } diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs new file mode 100644 index 00000000000..0ff3dbe1506 --- /dev/null +++ b/src/libsyntax/ext/auto_encode.rs @@ -0,0 +1,1161 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/* + +The compiler code necessary to implement the #[auto_encode] and +#[auto_decode] extension. The idea here is that type-defining items may +be tagged with #[auto_encode] and #[auto_decode], which will cause +us to generate a little companion module with the same name as the item. + +For example, a type like: + + #[auto_encode] + #[auto_decode] + struct Node {id: uint} + +would generate two implementations like: + + impl<S: Encoder> node_id: Encodable<S> { + fn encode(s: &S) { + do s.emit_struct("Node") { + s.emit_field("id", 0, || s.emit_uint(self)) + } + } + } + + impl<D: Decoder> node_id: Decodable { + static fn decode(d: &D) -> Node { + do d.read_struct("Node") { + Node { + id: d.read_field(~"x", 0, || decode(d)) + } + } + } + } + +Other interesting scenarios are whe the item has type parameters or +references other non-built-in types. A type definition like: + + #[auto_encode] + #[auto_decode] + type spanned<T> = {node: T, span: span}; + +would yield functions like: + + impl< + S: Encoder, + T: Encodable<S> + > spanned<T>: Encodable<S> { + fn encode<S: Encoder>(s: &S) { + do s.emit_rec { + s.emit_field("node", 0, || self.node.encode(s)); + s.emit_field("span", 1, || self.span.encode(s)); + } + } + } + + impl< + D: Decoder, + T: Decodable<D> + > spanned<T>: Decodable<D> { + static fn decode(d: &D) -> spanned<T> { + do d.read_rec { + { + node: d.read_field(~"node", 0, || decode(d)), + span: d.read_field(~"span", 1, || decode(d)), + } + } + } + } + +FIXME (#2810)--Hygiene. Search for "__" strings. We also assume "std" is the +standard library. + +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. + +*/ + +use ext::base::*; +use codemap::span; +use std::map; +use std::map::HashMap; + +export expand_auto_encode; +export expand_auto_decode; + +// Transitional reexports so qquote can find the paths it is looking for +mod syntax { + pub use ext; + pub use parse; +} + +fn expand_auto_encode( + cx: ext_ctxt, + span: span, + _mitem: ast::meta_item, + in_items: ~[@ast::item] +) -> ~[@ast::item] { + fn is_auto_encode(a: &ast::attribute) -> bool { + attr::get_attr_name(*a) == ~"auto_encode" + } + + fn filter_attrs(item: @ast::item) -> @ast::item { + @{attrs: vec::filter(item.attrs, |a| !is_auto_encode(a)), + .. *item} + } + + do vec::flat_map(in_items) |item| { + if item.attrs.any(is_auto_encode) { + match item.node { + ast::item_ty(@{node: ast::ty_rec(ref fields), _}, tps) => { + let ser_impl = mk_rec_ser_impl( + cx, + item.span, + item.ident, + (*fields), + tps + ); + + ~[filter_attrs(*item), ser_impl] + }, + ast::item_struct(@{ fields, _}, tps) => { + let ser_impl = mk_struct_ser_impl( + cx, + item.span, + item.ident, + fields, + tps + ); + + ~[filter_attrs(*item), ser_impl] + }, + ast::item_enum(ref enum_def, tps) => { + let ser_impl = mk_enum_ser_impl( + cx, + item.span, + item.ident, + (*enum_def), + tps + ); + + ~[filter_attrs(*item), ser_impl] + }, + _ => { + cx.span_err(span, ~"#[auto_encode] can only be \ + applied to structs, record types, \ + and enum definitions"); + ~[*item] + } + } + } else { + ~[*item] + } + } +} + +fn expand_auto_decode( + cx: ext_ctxt, + span: span, + _mitem: ast::meta_item, + in_items: ~[@ast::item] +) -> ~[@ast::item] { + fn is_auto_decode(a: &ast::attribute) -> bool { + attr::get_attr_name(*a) == ~"auto_decode" + } + + fn filter_attrs(item: @ast::item) -> @ast::item { + @{attrs: vec::filter(item.attrs, |a| !is_auto_decode(a)), + .. *item} + } + + do vec::flat_map(in_items) |item| { + if item.attrs.any(is_auto_decode) { + match item.node { + ast::item_ty(@{node: ast::ty_rec(ref fields), _}, tps) => { + let deser_impl = mk_rec_deser_impl( + cx, + item.span, + item.ident, + (*fields), + tps + ); + + ~[filter_attrs(*item), deser_impl] + }, + ast::item_struct(@{ fields, _}, tps) => { + let deser_impl = mk_struct_deser_impl( + cx, + item.span, + item.ident, + fields, + tps + ); + + ~[filter_attrs(*item), deser_impl] + }, + ast::item_enum(ref enum_def, tps) => { + let deser_impl = mk_enum_deser_impl( + cx, + item.span, + item.ident, + (*enum_def), + tps + ); + + ~[filter_attrs(*item), deser_impl] + }, + _ => { + cx.span_err(span, ~"#[auto_decode] can only be \ + applied to structs, record types, \ + and enum definitions"); + ~[*item] + } + } + } else { + ~[*item] + } + } +} + +priv impl ext_ctxt { + fn bind_path( + span: span, + ident: ast::ident, + path: @ast::path, + bounds: @~[ast::ty_param_bound] + ) -> ast::ty_param { + let bound = ast::ty_param_bound(@{ + id: self.next_id(), + node: ast::ty_path(path, self.next_id()), + span: span, + }); + + { + ident: ident, + id: self.next_id(), + bounds: @vec::append(~[bound], *bounds) + } + } + + fn expr(span: span, node: ast::expr_) -> @ast::expr { + @{id: self.next_id(), callee_id: self.next_id(), + node: node, span: span} + } + + fn path(span: span, strs: ~[ast::ident]) -> @ast::path { + @{span: span, global: false, idents: strs, rp: None, types: ~[]} + } + + fn path_tps(span: span, strs: ~[ast::ident], + tps: ~[@ast::Ty]) -> @ast::path { + @{span: span, global: false, idents: strs, rp: None, types: tps} + } + + fn ty_path(span: span, strs: ~[ast::ident], + tps: ~[@ast::Ty]) -> @ast::Ty { + @{id: self.next_id(), + node: ast::ty_path(self.path_tps(span, strs, tps), self.next_id()), + span: span} + } + + fn binder_pat(span: span, nm: ast::ident) -> @ast::pat { + let path = @{span: span, global: false, idents: ~[nm], + rp: None, types: ~[]}; + @{id: self.next_id(), + node: ast::pat_ident(ast::bind_by_ref(ast::m_imm), + path, + None), + span: span} + } + + fn stmt(expr: @ast::expr) -> @ast::stmt { + @{node: ast::stmt_semi(expr, self.next_id()), + span: expr.span} + } + + fn lit_str(span: span, s: @~str) -> @ast::expr { + self.expr( + span, + ast::expr_vstore( + self.expr( + span, + ast::expr_lit( + @{node: ast::lit_str(s), + span: span})), + ast::expr_vstore_uniq)) + } + + 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})) + } + + fn lambda(blk: ast::blk) -> @ast::expr { + let ext_cx = self; + let blk_e = self.expr(blk.span, ast::expr_block(blk)); + quote_expr!( || $blk_e ) + } + + fn blk(span: span, stmts: ~[@ast::stmt]) -> ast::blk { + {node: {view_items: ~[], + stmts: stmts, + expr: None, + id: self.next_id(), + rules: ast::default_blk}, + 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 expr_path(span: span, strs: ~[ast::ident]) -> @ast::expr { + self.expr(span, ast::expr_path(self.path(span, strs))) + } + + fn expr_var(span: span, var: ~str) -> @ast::expr { + self.expr_path(span, ~[self.ident_of(var)]) + } + + fn expr_field( + span: span, + expr: @ast::expr, + ident: ast::ident + ) -> @ast::expr { + self.expr(span, ast::expr_field(expr, ident, ~[])) + } + + fn expr_call( + span: span, + expr: @ast::expr, + args: ~[@ast::expr] + ) -> @ast::expr { + self.expr(span, ast::expr_call(expr, args, false)) + } + + fn lambda_expr(expr: @ast::expr) -> @ast::expr { + self.lambda(self.expr_blk(expr)) + } + + fn lambda_stmts(span: span, stmts: ~[@ast::stmt]) -> @ast::expr { + self.lambda(self.blk(span, stmts)) + } +} + +fn mk_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + ty_param: ast::ty_param, + path: @ast::path, + tps: ~[ast::ty_param], + f: fn(@ast::Ty) -> @ast::method +) -> @ast::item { + // All the type parameters need to bound to the trait. + let mut trait_tps = vec::append( + ~[ty_param], + do tps.map |tp| { + let t_bound = ast::ty_param_bound(@{ + id: cx.next_id(), + node: ast::ty_path(path, cx.next_id()), + span: span, + }); + + { + ident: tp.ident, + id: cx.next_id(), + bounds: @vec::append(~[t_bound], *tp.bounds) + } + } + ); + + let opt_trait = Some(@{ + path: path, + ref_id: cx.next_id(), + }); + + let ty = cx.ty_path( + span, + ~[ident], + tps.map(|tp| cx.ty_path(span, ~[tp.ident], ~[])) + ); + + @{ + // This is a new-style impl declaration. + // XXX: clownshoes + ident: ast::token::special_idents::clownshoes_extensions, + attrs: ~[], + id: cx.next_id(), + node: ast::item_impl(trait_tps, opt_trait, ty, ~[f(ty)]), + vis: ast::public, + span: span, + } +} + +fn mk_ser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + tps: ~[ast::ty_param], + body: @ast::expr +) -> @ast::item { + // Make a path to the std::serialize::Encodable typaram. + let ty_param = cx.bind_path( + span, + cx.ident_of(~"__S"), + cx.path( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Encoder"), + ] + ), + @~[] + ); + + // Make a path to the std::serialize::Encodable trait. + let path = cx.path_tps( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Encodable"), + ], + ~[cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[])] + ); + + mk_impl( + cx, + span, + ident, + ty_param, + path, + tps, + |_ty| mk_ser_method(cx, span, cx.expr_blk(body)) + ) +} + +fn mk_deser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + tps: ~[ast::ty_param], + body: @ast::expr +) -> @ast::item { + // Make a path to the std::serialize::Decodable typaram. + let ty_param = cx.bind_path( + span, + cx.ident_of(~"__D"), + cx.path( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decoder"), + ] + ), + @~[] + ); + + // Make a path to the std::serialize::Decodable trait. + let path = cx.path_tps( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decodable"), + ], + ~[cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[])] + ); + + mk_impl( + cx, + span, + ident, + ty_param, + path, + tps, + |ty| mk_deser_method(cx, span, ty, cx.expr_blk(body)) + ) +} + +fn mk_ser_method( + cx: ext_ctxt, + span: span, + ser_body: ast::blk +) -> @ast::method { + let ty_s = @{ + id: cx.next_id(), + node: ast::ty_rptr( + @{ + id: cx.next_id(), + node: ast::re_anon, + }, + { + ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]), + mutbl: ast::m_imm + } + ), + span: span, + }; + + let ser_inputs = ~[{ + mode: ast::infer(cx.next_id()), + ty: ty_s, + pat: @{id: cx.next_id(), + node: ast::pat_ident( + ast::bind_by_value, + ast_util::ident_to_path(span, cx.ident_of(~"__s")), + None), + span: span}, + id: cx.next_id(), + }]; + + let ser_output = @{ + id: cx.next_id(), + node: ast::ty_nil, + span: span, + }; + + let ser_decl = { + inputs: ser_inputs, + output: ser_output, + cf: ast::return_val, + }; + + @{ + ident: cx.ident_of(~"encode"), + attrs: ~[], + tps: ~[], + self_ty: { node: ast::sty_region(ast::m_imm), span: span }, + purity: ast::impure_fn, + decl: ser_decl, + body: ser_body, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: ast::public, + } +} + +fn mk_deser_method( + cx: ext_ctxt, + span: span, + ty: @ast::Ty, + deser_body: ast::blk +) -> @ast::method { + let ty_d = @{ + id: cx.next_id(), + node: ast::ty_rptr( + @{ + id: cx.next_id(), + node: ast::re_anon, + }, + { + ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]), + mutbl: ast::m_imm + } + ), + span: span, + }; + + let deser_inputs = ~[{ + mode: ast::infer(cx.next_id()), + ty: ty_d, + pat: @{id: cx.next_id(), + node: ast::pat_ident( + ast::bind_by_value, + ast_util::ident_to_path(span, cx.ident_of(~"__d")), + None), + span: span}, + id: cx.next_id(), + }]; + + let deser_decl = { + inputs: deser_inputs, + output: ty, + cf: ast::return_val, + }; + + @{ + ident: cx.ident_of(~"decode"), + attrs: ~[], + tps: ~[], + self_ty: { node: ast::sty_static, span: span }, + purity: ast::impure_fn, + decl: deser_decl, + body: deser_body, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: ast::public, + } +} + +fn mk_rec_ser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + fields: ~[ast::ty_field], + tps: ~[ast::ty_param] +) -> @ast::item { + let fields = mk_ser_fields(cx, span, mk_rec_fields(fields)); + + // ast for `__s.emit_rec(|| $(fields))` + let body = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_rec") + ), + ~[cx.lambda_stmts(span, fields)] + ); + + mk_ser_impl(cx, span, ident, tps, body) +} + +fn mk_rec_deser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + fields: ~[ast::ty_field], + tps: ~[ast::ty_param] +) -> @ast::item { + let fields = mk_deser_fields(cx, span, mk_rec_fields(fields)); + + // ast for `read_rec(|| $(fields))` + let body = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_rec") + ), + ~[ + cx.lambda_expr( + cx.expr( + span, + ast::expr_rec(fields, None) + ) + ) + ] + ); + + mk_deser_impl(cx, span, ident, tps, body) +} + +fn mk_struct_ser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + fields: ~[@ast::struct_field], + tps: ~[ast::ty_param] +) -> @ast::item { + let fields = mk_ser_fields(cx, span, mk_struct_fields(fields)); + + // ast for `__s.emit_struct($(name), || $(fields))` + let ser_body = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_struct") + ), + ~[ + cx.lit_str(span, @cx.str_of(ident)), + cx.lambda_stmts(span, fields), + ] + ); + + mk_ser_impl(cx, span, ident, tps, ser_body) +} + +fn mk_struct_deser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + fields: ~[@ast::struct_field], + tps: ~[ast::ty_param] +) -> @ast::item { + let fields = mk_deser_fields(cx, span, mk_struct_fields(fields)); + + // ast for `read_struct($(name), || $(fields))` + let body = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_struct") + ), + ~[ + cx.lit_str(span, @cx.str_of(ident)), + cx.lambda_expr( + cx.expr( + span, + ast::expr_struct( + cx.path(span, ~[ident]), + fields, + None + ) + ) + ), + ] + ); + + mk_deser_impl(cx, span, ident, tps, body) +} + +// Records and structs don't have the same fields types, but they share enough +// that if we extract the right subfields out we can share the code +// generator code. +type field = { span: span, ident: ast::ident, mutbl: ast::mutability }; + +fn mk_rec_fields(fields: ~[ast::ty_field]) -> ~[field] { + do fields.map |field| { + { + span: field.span, + ident: field.node.ident, + mutbl: field.node.mt.mutbl, + } + } +} + +fn mk_struct_fields(fields: ~[@ast::struct_field]) -> ~[field] { + do fields.map |field| { + let (ident, mutbl) = match field.node.kind { + ast::named_field(ident, mutbl, _) => (ident, mutbl), + _ => fail ~"[auto_encode] does not support \ + unnamed fields", + }; + + { + span: field.span, + ident: ident, + mutbl: match mutbl { + ast::struct_mutable => ast::m_mutbl, + ast::struct_immutable => ast::m_imm, + }, + } + } +} + +fn mk_ser_fields( + cx: ext_ctxt, + span: span, + fields: ~[field] +) -> ~[@ast::stmt] { + do fields.mapi |idx, field| { + // ast for `|| self.$(name).encode(__s)` + let expr_lambda = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"self"), + field.ident + ), + cx.ident_of(~"encode") + ), + ~[cx.expr_var(span, ~"__s")] + ) + ); + + // ast for `__s.emit_field($(name), $(idx), $(expr_lambda))` + cx.stmt( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_field") + ), + ~[ + cx.lit_str(span, @cx.str_of(field.ident)), + cx.lit_uint(span, idx), + expr_lambda, + ] + ) + ) + } +} + +fn mk_deser_fields( + cx: ext_ctxt, + span: span, + fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }] +) -> ~[ast::field] { + do fields.mapi |idx, field| { + // ast for `|| std::serialize::decode(__d)` + let expr_lambda = cx.lambda( + cx.expr_blk( + cx.expr_call( + span, + cx.expr_path(span, ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"decode"), + ]), + ~[cx.expr_var(span, ~"__d")] + ) + ) + ); + + // ast for `__d.read_field($(name), $(idx), $(expr_lambda))` + let expr: @ast::expr = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_field") + ), + ~[ + cx.lit_str(span, @cx.str_of(field.ident)), + cx.lit_uint(span, idx), + expr_lambda, + ] + ); + + { + node: { mutbl: field.mutbl, ident: field.ident, expr: expr }, + span: span, + } + } +} + +fn mk_enum_ser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + enum_def: ast::enum_def, + tps: ~[ast::ty_param] +) -> @ast::item { + let body = mk_enum_ser_body( + cx, + span, + ident, + enum_def.variants + ); + + mk_ser_impl(cx, span, ident, tps, body) +} + +fn mk_enum_deser_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + enum_def: ast::enum_def, + tps: ~[ast::ty_param] +) -> @ast::item { + let body = mk_enum_deser_body( + cx, + span, + ident, + enum_def.variants + ); + + mk_deser_impl(cx, span, ident, tps, body) +} + +fn ser_variant( + cx: ext_ctxt, + span: span, + v_name: ast::ident, + v_idx: uint, + args: ~[ast::variant_arg] +) -> ast::arm { + // Name the variant arguments. + let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i))); + + // Bind the names to the variant argument type. + let pats = args.mapi(|i, arg| cx.binder_pat(arg.ty.span, names[i])); + + let pat_node = if pats.is_empty() { + ast::pat_ident( + ast::bind_by_ref(ast::m_imm), + cx.path(span, ~[v_name]), + None + ) + } else { + ast::pat_enum( + cx.path(span, ~[v_name]), + Some(pats) + ) + }; + + let pat = @{ + id: cx.next_id(), + node: pat_node, + span: span, + }; + + let stmts = do args.mapi |a_idx, _arg| { + // ast for `__s.emit_enum_variant_arg` + let expr_emit = cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_enum_variant_arg") + ); + + // ast for `|| $(v).encode(__s)` + let expr_encode = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_path(span, ~[names[a_idx]]), + cx.ident_of(~"encode") + ), + ~[cx.expr_var(span, ~"__s")] + ) + ); + + // ast for `$(expr_emit)($(a_idx), $(expr_encode))` + cx.stmt( + cx.expr_call( + span, + expr_emit, + ~[cx.lit_uint(span, a_idx), expr_encode] + ) + ) + }; + + // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))` + let body = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_enum_variant") + ), + ~[ + cx.lit_str(span, @cx.str_of(v_name)), + cx.lit_uint(span, v_idx), + cx.lit_uint(span, stmts.len()), + cx.lambda_stmts(span, stmts), + ] + ); + + { pats: ~[pat], guard: None, body: cx.expr_blk(body) } +} + +fn mk_enum_ser_body( + cx: ext_ctxt, + span: span, + name: ast::ident, + variants: ~[ast::variant] +) -> @ast::expr { + let arms = do variants.mapi |v_idx, variant| { + match variant.node.kind { + ast::tuple_variant_kind(args) => + ser_variant(cx, span, variant.node.name, v_idx, args), + ast::struct_variant_kind(*) => + fail ~"struct variants unimplemented", + ast::enum_variant_kind(*) => + fail ~"enum variants unimplemented", + } + }; + + // ast for `match *self { $(arms) }` + let match_expr = cx.expr( + span, + ast::expr_match( + cx.expr( + span, + ast::expr_unary(ast::deref, cx.expr_var(span, ~"self")) + ), + arms + ) + ); + + // ast for `__s.emit_enum($(name), || $(match_expr))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_enum") + ), + ~[ + cx.lit_str(span, @cx.str_of(name)), + cx.lambda_expr(match_expr), + ] + ) +} + +fn mk_enum_deser_variant_nary( + cx: ext_ctxt, + span: span, + name: ast::ident, + args: ~[ast::variant_arg] +) -> @ast::expr { + let args = do args.mapi |idx, _arg| { + // ast for `|| std::serialize::decode(__d)` + let expr_lambda = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_path(span, ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"decode"), + ]), + ~[cx.expr_var(span, ~"__d")] + ) + ); + + // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_enum_variant_arg") + ), + ~[cx.lit_uint(span, idx), expr_lambda] + ) + }; + + // ast for `$(name)($(args))` + cx.expr_call(span, cx.expr_path(span, ~[name]), args) +} + +fn mk_enum_deser_body( + cx: ext_ctxt, + span: span, + name: ast::ident, + variants: ~[ast::variant] +) -> @ast::expr { + let mut arms = do variants.mapi |v_idx, variant| { + let body = match variant.node.kind { + ast::tuple_variant_kind(args) => { + if args.is_empty() { + // for a nullary variant v, do "v" + cx.expr_path(span, ~[variant.node.name]) + } else { + // for an n-ary variant v, do "v(a_1, ..., a_n)" + mk_enum_deser_variant_nary( + cx, + span, + variant.node.name, + args + ) + } + }, + ast::struct_variant_kind(*) => + fail ~"struct variants unimplemented", + ast::enum_variant_kind(*) => + fail ~"enum variants unimplemented", + }; + + let pat = @{ + id: cx.next_id(), + node: ast::pat_lit(cx.lit_uint(span, v_idx)), + span: span, + }; + + { + pats: ~[pat], + guard: None, + body: cx.expr_blk(body), + } + }; + + let impossible_case = { + pats: ~[@{ id: cx.next_id(), node: ast::pat_wild, span: span}], + guard: None, + + // FIXME(#3198): proper error message + body: cx.expr_blk(cx.expr(span, ast::expr_fail(None))), + }; + + arms.push(impossible_case); + + // ast for `|i| { match i { $(arms) } }` + let expr_lambda = cx.expr( + span, + ast::expr_fn_block( + { + inputs: ~[{ + mode: ast::infer(cx.next_id()), + ty: @{ + id: cx.next_id(), + node: ast::ty_infer, + span: span + }, + pat: @{id: cx.next_id(), + node: ast::pat_ident( + ast::bind_by_value, + ast_util::ident_to_path(span, + cx.ident_of(~"i")), + None), + span: span}, + id: cx.next_id(), + }], + output: @{ + id: cx.next_id(), + node: ast::ty_infer, + span: span, + }, + cf: ast::return_val, + }, + cx.expr_blk( + cx.expr( + span, + ast::expr_match(cx.expr_var(span, ~"i"), arms) + ) + ), + @~[] + ) + ); + + // ast for `__d.read_enum_variant($(expr_lambda))` + let expr_lambda = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_enum_variant") + ), + ~[expr_lambda] + ) + ); + + // ast for `__d.read_enum($(e_name), $(expr_lambda))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_enum") + ), + ~[ + cx.lit_str(span, @cx.str_of(name)), + expr_lambda + ] + ) +} diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs index 359414cff42..4c1725b1000 100644 --- a/src/libsyntax/ext/auto_serialize.rs +++ b/src/libsyntax/ext/auto_serialize.rs @@ -230,139 +230,6 @@ fn expand_auto_deserialize( } } -priv impl ext_ctxt { - fn bind_path( - span: span, - ident: ast::ident, - path: @ast::path, - bounds: @~[ast::ty_param_bound] - ) -> ast::ty_param { - let bound = ast::ty_param_bound(@{ - id: self.next_id(), - node: ast::ty_path(path, self.next_id()), - span: span, - }); - - { - ident: ident, - id: self.next_id(), - bounds: @vec::append(~[bound], *bounds) - } - } - - fn expr(span: span, node: ast::expr_) -> @ast::expr { - @{id: self.next_id(), callee_id: self.next_id(), - node: node, span: span} - } - - fn path(span: span, strs: ~[ast::ident]) -> @ast::path { - @{span: span, global: false, idents: strs, rp: None, types: ~[]} - } - - fn path_tps(span: span, strs: ~[ast::ident], - tps: ~[@ast::Ty]) -> @ast::path { - @{span: span, global: false, idents: strs, rp: None, types: tps} - } - - fn ty_path(span: span, strs: ~[ast::ident], - tps: ~[@ast::Ty]) -> @ast::Ty { - @{id: self.next_id(), - node: ast::ty_path(self.path_tps(span, strs, tps), self.next_id()), - span: span} - } - - fn binder_pat(span: span, nm: ast::ident) -> @ast::pat { - let path = @{span: span, global: false, idents: ~[nm], - rp: None, types: ~[]}; - @{id: self.next_id(), - node: ast::pat_ident(ast::bind_by_ref(ast::m_imm), - path, - None), - span: span} - } - - fn stmt(expr: @ast::expr) -> @ast::stmt { - @{node: ast::stmt_semi(expr, self.next_id()), - span: expr.span} - } - - fn lit_str(span: span, s: @~str) -> @ast::expr { - self.expr( - span, - ast::expr_vstore( - self.expr( - span, - ast::expr_lit( - @{node: ast::lit_str(s), - span: span})), - ast::expr_vstore_uniq)) - } - - 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})) - } - - fn lambda(blk: ast::blk) -> @ast::expr { - let ext_cx = self; - let blk_e = self.expr(blk.span, ast::expr_block(blk)); - quote_expr!( || $blk_e ) - } - - fn blk(span: span, stmts: ~[@ast::stmt]) -> ast::blk { - {node: {view_items: ~[], - stmts: stmts, - expr: None, - id: self.next_id(), - rules: ast::default_blk}, - 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 expr_path(span: span, strs: ~[ast::ident]) -> @ast::expr { - self.expr(span, ast::expr_path(self.path(span, strs))) - } - - fn expr_var(span: span, var: ~str) -> @ast::expr { - self.expr_path(span, ~[self.ident_of(var)]) - } - - fn expr_field( - span: span, - expr: @ast::expr, - ident: ast::ident - ) -> @ast::expr { - self.expr(span, ast::expr_field(expr, ident, ~[])) - } - - fn expr_call( - span: span, - expr: @ast::expr, - args: ~[@ast::expr] - ) -> @ast::expr { - self.expr(span, ast::expr_call(expr, args, false)) - } - - fn lambda_expr(expr: @ast::expr) -> @ast::expr { - self.lambda(self.expr_blk(expr)) - } - - fn lambda_stmts(span: span, stmts: ~[@ast::stmt]) -> @ast::expr { - self.lambda(self.blk(span, stmts)) - } -} - fn mk_impl( cx: ext_ctxt, span: span, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a5ed1f5e101..d245aa1c050 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -47,7 +47,7 @@ enum mac_result { enum syntax_extension { - // #[auto_serialize] and such + // #[auto_encode] and such item_decorator(item_decorator), // Token-tree expanders @@ -79,6 +79,12 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { syntax_expanders.insert( ~"auto_deserialize", item_decorator(ext::auto_serialize::expand_auto_deserialize)); + syntax_expanders.insert( + ~"auto_encode", + item_decorator(ext::auto_encode::expand_auto_encode)); + syntax_expanders.insert( + ~"auto_decode", + item_decorator(ext::auto_encode::expand_auto_decode)); syntax_expanders.insert(~"env", builtin_normal_tt(ext::env::expand_syntax_ext)); syntax_expanders.insert(~"concat_idents", diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 119e1e25fb7..6013178c5ee 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -117,6 +117,9 @@ mod ext { #[path = "ext/log_syntax.rs"] mod log_syntax; #[legacy_exports] + #[path = "ext/auto_encode.rs"] + mod auto_encode; + #[legacy_exports] #[path = "ext/auto_serialize.rs"] mod auto_serialize; #[legacy_exports] |
