blob: 1ac6a5476597803be7cf5c85213f6757646456e8 [file] [log] [blame]
Elly Jones656a2af2011-11-07 23:24:441// Rust JSON serialization library
2// Copyright (c) 2011 Google Inc.
Elly Jonesbd726262011-11-07 19:01:283
Brian Anderson95521c42012-03-08 02:17:304#[doc = "json serialization"];
5
Brian Anderson47d468f2012-03-16 22:14:376import result::{result, ok, err};
Erick Tryzelaar012dec52012-02-26 00:39:327import io;
8import io::{reader_util, writer_util};
Elly Jonesbd726262011-11-07 19:01:289import map;
Patrick Waltonc9375fe2012-03-08 00:48:5710import map::hashmap;
Elly Jonesbd726262011-11-07 19:01:2811
12export json;
Erick Tryzelaarfaccd4a2012-03-05 16:47:2113export error;
Erick Tryzelaar012dec52012-02-26 00:39:3214export to_writer;
Elly Jones656a2af2011-11-07 23:24:4415export to_str;
Erick Tryzelaar012dec52012-02-26 00:39:3216export from_reader;
Elly Jones656a2af2011-11-07 23:24:4417export from_str;
Erick Tryzelaar012dec52012-02-26 00:39:3218export eq;
Erick Tryzelaared5af702012-05-28 19:10:3219export to_json;
Elly Jonesbd726262011-11-07 19:01:2820
Elly Jones656a2af2011-11-07 23:24:4421export num;
22export string;
23export boolean;
24export list;
25export dict;
Erick Tryzelaar012dec52012-02-26 00:39:3226export null;
Elly Jones656a2af2011-11-07 23:24:4427
Brian Anderson95521c42012-03-08 02:17:3028#[doc = "Represents a json value"]
Patrick Waltonc5a407b2012-01-19 23:20:5729enum json {
Patrick Walton194d8e32012-01-20 01:55:3430 num(float),
Erick Tryzelaarb361f6c2012-06-13 00:20:5131 string(@str),
Patrick Walton194d8e32012-01-20 01:55:3432 boolean(bool),
Erick Tryzelaarb361f6c2012-06-13 00:20:5133 list(@[json]),
34 dict(map::hashmap<str, json>),
Patrick Walton194d8e32012-01-20 01:55:3435 null,
Elly Jonesbd726262011-11-07 19:01:2836}
37
Erick Tryzelaar012dec52012-02-26 00:39:3238type error = {
39 line: uint,
40 col: uint,
Erick Tryzelaarb361f6c2012-06-13 00:20:5141 msg: @str,
Erick Tryzelaar012dec52012-02-26 00:39:3242};
43
Brian Anderson95521c42012-03-08 02:17:3044#[doc = "Serializes a json value into a io::writer"]
Erick Tryzelaar012dec52012-02-26 00:39:3245fn to_writer(wr: io::writer, j: json) {
46 alt j {
47 num(n) { wr.write_str(float::to_str(n, 6u)); }
48 string(s) {
Erick Tryzelaarb361f6c2012-06-13 00:20:5149 wr.write_str(escape_str(*s));
Erick Tryzelaar012dec52012-02-26 00:39:3250 }
51 boolean(b) {
52 wr.write_str(if b { "true" } else { "false" });
53 }
54 list(v) {
55 wr.write_char('[');
Niko Matsakis6b358752012-03-14 18:03:5656 let mut first = true;
Erick Tryzelaarb361f6c2012-06-13 00:20:5157 for (*v).each { |item|
Erick Tryzelaar012dec52012-02-26 00:39:3258 if !first {
59 wr.write_str(", ");
60 }
61 first = false;
62 to_writer(wr, item);
63 };
64 wr.write_char(']');
65 }
66 dict(d) {
67 if d.size() == 0u {
68 wr.write_str("{}");
69 ret;
70 }
71
72 wr.write_str("{ ");
Niko Matsakis6b358752012-03-14 18:03:5673 let mut first = true;
Marijn Haverbeke9053f542012-04-23 11:42:1574 for d.each { |key, value|
Erick Tryzelaar012dec52012-02-26 00:39:3275 if !first {
76 wr.write_str(", ");
77 }
78 first = false;
Erick Tryzelaarb361f6c2012-06-13 00:20:5179 wr.write_str(escape_str(key));
Erick Tryzelaar012dec52012-02-26 00:39:3280 wr.write_str(": ");
81 to_writer(wr, value);
82 };
83 wr.write_str(" }");
84 }
85 null {
86 wr.write_str("null");
87 }
88 }
89}
90
Erick Tryzelaarb361f6c2012-06-13 00:20:5191fn escape_str(s: str) -> str {
92 let mut escaped = "\"";
93 str::chars_iter(s) { |c|
94 alt c {
95 '"' { escaped += "\\\""; }
96 '\\' { escaped += "\\\\"; }
97 '\x08' { escaped += "\\b"; }
98 '\x0c' { escaped += "\\f"; }
99 '\n' { escaped += "\\n"; }
100 '\r' { escaped += "\\r"; }
101 '\t' { escaped += "\\t"; }
102 _ { escaped += str::from_char(c); }
103 }
104 };
105
106 escaped += "\"";
107
108 escaped
109}
110
Brian Anderson95521c42012-03-08 02:17:30111#[doc = "Serializes a json value into a string"]
Elly Jones656a2af2011-11-07 23:24:44112fn to_str(j: json) -> str {
Erick Tryzelaar012dec52012-02-26 00:39:32113 io::with_str_writer { |wr| to_writer(wr, j) }
Elly Jonesbd726262011-11-07 19:01:28114}
115
Erick Tryzelaar012dec52012-02-26 00:39:32116type parser = {
117 rdr: io::reader,
Graydon Hoare6e6798c2012-03-27 01:35:18118 mut ch: char,
119 mut line: uint,
120 mut col: uint,
Erick Tryzelaar012dec52012-02-26 00:39:32121};
Elly Jonesbd726262011-11-07 19:01:28122
Erick Tryzelaar012dec52012-02-26 00:39:32123impl parser for parser {
124 fn eof() -> bool { self.ch == -1 as char }
Elly Jonesbd726262011-11-07 19:01:28125
Erick Tryzelaar012dec52012-02-26 00:39:32126 fn bump() {
127 self.ch = self.rdr.read_char();
128
129 if self.ch == '\n' {
130 self.line += 1u;
131 self.col = 1u;
132 } else {
133 self.col += 1u;
134 }
Elly Jonesbd726262011-11-07 19:01:28135 }
136
Erick Tryzelaar012dec52012-02-26 00:39:32137 fn next_char() -> char {
138 self.bump();
139 self.ch
Elly Jonesbd726262011-11-07 19:01:28140 }
141
Erick Tryzelaarb361f6c2012-06-13 00:20:51142 fn error<T>(+msg: str) -> result<T, error> {
143 err({ line: self.line, col: self.col, msg: @msg })
Elly Jonesbd726262011-11-07 19:01:28144 }
Elly Jonesbd726262011-11-07 19:01:28145
Brian Andersonb968c8e2012-03-13 21:39:28146 fn parse() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32147 alt self.parse_value() {
148 ok(value) {
Tycho Sciecf87c32012-02-29 08:47:17149 // Skip trailing whitespaces.
150 self.parse_whitespace();
Erick Tryzelaar012dec52012-02-26 00:39:32151 // Make sure there is no trailing characters.
152 if self.eof() {
153 ok(value)
154 } else {
155 self.error("trailing characters")
156 }
157 }
158 e { e }
Elly Jonesbd726262011-11-07 19:01:28159 }
Elly Jonesbd726262011-11-07 19:01:28160 }
Elly Jonesbd726262011-11-07 19:01:28161
Brian Andersonb968c8e2012-03-13 21:39:28162 fn parse_value() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32163 self.parse_whitespace();
Elly Jonesbd726262011-11-07 19:01:28164
Erick Tryzelaar012dec52012-02-26 00:39:32165 if self.eof() { ret self.error("EOF while parsing value"); }
166
167 alt self.ch {
168 'n' { self.parse_ident("ull", null) }
169 't' { self.parse_ident("rue", boolean(true)) }
170 'f' { self.parse_ident("alse", boolean(false)) }
171 '0' to '9' | '-' { self.parse_number() }
172 '"' {
173 alt self.parse_str() {
174 ok(s) { ok(string(s)) }
175 err(e) { err(e) }
176 }
177 }
178 '[' { self.parse_list() }
179 '{' { self.parse_object() }
180 _ { self.error("invalid syntax") }
181 }
182 }
183
184 fn parse_whitespace() {
185 while char::is_whitespace(self.ch) { self.bump(); }
186 }
187
Brian Andersonb968c8e2012-03-13 21:39:28188 fn parse_ident(ident: str, value: json) -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32189 if str::all(ident, { |c| c == self.next_char() }) {
190 self.bump();
191 ok(value)
192 } else {
193 self.error("invalid syntax")
194 }
195 }
196
Brian Andersonb968c8e2012-03-13 21:39:28197 fn parse_number() -> result<json, error> {
Niko Matsakis6b358752012-03-14 18:03:56198 let mut neg = 1f;
Erick Tryzelaar012dec52012-02-26 00:39:32199
200 if self.ch == '-' {
201 self.bump();
Marijn Haverbeke4f826d82011-12-16 09:11:00202 neg = -1f;
Elly Jonesbd726262011-11-07 19:01:28203 }
Elly Jonesbd726262011-11-07 19:01:28204
Niko Matsakis6b358752012-03-14 18:03:56205 let mut res = alt self.parse_integer() {
Erick Tryzelaar012dec52012-02-26 00:39:32206 ok(res) { res }
207 err(e) { ret err(e); }
208 };
209
210 if self.ch == '.' {
211 alt self.parse_decimal(res) {
212 ok(r) { res = r; }
213 err(e) { ret err(e); }
Elly Jonesbd726262011-11-07 19:01:28214 }
Elly Jonesbd726262011-11-07 19:01:28215 }
Erick Tryzelaar012dec52012-02-26 00:39:32216
217 if self.ch == 'e' || self.ch == 'E' {
218 alt self.parse_exponent(res) {
219 ok(r) { res = r; }
220 err(e) { ret err(e); }
221 }
222 }
223
224 ok(num(neg * res))
Elly Jonesbd726262011-11-07 19:01:28225 }
226
Brian Andersonb968c8e2012-03-13 21:39:28227 fn parse_integer() -> result<float, error> {
Niko Matsakis6b358752012-03-14 18:03:56228 let mut res = 0f;
Erick Tryzelaar012dec52012-02-26 00:39:32229
230 alt self.ch {
231 '0' {
232 self.bump();
233
234 // There can be only one leading '0'.
235 alt self.ch {
236 '0' to '9' { ret self.error("invalid number"); }
237 _ {}
238 }
239 }
240 '1' to '9' {
241 while !self.eof() {
242 alt self.ch {
243 '0' to '9' {
244 res *= 10f;
245 res += ((self.ch as int) - ('0' as int)) as float;
246
247 self.bump();
248 }
249 _ { break; }
250 }
251 }
252 }
253 _ { ret self.error("invalid number"); }
254 }
255
256 ok(res)
Elly Jonesbd726262011-11-07 19:01:28257 }
258
Brian Andersonb968c8e2012-03-13 21:39:28259 fn parse_decimal(res: float) -> result<float, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32260 self.bump();
261
262 // Make sure a digit follows the decimal place.
263 alt self.ch {
264 '0' to '9' {}
265 _ { ret self.error("invalid number"); }
266 }
267
Niko Matsakis6b358752012-03-14 18:03:56268 let mut res = res;
269 let mut dec = 1f;
Erick Tryzelaar012dec52012-02-26 00:39:32270 while !self.eof() {
271 alt self.ch {
272 '0' to '9' {
Marijn Haverbeke4f826d82011-12-16 09:11:00273 dec /= 10f;
Erick Tryzelaar012dec52012-02-26 00:39:32274 res += (((self.ch as int) - ('0' as int)) as float) * dec;
275
276 self.bump();
277 }
278 _ { break; }
Elly Jonesbd726262011-11-07 19:01:28279 }
Elly Jonesbd726262011-11-07 19:01:28280 }
Elly Jonesbd726262011-11-07 19:01:28281
Erick Tryzelaar012dec52012-02-26 00:39:32282 ok(res)
283 }
284
Brian Andersonb968c8e2012-03-13 21:39:28285 fn parse_exponent(res: float) -> result<float, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32286 self.bump();
287
Niko Matsakis6b358752012-03-14 18:03:56288 let mut res = res;
289 let mut exp = 0u;
290 let mut neg_exp = false;
Erick Tryzelaar012dec52012-02-26 00:39:32291
292 alt self.ch {
293 '+' { self.bump(); }
294 '-' { self.bump(); neg_exp = true; }
295 _ {}
296 }
297
298 // Make sure a digit follows the exponent place.
299 alt self.ch {
300 '0' to '9' {}
301 _ { ret self.error("invalid number"); }
302 }
303
304 while !self.eof() {
305 alt self.ch {
306 '0' to '9' {
307 exp *= 10u;
308 exp += (self.ch as uint) - ('0' as uint);
309
310 self.bump();
311 }
312 _ { break; }
313 }
314 }
315
316 let exp = float::pow_with_uint(10u, exp);
317 if neg_exp {
318 res /= exp;
319 } else {
320 res *= exp;
321 }
322
323 ok(res)
324 }
325
Erick Tryzelaarb361f6c2012-06-13 00:20:51326 fn parse_str() -> result<@str, error> {
Niko Matsakis6b358752012-03-14 18:03:56327 let mut escape = false;
328 let mut res = "";
Erick Tryzelaar012dec52012-02-26 00:39:32329
330 while !self.eof() {
331 self.bump();
332
333 if (escape) {
334 alt self.ch {
335 '"' { str::push_char(res, '"'); }
336 '\\' { str::push_char(res, '\\'); }
337 '/' { str::push_char(res, '/'); }
338 'b' { str::push_char(res, '\x08'); }
339 'f' { str::push_char(res, '\x0c'); }
340 'n' { str::push_char(res, '\n'); }
341 'r' { str::push_char(res, '\r'); }
342 't' { str::push_char(res, '\t'); }
343 'u' {
344 // Parse \u1234.
Niko Matsakis6b358752012-03-14 18:03:56345 let mut i = 0u;
346 let mut n = 0u;
Erick Tryzelaar012dec52012-02-26 00:39:32347 while i < 4u {
348 alt self.next_char() {
349 '0' to '9' {
350 n = n * 10u +
351 (self.ch as uint) - ('0' as uint);
352 }
353 _ { ret self.error("invalid \\u escape"); }
354 }
Niko Matsakis6b358752012-03-14 18:03:56355 i += 1u;
Erick Tryzelaar012dec52012-02-26 00:39:32356 }
357
358 // Error out if we didn't parse 4 digits.
359 if i != 4u {
360 ret self.error("invalid \\u escape");
361 }
362
363 str::push_char(res, n as char);
364 }
365 _ { ret self.error("invalid escape"); }
366 }
367 escape = false;
368 } else if self.ch == '\\' {
369 escape = true;
370 } else {
371 if self.ch == '"' {
372 self.bump();
Erick Tryzelaarb361f6c2012-06-13 00:20:51373 ret ok(@res);
Erick Tryzelaar012dec52012-02-26 00:39:32374 }
375 str::push_char(res, self.ch);
376 }
377 }
378
379 self.error("EOF while parsing string")
380 }
381
Brian Andersonb968c8e2012-03-13 21:39:28382 fn parse_list() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32383 self.bump();
384 self.parse_whitespace();
385
Niko Matsakis6b358752012-03-14 18:03:56386 let mut values = [];
Erick Tryzelaar012dec52012-02-26 00:39:32387
388 if self.ch == ']' {
389 self.bump();
Erick Tryzelaarb361f6c2012-06-13 00:20:51390 ret ok(list(@values));
Erick Tryzelaar012dec52012-02-26 00:39:32391 }
392
Tim Chevalier35400e12012-03-11 04:34:17393 loop {
Erick Tryzelaar012dec52012-02-26 00:39:32394 alt self.parse_value() {
395 ok(v) { vec::push(values, v); }
396 e { ret e; }
397 }
398
399 self.parse_whitespace();
Tim Chevalier35400e12012-03-11 04:34:17400 if self.eof() {
401 ret self.error("EOF while parsing list");
402 }
Erick Tryzelaar012dec52012-02-26 00:39:32403
404 alt self.ch {
405 ',' { self.bump(); }
Erick Tryzelaarb361f6c2012-06-13 00:20:51406 ']' { self.bump(); ret ok(list(@values)); }
Erick Tryzelaar012dec52012-02-26 00:39:32407 _ { ret self.error("expecting ',' or ']'"); }
408 }
Tim Chevalier35400e12012-03-11 04:34:17409 };
Erick Tryzelaar012dec52012-02-26 00:39:32410 }
411
Brian Andersonb968c8e2012-03-13 21:39:28412 fn parse_object() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32413 self.bump();
414 self.parse_whitespace();
415
Brian Anderson3864d6d2012-03-14 19:07:23416 let values = map::str_hash();
Erick Tryzelaar012dec52012-02-26 00:39:32417
418 if self.ch == '}' {
419 self.bump();
420 ret ok(dict(values));
421 }
422
423 while !self.eof() {
424 self.parse_whitespace();
425
426 if self.ch != '"' {
427 ret self.error("key must be a string");
428 }
429
430 let key = alt self.parse_str() {
431 ok(key) { key }
432 err(e) { ret err(e); }
433 };
434
435 self.parse_whitespace();
436
437 if self.ch != ':' {
438 if self.eof() { break; }
439 ret self.error("expecting ':'");
440 }
441 self.bump();
442
443 alt self.parse_value() {
Erick Tryzelaarb361f6c2012-06-13 00:20:51444 ok(value) { values.insert(copy *key, value); }
Erick Tryzelaar012dec52012-02-26 00:39:32445 e { ret e; }
446 }
447 self.parse_whitespace();
448
449 alt self.ch {
450 ',' { self.bump(); }
Tycho Sciecf87c32012-02-29 08:47:17451 '}' { self.bump(); ret ok(dict(values)); }
Erick Tryzelaar012dec52012-02-26 00:39:32452 _ {
453 if self.eof() { break; }
454 ret self.error("expecting ',' or '}'");
455 }
456 }
457 }
458
459 ret self.error("EOF while parsing object");
Elly Jonesbd726262011-11-07 19:01:28460 }
461}
462
Brian Anderson95521c42012-03-08 02:17:30463#[doc = "Deserializes a json value from an io::reader"]
Brian Andersonb968c8e2012-03-13 21:39:28464fn from_reader(rdr: io::reader) -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32465 let parser = {
466 rdr: rdr,
Graydon Hoare6e6798c2012-03-27 01:35:18467 mut ch: rdr.read_char(),
468 mut line: 1u,
469 mut col: 1u,
Erick Tryzelaar012dec52012-02-26 00:39:32470 };
471
472 parser.parse()
Elly Jonesbd726262011-11-07 19:01:28473}
474
Brian Anderson95521c42012-03-08 02:17:30475#[doc = "Deserializes a json value from a string"]
Brian Andersonb968c8e2012-03-13 21:39:28476fn from_str(s: str) -> result<json, error> {
Erick Tryzelaar1404a862012-02-29 18:48:57477 io::with_str_reader(s, from_reader)
Erick Tryzelaar012dec52012-02-26 00:39:32478}
479
Brian Anderson95521c42012-03-08 02:17:30480#[doc = "Test if two json values are equal"]
Erick Tryzelaar012dec52012-02-26 00:39:32481fn eq(value0: json, value1: json) -> bool {
482 alt (value0, value1) {
483 (num(f0), num(f1)) { f0 == f1 }
484 (string(s0), string(s1)) { s0 == s1 }
485 (boolean(b0), boolean(b1)) { b0 == b1 }
Erick Tryzelaarb361f6c2012-06-13 00:20:51486 (list(l0), list(l1)) { vec::all2(*l0, *l1, eq) }
Erick Tryzelaar012dec52012-02-26 00:39:32487 (dict(d0), dict(d1)) {
488 if d0.size() == d1.size() {
Niko Matsakis6b358752012-03-14 18:03:56489 let mut equal = true;
Marijn Haverbeke9053f542012-04-23 11:42:15490 for d0.each { |k, v0|
Erick Tryzelaar012dec52012-02-26 00:39:32491 alt d1.find(k) {
492 some(v1) {
493 if !eq(v0, v1) { equal = false; } }
494 none { equal = false; }
495 }
496 };
497 equal
498 } else {
499 false
500 }
501 }
502 (null, null) { true }
503 _ { false }
504 }
Elly Jonesbd726262011-11-07 19:01:28505}
Brian Anderson6e27b272012-01-18 03:05:07506
Erick Tryzelaared5af702012-05-28 19:10:32507iface to_json { fn to_json() -> json; }
508
509impl of to_json for json {
510 fn to_json() -> json { self }
511}
512
513impl of to_json for i8 {
514 fn to_json() -> json { num(self as float) }
515}
516
517impl of to_json for i16 {
518 fn to_json() -> json { num(self as float) }
519}
520
521impl of to_json for i32 {
522 fn to_json() -> json { num(self as float) }
523}
524
525impl of to_json for i64 {
526 fn to_json() -> json { num(self as float) }
527}
528
529impl of to_json for u8 {
530 fn to_json() -> json { num(self as float) }
531}
532
533impl of to_json for u16 {
534 fn to_json() -> json { num(self as float) }
535}
536
537impl of to_json for u32 {
538 fn to_json() -> json { num(self as float) }
539}
540
541impl of to_json for u64 {
542 fn to_json() -> json { num(self as float) }
543}
544
545impl of to_json for float {
546 fn to_json() -> json { num(self) }
547}
548
549impl of to_json for f32 {
550 fn to_json() -> json { num(self as float) }
551}
552
553impl of to_json for f64 {
554 fn to_json() -> json { num(self as float) }
555}
556
557impl of to_json for () {
558 fn to_json() -> json { null }
559}
560
561impl of to_json for bool {
562 fn to_json() -> json { boolean(self) }
563}
564
565impl of to_json for str {
Erick Tryzelaarb361f6c2012-06-13 00:20:51566 fn to_json() -> json { string(@copy self) }
567}
568
569impl of to_json for @str {
Erick Tryzelaared5af702012-05-28 19:10:32570 fn to_json() -> json { string(self) }
571}
572
573impl <A: to_json copy, B: to_json copy> of to_json for (A, B) {
574 fn to_json() -> json {
575 let (a, b) = self;
Erick Tryzelaarb361f6c2012-06-13 00:20:51576 list(@[a.to_json(), b.to_json()])
Erick Tryzelaared5af702012-05-28 19:10:32577 }
578}
579
580impl <A: to_json copy, B: to_json copy, C: to_json copy>
581 of to_json for (A, B, C) {
582 fn to_json() -> json {
583 let (a, b, c) = self;
Erick Tryzelaarb361f6c2012-06-13 00:20:51584 list(@[a.to_json(), b.to_json(), c.to_json()])
Erick Tryzelaared5af702012-05-28 19:10:32585 }
586}
587
588impl <A: to_json> of to_json for [A] {
Erick Tryzelaarb361f6c2012-06-13 00:20:51589 fn to_json() -> json { list(@self.map { |elt| elt.to_json() }) }
Erick Tryzelaared5af702012-05-28 19:10:32590}
591
592impl <A: to_json copy> of to_json for hashmap<str, A> {
593 fn to_json() -> json {
594 let d = map::str_hash();
595 for self.each() { |key, value|
Erick Tryzelaarb361f6c2012-06-13 00:20:51596 d.insert(copy key, value.to_json());
Erick Tryzelaared5af702012-05-28 19:10:32597 }
598 dict(d)
599 }
600}
601
602impl <A: to_json> of to_json for option<A> {
603 fn to_json() -> json {
604 alt self {
605 none { null }
606 some(value) { value.to_json() }
607 }
608 }
609}
610
611impl of to_str::to_str for json {
612 fn to_str() -> str { to_str(self) }
613}
614
Erick Tryzelaara8161762012-06-11 15:32:38615impl of to_str::to_str for error {
616 fn to_str() -> str {
Erick Tryzelaarb361f6c2012-06-13 00:20:51617 #fmt("%u:%u: %s", self.line, self.col, *self.msg)
Erick Tryzelaara8161762012-06-11 15:32:38618 }
619}
620
Brian Anderson6e27b272012-01-18 03:05:07621#[cfg(test)]
622mod tests {
Erick Tryzelaar012dec52012-02-26 00:39:32623 fn mk_dict(items: [(str, json)]) -> json {
Brian Anderson3864d6d2012-03-14 19:07:23624 let d = map::str_hash();
Erick Tryzelaar012dec52012-02-26 00:39:32625
626 vec::iter(items) { |item|
Erick Tryzelaarb361f6c2012-06-13 00:20:51627 let (key, value) = copy item;
Erick Tryzelaar012dec52012-02-26 00:39:32628 d.insert(key, value);
629 };
630
631 dict(d)
Brian Anderson6e27b272012-01-18 03:05:07632 }
633
634 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32635 fn test_write_null() {
636 assert to_str(null) == "null";
Brian Anderson6e27b272012-01-18 03:05:07637 }
638
639 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32640 fn test_write_num() {
641 assert to_str(num(3f)) == "3";
642 assert to_str(num(3.1f)) == "3.1";
643 assert to_str(num(-1.5f)) == "-1.5";
644 assert to_str(num(0.5f)) == "0.5";
Brian Anderson6e27b272012-01-18 03:05:07645 }
646
647 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32648 fn test_write_str() {
Erick Tryzelaarb361f6c2012-06-13 00:20:51649 assert to_str(string(@"")) == "\"\"";
650 assert to_str(string(@"foo")) == "\"foo\"";
Brian Anderson6e27b272012-01-18 03:05:07651 }
652
653 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32654 fn test_write_bool() {
655 assert to_str(boolean(true)) == "true";
656 assert to_str(boolean(false)) == "false";
Brian Anderson6e27b272012-01-18 03:05:07657 }
658
659 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32660 fn test_write_list() {
Erick Tryzelaarb361f6c2012-06-13 00:20:51661 assert to_str(list(@[])) == "[]";
662 assert to_str(list(@[boolean(true)])) == "[true]";
663 assert to_str(list(@[
Erick Tryzelaar012dec52012-02-26 00:39:32664 boolean(false),
665 null,
Erick Tryzelaarb361f6c2012-06-13 00:20:51666 list(@[string(@"foo\nbar"), num(3.5f)])
Erick Tryzelaar012dec52012-02-26 00:39:32667 ])) == "[false, null, [\"foo\\nbar\", 3.5]]";
668 }
669
670 #[test]
671 fn test_write_dict() {
672 assert to_str(mk_dict([])) == "{}";
673 assert to_str(mk_dict([("a", boolean(true))])) == "{ \"a\": true }";
674 assert to_str(mk_dict([
675 ("a", boolean(true)),
Erick Tryzelaarb361f6c2012-06-13 00:20:51676 ("b", list(@[
677 mk_dict([("c", string(@"\x0c\r"))]),
678 mk_dict([("d", string(@""))])
Erick Tryzelaar012dec52012-02-26 00:39:32679 ]))
680 ])) ==
681 "{ " +
682 "\"a\": true, " +
683 "\"b\": [" +
684 "{ \"c\": \"\\f\\r\" }, " +
685 "{ \"d\": \"\" }" +
686 "]" +
687 " }";
688 }
689
690 #[test]
691 fn test_trailing_characters() {
692 assert from_str("nulla") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51693 err({line: 1u, col: 5u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32694 assert from_str("truea") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51695 err({line: 1u, col: 5u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32696 assert from_str("falsea") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51697 err({line: 1u, col: 6u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32698 assert from_str("1a") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51699 err({line: 1u, col: 2u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32700 assert from_str("[]a") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51701 err({line: 1u, col: 3u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32702 assert from_str("{}a") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51703 err({line: 1u, col: 3u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32704 }
705
706 #[test]
707 fn test_read_identifiers() {
708 assert from_str("n") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51709 err({line: 1u, col: 2u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32710 assert from_str("nul") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51711 err({line: 1u, col: 4u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32712
713 assert from_str("t") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51714 err({line: 1u, col: 2u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32715 assert from_str("truz") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51716 err({line: 1u, col: 4u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32717
718 assert from_str("f") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51719 err({line: 1u, col: 2u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32720 assert from_str("faz") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51721 err({line: 1u, col: 3u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32722
723 assert from_str("null") == ok(null);
724 assert from_str("true") == ok(boolean(true));
725 assert from_str("false") == ok(boolean(false));
Tycho Sciecf87c32012-02-29 08:47:17726 assert from_str(" null ") == ok(null);
727 assert from_str(" true ") == ok(boolean(true));
728 assert from_str(" false ") == ok(boolean(false));
Erick Tryzelaar012dec52012-02-26 00:39:32729 }
730
731 #[test]
732 fn test_read_num() {
733 assert from_str("+") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51734 err({line: 1u, col: 1u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32735 assert from_str(".") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51736 err({line: 1u, col: 1u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32737
738 assert from_str("-") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51739 err({line: 1u, col: 2u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32740 assert from_str("00") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51741 err({line: 1u, col: 2u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32742 assert from_str("1.") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51743 err({line: 1u, col: 3u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32744 assert from_str("1e") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51745 err({line: 1u, col: 3u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32746 assert from_str("1e+") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51747 err({line: 1u, col: 4u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32748
749 assert from_str("3") == ok(num(3f));
750 assert from_str("3.1") == ok(num(3.1f));
751 assert from_str("-1.2") == ok(num(-1.2f));
752 assert from_str("0.4") == ok(num(0.4f));
753 assert from_str("0.4e5") == ok(num(0.4e5f));
754 assert from_str("0.4e+15") == ok(num(0.4e15f));
755 assert from_str("0.4e-01") == ok(num(0.4e-01f));
Tycho Sciecf87c32012-02-29 08:47:17756 assert from_str(" 3 ") == ok(num(3f));
Erick Tryzelaar012dec52012-02-26 00:39:32757 }
758
759 #[test]
760 fn test_read_str() {
761 assert from_str("\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51762 err({line: 1u, col: 2u, msg: @"EOF while parsing string"});
Erick Tryzelaar012dec52012-02-26 00:39:32763 assert from_str("\"lol") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51764 err({line: 1u, col: 5u, msg: @"EOF while parsing string"});
Erick Tryzelaar012dec52012-02-26 00:39:32765
Erick Tryzelaarb361f6c2012-06-13 00:20:51766 assert from_str("\"\"") == ok(string(@""));
767 assert from_str("\"foo\"") == ok(string(@"foo"));
768 assert from_str("\"\\\"\"") == ok(string(@"\""));
769 assert from_str("\"\\b\"") == ok(string(@"\x08"));
770 assert from_str("\"\\n\"") == ok(string(@"\n"));
771 assert from_str("\"\\r\"") == ok(string(@"\r"));
772 assert from_str("\"\\t\"") == ok(string(@"\t"));
773 assert from_str(" \"foo\" ") == ok(string(@"foo"));
Erick Tryzelaar012dec52012-02-26 00:39:32774 }
775
776 #[test]
777 fn test_read_list() {
778 assert from_str("[") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51779 err({line: 1u, col: 2u, msg: @"EOF while parsing value"});
Erick Tryzelaar012dec52012-02-26 00:39:32780 assert from_str("[1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51781 err({line: 1u, col: 3u, msg: @"EOF while parsing list"});
Erick Tryzelaar012dec52012-02-26 00:39:32782 assert from_str("[1,") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51783 err({line: 1u, col: 4u, msg: @"EOF while parsing value"});
Erick Tryzelaar012dec52012-02-26 00:39:32784 assert from_str("[1,]") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51785 err({line: 1u, col: 4u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32786 assert from_str("[6 7]") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51787 err({line: 1u, col: 4u, msg: @"expecting ',' or ']'"});
Erick Tryzelaar012dec52012-02-26 00:39:32788
Erick Tryzelaarb361f6c2012-06-13 00:20:51789 assert from_str("[]") == ok(list(@[]));
790 assert from_str("[ ]") == ok(list(@[]));
791 assert from_str("[true]") == ok(list(@[boolean(true)]));
792 assert from_str("[ false ]") == ok(list(@[boolean(false)]));
793 assert from_str("[null]") == ok(list(@[null]));
794 assert from_str("[3, 1]") == ok(list(@[num(3f), num(1f)]));
795 assert from_str("\n[3, 2]\n") == ok(list(@[num(3f), num(2f)]));
Erick Tryzelaar012dec52012-02-26 00:39:32796 assert from_str("[2, [4, 1]]") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51797 ok(list(@[num(2f), list(@[num(4f), num(1f)])]));
Erick Tryzelaar012dec52012-02-26 00:39:32798 }
799
800 #[test]
801 fn test_read_dict() {
802 assert from_str("{") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51803 err({line: 1u, col: 2u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32804 assert from_str("{ ") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51805 err({line: 1u, col: 3u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32806 assert from_str("{1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51807 err({line: 1u, col: 2u, msg: @"key must be a string"});
Erick Tryzelaar012dec52012-02-26 00:39:32808 assert from_str("{ \"a\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51809 err({line: 1u, col: 6u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32810 assert from_str("{\"a\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51811 err({line: 1u, col: 5u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32812 assert from_str("{\"a\" ") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51813 err({line: 1u, col: 6u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32814
815 assert from_str("{\"a\" 1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51816 err({line: 1u, col: 6u, msg: @"expecting ':'"});
Erick Tryzelaar012dec52012-02-26 00:39:32817 assert from_str("{\"a\":") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51818 err({line: 1u, col: 6u, msg: @"EOF while parsing value"});
Erick Tryzelaar012dec52012-02-26 00:39:32819 assert from_str("{\"a\":1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51820 err({line: 1u, col: 7u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32821 assert from_str("{\"a\":1 1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51822 err({line: 1u, col: 8u, msg: @"expecting ',' or '}'"});
Erick Tryzelaar012dec52012-02-26 00:39:32823 assert from_str("{\"a\":1,") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51824 err({line: 1u, col: 8u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32825
826 assert eq(result::get(from_str("{}")), mk_dict([]));
827 assert eq(result::get(from_str("{\"a\": 3}")),
828 mk_dict([("a", num(3.0f))]));
829
830 assert eq(result::get(from_str("{ \"a\": null, \"b\" : true }")),
Erick Tryzelaarb361f6c2012-06-13 00:20:51831 mk_dict([
832 ("a", null),
833 ("b", boolean(true))]));
Tycho Sci0465d522012-02-29 07:14:43834 assert eq(result::get(from_str("\n{ \"a\": null, \"b\" : true }\n")),
Erick Tryzelaarb361f6c2012-06-13 00:20:51835 mk_dict([
836 ("a", null),
837 ("b", boolean(true))]));
Erick Tryzelaar012dec52012-02-26 00:39:32838 assert eq(result::get(from_str("{\"a\" : 1.0 ,\"b\": [ true ]}")),
839 mk_dict([
840 ("a", num(1.0)),
Erick Tryzelaarb361f6c2012-06-13 00:20:51841 ("b", list(@[boolean(true)]))
Erick Tryzelaar012dec52012-02-26 00:39:32842 ]));
843 assert eq(result::get(from_str(
844 "{" +
845 "\"a\": 1.0, " +
846 "\"b\": [" +
847 "true," +
848 "\"foo\\nbar\", " +
849 "{ \"c\": {\"d\": null} } " +
850 "]" +
851 "}")),
852 mk_dict([
853 ("a", num(1.0f)),
Erick Tryzelaarb361f6c2012-06-13 00:20:51854 ("b", list(@[
Erick Tryzelaar012dec52012-02-26 00:39:32855 boolean(true),
Erick Tryzelaarb361f6c2012-06-13 00:20:51856 string(@"foo\nbar"),
Erick Tryzelaar012dec52012-02-26 00:39:32857 mk_dict([
858 ("c", mk_dict([("d", null)]))
859 ])
860 ]))
861 ]));
862 }
863
864 #[test]
865 fn test_multiline_errors() {
866 assert from_str("{\n \"foo\":\n \"bar\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51867 err({line: 3u, col: 8u, msg: @"EOF while parsing object"});
Brian Anderson6e27b272012-01-18 03:05:07868 }
869}