auto merge of #5578 : erickt/rust/incoming, r=jbclements,erickt

Hey folks,

This patch series does some work on the json decoder, specifically with auto decoding of enums. Previously, we would take this code:

```
enum A {
    B,
    C(~str, uint)
}
```

and would encode a value of this enum to either `["B", []]` or `["C", ["D", 123]]`. I've changed this to `"B"` or `["C", "D", 123]`. This matches the style of the O'Caml json library [json-wheel](http://mjambon.com/json-wheel.html). I've added tests to make sure all this work.

In order to make this change, I added passing a `&[&str]` vec to `Decode::emit_enum_variant` so the json decoder can convert the name of a variant into it's position. I also changed the impl of `Encodable` for `Option<T>` to have the right upper casing.

I also did some work on the parser, which allows for `fn foo<T: ::cmp::Eq>() { ... }` statements (#5572), fixed the pretty printer properly expanding `debug!("...")` expressions, and removed `ast::expr_vstore_fixed`, which doesn't appear to be used anymore.
This commit is contained in:
bors 2013-03-27 21:51:53 -07:00
commit 84ddff3909
24 changed files with 820 additions and 316 deletions

View file

@ -681,6 +681,7 @@ fn read_vtable_res(&self, xcx: @ExtendedDecodeContext)
@self.read_to_vec(|| self.read_vtable_origin(xcx) )
}
#[cfg(stage0)]
fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext)
-> typeck::vtable_origin {
do self.read_enum(~"vtable_origin") {
@ -715,6 +716,44 @@ fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext)
}
}
}
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext)
-> typeck::vtable_origin {
do self.read_enum("vtable_origin") {
do self.read_enum_variant(["vtable_static", "vtable_param"]) |i| {
match i {
0 => {
typeck::vtable_static(
do self.read_enum_variant_arg(0u) {
self.read_def_id(xcx)
},
do self.read_enum_variant_arg(1u) {
self.read_tys(xcx)
},
do self.read_enum_variant_arg(2u) {
self.read_vtable_res(xcx)
}
)
}
1 => {
typeck::vtable_param(
do self.read_enum_variant_arg(0u) {
self.read_uint()
},
do self.read_enum_variant_arg(1u) {
self.read_uint()
}
)
}
// hard to avoid - user input
_ => fail!(~"bad enum variant")
}
}
}
}
}
// ______________________________________________________________________

View file

