2012-08-11 09:08:42 -05:00
|
|
|
#[deny(non_camel_case_types)];
|
|
|
|
|
2011-11-07 17:24:44 -06:00
|
|
|
// Rust JSON serialization library
|
|
|
|
// Copyright (c) 2011 Google Inc.
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
//! json serialization
|
2012-03-07 20:17:30 -06:00
|
|
|
|
2012-08-27 18:26:35 -05:00
|
|
|
import core::cmp::Eq;
|
2012-08-26 18:54:31 -05:00
|
|
|
import result::{Result, Ok, Err};
|
2012-02-25 18:39:32 -06:00
|
|
|
import io;
|
2012-08-14 15:38:35 -05:00
|
|
|
import io::WriterUtil;
|
2011-11-07 13:01:28 -06:00
|
|
|
import map;
|
2012-03-07 18:48:57 -06:00
|
|
|
import map::hashmap;
|
2012-07-11 17:00:40 -05:00
|
|
|
import map::map;
|
2012-08-30 19:38:07 -05:00
|
|
|
import sort;
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
export Json;
|
|
|
|
export Error;
|
2012-02-25 18:39:32 -06:00
|
|
|
export to_writer;
|
2012-08-30 19:38:07 -05:00
|
|
|
export to_writer_pretty;
|
2011-11-07 17:24:44 -06:00
|
|
|
export to_str;
|
2012-08-30 19:38:07 -05:00
|
|
|
export to_str_pretty;
|
2012-02-25 18:39:32 -06:00
|
|
|
export from_reader;
|
2011-11-07 17:24:44 -06:00
|
|
|
export from_str;
|
2012-02-25 18:39:32 -06:00
|
|
|
export eq;
|
2012-08-11 09:08:42 -05:00
|
|
|
export ToJson;
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
export Num;
|
|
|
|
export String;
|
|
|
|
export Boolean;
|
|
|
|
export List;
|
|
|
|
export Dict;
|
|
|
|
export Null;
|
2011-11-07 17:24:44 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Represents a json value
|
2012-08-11 09:08:42 -05:00
|
|
|
enum Json {
|
|
|
|
Num(float),
|
|
|
|
String(@~str),
|
|
|
|
Boolean(bool),
|
|
|
|
List(@~[Json]),
|
|
|
|
Dict(map::hashmap<~str, Json>),
|
|
|
|
Null,
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
type Error = {
|
2012-02-25 18:39:32 -06:00
|
|
|
line: uint,
|
|
|
|
col: uint,
|
2012-07-14 00:57:48 -05:00
|
|
|
msg: @~str,
|
2012-02-25 18:39:32 -06:00
|
|
|
};
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Serializes a json value into a io::writer
|
2012-08-11 09:08:42 -05:00
|
|
|
fn to_writer(wr: io::Writer, j: Json) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match j {
|
2012-08-11 09:08:42 -05:00
|
|
|
Num(n) => wr.write_str(float::to_str(n, 6u)),
|
|
|
|
String(s) => wr.write_str(escape_str(*s)),
|
|
|
|
Boolean(b) => wr.write_str(if b { ~"true" } else { ~"false" }),
|
|
|
|
List(v) => {
|
2012-02-25 18:39:32 -06:00
|
|
|
wr.write_char('[');
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut first = true;
|
2012-06-30 18:19:07 -05:00
|
|
|
for (*v).each |item| {
|
2012-02-25 18:39:32 -06:00
|
|
|
if !first {
|
2012-07-14 00:57:48 -05:00
|
|
|
wr.write_str(~", ");
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
to_writer(wr, item);
|
|
|
|
};
|
|
|
|
wr.write_char(']');
|
|
|
|
}
|
2012-08-11 09:08:42 -05:00
|
|
|
Dict(d) => {
|
2012-02-25 18:39:32 -06:00
|
|
|
if d.size() == 0u {
|
2012-07-14 00:57:48 -05:00
|
|
|
wr.write_str(~"{}");
|
2012-08-01 19:30:05 -05:00
|
|
|
return;
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
wr.write_str(~"{ ");
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut first = true;
|
2012-06-30 18:19:07 -05:00
|
|
|
for d.each |key, value| {
|
2012-02-25 18:39:32 -06:00
|
|
|
if !first {
|
2012-07-14 00:57:48 -05:00
|
|
|
wr.write_str(~", ");
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
first = false;
|
2012-06-12 19:20:51 -05:00
|
|
|
wr.write_str(escape_str(key));
|
2012-07-14 00:57:48 -05:00
|
|
|
wr.write_str(~": ");
|
2012-02-25 18:39:32 -06:00
|
|
|
to_writer(wr, value);
|
|
|
|
};
|
2012-07-14 00:57:48 -05:00
|
|
|
wr.write_str(~" }");
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2012-08-11 09:08:42 -05:00
|
|
|
Null => wr.write_str(~"null")
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-30 18:39:56 -05:00
|
|
|
/// Serializes a json value into a io::writer
|
|
|
|
fn to_writer_pretty(wr: io::Writer, j: Json, indent: uint) {
|
|
|
|
fn spaces(n: uint) -> ~str {
|
2012-08-30 19:38:07 -05:00
|
|
|
let mut ss = ~"";
|
|
|
|
for n.times { str::push_str(ss, " "); }
|
2012-08-30 18:39:56 -05:00
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
|
|
|
|
match j {
|
|
|
|
Num(n) => wr.write_str(float::to_str(n, 6u)),
|
|
|
|
String(s) => wr.write_str(escape_str(*s)),
|
|
|
|
Boolean(b) => wr.write_str(if b { ~"true" } else { ~"false" }),
|
2012-08-30 19:38:07 -05:00
|
|
|
List(vv) => {
|
2012-08-30 18:39:56 -05:00
|
|
|
// [
|
|
|
|
wr.write_str(spaces(indent));
|
|
|
|
wr.write_str("[ ");
|
|
|
|
|
|
|
|
// [ elem,
|
|
|
|
// elem,
|
|
|
|
// elem ]
|
|
|
|
let inner_indent = indent + 2;
|
|
|
|
let mut first = true;
|
2012-08-30 19:38:07 -05:00
|
|
|
for (*vv).each |item| {
|
2012-08-30 18:39:56 -05:00
|
|
|
if !first {
|
|
|
|
wr.write_str(~",\n");
|
|
|
|
wr.write_str(spaces(inner_indent));
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
to_writer_pretty(wr, item, inner_indent);
|
|
|
|
};
|
|
|
|
|
|
|
|
// ]
|
|
|
|
wr.write_str(~" ]");
|
|
|
|
}
|
2012-08-30 19:38:07 -05:00
|
|
|
Dict(dd) => {
|
|
|
|
// convert from a dictionary
|
|
|
|
let mut pairs = ~[];
|
|
|
|
for dd.each |key, value| {
|
|
|
|
vec::push(pairs, (key, value));
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort by key strings
|
|
|
|
let sorted_pairs = sort::merge_sort(|a,b| *a <= *b, pairs);
|
|
|
|
|
2012-08-30 18:39:56 -05:00
|
|
|
// {
|
|
|
|
wr.write_str(spaces(indent));
|
|
|
|
wr.write_str(~"{ ");
|
|
|
|
|
|
|
|
// { k: v,
|
|
|
|
// k: v,
|
|
|
|
// k: v }
|
|
|
|
let inner_indent = indent + 2;
|
|
|
|
let mut first = true;
|
2012-08-30 19:38:07 -05:00
|
|
|
for sorted_pairs.each |kv| {
|
|
|
|
let (key, value) = kv;
|
2012-08-30 18:39:56 -05:00
|
|
|
if !first {
|
|
|
|
wr.write_str(~",\n");
|
|
|
|
wr.write_str(spaces(inner_indent));
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
let key = str::append(escape_str(key), ~": ");
|
|
|
|
let key_indent = str::len(key);
|
|
|
|
wr.write_str(key);
|
|
|
|
to_writer_pretty(wr, value, key_indent);
|
|
|
|
};
|
|
|
|
|
|
|
|
// }
|
|
|
|
wr.write_str(~" }");
|
|
|
|
}
|
|
|
|
Null => wr.write_str(~"null")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn escape_str(s: ~str) -> ~str {
|
|
|
|
let mut escaped = ~"\"";
|
2012-06-30 18:19:07 -05:00
|
|
|
do str::chars_iter(s) |c| {
|
2012-08-06 14:34:08 -05:00
|
|
|
match c {
|
2012-08-03 21:59:04 -05:00
|
|
|
'"' => escaped += ~"\\\"",
|
|
|
|
'\\' => escaped += ~"\\\\",
|
|
|
|
'\x08' => escaped += ~"\\b",
|
|
|
|
'\x0c' => escaped += ~"\\f",
|
|
|
|
'\n' => escaped += ~"\\n",
|
|
|
|
'\r' => escaped += ~"\\r",
|
|
|
|
'\t' => escaped += ~"\\t",
|
|
|
|
_ => escaped += str::from_char(c)
|
2012-06-12 19:20:51 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
escaped += ~"\"";
|
2012-06-12 19:20:51 -05:00
|
|
|
|
|
|
|
escaped
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Serializes a json value into a string
|
2012-08-11 09:08:42 -05:00
|
|
|
fn to_str(j: Json) -> ~str {
|
2012-06-30 18:19:07 -05:00
|
|
|
io::with_str_writer(|wr| to_writer(wr, j))
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-30 18:39:56 -05:00
|
|
|
/// Serializes a json value into a string, with whitespace and sorting
|
|
|
|
fn to_str_pretty(j: Json) -> ~str {
|
|
|
|
io::with_str_writer(|wr| to_writer_pretty(wr, j, 0))
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
type Parser_ = {
|
2012-08-14 15:38:35 -05:00
|
|
|
rdr: io::Reader,
|
2012-03-26 20:35:18 -05:00
|
|
|
mut ch: char,
|
|
|
|
mut line: uint,
|
|
|
|
mut col: uint,
|
2012-02-25 18:39:32 -06:00
|
|
|
};
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
enum Parser {
|
|
|
|
Parser_(Parser_)
|
2012-07-11 17:00:40 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl Parser {
|
2012-02-25 18:39:32 -06:00
|
|
|
fn eof() -> bool { self.ch == -1 as char }
|
|
|
|
|
|
|
|
fn bump() {
|
|
|
|
self.ch = self.rdr.read_char();
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-02-25 18:39:32 -06:00
|
|
|
if self.ch == '\n' {
|
|
|
|
self.line += 1u;
|
|
|
|
self.col = 1u;
|
|
|
|
} else {
|
|
|
|
self.col += 1u;
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn next_char() -> char {
|
|
|
|
self.bump();
|
|
|
|
self.ch
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn error<T>(+msg: ~str) -> Result<T, Error> {
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({ line: self.line, col: self.col, msg: @msg })
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse() -> Result<Json, Error> {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.parse_value() {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(value) => {
|
2012-02-29 02:47:17 -06:00
|
|
|
// Skip trailing whitespaces.
|
|
|
|
self.parse_whitespace();
|
2012-02-25 18:39:32 -06:00
|
|
|
// Make sure there is no trailing characters.
|
|
|
|
if self.eof() {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(value)
|
2012-02-25 18:39:32 -06:00
|
|
|
} else {
|
2012-07-14 00:57:48 -05:00
|
|
|
self.error(~"trailing characters")
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
e => e
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_value() -> Result<Json, Error> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.parse_whitespace();
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
if self.eof() { return self.error(~"EOF while parsing value"); }
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-11 09:08:42 -05:00
|
|
|
'n' => self.parse_ident(~"ull", Null),
|
|
|
|
't' => self.parse_ident(~"rue", Boolean(true)),
|
|
|
|
'f' => self.parse_ident(~"alse", Boolean(false)),
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' | '-' => self.parse_number(),
|
2012-08-06 14:34:08 -05:00
|
|
|
'"' => match self.parse_str() {
|
2012-08-11 09:08:42 -05:00
|
|
|
Ok(s) => Ok(String(s)),
|
2012-08-26 18:54:31 -05:00
|
|
|
Err(e) => Err(e)
|
2012-08-06 19:14:32 -05:00
|
|
|
},
|
2012-08-03 21:59:04 -05:00
|
|
|
'[' => self.parse_list(),
|
|
|
|
'{' => self.parse_object(),
|
|
|
|
_ => self.error(~"invalid syntax")
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_whitespace() {
|
|
|
|
while char::is_whitespace(self.ch) { self.bump(); }
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_ident(ident: ~str, value: Json) -> Result<Json, Error> {
|
2012-06-30 18:19:07 -05:00
|
|
|
if str::all(ident, |c| c == self.next_char()) {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(value)
|
2012-02-25 18:39:32 -06:00
|
|
|
} else {
|
2012-07-14 00:57:48 -05:00
|
|
|
self.error(~"invalid syntax")
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_number() -> Result<Json, Error> {
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut neg = 1f;
|
2012-02-25 18:39:32 -06:00
|
|
|
|
|
|
|
if self.ch == '-' {
|
|
|
|
self.bump();
|
|
|
|
neg = -1f;
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
let mut res = match self.parse_integer() {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(res) => res,
|
|
|
|
Err(e) => return Err(e)
|
2012-02-25 18:39:32 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
if self.ch == '.' {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.parse_decimal(res) {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(r) => res = r,
|
|
|
|
Err(e) => return Err(e)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
|
|
|
if self.ch == 'e' || self.ch == 'E' {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.parse_exponent(res) {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(r) => res = r,
|
|
|
|
Err(e) => return Err(e)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
Ok(Num(neg * res))
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_integer() -> Result<float, Error> {
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut res = 0f;
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' => {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
|
|
|
|
// There can be only one leading '0'.
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' => return self.error(~"invalid number"),
|
|
|
|
_ => ()
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
'1' to '9' => {
|
2012-02-25 18:39:32 -06:00
|
|
|
while !self.eof() {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' => {
|
2012-02-25 18:39:32 -06:00
|
|
|
res *= 10f;
|
|
|
|
res += ((self.ch as int) - ('0' as int)) as float;
|
|
|
|
|
|
|
|
self.bump();
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => break
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => return self.error(~"invalid number")
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(res)
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_decimal(res: float) -> Result<float, Error> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
|
|
|
|
// Make sure a digit follows the decimal place.
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' => (),
|
|
|
|
_ => return self.error(~"invalid number")
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut res = res;
|
|
|
|
let mut dec = 1f;
|
2012-02-25 18:39:32 -06:00
|
|
|
while !self.eof() {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' => {
|
2012-02-25 18:39:32 -06:00
|
|
|
dec /= 10f;
|
|
|
|
res += (((self.ch as int) - ('0' as int)) as float) * dec;
|
|
|
|
|
|
|
|
self.bump();
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => break
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(res)
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_exponent(res: float) -> Result<float, Error> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut res = res;
|
|
|
|
let mut exp = 0u;
|
|
|
|
let mut neg_exp = false;
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'+' => self.bump(),
|
|
|
|
'-' => { self.bump(); neg_exp = true; }
|
|
|
|
_ => ()
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure a digit follows the exponent place.
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' => (),
|
|
|
|
_ => return self.error(~"invalid number")
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
while !self.eof() {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' => {
|
2012-02-25 18:39:32 -06:00
|
|
|
exp *= 10u;
|
|
|
|
exp += (self.ch as uint) - ('0' as uint);
|
|
|
|
|
|
|
|
self.bump();
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => break
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let exp = float::pow_with_uint(10u, exp);
|
|
|
|
if neg_exp {
|
|
|
|
res /= exp;
|
|
|
|
} else {
|
|
|
|
res *= exp;
|
|
|
|
}
|
|
|
|
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(res)
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_str() -> Result<@~str, Error> {
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut escape = false;
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut res = ~"";
|
2012-02-25 18:39:32 -06:00
|
|
|
|
|
|
|
while !self.eof() {
|
|
|
|
self.bump();
|
|
|
|
|
|
|
|
if (escape) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
'"' => str::push_char(res, '"'),
|
|
|
|
'\\' => str::push_char(res, '\\'),
|
|
|
|
'/' => str::push_char(res, '/'),
|
|
|
|
'b' => str::push_char(res, '\x08'),
|
|
|
|
'f' => str::push_char(res, '\x0c'),
|
|
|
|
'n' => str::push_char(res, '\n'),
|
|
|
|
'r' => str::push_char(res, '\r'),
|
|
|
|
't' => str::push_char(res, '\t'),
|
|
|
|
'u' => {
|
2012-02-25 18:39:32 -06:00
|
|
|
// Parse \u1234.
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut i = 0u;
|
|
|
|
let mut n = 0u;
|
2012-02-25 18:39:32 -06:00
|
|
|
while i < 4u {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.next_char() {
|
2012-08-03 21:59:04 -05:00
|
|
|
'0' to '9' => {
|
2012-08-30 22:12:10 -05:00
|
|
|
n = n * 16u + (self.ch as uint)
|
|
|
|
- ('0' as uint);
|
|
|
|
},
|
|
|
|
'a' | 'A' => n = n * 16u + 10u,
|
|
|
|
'b' | 'B' => n = n * 16u + 11u,
|
|
|
|
'c' | 'C' => n = n * 16u + 12u,
|
|
|
|
'd' | 'D' => n = n * 16u + 13u,
|
|
|
|
'e' | 'E' => n = n * 16u + 14u,
|
|
|
|
'f' | 'F' => n = n * 16u + 15u,
|
|
|
|
_ => return self.error(
|
|
|
|
~"invalid \\u escape (unrecognized hex)")
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2012-03-14 13:03:56 -05:00
|
|
|
i += 1u;
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Error out if we didn't parse 4 digits.
|
|
|
|
if i != 4u {
|
2012-08-30 22:12:10 -05:00
|
|
|
return self.error(
|
|
|
|
~"invalid \\u escape (not four digits)");
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
str::push_char(res, n as char);
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => return self.error(~"invalid escape")
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
escape = false;
|
|
|
|
} else if self.ch == '\\' {
|
|
|
|
escape = true;
|
|
|
|
} else {
|
|
|
|
if self.ch == '"' {
|
|
|
|
self.bump();
|
2012-08-26 18:54:31 -05:00
|
|
|
return Ok(@res);
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
str::push_char(res, self.ch);
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
self.error(~"EOF while parsing string")
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_list() -> Result<Json, Error> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
self.parse_whitespace();
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut values = ~[];
|
2012-02-25 18:39:32 -06:00
|
|
|
|
|
|
|
if self.ch == ']' {
|
|
|
|
self.bump();
|
2012-08-11 09:08:42 -05:00
|
|
|
return Ok(List(@values));
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2012-03-10 22:34:17 -06:00
|
|
|
loop {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.parse_value() {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(v) => vec::push(values, v),
|
2012-08-03 21:59:04 -05:00
|
|
|
e => return e
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
self.parse_whitespace();
|
2012-03-10 22:34:17 -06:00
|
|
|
if self.eof() {
|
2012-08-01 19:30:05 -05:00
|
|
|
return self.error(~"EOF while parsing list");
|
2012-03-10 22:34:17 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
',' => self.bump(),
|
2012-08-11 09:08:42 -05:00
|
|
|
']' => { self.bump(); return Ok(List(@values)); }
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => return self.error(~"expected `,` or `]`")
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2012-03-10 22:34:17 -06:00
|
|
|
};
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn parse_object() -> Result<Json, Error> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
self.parse_whitespace();
|
|
|
|
|
2012-03-14 14:07:23 -05:00
|
|
|
let values = map::str_hash();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
|
|
|
if self.ch == '}' {
|
|
|
|
self.bump();
|
2012-08-11 09:08:42 -05:00
|
|
|
return Ok(Dict(values));
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
while !self.eof() {
|
|
|
|
self.parse_whitespace();
|
|
|
|
|
|
|
|
if self.ch != '"' {
|
2012-08-01 19:30:05 -05:00
|
|
|
return self.error(~"key must be a string");
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
let key = match self.parse_str() {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(key) => key,
|
|
|
|
Err(e) => return Err(e)
|
2012-02-25 18:39:32 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
self.parse_whitespace();
|
|
|
|
|
|
|
|
if self.ch != ':' {
|
|
|
|
if self.eof() { break; }
|
2012-08-01 19:30:05 -05:00
|
|
|
return self.error(~"expected `:`");
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
self.bump();
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.parse_value() {
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(value) => { values.insert(copy *key, value); }
|
2012-08-03 21:59:04 -05:00
|
|
|
e => return e
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
self.parse_whitespace();
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.ch {
|
2012-08-03 21:59:04 -05:00
|
|
|
',' => self.bump(),
|
2012-08-11 09:08:42 -05:00
|
|
|
'}' => { self.bump(); return Ok(Dict(values)); }
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {
|
2012-02-25 18:39:32 -06:00
|
|
|
if self.eof() { break; }
|
2012-08-01 19:30:05 -05:00
|
|
|
return self.error(~"expected `,` or `}`");
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return self.error(~"EOF while parsing object");
|
2011-12-21 14:36:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Deserializes a json value from an io::reader
|
2012-08-11 09:08:42 -05:00
|
|
|
fn from_reader(rdr: io::Reader) -> Result<Json, Error> {
|
|
|
|
let parser = Parser_({
|
2012-02-25 18:39:32 -06:00
|
|
|
rdr: rdr,
|
2012-03-26 20:35:18 -05:00
|
|
|
mut ch: rdr.read_char(),
|
|
|
|
mut line: 1u,
|
|
|
|
mut col: 1u,
|
2012-07-11 17:00:40 -05:00
|
|
|
});
|
2012-02-25 18:39:32 -06:00
|
|
|
|
|
|
|
parser.parse()
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Deserializes a json value from a string
|
2012-08-11 09:08:42 -05:00
|
|
|
fn from_str(s: ~str) -> Result<Json, Error> {
|
2012-02-29 12:48:57 -06:00
|
|
|
io::with_str_reader(s, from_reader)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Test if two json values are equal
|
2012-08-27 18:26:35 -05:00
|
|
|
pure fn eq(value0: Json, value1: Json) -> bool {
|
2012-08-06 14:34:08 -05:00
|
|
|
match (value0, value1) {
|
2012-08-11 09:08:42 -05:00
|
|
|
(Num(f0), Num(f1)) => f0 == f1,
|
|
|
|
(String(s0), String(s1)) => s0 == s1,
|
|
|
|
(Boolean(b0), Boolean(b1)) => b0 == b1,
|
|
|
|
(List(l0), List(l1)) => vec::all2(*l0, *l1, eq),
|
|
|
|
(Dict(d0), Dict(d1)) => {
|
2012-02-25 18:39:32 -06:00
|
|
|
if d0.size() == d1.size() {
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut equal = true;
|
2012-06-30 18:19:07 -05:00
|
|
|
for d0.each |k, v0| {
|
2012-08-06 14:34:08 -05:00
|
|
|
match d1.find(k) {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(v1) => if !eq(v0, v1) { equal = false },
|
|
|
|
None => equal = false
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
equal
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2012-08-11 09:08:42 -05:00
|
|
|
(Null, Null) => true,
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => false
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
|
2012-08-27 18:26:35 -05:00
|
|
|
impl Error : Eq {
|
|
|
|
pure fn eq(&&other: Error) -> bool {
|
|
|
|
self.line == other.line &&
|
|
|
|
self.col == other.col &&
|
|
|
|
self.msg == other.msg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Json : Eq {
|
|
|
|
pure fn eq(&&other: Json) -> bool {
|
|
|
|
eq(self, other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
trait ToJson { fn to_json() -> Json; }
|
2012-05-28 14:10:32 -05:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl Json: ToJson {
|
|
|
|
fn to_json() -> Json { self }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl @Json: ToJson {
|
|
|
|
fn to_json() -> Json { *self }
|
2012-06-13 10:30:54 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl int: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-06-13 10:30:54 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl i8: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl i16: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl i32: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl i64: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl uint: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-06-13 10:30:54 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl u8: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl u16: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl u32: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl u64: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl float: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl f32: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl f64: ToJson {
|
|
|
|
fn to_json() -> Json { Num(self as float) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl (): ToJson {
|
|
|
|
fn to_json() -> Json { Null }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl bool: ToJson {
|
|
|
|
fn to_json() -> Json { Boolean(self) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl ~str: ToJson {
|
|
|
|
fn to_json() -> Json { String(@copy self) }
|
2012-06-12 19:20:51 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl @~str: ToJson {
|
|
|
|
fn to_json() -> Json { String(self) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl <A: ToJson, B: ToJson> (A, B): ToJson {
|
|
|
|
fn to_json() -> Json {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self {
|
2012-08-02 17:42:56 -05:00
|
|
|
(a, b) => {
|
2012-08-11 09:08:42 -05:00
|
|
|
List(@~[a.to_json(), b.to_json()])
|
2012-08-02 17:42:56 -05:00
|
|
|
}
|
|
|
|
}
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl <A: ToJson, B: ToJson, C: ToJson> (A, B, C): ToJson {
|
2012-08-07 20:10:06 -05:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn to_json() -> Json {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self {
|
2012-08-02 17:42:56 -05:00
|
|
|
(a, b, c) => {
|
2012-08-11 09:08:42 -05:00
|
|
|
List(@~[a.to_json(), b.to_json(), c.to_json()])
|
2012-08-02 17:42:56 -05:00
|
|
|
}
|
|
|
|
}
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl <A: ToJson> ~[A]: ToJson {
|
|
|
|
fn to_json() -> Json { List(@self.map(|elt| elt.to_json())) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl <A: ToJson copy> hashmap<~str, A>: ToJson {
|
|
|
|
fn to_json() -> Json {
|
2012-05-28 14:10:32 -05:00
|
|
|
let d = map::str_hash();
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each() |key, value| {
|
2012-06-12 19:20:51 -05:00
|
|
|
d.insert(copy key, value.to_json());
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
2012-08-11 09:08:42 -05:00
|
|
|
Dict(d)
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl <A: ToJson> Option<A>: ToJson {
|
|
|
|
fn to_json() -> Json {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self {
|
2012-08-11 09:08:42 -05:00
|
|
|
None => Null,
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(value) => value.to_json()
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl Json: to_str::ToStr {
|
2012-07-14 00:57:48 -05:00
|
|
|
fn to_str() -> ~str { to_str(self) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
impl Error: to_str::ToStr {
|
2012-07-14 00:57:48 -05:00
|
|
|
fn to_str() -> ~str {
|
2012-08-22 19:24:52 -05:00
|
|
|
fmt!("%u:%u: %s", self.line, self.col, *self.msg)
|
2012-06-11 10:32:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2012-08-11 09:08:42 -05:00
|
|
|
fn mk_dict(items: ~[(~str, Json)]) -> Json {
|
2012-03-14 14:07:23 -05:00
|
|
|
let d = map::str_hash();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-06-30 18:19:07 -05:00
|
|
|
do vec::iter(items) |item| {
|
2012-06-12 19:20:51 -05:00
|
|
|
let (key, value) = copy item;
|
2012-02-25 18:39:32 -06:00
|
|
|
d.insert(key, value);
|
|
|
|
};
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
Dict(d)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_null() {
|
2012-08-11 09:08:42 -05:00
|
|
|
assert to_str(Null) == ~"null";
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_num() {
|
2012-08-11 09:08:42 -05:00
|
|
|
assert to_str(Num(3f)) == ~"3";
|
|
|
|
assert to_str(Num(3.1f)) == ~"3.1";
|
|
|
|
assert to_str(Num(-1.5f)) == ~"-1.5";
|
|
|
|
assert to_str(Num(0.5f)) == ~"0.5";
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_str() {
|
2012-08-11 09:08:42 -05:00
|
|
|
assert to_str(String(@~"")) == ~"\"\"";
|
|
|
|
assert to_str(String(@~"foo")) == ~"\"foo\"";
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_bool() {
|
2012-08-11 09:08:42 -05:00
|
|
|
assert to_str(Boolean(true)) == ~"true";
|
|
|
|
assert to_str(Boolean(false)) == ~"false";
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_list() {
|
2012-08-11 09:08:42 -05:00
|
|
|
assert to_str(List(@~[])) == ~"[]";
|
|
|
|
assert to_str(List(@~[Boolean(true)])) == ~"[true]";
|
|
|
|
assert to_str(List(@~[
|
|
|
|
Boolean(false),
|
|
|
|
Null,
|
|
|
|
List(@~[String(@~"foo\nbar"), Num(3.5f)])
|
2012-07-14 00:57:48 -05:00
|
|
|
])) == ~"[false, null, [\"foo\\nbar\", 3.5]]";
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_dict() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert to_str(mk_dict(~[])) == ~"{}";
|
2012-08-11 09:08:42 -05:00
|
|
|
assert to_str(mk_dict(~[(~"a", Boolean(true))]))
|
2012-07-14 00:57:48 -05:00
|
|
|
== ~"{ \"a\": true }";
|
2012-08-30 18:27:15 -05:00
|
|
|
let a = mk_dict(~[
|
2012-08-11 09:08:42 -05:00
|
|
|
(~"a", Boolean(true)),
|
|
|
|
(~"b", List(@~[
|
|
|
|
mk_dict(~[(~"c", String(@~"\x0c\r"))]),
|
|
|
|
mk_dict(~[(~"d", String(@~""))])
|
2012-06-29 18:26:56 -05:00
|
|
|
]))
|
2012-08-30 18:27:15 -05:00
|
|
|
]);
|
|
|
|
let astr = to_str(a);
|
|
|
|
let b = result::get(from_str(astr));
|
|
|
|
let bstr = to_str(b);
|
|
|
|
assert astr == bstr;
|
|
|
|
assert a == b;
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_trailing_characters() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"nulla") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 5u, msg: @~"trailing characters"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"truea") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 5u, msg: @~"trailing characters"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"falsea") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 6u, msg: @~"trailing characters"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"1a") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"trailing characters"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"[]a") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 3u, msg: @~"trailing characters"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{}a") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 3u, msg: @~"trailing characters"});
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_read_identifiers() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"n") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"invalid syntax"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"nul") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 4u, msg: @~"invalid syntax"});
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"t") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"invalid syntax"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"truz") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 4u, msg: @~"invalid syntax"});
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"f") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"invalid syntax"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"faz") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 3u, msg: @~"invalid syntax"});
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
assert from_str(~"null") == Ok(Null);
|
|
|
|
assert from_str(~"true") == Ok(Boolean(true));
|
|
|
|
assert from_str(~"false") == Ok(Boolean(false));
|
|
|
|
assert from_str(~" null ") == Ok(Null);
|
|
|
|
assert from_str(~" true ") == Ok(Boolean(true));
|
|
|
|
assert from_str(~" false ") == Ok(Boolean(false));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_read_num() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"+") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 1u, msg: @~"invalid syntax"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~".") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 1u, msg: @~"invalid syntax"});
|
2012-07-14 00:57:48 -05:00
|
|
|
|
|
|
|
assert from_str(~"-") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"invalid number"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"00") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"invalid number"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"1.") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 3u, msg: @~"invalid number"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"1e") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 3u, msg: @~"invalid number"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"1e+") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 4u, msg: @~"invalid number"});
|
2012-07-14 00:57:48 -05:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
assert from_str(~"3") == Ok(Num(3f));
|
|
|
|
assert from_str(~"3.1") == Ok(Num(3.1f));
|
|
|
|
assert from_str(~"-1.2") == Ok(Num(-1.2f));
|
|
|
|
assert from_str(~"0.4") == Ok(Num(0.4f));
|
|
|
|
assert from_str(~"0.4e5") == Ok(Num(0.4e5f));
|
|
|
|
assert from_str(~"0.4e+15") == Ok(Num(0.4e15f));
|
|
|
|
assert from_str(~"0.4e-01") == Ok(Num(0.4e-01f));
|
|
|
|
assert from_str(~" 3 ") == Ok(Num(3f));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_read_str() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"\"") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"EOF while parsing string"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"\"lol") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 5u, msg: @~"EOF while parsing string"});
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
assert from_str(~"\"\"") == Ok(String(@~""));
|
|
|
|
assert from_str(~"\"foo\"") == Ok(String(@~"foo"));
|
|
|
|
assert from_str(~"\"\\\"\"") == Ok(String(@~"\""));
|
|
|
|
assert from_str(~"\"\\b\"") == Ok(String(@~"\x08"));
|
|
|
|
assert from_str(~"\"\\n\"") == Ok(String(@~"\n"));
|
|
|
|
assert from_str(~"\"\\r\"") == Ok(String(@~"\r"));
|
|
|
|
assert from_str(~"\"\\t\"") == Ok(String(@~"\t"));
|
|
|
|
assert from_str(~" \"foo\" ") == Ok(String(@~"foo"));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_read_list() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"[") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"EOF while parsing value"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"[1") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 3u, msg: @~"EOF while parsing list"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"[1,") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 4u, msg: @~"EOF while parsing value"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"[1,]") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 4u, msg: @~"invalid syntax"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"[6 7]") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 4u, msg: @~"expected `,` or `]`"});
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
assert from_str(~"[]") == Ok(List(@~[]));
|
|
|
|
assert from_str(~"[ ]") == Ok(List(@~[]));
|
|
|
|
assert from_str(~"[true]") == Ok(List(@~[Boolean(true)]));
|
|
|
|
assert from_str(~"[ false ]") == Ok(List(@~[Boolean(false)]));
|
|
|
|
assert from_str(~"[null]") == Ok(List(@~[Null]));
|
|
|
|
assert from_str(~"[3, 1]") == Ok(List(@~[Num(3f), Num(1f)]));
|
|
|
|
assert from_str(~"\n[3, 2]\n") == Ok(List(@~[Num(3f), Num(2f)]));
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"[2, [4, 1]]") ==
|
2012-08-11 09:08:42 -05:00
|
|
|
Ok(List(@~[Num(2f), List(@~[Num(4f), Num(1f)])]));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_read_dict() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"EOF while parsing object"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{ ") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 3u, msg: @~"EOF while parsing object"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{1") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 2u, msg: @~"key must be a string"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{ \"a\"") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 6u, msg: @~"EOF while parsing object"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{\"a\"") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 5u, msg: @~"EOF while parsing object"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{\"a\" ") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 6u, msg: @~"EOF while parsing object"});
|
2012-07-14 00:57:48 -05:00
|
|
|
|
|
|
|
assert from_str(~"{\"a\" 1") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 6u, msg: @~"expected `:`"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{\"a\":") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 6u, msg: @~"EOF while parsing value"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{\"a\":1") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 7u, msg: @~"EOF while parsing object"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{\"a\":1 1") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 8u, msg: @~"expected `,` or `}`"});
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{\"a\":1,") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 1u, col: 8u, msg: @~"EOF while parsing object"});
|
2012-07-14 00:57:48 -05:00
|
|
|
|
|
|
|
assert eq(result::get(from_str(~"{}")), mk_dict(~[]));
|
|
|
|
assert eq(result::get(from_str(~"{\"a\": 3}")),
|
2012-08-11 09:08:42 -05:00
|
|
|
mk_dict(~[(~"a", Num(3.0f))]));
|
2012-07-14 00:57:48 -05:00
|
|
|
|
|
|
|
assert eq(result::get(from_str(~"{ \"a\": null, \"b\" : true }")),
|
2012-06-29 18:26:56 -05:00
|
|
|
mk_dict(~[
|
2012-08-11 09:08:42 -05:00
|
|
|
(~"a", Null),
|
|
|
|
(~"b", Boolean(true))]));
|
2012-07-14 00:57:48 -05:00
|
|
|
assert eq(result::get(from_str(~"\n{ \"a\": null, \"b\" : true }\n")),
|
2012-06-29 18:26:56 -05:00
|
|
|
mk_dict(~[
|
2012-08-11 09:08:42 -05:00
|
|
|
(~"a", Null),
|
|
|
|
(~"b", Boolean(true))]));
|
2012-07-14 00:57:48 -05:00
|
|
|
assert eq(result::get(from_str(~"{\"a\" : 1.0 ,\"b\": [ true ]}")),
|
2012-06-29 18:26:56 -05:00
|
|
|
mk_dict(~[
|
2012-08-11 09:08:42 -05:00
|
|
|
(~"a", Num(1.0)),
|
|
|
|
(~"b", List(@~[Boolean(true)]))
|
2012-06-29 18:26:56 -05:00
|
|
|
]));
|
2012-02-25 18:39:32 -06:00
|
|
|
assert eq(result::get(from_str(
|
2012-07-14 00:57:48 -05:00
|
|
|
~"{" +
|
|
|
|
~"\"a\": 1.0, " +
|
|
|
|
~"\"b\": [" +
|
|
|
|
~"true," +
|
|
|
|
~"\"foo\\nbar\", " +
|
|
|
|
~"{ \"c\": {\"d\": null} } " +
|
|
|
|
~"]" +
|
|
|
|
~"}")),
|
2012-06-29 18:26:56 -05:00
|
|
|
mk_dict(~[
|
2012-08-11 09:08:42 -05:00
|
|
|
(~"a", Num(1.0f)),
|
|
|
|
(~"b", List(@~[
|
|
|
|
Boolean(true),
|
|
|
|
String(@~"foo\nbar"),
|
2012-06-29 18:26:56 -05:00
|
|
|
mk_dict(~[
|
2012-08-11 09:08:42 -05:00
|
|
|
(~"c", mk_dict(~[(~"d", Null)]))
|
2012-06-29 18:26:56 -05:00
|
|
|
])
|
|
|
|
]))
|
|
|
|
]));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_multiline_errors() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert from_str(~"{\n \"foo\":\n \"bar\"") ==
|
2012-08-26 18:54:31 -05:00
|
|
|
Err({line: 3u, col: 8u, msg: @~"EOF while parsing object"});
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
}
|