diff --git a/src/lib/json.rs b/src/lib/json.rs index 02d5d3d5e7e..2fa38da2c10 100644 --- a/src/lib/json.rs +++ b/src/lib/json.rs @@ -1,10 +1,5 @@ -#[link(name = "json", - vers = "0.1", - uuid = "09d7f2fc-1fad-48b2-9f9d-a65512342f16", - url = "http://www.leptoquark.net/~elly/rust/")]; -#[copyright = "Google Inc. 2011"]; -#[comment = "JSON serialization format library"]; -#[license = "BSD"]; +// Rust JSON serialization library +// Copyright (c) 2011 Google Inc. import float; import map; @@ -14,18 +9,39 @@ import str; import vec; export json; -export tostr; -export fromstr; +export to_str; +export from_str; +export num; +export string; +export boolean; +export list; +export dict; + +/* +Tag: json + +Represents a json value. +*/ tag json { + /* Variant: num */ num(float); + /* Variant: string */ string(str); + /* Variant: boolean */ boolean(bool); + /* Variant: list */ list(@[json]); + /* Variant: dict */ dict(map::hashmap); } -fn tostr(j: json) -> str { +/* +Function: to_str + +Serializes a json value into a string. +*/ +fn to_str(j: json) -> str { alt j { num(f) { float::to_str(f, 6u) } string(s) { #fmt["\"%s\"", s] } // XXX: escape @@ -34,7 +50,7 @@ fn tostr(j: json) -> str { list(@js) { str::concat(["[", str::connect( - vec::map::({ |e| tostr(e) }, js), + vec::map::({ |e| to_str(e) }, js), ", "), "]"]) } @@ -42,7 +58,7 @@ fn tostr(j: json) -> str { let parts = []; m.items({ |k, v| vec::grow(parts, 1u, - str::concat(["\"", k, "\": ", tostr(v)]) + str::concat(["\"", k, "\": ", to_str(v)]) ) }); str::concat(["{ ", str::connect(parts, ", "), " }"]) @@ -51,10 +67,11 @@ fn tostr(j: json) -> str { } fn rest(s: str) -> str { + assert(str::char_len(s) >= 1u); str::char_slice(s, 1u, str::char_len(s)) } -fn fromstr_str(s: str) -> (option::t, str) { +fn from_str_str(s: str) -> (option::t, str) { let pos = 0u; let len = str::byte_len(s); let escape = false; @@ -86,7 +103,7 @@ fn fromstr_str(s: str) -> (option::t, str) { ret (none, s); } -fn fromstr_list(s: str) -> (option::t, str) { +fn from_str_list(s: str) -> (option::t, str) { if str::char_at(s, 0u) != '[' { ret (none, s); } let s0 = str::trim_left(rest(s)); let vals = []; @@ -94,7 +111,7 @@ fn fromstr_list(s: str) -> (option::t, str) { if str::char_at(s0, 0u) == ']' { ret (some(list(@[])), rest(s0)); } while str::is_not_empty(s0) { s0 = str::trim_left(s0); - let (next, s1) = fromstr_helper(s0); + let (next, s1) = from_str_helper(s0); s0 = s1; alt next { some(j) { vec::grow(vals, 1u, j); } @@ -112,7 +129,7 @@ fn fromstr_list(s: str) -> (option::t, str) { ret (none, s0); } -fn fromstr_dict(s: str) -> (option::t, str) { +fn from_str_dict(s: str) -> (option::t, str) { if str::char_at(s, 0u) != '{' { ret (none, s); } let s0 = str::trim_left(rest(s)); let vals = map::new_str_hash::(); @@ -120,7 +137,7 @@ fn fromstr_dict(s: str) -> (option::t, str) { if str::char_at(s0, 0u) == '}' { ret (some(dict(vals)), rest(s0)); } while str::is_not_empty(s0) { s0 = str::trim_left(s0); - let (next, s1) = fromstr_helper(s0); // key + let (next, s1) = from_str_helper(s0); // key let key = ""; s0 = s1; alt next { @@ -131,7 +148,7 @@ fn fromstr_dict(s: str) -> (option::t, str) { if str::is_empty(s0) { ret (none, s0); } if str::char_at(s0, 0u) != ':' { ret (none, s0); } s0 = str::trim_left(rest(s0)); - let (next, s1) = fromstr_helper(s0); // value + let (next, s1) = from_str_helper(s0); // value s0 = s1; alt next { some(j) { vals.insert(key, j); } @@ -149,7 +166,7 @@ fn fromstr_dict(s: str) -> (option::t, str) { (none, s) } -fn fromstr_float(s: str) -> (option::t, str) { +fn from_str_float(s: str) -> (option::t, str) { let pos = 0u; let len = str::byte_len(s); let res = 0f; @@ -205,7 +222,7 @@ fn fromstr_float(s: str) -> (option::t, str) { ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s))); } -fn fromstr_bool(s: str) -> (option::t, str) { +fn from_str_bool(s: str) -> (option::t, str) { if (str::starts_with(s, "true")) { (some(boolean(true)), str::slice(s, 4u, str::byte_len(s))) } else if (str::starts_with(s, "false")) { @@ -215,79 +232,26 @@ fn fromstr_bool(s: str) -> (option::t, str) { } } -fn fromstr_helper(s: str) -> (option::t, str) { +fn from_str_helper(s: str) -> (option::t, str) { let s = str::trim_left(s); if str::is_empty(s) { ret (none, s); } let start = str::char_at(s, 0u); alt start { - '"' { fromstr_str(s) } - '[' { fromstr_list(s) } - '{' { fromstr_dict(s) } - '0' to '9' | '-' | '+' | '.' { fromstr_float(s) } - 't' | 'f' { fromstr_bool(s) } + '"' { from_str_str(s) } + '[' { from_str_list(s) } + '{' { from_str_dict(s) } + '0' to '9' | '-' | '+' | '.' { from_str_float(s) } + 't' | 'f' { from_str_bool(s) } _ { ret (none, s); } } } -fn fromstr(s: str) -> option::t { - let (j, _) = fromstr_helper(s); +/* +Function: from_str + +Deserializes a json value from a string. +*/ +fn from_str(s: str) -> option::t { + let (j, _) = from_str_helper(s); j } - -fn main() { - let j = fromstr("{ \"foo\": [ 4, 5 ], \"bar\": { \"baz\": true}}"); - alt j { - some(j0) { - log tostr(j0); - } - _ { } - } -} - -#[cfg(test)] -mod tests { - #[test] - fn test_fromstr_num() { - assert(fromstr("3") == some(num(3f))); - assert(fromstr("3.1") == some(num(3.1f))); - assert(fromstr("-1.2") == some(num(-1.2f))); - assert(fromstr(".4") == some(num(0.4f))); - } - - #[test] - fn test_fromstr_str() { - assert(fromstr("\"foo\"") == some(string("foo"))); - assert(fromstr("\"\\\"\"") == some(string("\""))); - assert(fromstr("\"lol") == none); - } - - #[test] - fn test_fromstr_bool() { - assert(fromstr("true") == some(boolean(true))); - assert(fromstr("false") == some(boolean(false))); - assert(fromstr("truz") == none); - } - - #[test] - fn test_fromstr_list() { - assert(fromstr("[]") == some(list(@[]))); - assert(fromstr("[true]") == some(list(@[boolean(true)]))); - assert(fromstr("[3, 1]") == some(list(@[num(3f), num(1f)]))); - assert(fromstr("[2, [4, 1]]") == - some(list(@[num(2f), list(@[num(4f), num(1f)])]))); - assert(fromstr("[2, ]") == none); - assert(fromstr("[5, ") == none); - assert(fromstr("[6 7]") == none); - assert(fromstr("[3") == none); - } - - #[test] - fn test_fromstr_dict() { - assert(fromstr("{}") != none); - assert(fromstr("{\"a\": 3}") != none); - assert(fromstr("{\"a\": }") == none); - assert(fromstr("{\"a\" }") == none); - assert(fromstr("{\"a\"") == none); - assert(fromstr("{") == none); - } -} diff --git a/src/lib/std.rc b/src/lib/std.rc index 86335d6312e..bc085c1803f 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -12,7 +12,7 @@ export aio, comm, fs, io, net, run, sio, sys, task; export ctypes, either, option, result, util; export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap, ufind; export rope; -export ebml, dbg, getopts, math, rand, sha1, term, time, unsafe; +export ebml, dbg, getopts, json, math, rand, sha1, term, time, unsafe; export extfmt, test; // FIXME: generic_os and os_fs shouldn't be exported export generic_os, os, os_fs; diff --git a/src/test/stdtest/json.rs b/src/test/stdtest/json.rs new file mode 100644 index 00000000000..a19ddec5e7d --- /dev/null +++ b/src/test/stdtest/json.rs @@ -0,0 +1,48 @@ +use std; +import std::json::*; +import std::option::{none, some}; + +#[test] +fn test_from_str_num() { + assert(from_str("3") == some(num(3f))); + assert(from_str("3.1") == some(num(3.1f))); + assert(from_str("-1.2") == some(num(-1.2f))); + assert(from_str(".4") == some(num(0.4f))); +} + +#[test] +fn test_from_str_str() { + assert(from_str("\"foo\"") == some(string("foo"))); + assert(from_str("\"\\\"\"") == some(string("\""))); + assert(from_str("\"lol") == none); +} + +#[test] +fn test_from_str_bool() { + assert(from_str("true") == some(boolean(true))); + assert(from_str("false") == some(boolean(false))); + assert(from_str("truz") == none); +} + +#[test] +fn test_from_str_list() { + assert(from_str("[]") == some(list(@[]))); + assert(from_str("[true]") == some(list(@[boolean(true)]))); + assert(from_str("[3, 1]") == some(list(@[num(3f), num(1f)]))); + assert(from_str("[2, [4, 1]]") == + some(list(@[num(2f), list(@[num(4f), num(1f)])]))); + assert(from_str("[2, ]") == none); + assert(from_str("[5, ") == none); + assert(from_str("[6 7]") == none); + assert(from_str("[3") == none); +} + +#[test] +fn test_from_str_dict() { + assert(from_str("{}") != none); + assert(from_str("{\"a\": 3}") != none); + assert(from_str("{\"a\": }") == none); + assert(from_str("{\"a\" }") == none); + assert(from_str("{\"a\"") == none); + assert(from_str("{") == none); +} diff --git a/src/test/stdtest/stdtest.rc b/src/test/stdtest/stdtest.rc index 18ba19d0151..09eabb632d6 100644 --- a/src/test/stdtest/stdtest.rc +++ b/src/test/stdtest/stdtest.rc @@ -6,14 +6,15 @@ mod char; mod comm; mod deque; mod either; +mod float; mod fs; mod getopts; mod int; mod io; -mod vec; +mod json; mod list; mod map; -mod treemap; +mod math; mod net; mod option; mod os; @@ -22,6 +23,8 @@ mod ptr; mod qsort3; mod qsort; mod rand; +mod result; +mod rope; mod run; mod sha1; mod sort; @@ -29,11 +32,9 @@ mod str; mod sys; mod task; mod test; +mod treemap; mod uint; -mod float; -mod math; -mod result; -mod rope; +mod vec; // Local Variables: // mode: rust