@ -156,7 +156,6 @@ pub fn check_expr(sess: Session,
expr_paren(e) => { check_expr(sess, def_map, method_map,
tcx, e, is_const, v); }
expr_vstore(_, expr_vstore_slice) |
expr_vstore(_, expr_vstore_fixed(_)) |
expr_vec(_, m_imm) |
expr_addr_of(m_imm, _) |
expr_field(*) |

View file

@ -110,7 +110,6 @@ pub fn classify(e: @expr,
ast::expr_vstore(e, vstore) => {
match vstore {
ast::expr_vstore_fixed(_) |
ast::expr_vstore_slice => classify(e, tcx),
ast::expr_vstore_uniq |
ast::expr_vstore_box |

View file

@ -1290,7 +1290,7 @@ fn propagate_through_expr(&self, expr: @expr, succ: LiveNode)
self.propagate_through_expr(l, ln)
}
expr_log(_, l, r) |
expr_log(l, r) |
expr_index(l, r) |
expr_binary(_, l, r) => {
self.propagate_through_exprs(~[l, r], succ)

View file

@ -567,7 +567,7 @@ fn use_expr(&self,
self.consume_block(blk, visitor);
}
expr_log(_, a_expr, b_expr) => {
expr_log(a_expr, b_expr) => {
self.consume_expr(a_expr, visitor);
self.use_expr(b_expr, Read, visitor);
}

View file

@ -466,9 +466,6 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef {
let (v, _, _) = const_vec(cx, e, *es);
v
}
ast::expr_vstore(e, ast::expr_vstore_fixed(_)) => {
const_expr(cx, e)
}
ast::expr_vstore(sub, ast::expr_vstore_slice) => {
match sub.node {
ast::expr_lit(ref lit) => {

View file

@ -496,7 +496,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
ast::expr_ret(ex) => {
return controlflow::trans_ret(bcx, ex);
}
ast::expr_log(_, lvl, a) => {
ast::expr_log(lvl, a) => {
return controlflow::trans_log(expr, lvl, bcx, a);
}
ast::expr_while(cond, ref body) => {
@ -703,9 +703,6 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
ast::expr_vstore(contents, ast::expr_vstore_mut_slice) => {
return tvec::trans_slice_vstore(bcx, expr, contents, dest);
}
ast::expr_vstore(contents, ast::expr_vstore_fixed(_)) => {
return tvec::trans_fixed_vstore(bcx, expr, contents, dest);
}
ast::expr_vec(*) | ast::expr_repeat(*) => {
return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
}

View file

@ -329,7 +329,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty));
mark_for_method_call(cx, e.id, e.callee_id);
}
expr_log(_, _, val) => {
expr_log(_, val) => {
node_type_needs(cx, use_tydesc, val.id);
}
expr_call(f, _, _) => {

View file

@ -3114,7 +3114,6 @@ pub fn expr_kind(tcx: ctxt,
ast::expr_lit(@codemap::spanned {node: lit_str(_), _}) |
ast::expr_vstore(_, ast::expr_vstore_slice) |
ast::expr_vstore(_, ast::expr_vstore_mut_slice) |
ast::expr_vstore(_, ast::expr_vstore_fixed(_)) |
ast::expr_vec(*) => {
RvalueDpsExpr
}

View file

@ -2366,7 +2366,7 @@ fn check_loop_body(fcx: @mut FnCtxt,
}
fcx.write_bot(id);
}
ast::expr_log(_, lv, e) => {
ast::expr_log(lv, e) => {
check_expr_has_type(fcx, lv,
ty::mk_mach_uint(tcx, ast::ty_u32));
@ -3301,14 +3301,6 @@ pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt,
v: ast::expr_vstore)
-> ty::vstore {
match v {
ast::expr_vstore_fixed(None) => ty::vstore_fixed(n),
ast::expr_vstore_fixed(Some(u)) => {
if n != u {
let s = fmt!("fixed-size sequence mismatch: %u vs. %u",u, n);
fcx.ccx.tcx.sess.span_err(e.span,s);
}
ty::vstore_fixed(u)
}
ast::expr_vstore_uniq => ty::vstore_uniq,
ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box,
ast::expr_vstore_slice | ast::expr_vstore_mut_slice => {

View file

@ -335,6 +335,7 @@ fn read_enum<T>(&self, name: &str, f: &fn() -> T) -> T {
self.push_doc(self.next_doc(EsEnum), f)
}
#[cfg(stage0)]
fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T {
debug!("read_enum_variant()");
let idx = self._next_uint(EsEnumVid);
@ -344,6 +345,18 @@ fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T {
}
}
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn read_enum_variant<T>(&self, _names: &[&str], f: &fn(uint) -> T) -> T {
debug!("read_enum_variant()");
let idx = self._next_uint(EsEnumVid);
debug!(" idx=%u", idx);
do self.push_doc(self.next_doc(EsEnumBody)) {
f(idx)
}
}
fn read_enum_variant_arg<T>(&self, idx: uint, f: &fn() -> T) -> T {
debug!("read_enum_variant_arg(idx=%u)", idx);
f()
@ -397,8 +410,37 @@ fn read_tup_elt<T>(&self, idx: uint, f: &fn() -> T) -> T {
debug!("read_tup_elt(idx=%u)", idx);
f()
}
}
#[cfg(stage0)]
fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
debug!("read_option()");
do self.read_enum("Option") || {
do self.read_enum_variant |idx| {
match idx {
0 => None,
1 => Some(f()),
_ => fail!(),
}
}
}
}
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
debug!("read_option()");
do self.read_enum("Option") || {
do self.read_enum_variant(["None", "Some"]) |idx| {
match idx {
0 => None,
1 => Some(f()),
_ => fail!(),
}
}
}
}
}
}
pub mod writer {
@ -664,9 +706,19 @@ fn emit_field(&self, name: &str, _idx: uint, f: &fn()) {
fn emit_tup(&self, _len: uint, f: &fn()) { f() }
fn emit_tup_elt(&self, _idx: uint, f: &fn()) { f() }
}
fn emit_option(&self, f: &fn()) {
self.emit_enum("Option", f);
}
fn emit_option_none(&self) {
self.emit_enum_variant("None", 0, 0, || ())
}
fn emit_option_some(&self, f: &fn()) {
self.emit_enum_variant("Some", 1, 1, f)
}
}
}
// ___________________________________________________________________________
// Testing

View file

@ -119,39 +119,19 @@ fn emit_enum(&self, _name: &str, f: &fn()) {
f()
}
fn emit_enum_variant(&self, name: &str, _id: uint, _cnt: uint, f: &fn()) {
// encoding of enums is special-cased for Option. Specifically:
// Some(34) => 34
// None => null
// other enums are encoded as vectors:
fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
// enums are encoded as strings or vectors:
// Bunny => "Bunny"
// Kangaroo(34,"William") => ["Kangaroo",[34,"William"]]
// the default expansion for enums is more verbose than I'd like;
// specifically, the inner pair of brackets seems superfluous,
// BUT the design of the enumeration framework and the requirements
// of the special-case for Option mean that a first argument must
// be encoded "naked"--with no commas--and that the option name
// can't be followed by just a comma, because there might not
// be any elements in the tuple.
// FIXME #4872: this would be more precise and less frightening
// with fully-qualified option names. To get that information,
// we'd have to change the expansion of auto-encode to pass
// those along.
if (name == ~"Some") {
f();
} else if (name == ~"None") {
self.wr.write_str(~"null");
if cnt == 0 {
self.wr.write_str(escape_str(name));
} else {
self.wr.write_char('[');
self.wr.write_str(escape_str(name));
self.wr.write_char(',');
self.wr.write_char('[');
f();
self.wr.write_char(']');
self.wr.write_char(']');
}
}
@ -200,6 +180,10 @@ fn emit_tup(&self, len: uint, f: &fn()) {
fn emit_tup_elt(&self, idx: uint, f: &fn()) {
self.emit_vec_elt(idx, f)
}
fn emit_option(&self, f: &fn()) { f(); }
fn emit_option_none(&self) { self.emit_nil(); }
fn emit_option_some(&self, f: &fn()) { f(); }
}
pub struct PrettyEncoder {
@ -250,27 +234,44 @@ fn emit_borrowed(&self, f: &fn()) { f() }
fn emit_owned(&self, f: &fn()) { f() }
fn emit_managed(&self, f: &fn()) { f() }
fn emit_enum(&self, name: &str, f: &fn()) {
if name != "option" { fail!(~"only supports option enum") }
f()
}
fn emit_enum_variant(&self, _name: &str, id: uint, _cnt: uint, f: &fn()) {
if id == 0 {
self.emit_nil();
fn emit_enum(&self, _name: &str, f: &fn()) { f() }
fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) {
if cnt == 0 {
self.wr.write_str(escape_str(name));
} else {
f()
self.wr.write_char('[');
self.indent += 2;
self.wr.write_char('\n');
self.wr.write_str(spaces(self.indent));
self.wr.write_str(escape_str(name));
self.wr.write_str(",\n");
f();
self.wr.write_char('\n');
self.indent -= 2;
self.wr.write_str(spaces(self.indent));
self.wr.write_char(']');
}
}
fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) {
fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) {
if idx != 0 {
self.wr.write_str(",\n");
}
self.wr.write_str(spaces(self.indent));
f()
}
fn emit_borrowed_vec(&self, _len: uint, f: &fn()) {
self.wr.write_char('[');
self.indent += 2;
f();
self.indent -= 2;
self.wr.write_char(']');
fn emit_borrowed_vec(&self, len: uint, f: &fn()) {
if len == 0 {
self.wr.write_str("[]");
} else {
self.wr.write_char('[');
self.indent += 2;
f();
self.wr.write_char('\n');
self.indent -= 2;
self.wr.write_str(spaces(self.indent));
self.wr.write_char(']');
}
}
fn emit_owned_vec(&self, len: uint, f: &fn()) {
self.emit_borrowed_vec(len, f)
@ -292,11 +293,17 @@ fn emit_rec(&self, f: &fn()) {
self.wr.write_char('{');
self.indent += 2;
f();
self.wr.write_char('\n');
self.indent -= 2;
self.wr.write_str(spaces(self.indent));
self.wr.write_char('}');
}
fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) {
self.emit_rec(f)
fn emit_struct(&self, _name: &str, len: uint, f: &fn()) {
if len == 0 {
self.wr.write_str("{}");
} else {
self.emit_rec(f)
}
}
fn emit_field(&self, name: &str, idx: uint, f: &fn()) {
if idx == 0 {
@ -315,6 +322,10 @@ fn emit_tup(&self, sz: uint, f: &fn()) {
fn emit_tup_elt(&self, idx: uint, f: &fn()) {
self.emit_vec_elt(idx, f)
}
fn emit_option(&self, f: &fn()) { f(); }
fn emit_option_none(&self) { self.emit_nil(); }
fn emit_option_some(&self, f: &fn()) { f(); }
}
impl<S:serialize::Encoder> serialize::Encodable<S> for Json {
@ -816,7 +827,7 @@ fn read_owned_str(&self) -> ~str {
debug!("read_owned_str");
match *self.pop() {
String(ref s) => copy *s,
_ => fail!(~"not a string")
ref json => fail!(fmt!("not a string: %?", *json))
}
}
@ -824,7 +835,7 @@ fn read_managed_str(&self) -> @str {
debug!("read_managed_str");
match *self.pop() {
String(ref s) => s.to_managed(),
_ => fail!(~"not a string")
ref json => fail!(fmt!("not a string: %?", *json))
}
}
@ -840,10 +851,10 @@ fn read_managed<T>(&self, f: &fn() -> T) -> T {
fn read_enum<T>(&self, name: &str, f: &fn() -> T) -> T {
debug!("read_enum(%s)", name);
if name != ~"option" { fail!(~"only supports the option enum") }
f()
}
#[cfg(stage0)]
fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T {
debug!("read_enum_variant()");
let idx = match *self.peek() {
@ -853,10 +864,32 @@ fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T {
f(idx)
}
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn read_enum_variant<T>(&self, names: &[&str], f: &fn(uint) -> T) -> T {
debug!("read_enum_variant(names=%?)", names);
let name = match *self.peek() {
String(ref s) => s,
List([String(ref s), .. _]) => s,
ref json => fail!(fmt!("invalid variant: %?", *json)),
};
let idx = match vec::position(names, |n| str::eq_slice(*n, *name)) {
Some(idx) => idx,
None => fail!(fmt!("Unknown variant name: %?", name)),
};
f(idx)
}
fn read_enum_variant_arg<T>(&self, idx: uint, f: &fn() -> T) -> T {
debug!("read_enum_variant_arg(idx=%u)", idx);
if idx != 0 { fail!(~"unknown index") }
f()
match *self.peek() {
List(ref list) => {
self.stack.push(&list[idx + 1]);
f()
}
ref json => fail!(fmt!("not a list: %?", json)),
}
}
fn read_owned_vec<T>(&self, f: &fn(uint) -> T) -> T {
@ -946,6 +979,13 @@ fn read_tup_elt<T>(&self, idx: uint, f: &fn() -> T) -> T {
_ => fail!(~"not a list")
}
}
fn read_option<T>(&self, f: &fn() -> T) -> Option<T> {
match *self.peek() {
Null => { self.pop(); None }
_ => Some(f()),
}
}
}
impl Eq for Json {
@ -1195,14 +1235,12 @@ fn to_str(&self) -> ~str {
#[cfg(test)]
mod tests {
use super::*;
use core::prelude::*;
use json::*;
use serialize;
use core::result;
use core::hashmap::linear::LinearMap;
use std::serialize::Decodable;
fn mk_object(items: &[(~str, Json)]) -> Json {
let mut d = ~LinearMap::new();
@ -1218,45 +1256,89 @@ fn mk_object(items: &[(~str, Json)]) -> Json {
#[test]
fn test_write_null() {
fail_unless!(to_str(&Null) == ~"null");
assert_eq!(to_str(&Null), ~"null");
}
#[test]
fn test_write_number() {
fail_unless!(to_str(&Number(3f)) == ~"3");
fail_unless!(to_str(&Number(3.1f)) == ~"3.1");
fail_unless!(to_str(&Number(-1.5f)) == ~"-1.5");
fail_unless!(to_str(&Number(0.5f)) == ~"0.5");
assert_eq!(to_str(&Number(3f)), ~"3");
assert_eq!(to_str(&Number(3.1f)), ~"3.1");
assert_eq!(to_str(&Number(-1.5f)), ~"-1.5");
assert_eq!(to_str(&Number(0.5f)), ~"0.5");
}
#[test]
fn test_write_str() {
fail_unless!(to_str(&String(~"")) == ~"\"\"");
fail_unless!(to_str(&String(~"foo")) == ~"\"foo\"");
assert_eq!(to_str(&String(~"")), ~"\"\"");
assert_eq!(to_str(&String(~"foo")), ~"\"foo\"");
}
#[test]
fn test_write_bool() {
fail_unless!(to_str(&Boolean(true)) == ~"true");
fail_unless!(to_str(&Boolean(false)) == ~"false");
assert_eq!(to_str(&Boolean(true)), ~"true");
assert_eq!(to_str(&Boolean(false)), ~"false");
}
#[test]
fn test_write_list() {
fail_unless!(to_str(&List(~[])) == ~"[]");
fail_unless!(to_str(&List(~[Boolean(true)])) == ~"[true]");
fail_unless!(to_str(&List(~[
assert_eq!(to_str(&List(~[])), ~"[]");
assert_eq!(to_str(&List(~[Boolean(true)])), ~"[true]");
assert_eq!(to_str(&List(~[
Boolean(false),
Null,
List(~[String(~"foo\nbar"), Number(3.5f)])
])) == ~"[false,null,[\"foo\\nbar\",3.5]]");
])), ~"[false,null,[\"foo\\nbar\",3.5]]");
}
#[test]
fn test_write_list_pretty() {
assert_eq!(to_pretty_str(&List(~[])), ~"[]");
assert_eq!(
to_pretty_str(&List(~[Boolean(true)])),
~"\
[\n \
true\n\
]"
);
assert_eq!(
to_pretty_str(&List(~[
Boolean(false),
Null,
List(~[String(~"foo\nbar"), Number(3.5f)])
])),
~"\
[\n \
false,\n \
null,\n \
[\n \
\"foo\\nbar\",\n \
3.5\n \
]\n\
]"
);
}
#[test]
fn test_write_object() {
fail_unless!(to_str(&mk_object(~[])) == ~"{}");
fail_unless!(to_str(&mk_object(~[(~"a", Boolean(true))]))
== ~"{\"a\":true}");
assert_eq!(to_str(&mk_object(~[])), ~"{}");
assert_eq!(
to_str(&mk_object(~[(~"a", Boolean(true))])),
~"{\"a\":true}"
);
assert_eq!(
to_str(&mk_object(~[
(~"b", List(~[
mk_object(~[(~"c", String(~"\x0c\r"))]),
mk_object(~[(~"d", String(~""))])
]))
])),
~"{\
\"b\":[\
{\"c\":\"\\f\\r\"},\
{\"d\":\"\"}\
]\
}"
);
let a = mk_object(~[
(~"a", Boolean(true)),
(~"b", List(~[
@ -1266,248 +1348,343 @@ fn test_write_object() {
]);
// We can't compare the strings directly because the object fields be
// printed in a different order.
let b = result::unwrap(from_str(to_str(&a)));
fail_unless!(a == b);
let b = from_str(to_str(&a)).unwrap();
assert_eq!(a, b);
}
#[test]
fn test_write_enum () {
let bw = @io::BytesWriter();
let bww : @io::Writer = (bw as @io::Writer);
let encoder = (@Encoder(bww) as @serialize::Encoder);
do encoder.emit_enum(~"animal") {
do encoder.emit_enum_variant (~"frog",37,1242) {
// name of frog:
do encoder.emit_enum_variant_arg (0) {
encoder.emit_owned_str(~"Henry")
}
// mass of frog in grams:
do encoder.emit_enum_variant_arg (1) {
encoder.emit_int(349);
}
}
}
assert_eq!(str::from_bytes(bw.bytes), ~"[\"frog\",[\"Henry\",349]]");
fn test_write_object_pretty() {
assert_eq!(to_pretty_str(&mk_object(~[])), ~"{\n}");
assert_eq!(
to_pretty_str(&mk_object(~[(~"a", Boolean(true))])),
~"\
{\n \
\"a\": true\n\
}"
);
assert_eq!(
to_pretty_str(&mk_object(~[
(~"b", List(~[
mk_object(~[(~"c", String(~"\x0c\r"))]),
mk_object(~[(~"d", String(~""))])
]))
])),
~"\
{\n \
\"b\": [\n \
{\n \
\"c\": \"\\f\\r\"\n \
},\n \
{\n \
\"d\": \"\"\n \
}\n \
]\n\
}"
);
let a = mk_object(~[
(~"a", Boolean(true)),
(~"b", List(~[
mk_object(~[(~"c", String(~"\x0c\r"))]),
mk_object(~[(~"d", String(~""))])
]))
]);
// We can't compare the strings directly because the object fields be
// printed in a different order.
let b = from_str(to_str(&a)).unwrap();
assert_eq!(a, b);
}
#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
enum Animal {
Dog,
Frog(~str, int)
}
#[test]
fn test_write_some () {
let bw = @io::BytesWriter();
let bww : @io::Writer = (bw as @io::Writer);
let encoder = (@Encoder(bww) as @serialize::Encoder);
do encoder.emit_enum(~"Option") {
do encoder.emit_enum_variant (~"Some",37,1242) {
do encoder.emit_enum_variant_arg (0) {
encoder.emit_owned_str(~"jodhpurs")
}
}
}
assert_eq!(str::from_bytes(bw.bytes), ~"\"jodhpurs\"");
fn test_write_enum_no_args() {
let animal = Dog;
let s = do io::with_str_writer |wr| {
let encoder = Encoder(wr);
animal.encode(&encoder);
};
assert_eq!(s, ~"\"Dog\"");
}
#[test]
fn test_write_none () {
let bw = @io::BytesWriter();
let bww : @io::Writer = (bw as @io::Writer);
let encoder = (@Encoder(bww) as @serialize::Encoder);
do encoder.emit_enum(~"Option") {
do encoder.emit_enum_variant (~"None",37,1242) {
}
}
assert_eq!(str::from_bytes(bw.bytes), ~"null");
fn test_write_enum_no_args_pretty() {
let animal = Dog;
let s = do io::with_str_writer |wr| {
let encoder = PrettyEncoder(wr);
animal.encode(&encoder);
};
assert_eq!(s, ~"\"Dog\"");
}
#[test]
fn test_write_enum_multiple_args() {
let animal = Frog(~"Henry", 349);
let s = do io::with_str_writer |wr| {
let encoder = Encoder(wr);
animal.encode(&encoder);
};
assert_eq!(s, ~"[\"Frog\",\"Henry\",349]");
}
#[test]
fn test_write_enum_multiple_args_pretty() {
let animal = Frog(~"Henry", 349);
let s = do io::with_str_writer |wr| {
let encoder = PrettyEncoder(wr);
animal.encode(&encoder);
};
assert_eq!(
s,
~"\
[\n \
\"Frog\",\n \
\"Henry\",\n \
349\n\
]"
);
}
#[test]
fn test_write_some() {
let value = Some(~"jodhpurs");
let s = do io::with_str_writer |wr| {
let encoder = Encoder(wr);
value.encode(&encoder);
};
assert_eq!(s, ~"\"jodhpurs\"");
}
#[test]
fn test_write_some_pretty() {
let value = Some(~"jodhpurs");
let s = do io::with_str_writer |wr| {
let encoder = PrettyEncoder(wr);
value.encode(&encoder);
};
assert_eq!(s, ~"\"jodhpurs\"");
}
#[test]
fn test_write_none() {
let value: Option<~str> = None;
let s = do io::with_str_writer |wr| {
let encoder = Encoder(wr);
value.encode(&encoder);
};
assert_eq!(s, ~"null");
}
#[test]
fn test_write_none_pretty() {
let value: Option<~str> = None;
let s = do io::with_str_writer |wr| {
let encoder = Encoder(wr);
value.encode(&encoder);
};
assert_eq!(s, ~"null");
}
#[test]
fn test_trailing_characters() {
fail_unless!(from_str(~"nulla") ==
assert_eq!(from_str(~"nulla"),
Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"}));
fail_unless!(from_str(~"truea") ==
assert_eq!(from_str(~"truea"),
Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"}));
fail_unless!(from_str(~"falsea") ==
assert_eq!(from_str(~"falsea"),
Err(Error {line: 1u, col: 6u, msg: @~"trailing characters"}));
fail_unless!(from_str(~"1a") ==
assert_eq!(from_str(~"1a"),
Err(Error {line: 1u, col: 2u, msg: @~"trailing characters"}));
fail_unless!(from_str(~"[]a") ==
assert_eq!(from_str(~"[]a"),
Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"}));
fail_unless!(from_str(~"{}a") ==
assert_eq!(from_str(~"{}a"),
Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"}));
}
#[test]
fn test_read_identifiers() {
fail_unless!(from_str(~"n") ==
assert_eq!(from_str(~"n"),
Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"nul") ==
assert_eq!(from_str(~"nul"),
Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"t") ==
assert_eq!(from_str(~"t"),
Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"truz") ==
assert_eq!(from_str(~"truz"),
Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"f") ==
assert_eq!(from_str(~"f"),
Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"faz") ==
assert_eq!(from_str(~"faz"),
Err(Error {line: 1u, col: 3u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"null") == Ok(Null));
fail_unless!(from_str(~"true") == Ok(Boolean(true)));
fail_unless!(from_str(~"false") == Ok(Boolean(false)));
fail_unless!(from_str(~" null ") == Ok(Null));
fail_unless!(from_str(~" true ") == Ok(Boolean(true)));
fail_unless!(from_str(~" false ") == Ok(Boolean(false)));
assert_eq!(from_str(~"null"), Ok(Null));
assert_eq!(from_str(~"true"), Ok(Boolean(true)));
assert_eq!(from_str(~"false"), Ok(Boolean(false)));
assert_eq!(from_str(~" null "), Ok(Null));
assert_eq!(from_str(~" true "), Ok(Boolean(true)));
assert_eq!(from_str(~" false "), Ok(Boolean(false)));
}
#[test]
fn test_read_number() {
fail_unless!(from_str(~"+") ==
assert_eq!(from_str(~"+"),
Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~".") ==
assert_eq!(from_str(~"."),
Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"-") ==
assert_eq!(from_str(~"-"),
Err(Error {line: 1u, col: 2u, msg: @~"invalid number"}));
fail_unless!(from_str(~"00") ==
assert_eq!(from_str(~"00"),
Err(Error {line: 1u, col: 2u, msg: @~"invalid number"}));
fail_unless!(from_str(~"1.") ==
assert_eq!(from_str(~"1."),
Err(Error {line: 1u, col: 3u, msg: @~"invalid number"}));
fail_unless!(from_str(~"1e") ==
assert_eq!(from_str(~"1e"),
Err(Error {line: 1u, col: 3u, msg: @~"invalid number"}));
fail_unless!(from_str(~"1e+") ==
assert_eq!(from_str(~"1e+"),
Err(Error {line: 1u, col: 4u, msg: @~"invalid number"}));
fail_unless!(from_str(~"3") == Ok(Number(3f)));
fail_unless!(from_str(~"3.1") == Ok(Number(3.1f)));
fail_unless!(from_str(~"-1.2") == Ok(Number(-1.2f)));
fail_unless!(from_str(~"0.4") == Ok(Number(0.4f)));
fail_unless!(from_str(~"0.4e5") == Ok(Number(0.4e5f)));
fail_unless!(from_str(~"0.4e+15") == Ok(Number(0.4e15f)));
fail_unless!(from_str(~"0.4e-01") == Ok(Number(0.4e-01f)));
fail_unless!(from_str(~" 3 ") == Ok(Number(3f)));
assert_eq!(from_str(~"3"), Ok(Number(3f)));
assert_eq!(from_str(~"3.1"), Ok(Number(3.1f)));
assert_eq!(from_str(~"-1.2"), Ok(Number(-1.2f)));
assert_eq!(from_str(~"0.4"), Ok(Number(0.4f)));
assert_eq!(from_str(~"0.4e5"), Ok(Number(0.4e5f)));
assert_eq!(from_str(~"0.4e+15"), Ok(Number(0.4e15f)));
assert_eq!(from_str(~"0.4e-01"), Ok(Number(0.4e-01f)));
assert_eq!(from_str(~" 3 "), Ok(Number(3f)));
}
#[test]
fn test_read_str() {
fail_unless!(from_str(~"\"") ==
assert_eq!(from_str(~"\""),
Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing string"
}));
fail_unless!(from_str(~"\"lol") ==
assert_eq!(from_str(~"\"lol"),
Err(Error {line: 1u, col: 5u, msg: @~"EOF while parsing string"
}));
fail_unless!(from_str(~"\"\"") == Ok(String(~"")));
fail_unless!(from_str(~"\"foo\"") == Ok(String(~"foo")));
fail_unless!(from_str(~"\"\\\"\"") == Ok(String(~"\"")));
fail_unless!(from_str(~"\"\\b\"") == Ok(String(~"\x08")));
fail_unless!(from_str(~"\"\\n\"") == Ok(String(~"\n")));
fail_unless!(from_str(~"\"\\r\"") == Ok(String(~"\r")));
fail_unless!(from_str(~"\"\\t\"") == Ok(String(~"\t")));
fail_unless!(from_str(~" \"foo\" ") == Ok(String(~"foo")));
assert_eq!(from_str(~"\"\""), Ok(String(~"")));
assert_eq!(from_str(~"\"foo\""), Ok(String(~"foo")));
assert_eq!(from_str(~"\"\\\"\""), Ok(String(~"\"")));
assert_eq!(from_str(~"\"\\b\""), Ok(String(~"\x08")));
assert_eq!(from_str(~"\"\\n\""), Ok(String(~"\n")));
assert_eq!(from_str(~"\"\\r\""), Ok(String(~"\r")));
assert_eq!(from_str(~"\"\\t\""), Ok(String(~"\t")));
assert_eq!(from_str(~" \"foo\" "), Ok(String(~"foo")));
}
#[test]
fn test_unicode_hex_escapes_in_str() {
fail_unless!(from_str(~"\"\\u12ab\"") == Ok(String(~"\u12ab")));
fail_unless!(from_str(~"\"\\uAB12\"") == Ok(String(~"\uAB12")));
assert_eq!(from_str(~"\"\\u12ab\""), Ok(String(~"\u12ab")));
assert_eq!(from_str(~"\"\\uAB12\""), Ok(String(~"\uAB12")));
}
#[test]
fn test_read_list() {
fail_unless!(from_str(~"[") ==
assert_eq!(from_str(~"["),
Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing value"}));
fail_unless!(from_str(~"[1") ==
assert_eq!(from_str(~"[1"),
Err(Error {line: 1u, col: 3u, msg: @~"EOF while parsing list"}));
fail_unless!(from_str(~"[1,") ==
assert_eq!(from_str(~"[1,"),
Err(Error {line: 1u, col: 4u, msg: @~"EOF while parsing value"}));
fail_unless!(from_str(~"[1,]") ==
assert_eq!(from_str(~"[1,]"),
Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}));
fail_unless!(from_str(~"[6 7]") ==
assert_eq!(from_str(~"[6 7]"),
Err(Error {line: 1u, col: 4u, msg: @~"expected `,` or `]`"}));
fail_unless!(from_str(~"[]") == Ok(List(~[])));
fail_unless!(from_str(~"[ ]") == Ok(List(~[])));
fail_unless!(from_str(~"[true]") == Ok(List(~[Boolean(true)])));
fail_unless!(from_str(~"[ false ]") == Ok(List(~[Boolean(false)])));
fail_unless!(from_str(~"[null]") == Ok(List(~[Null])));
fail_unless!(from_str(~"[3, 1]") ==
assert_eq!(from_str(~"[]"), Ok(List(~[])));
assert_eq!(from_str(~"[ ]"), Ok(List(~[])));
assert_eq!(from_str(~"[true]"), Ok(List(~[Boolean(true)])));
assert_eq!(from_str(~"[ false ]"), Ok(List(~[Boolean(false)])));
assert_eq!(from_str(~"[null]"), Ok(List(~[Null])));
assert_eq!(from_str(~"[3, 1]"),
Ok(List(~[Number(3f), Number(1f)])));
fail_unless!(from_str(~"\n[3, 2]\n") ==
assert_eq!(from_str(~"\n[3, 2]\n"),
Ok(List(~[Number(3f), Number(2f)])));
fail_unless!(from_str(~"[2, [4, 1]]") ==
assert_eq!(from_str(~"[2, [4, 1]]"),
Ok(List(~[Number(2f), List(~[Number(4f), Number(1f)])])));
}
#[test]
fn test_read_object() {
fail_unless!(from_str(~"{") ==
assert_eq!(from_str(~"{"),
Err(Error {
line: 1u,
col: 2u,
msg: @~"EOF while parsing object"}));
fail_unless!(from_str(~"{ ") ==
assert_eq!(from_str(~"{ "),
Err(Error {
line: 1u,
col: 3u,
msg: @~"EOF while parsing object"}));
fail_unless!(from_str(~"{1") ==
assert_eq!(from_str(~"{1"),
Err(Error {
line: 1u,
col: 2u,
msg: @~"key must be a string"}));
fail_unless!(from_str(~"{ \"a\"") ==
assert_eq!(from_str(~"{ \"a\""),
Err(Error {
line: 1u,
col: 6u,
msg: @~"EOF while parsing object"}));
fail_unless!(from_str(~"{\"a\"") ==
assert_eq!(from_str(~"{\"a\""),
Err(Error {
line: 1u,
col: 5u,
msg: @~"EOF while parsing object"}));
fail_unless!(from_str(~"{\"a\" ") ==
assert_eq!(from_str(~"{\"a\" "),
Err(Error {
line: 1u,
col: 6u,
msg: @~"EOF while parsing object"}));
fail_unless!(from_str(~"{\"a\" 1") ==
assert_eq!(from_str(~"{\"a\" 1"),
Err(Error {line: 1u, col: 6u, msg: @~"expected `:`"}));
fail_unless!(from_str(~"{\"a\":") ==
assert_eq!(from_str(~"{\"a\":"),
Err(Error {line: 1u, col: 6u, msg: @~"EOF while parsing value"}));
fail_unless!(from_str(~"{\"a\":1") ==
assert_eq!(from_str(~"{\"a\":1"),
Err(Error {
line: 1u,
col: 7u,
msg: @~"EOF while parsing object"}));
fail_unless!(from_str(~"{\"a\":1 1") ==
assert_eq!(from_str(~"{\"a\":1 1"),
Err(Error {line: 1u, col: 8u, msg: @~"expected `,` or `}`"}));
fail_unless!(from_str(~"{\"a\":1,") ==
assert_eq!(from_str(~"{\"a\":1,"),
Err(Error {
line: 1u,
col: 8u,
msg: @~"EOF while parsing object"}));
fail_unless!(result::unwrap(from_str(~"{}")) == mk_object(~[]));
fail_unless!(result::unwrap(from_str(~"{\"a\": 3}")) ==
assert_eq!(result::unwrap(from_str(~"{}")), mk_object(~[]));
assert_eq!(result::unwrap(from_str(~"{\"a\": 3}")),
mk_object(~[(~"a", Number(3.0f))]));
fail_unless!(result::unwrap(from_str(
~"{ \"a\": null, \"b\" : true }")) ==
assert_eq!(result::unwrap(from_str(
~"{ \"a\": null, \"b\" : true }")),
mk_object(~[
(~"a", Null),
(~"b", Boolean(true))]));
fail_unless!(result::unwrap(
from_str(~"\n{ \"a\": null, \"b\" : true }\n")) ==
assert_eq!(result::unwrap(
from_str(~"\n{ \"a\": null, \"b\" : true }\n")),
mk_object(~[
(~"a", Null),
(~"b", Boolean(true))]));
fail_unless!(result::unwrap(from_str(
~"{\"a\" : 1.0 ,\"b\": [ true ]}")) ==
assert_eq!(result::unwrap(from_str(
~"{\"a\" : 1.0 ,\"b\": [ true ]}")),
mk_object(~[
(~"a", Number(1.0)),
(~"b", List(~[Boolean(true)]))
]));
fail_unless!(result::unwrap(from_str(
assert_eq!(result::unwrap(from_str(
~"{" +
~"\"a\": 1.0, " +
~"\"b\": [" +
@ -1515,7 +1692,7 @@ fn test_read_object() {
~"\"foo\\nbar\", " +
~"{ \"c\": {\"d\": null} } " +
~"]" +
~"}")) ==
~"}")),
mk_object(~[
(~"a", Number(1.0f)),
(~"b", List(~[
@ -1528,9 +1705,37 @@ fn test_read_object() {
]));
}
#[test]
fn test_read_none() {
let decoder = Decoder(from_str(~"null").unwrap());
let value: Option<~str> = Decodable::decode(&decoder);
assert_eq!(value, None);
}
#[test]
fn test_read_some() {
let decoder = Decoder(from_str(~"\"jodhpurs\"").unwrap());
let value: Option<~str> = Decodable::decode(&decoder);
assert_eq!(value, Some(~"jodhpurs"));
}
#[test]
fn test_read_enum_no_args() {
let decoder = Decoder(from_str(~"\"Dog\"").unwrap());
let value: Animal = Decodable::decode(&decoder);
assert_eq!(value, Dog);
}
#[test]
fn test_read_enum_multiple_args() {
let decoder = Decoder(from_str(~"[\"Frog\",\"Henry\",349]").unwrap());
let value: Animal = Decodable::decode(&decoder);
assert_eq!(value, Frog(~"Henry", 349));
}
#[test]
fn test_multiline_errors() {
fail_unless!(from_str(~"{\n \"foo\":\n \"bar\"") ==
assert_eq!(from_str(~"{\n \"foo\":\n \"bar\""),
Err(Error {
line: 3u,
col: 8u,

View file

@ -182,4 +182,18 @@ fn emit_tup_elt(&self, idx: uint, f: &fn()) {
if idx > 0u { self.wr.write_str(~", "); }
f();
}
fn emit_option(&self, f: &fn()) {
f();
}
fn emit_option_none(&self) {
self.wr.write_str("None");
}
fn emit_option_some(&self, f: &fn()) {
self.wr.write_str("Some(");
f();
self.wr.write_char(')');
}
}

View file

@ -62,6 +62,11 @@ pub trait Encoder {
fn emit_tup(&self, len: uint, f: &fn());
fn emit_tup_elt(&self, idx: uint, f: &fn());
// Specialized types:
fn emit_option(&self, f: &fn());
fn emit_option_none(&self);
fn emit_option_some(&self, f: &fn());
}
pub trait Decoder {
@ -87,7 +92,15 @@ pub trait Decoder {
// Compound types:
fn read_enum<T>(&self, name: &str, f: &fn() -> T) -> T;
#[cfg(stage0)]
fn read_enum_variant<T>(&self, f: &fn(uint) -> T) -> T;
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn read_enum_variant<T>(&self, names: &[&str], 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;
@ -103,6 +116,9 @@ pub trait Decoder {
fn read_tup<T>(&self, sz: uint, f: &fn() -> T) -> T;
fn read_tup_elt<T>(&self, idx: uint, f: &fn() -> T) -> T;
// Specialized types:
fn read_option<T>(&self, f: &fn() -> T) -> Option<T>;
}
pub trait Encodable<S:Encoder> {
@ -368,14 +384,10 @@ fn decode(d: &D) -> @[T] {
impl<S:Encoder,T:Encodable<S>> Encodable<S> for Option<T> {
fn encode(&self, s: &S) {
do s.emit_enum(~"option") {
do s.emit_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))
}
None => s.emit_option_none(),
Some(ref v) => s.emit_option_some(|| v.encode(s)),
}
}
}
@ -383,16 +395,7 @@ fn encode(&self, s: &S) {
impl<D:Decoder,T:Decodable<D>> Decodable<D> for Option<T> {
fn decode(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, || Decodable::decode(d))),
_ => fail!(fmt!("Bad variant for option: %u", i))
}
}
}
d.read_option(|| Decodable::decode(d))
}
}

View file

@ -386,7 +386,6 @@ pub enum vstore {
#[auto_decode]
#[deriving(Eq)]
pub enum expr_vstore {
expr_vstore_fixed(Option<uint>), // [1,2,3,4]
expr_vstore_uniq, // ~[1,2,3,4]
expr_vstore_box, // @[1,2,3,4]
expr_vstore_mut_box, // @mut [1,2,3,4]
@ -543,12 +542,6 @@ pub struct expr {
span: span,
}
#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
pub enum log_level { error, debug, log_other }
// 0 = error, 1 = debug, 2 = log_other
#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
@ -598,7 +591,7 @@ pub enum expr_ {
expr_break(Option<ident>),
expr_again(Option<ident>),
expr_ret(Option<@expr>),
expr_log(log_level, @expr, @expr),
expr_log(@expr, @expr),
expr_inline_asm(@~str, // asm
~[(@~str, @expr)], // inputs

View file

@ -1059,6 +1059,18 @@ fn mk_enum_deser_body(
name: ast::ident,
variants: ~[ast::variant]
) -> @ast::expr {
let expr_arm_names = build::mk_base_vec_e(
ext_cx,
span,
do variants.map |variant| {
build::mk_base_str(
ext_cx,
span,
ext_cx.str_of(variant.node.name)
)
}
);
let mut arms = do variants.mapi |v_idx, variant| {
let body = match variant.node.kind {
ast::tuple_variant_kind(ref args) => {
@ -1152,13 +1164,13 @@ fn mk_enum_deser_body(
)
);
// ast for `__d.read_enum_variant($(expr_lambda))`
// ast for `__d.read_enum_variant($expr_arm_names, $(expr_lambda))`
let expr_lambda = ext_cx.lambda_expr(
ext_cx.expr_method_call(
span,
ext_cx.expr_var(span, ~"__d"),
ext_cx.ident_of(~"read_enum_variant"),
~[expr_lambda]
~[expr_arm_names, expr_lambda]
)
);
@ -1174,9 +1186,9 @@ fn mk_enum_deser_body(
)
}
#[cfg(test)]
mod test {
use core::option::{None, Some};
use std::serialize::Encodable;
use std::serialize::Encoder;
@ -1190,6 +1202,9 @@ pub enum call {
CallToEmitNil,
CallToEmitStruct(~str,uint),
CallToEmitField(~str,uint),
CallToEmitOption,
CallToEmitOptionNone,
CallToEmitOptionSome,
// all of the ones I was too lazy to handle:
CallToOther
}
@ -1281,6 +1296,18 @@ fn emit_tup(&self, +_len: uint, f: &fn()) {
fn emit_tup_elt(&self, +_idx: uint, f: &fn()) {
self.add_unknown_to_log(); f();
}
fn emit_option(&self, f: &fn()) {
self.add_to_log(CallToEmitOption);
f();
}
fn emit_option_none(&self) {
self.add_to_log(CallToEmitOptionNone);
}
fn emit_option_some(&self, f: &fn()) {
self.add_to_log(CallToEmitOptionSome);
f();
}
}
@ -1296,13 +1323,58 @@ enum Written {
Magazine(~str)
}
#[test] fn encode_enum_test () {
assert_eq!(to_call_log(Book(34,44)),
~[CallToEmitEnum (~"Written"),
CallToEmitEnumVariant (~"Book",0,2),
CallToEmitEnumVariantArg (0),
CallToEmitUint (34),
CallToEmitEnumVariantArg (1),
CallToEmitUint (44)]);
}
#[test]
fn test_encode_enum() {
assert_eq!(
to_call_log(Book(34,44)),
~[
CallToEmitEnum(~"Written"),
CallToEmitEnumVariant(~"Book",0,2),
CallToEmitEnumVariantArg(0),
CallToEmitUint(34),
CallToEmitEnumVariantArg(1),
CallToEmitUint(44),
]
);
}
pub struct BPos(uint);
#[auto_encode]
pub struct HasPos { pos : BPos }
#[test]
fn test_encode_newtype() {
assert_eq!(
to_call_log(HasPos { pos:BPos(48) }),
~[
CallToEmitStruct(~"HasPos",1),
CallToEmitField(~"pos",0),
CallToEmitUint(48),
]
);
}
#[test]
fn test_encode_option() {
let mut v = None;
assert_eq!(
to_call_log(v),
~[
CallToEmitOption,
CallToEmitOptionNone,
]
);
v = Some(54u);
assert_eq!(
to_call_log(v),
~[
CallToEmitOption,
CallToEmitOptionSome,
CallToEmitUint(54)
]
);
}
}

View file

@ -152,11 +152,6 @@ pub fn mk_slice_vec_e(cx: @ext_ctxt, sp: span, +exprs: ~[@ast::expr])
mk_vstore_e(cx, sp, mk_base_vec_e(cx, sp, exprs),
ast::expr_vstore_slice)
}
pub fn mk_fixed_vec_e(cx: @ext_ctxt, sp: span, +exprs: ~[@ast::expr])
-> @ast::expr {
mk_vstore_e(cx, sp, mk_base_vec_e(cx, sp, exprs),
ast::expr_vstore_fixed(None))
}
pub fn mk_base_str(cx: @ext_ctxt, sp: span, +s: ~str) -> @ast::expr {
let lit = ast::lit_str(@s);
return mk_lit(cx, sp, lit);

View file

@ -42,8 +42,7 @@ pub mod rt {
pub use ast::*;
pub use parse::token::*;
pub use parse::new_parser_from_tts;
pub use codemap::BytePos;
pub use codemap::span;
pub use codemap::{BytePos, span, dummy_spanned};
use print::pprust;
use print::pprust::{item_to_str, ty_to_str};
@ -89,7 +88,7 @@ fn to_source(&self, cx: @ext_ctxt) -> ~str {
}
}
impl ToSource for ~[@ast::item] {
impl<'self> ToSource for &'self [@ast::item] {
fn to_source(&self, cx: @ext_ctxt) -> ~str {
str::connect(self.map(|i| i.to_source(cx)), ~"\n\n")
}
@ -101,7 +100,7 @@ fn to_source(&self, cx: @ext_ctxt) -> ~str {
}
}
impl ToSource for ~[@ast::Ty] {
impl<'self> ToSource for &'self [@ast::Ty] {
fn to_source(&self, cx: @ext_ctxt) -> ~str {
str::connect(self.map(|i| i.to_source(cx)), ~", ")
}
@ -119,6 +118,90 @@ fn to_source(&self, cx: @ext_ctxt) -> ~str {
}
}
impl ToSource for ast::blk {
fn to_source(&self, cx: @ext_ctxt) -> ~str {
pprust::block_to_str(self, cx.parse_sess().interner)
}
}
impl<'self> ToSource for &'self str {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_str(@str::from_slice(*self)));
pprust::lit_to_str(@lit)
}
}
impl ToSource for int {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i));
pprust::lit_to_str(@lit)
}
}
impl ToSource for i8 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i8));
pprust::lit_to_str(@lit)
}
}
impl ToSource for i16 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i16));
pprust::lit_to_str(@lit)
}
}
impl ToSource for i32 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i32));
pprust::lit_to_str(@lit)
}
}
impl ToSource for i64 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_int(*self as i64, ast::ty_i64));
pprust::lit_to_str(@lit)
}
}
impl ToSource for uint {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u));
pprust::lit_to_str(@lit)
}
}
impl ToSource for u8 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u8));
pprust::lit_to_str(@lit)
}
}
impl ToSource for u16 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u16));
pprust::lit_to_str(@lit)
}
}
impl ToSource for u32 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u32));
pprust::lit_to_str(@lit)
}
}
impl ToSource for u64 {
fn to_source(&self, _cx: @ext_ctxt) -> ~str {
let lit = dummy_spanned(ast::lit_uint(*self as u64, ast::ty_u64));
pprust::lit_to_str(@lit)
}
}
// Alas ... we write these out instead. All redundant.
impl ToTokens for ast::ident {
@ -133,7 +216,7 @@ fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
}
}
impl ToTokens for ~[@ast::item] {
impl<'self> ToTokens for &'self [@ast::item] {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
@ -145,7 +228,7 @@ fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
}
}
impl ToTokens for ~[@ast::Ty] {
impl<'self> ToTokens for &'self [@ast::Ty] {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
@ -163,6 +246,78 @@ fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
}
}
impl ToTokens for ast::blk {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl<'self> ToTokens for &'self str {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for int {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for i8 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for i16 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for i32 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for i64 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for uint {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for u8 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for u16 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for u32 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
impl ToTokens for u64 {
fn to_tokens(&self, cx: @ext_ctxt) -> ~[token_tree] {
cx.parse_tts(self.to_source(cx))
}
}
pub trait ExtParseUtils {
fn parse_item(&self, s: ~str) -> @ast::item;
fn parse_expr(&self, s: ~str) -> @ast::expr;

View file

@ -552,9 +552,8 @@ fn fold_field_(field: field, fld: @ast_fold) -> field {
expr_ret(ref e) => {
expr_ret(e.map(|x| fld.fold_expr(*x)))
}
expr_log(i, lv, e) => {
expr_log(lv, e) => {
expr_log(
i,
fld.fold_expr(lv),
fld.fold_expr(e)
)

View file

@ -326,19 +326,32 @@ mod test {
@~"fn foo (x : int) { x; }",
~[],
new_parse_sess(None));
assert_eq!(to_json_str(@tts),
~"[[\"tt_tok\",[null,[\"IDENT\",[\"fn\",false]]]],\
[\"tt_tok\",[null,[\"IDENT\",[\"foo\",false]]]],\
[\"tt_delim\",[[[\"tt_tok\",[null,[\"LPAREN\",[]]]],\
[\"tt_tok\",[null,[\"IDENT\",[\"x\",false]]]],\
[\"tt_tok\",[null,[\"COLON\",[]]]],\
[\"tt_tok\",[null,[\"IDENT\",[\"int\",false]]]],\
[\"tt_tok\",[null,[\"RPAREN\",[]]]]]]],\
[\"tt_delim\",[[[\"tt_tok\",[null,[\"LBRACE\",[]]]],\
[\"tt_tok\",[null,[\"IDENT\",[\"x\",false]]]],\
[\"tt_tok\",[null,[\"SEMI\",[]]]],\
[\"tt_tok\",[null,[\"RBRACE\",[]]]]]]]]"
);
assert_eq!(
to_json_str(@tts),
~"[\
[\"tt_tok\",null,[\"IDENT\",\"fn\",false]],\
[\"tt_tok\",null,[\"IDENT\",\"foo\",false]],\
[\
\"tt_delim\",\
[\
[\"tt_tok\",null,\"LPAREN\"],\
[\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
[\"tt_tok\",null,\"COLON\"],\
[\"tt_tok\",null,[\"IDENT\",\"int\",false]],\
[\"tt_tok\",null,\"RPAREN\"]\
]\
],\
[\
\"tt_delim\",\
[\
[\"tt_tok\",null,\"LBRACE\"],\
[\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
[\"tt_tok\",null,\"SEMI\"],\
[\"tt_tok\",null,\"RBRACE\"]\
]\
]\
]"
);
let ast1 = new_parser_from_tts(new_parse_sess(None),~[],tts)
.parse_item(~[]);
let ast2 = parse_item_from_source_str(

View file

@ -28,7 +28,7 @@
use ast::{expr_method_call, expr_paren, expr_path, expr_repeat};
use ast::{expr_ret, expr_swap, expr_struct, expr_tup, expr_unary};
use ast::{expr_vec, expr_vstore, expr_vstore_mut_box, expr_inline_asm};
use ast::{expr_vstore_fixed, expr_vstore_slice, expr_vstore_box};
use ast::{expr_vstore_slice, expr_vstore_box};
use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
use ast::{expr_vstore_uniq, TyClosure, TyBareFn, Onceness, Once, Many};
use ast::{foreign_item, foreign_item_const, foreign_item_fn, foreign_mod};
@ -1223,7 +1223,7 @@ fn parse_bottom_expr(&self) -> @expr {
let lvl = self.parse_expr();
self.expect(&token::COMMA);
let e = self.parse_expr();
ex = expr_log(ast::log_other, lvl, e);
ex = expr_log(lvl, e);
hi = self.span.hi;
self.expect(&token::RPAREN);
} else if self.eat_keyword(&~"return") {
@ -2721,8 +2721,9 @@ fn parse_optional_ty_param_bounds(&self) -> @OptVec<TyParamBound> {
}
self.bump();
}
token::IDENT(*) => {
token::MOD_SEP | token::IDENT(*) => {
let maybe_bound = match *self.token {
token::MOD_SEP => None,
token::IDENT(copy sid, _) => {
match *self.id_to_str(sid) {
~"send" |
@ -2750,7 +2751,7 @@ fn parse_optional_ty_param_bounds(&self) -> @OptVec<TyParamBound> {
result.push(bound);
}
None => {
let ty = self.parse_ty(false);
let ty = self.parse_ty(true);
result.push(TraitTyParamBound(ty));
}
}
@ -3099,14 +3100,6 @@ fn parse_item_trait(&self) -> item_info {
// impl<T> Foo { ... }
// impl<T> ToStr for ~[T] { ... }
fn parse_item_impl(&self, visibility: ast::visibility) -> item_info {
fn wrap_path(p: &Parser, pt: @path) -> @Ty {
@Ty {
id: p.get_id(),
node: ty_path(pt, p.get_id()),
span: pt.span,
}
}
// First, parse type parameters if necessary.
let generics = self.parse_generics();

View file

@ -325,7 +325,7 @@ pub fn commasep<IN>(s: @ps, b: breaks, elts: &[IN], op: &fn(@ps, IN)) {
pub fn commasep_cmnt<IN>(s: @ps, b: breaks, elts: &[IN], op: &fn(@ps, IN),
get_span: &fn(IN) -> codemap::span) {
box(s, 0u, b);
let len = vec::len::<IN>(elts);
let len = elts.len();
let mut i = 0u;
for elts.each |elt| {
maybe_print_comment(s, get_span(*elt).hi);
@ -1029,8 +1029,6 @@ pub fn print_vstore(s: @ps, t: ast::vstore) {
pub fn print_expr_vstore(s: @ps, t: ast::expr_vstore) {
match t {
ast::expr_vstore_fixed(Some(i)) => word(s.s, fmt!("%u", i)),
ast::expr_vstore_fixed(None) => word(s.s, ~"_"),
ast::expr_vstore_uniq => word(s.s, ~"~"),
ast::expr_vstore_box => word(s.s, ~"@"),
ast::expr_vstore_mut_box => {
@ -1105,16 +1103,9 @@ fn print_field(s: @ps, field: ast::field) {
let ann_node = node_expr(s, expr);
(s.ann.pre)(ann_node);
match expr.node {
ast::expr_vstore(e, v) => match v {
ast::expr_vstore_fixed(_) => {
print_expr(s, e);
word(s.s, ~"/");
print_expr_vstore(s, v);
}
_ => {
print_expr_vstore(s, v);
print_expr(s, e);
}
ast::expr_vstore(e, v) => {
print_expr_vstore(s, v);
print_expr(s, e);
},
ast::expr_vec(ref exprs, mutbl) => {
ibox(s, indent_unit);
@ -1391,20 +1382,14 @@ fn print_field(s: @ps, field: ast::field) {
_ => ()
}
}
ast::expr_log(lvl, lexp, expr) => {
match lvl {
ast::debug => { word_nbsp(s, ~"log"); print_expr(s, expr); }
ast::error => { word_nbsp(s, ~"log_err"); print_expr(s, expr); }
ast::log_other => {
word_nbsp(s, ~"log");
popen(s);
print_expr(s, lexp);
word(s.s, ~",");
space_if_not_bol(s);
print_expr(s, expr);
pclose(s);
}
}
ast::expr_log(lexp, expr) => {
word(s.s, ~"__log");
popen(s);
print_expr(s, lexp);
word(s.s, ~",");
space_if_not_bol(s);
print_expr(s, expr);
pclose(s);
}
ast::expr_inline_asm(a, in, out, c, v, _) => {
if v {
@ -2139,7 +2124,7 @@ pub fn print_comment(s: @ps, cmnt: comments::cmnt) {
}
}
pub fn print_string(s: @ps, st: ~str) {
pub fn print_string(s: @ps, st: &str) {
word(s.s, ~"\"");
word(s.s, str::escape_default(st));
word(s.s, ~"\"");

View file

@ -559,7 +559,7 @@ pub fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
expr_break(_) => (),
expr_again(_) => (),
expr_ret(eo) => visit_expr_opt(eo, e, v),
expr_log(_, lv, x) => {
expr_log(lv, x) => {
(v.visit_expr)(lv, e, v);
(v.visit_expr)(x, e, v);
}

View file

@ -0,0 +1,3 @@
fn foo<T: ::cmp::Eq>(t: T) { }
fn main() { }