blob: d2bbc7dc5e736426dc1daadac122b58a4e106334 [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
Erick Tryzelaar012dec52012-02-26 00:39:324import result::{ok, err};
5import io;
6import io::{reader_util, writer_util};
Elly Jonesbd726262011-11-07 19:01:287import map;
Elly Jonesbd726262011-11-07 19:01:288
9export json;
Erick Tryzelaar012dec52012-02-26 00:39:3210export to_writer;
Elly Jones656a2af2011-11-07 23:24:4411export to_str;
Erick Tryzelaar012dec52012-02-26 00:39:3212export from_reader;
Elly Jones656a2af2011-11-07 23:24:4413export from_str;
Erick Tryzelaar012dec52012-02-26 00:39:3214export eq;
Elly Jonesbd726262011-11-07 19:01:2815
Elly Jones656a2af2011-11-07 23:24:4416export num;
17export string;
18export boolean;
19export list;
20export dict;
Erick Tryzelaar012dec52012-02-26 00:39:3221export null;
Elly Jones656a2af2011-11-07 23:24:4422
23/*
24Tag: json
25
26Represents a json value.
27*/
Patrick Waltonc5a407b2012-01-19 23:20:5728enum json {
Elly Jones656a2af2011-11-07 23:24:4429 /* Variant: num */
Patrick Walton194d8e32012-01-20 01:55:3430 num(float),
Elly Jones656a2af2011-11-07 23:24:4431 /* Variant: string */
Patrick Walton194d8e32012-01-20 01:55:3432 string(str),
Elly Jones656a2af2011-11-07 23:24:4433 /* Variant: boolean */
Patrick Walton194d8e32012-01-20 01:55:3434 boolean(bool),
Elly Jones656a2af2011-11-07 23:24:4435 /* Variant: list */
Erick Tryzelaar012dec52012-02-26 00:39:3236 list([json]),
Elly Jones656a2af2011-11-07 23:24:4437 /* Variant: dict */
Patrick Walton194d8e32012-01-20 01:55:3438 dict(map::map<str,json>),
Lenny2226f5a0a32011-12-21 20:36:4339 /* Variant: null */
Patrick Walton194d8e32012-01-20 01:55:3440 null,
Elly Jonesbd726262011-11-07 19:01:2841}
42
Erick Tryzelaar012dec52012-02-26 00:39:3243type error = {
44 line: uint,
45 col: uint,
46 msg: str,
47};
48
49/*
50Function: to_writer
51
52Serializes a json value into a io::writer.
53*/
54fn to_writer(wr: io::writer, j: json) {
55 alt j {
56 num(n) { wr.write_str(float::to_str(n, 6u)); }
57 string(s) {
58 wr.write_char('"');
59 let escaped = "";
60 str::chars_iter(s) { |c|
61 alt c {
62 '"' { escaped += "\\\""; }
63 '\\' { escaped += "\\\\"; }
64 '\x08' { escaped += "\\b"; }
65 '\x0c' { escaped += "\\f"; }
66 '\n' { escaped += "\\n"; }
67 '\r' { escaped += "\\r"; }
68 '\t' { escaped += "\\t"; }
69 _ { escaped += str::from_char(c); }
70 }
71 };
72 wr.write_str(escaped);
73 wr.write_char('"');
74 }
75 boolean(b) {
76 wr.write_str(if b { "true" } else { "false" });
77 }
78 list(v) {
79 wr.write_char('[');
80 let first = true;
81 vec::iter(v) { |item|
82 if !first {
83 wr.write_str(", ");
84 }
85 first = false;
86 to_writer(wr, item);
87 };
88 wr.write_char(']');
89 }
90 dict(d) {
91 if d.size() == 0u {
92 wr.write_str("{}");
93 ret;
94 }
95
96 wr.write_str("{ ");
97 let first = true;
98 d.items { |key, value|
99 if !first {
100 wr.write_str(", ");
101 }
102 first = false;
103 to_writer(wr, string(key));
104 wr.write_str(": ");
105 to_writer(wr, value);
106 };
107 wr.write_str(" }");
108 }
109 null {
110 wr.write_str("null");
111 }
112 }
113}
114
Elly Jones656a2af2011-11-07 23:24:44115/*
116Function: to_str
117
118Serializes a json value into a string.
119*/
120fn to_str(j: json) -> str {
Erick Tryzelaar012dec52012-02-26 00:39:32121 io::with_str_writer { |wr| to_writer(wr, j) }
Elly Jonesbd726262011-11-07 19:01:28122}
123
Erick Tryzelaar012dec52012-02-26 00:39:32124type parser = {
125 rdr: io::reader,
126 mutable ch: char,
127 mutable line: uint,
128 mutable col: uint,
129};
Elly Jonesbd726262011-11-07 19:01:28130
Erick Tryzelaar012dec52012-02-26 00:39:32131impl parser for parser {
132 fn eof() -> bool { self.ch == -1 as char }
Elly Jonesbd726262011-11-07 19:01:28133
Erick Tryzelaar012dec52012-02-26 00:39:32134 fn bump() {
135 self.ch = self.rdr.read_char();
136
137 if self.ch == '\n' {
138 self.line += 1u;
139 self.col = 1u;
140 } else {
141 self.col += 1u;
142 }
Elly Jonesbd726262011-11-07 19:01:28143 }
144
Erick Tryzelaar012dec52012-02-26 00:39:32145 fn next_char() -> char {
146 self.bump();
147 self.ch
Elly Jonesbd726262011-11-07 19:01:28148 }
149
Erick Tryzelaar012dec52012-02-26 00:39:32150 fn error<T>(msg: str) -> result::t<T, error> {
151 err({ line: self.line, col: self.col, msg: msg })
Elly Jonesbd726262011-11-07 19:01:28152 }
Elly Jonesbd726262011-11-07 19:01:28153
Erick Tryzelaar012dec52012-02-26 00:39:32154 fn parse() -> result::t<json, error> {
155 alt self.parse_value() {
156 ok(value) {
157 // Make sure there is no trailing characters.
158 if self.eof() {
159 ok(value)
160 } else {
161 self.error("trailing characters")
162 }
163 }
164 e { e }
Elly Jonesbd726262011-11-07 19:01:28165 }
Elly Jonesbd726262011-11-07 19:01:28166 }
Elly Jonesbd726262011-11-07 19:01:28167
Erick Tryzelaar012dec52012-02-26 00:39:32168 fn parse_value() -> result::t<json, error> {
169 self.parse_whitespace();
Elly Jonesbd726262011-11-07 19:01:28170
Erick Tryzelaar012dec52012-02-26 00:39:32171 if self.eof() { ret self.error("EOF while parsing value"); }
172
173 alt self.ch {
174 'n' { self.parse_ident("ull", null) }
175 't' { self.parse_ident("rue", boolean(true)) }
176 'f' { self.parse_ident("alse", boolean(false)) }
177 '0' to '9' | '-' { self.parse_number() }
178 '"' {
179 alt self.parse_str() {
180 ok(s) { ok(string(s)) }
181 err(e) { err(e) }
182 }
183 }
184 '[' { self.parse_list() }
185 '{' { self.parse_object() }
186 _ { self.error("invalid syntax") }
187 }
188 }
189
190 fn parse_whitespace() {
191 while char::is_whitespace(self.ch) { self.bump(); }
192 }
193
194 fn parse_ident(ident: str, value: json) -> result::t<json, error> {
195 if str::all(ident, { |c| c == self.next_char() }) {
196 self.bump();
197 ok(value)
198 } else {
199 self.error("invalid syntax")
200 }
201 }
202
203 fn parse_number() -> result::t<json, error> {
204 let neg = 1f;
205
206 if self.ch == '-' {
207 self.bump();
Marijn Haverbeke4f826d82011-12-16 09:11:00208 neg = -1f;
Elly Jonesbd726262011-11-07 19:01:28209 }
Elly Jonesbd726262011-11-07 19:01:28210
Erick Tryzelaar012dec52012-02-26 00:39:32211 let res = alt self.parse_integer() {
212 ok(res) { res }
213 err(e) { ret err(e); }
214 };
215
216 if self.ch == '.' {
217 alt self.parse_decimal(res) {
218 ok(r) { res = r; }
219 err(e) { ret err(e); }
Elly Jonesbd726262011-11-07 19:01:28220 }
Elly Jonesbd726262011-11-07 19:01:28221 }
Erick Tryzelaar012dec52012-02-26 00:39:32222
223 if self.ch == 'e' || self.ch == 'E' {
224 alt self.parse_exponent(res) {
225 ok(r) { res = r; }
226 err(e) { ret err(e); }
227 }
228 }
229
230 ok(num(neg * res))
Elly Jonesbd726262011-11-07 19:01:28231 }
232
Erick Tryzelaar012dec52012-02-26 00:39:32233 fn parse_integer() -> result::t<float, error> {
234 let res = 0f;
235
236 alt self.ch {
237 '0' {
238 self.bump();
239
240 // There can be only one leading '0'.
241 alt self.ch {
242 '0' to '9' { ret self.error("invalid number"); }
243 _ {}
244 }
245 }
246 '1' to '9' {
247 while !self.eof() {
248 alt self.ch {
249 '0' to '9' {
250 res *= 10f;
251 res += ((self.ch as int) - ('0' as int)) as float;
252
253 self.bump();
254 }
255 _ { break; }
256 }
257 }
258 }
259 _ { ret self.error("invalid number"); }
260 }
261
262 ok(res)
Elly Jonesbd726262011-11-07 19:01:28263 }
264
Erick Tryzelaar012dec52012-02-26 00:39:32265 fn parse_decimal(res: float) -> result::t<float, error> {
266 self.bump();
267
268 // Make sure a digit follows the decimal place.
269 alt self.ch {
270 '0' to '9' {}
271 _ { ret self.error("invalid number"); }
272 }
273
274 let res = res;
275 let dec = 1f;
276 while !self.eof() {
277 alt self.ch {
278 '0' to '9' {
Marijn Haverbeke4f826d82011-12-16 09:11:00279 dec /= 10f;
Erick Tryzelaar012dec52012-02-26 00:39:32280 res += (((self.ch as int) - ('0' as int)) as float) * dec;
281
282 self.bump();
283 }
284 _ { break; }
Elly Jonesbd726262011-11-07 19:01:28285 }
Elly Jonesbd726262011-11-07 19:01:28286 }
Elly Jonesbd726262011-11-07 19:01:28287
Erick Tryzelaar012dec52012-02-26 00:39:32288 ok(res)
289 }
290
291 fn parse_exponent(res: float) -> result::t<float, error> {
292 self.bump();
293
294 let res = res;
295 let exp = 0u;
296 let neg_exp = false;
297
298 alt self.ch {
299 '+' { self.bump(); }
300 '-' { self.bump(); neg_exp = true; }
301 _ {}
302 }
303
304 // Make sure a digit follows the exponent place.
305 alt self.ch {
306 '0' to '9' {}
307 _ { ret self.error("invalid number"); }
308 }
309
310 while !self.eof() {
311 alt self.ch {
312 '0' to '9' {
313 exp *= 10u;
314 exp += (self.ch as uint) - ('0' as uint);
315
316 self.bump();
317 }
318 _ { break; }
319 }
320 }
321
322 let exp = float::pow_with_uint(10u, exp);
323 if neg_exp {
324 res /= exp;
325 } else {
326 res *= exp;
327 }
328
329 ok(res)
330 }
331
332 fn parse_str() -> result::t<str, error> {
333 let escape = false;
334 let res = "";
335
336 while !self.eof() {
337 self.bump();
338
339 if (escape) {
340 alt self.ch {
341 '"' { str::push_char(res, '"'); }
342 '\\' { str::push_char(res, '\\'); }
343 '/' { str::push_char(res, '/'); }
344 'b' { str::push_char(res, '\x08'); }
345 'f' { str::push_char(res, '\x0c'); }
346 'n' { str::push_char(res, '\n'); }
347 'r' { str::push_char(res, '\r'); }
348 't' { str::push_char(res, '\t'); }
349 'u' {
350 // Parse \u1234.
351 let i = 0u;
352 let n = 0u;
353 while i < 4u {
354 alt self.next_char() {
355 '0' to '9' {
356 n = n * 10u +
357 (self.ch as uint) - ('0' as uint);
358 }
359 _ { ret self.error("invalid \\u escape"); }
360 }
361 }
362
363 // Error out if we didn't parse 4 digits.
364 if i != 4u {
365 ret self.error("invalid \\u escape");
366 }
367
368 str::push_char(res, n as char);
369 }
370 _ { ret self.error("invalid escape"); }
371 }
372 escape = false;
373 } else if self.ch == '\\' {
374 escape = true;
375 } else {
376 if self.ch == '"' {
377 self.bump();
378 ret ok(res);
379 }
380 str::push_char(res, self.ch);
381 }
382 }
383
384 self.error("EOF while parsing string")
385 }
386
387 fn parse_list() -> result::t<json, error> {
388 self.bump();
389 self.parse_whitespace();
390
391 let values = [];
392
393 if self.ch == ']' {
394 self.bump();
395 ret ok(list(values));
396 }
397
398 while true {
399 alt self.parse_value() {
400 ok(v) { vec::push(values, v); }
401 e { ret e; }
402 }
403
404 self.parse_whitespace();
405 if self.eof() { break; }
406
407 alt self.ch {
408 ',' { self.bump(); }
409 ']' { self.bump(); ret ok(list(values)); }
410 _ { ret self.error("expecting ',' or ']'"); }
411 }
412 }
413
414 ret self.error("EOF while parsing list");
415 }
416
417 fn parse_object() -> result::t<json, error> {
418 self.bump();
419 self.parse_whitespace();
420
421 let values = map::new_str_hash();
422
423 if self.ch == '}' {
424 self.bump();
425 ret ok(dict(values));
426 }
427
428 while !self.eof() {
429 self.parse_whitespace();
430
431 if self.ch != '"' {
432 ret self.error("key must be a string");
433 }
434
435 let key = alt self.parse_str() {
436 ok(key) { key }
437 err(e) { ret err(e); }
438 };
439
440 self.parse_whitespace();
441
442 if self.ch != ':' {
443 if self.eof() { break; }
444 ret self.error("expecting ':'");
445 }
446 self.bump();
447
448 alt self.parse_value() {
449 ok(value) { values.insert(key, value); }
450 e { ret e; }
451 }
452 self.parse_whitespace();
453
454 alt self.ch {
455 ',' { self.bump(); }
456 '}' { self.bump(); ret ok(dict(values)); }
457 _ {
458 if self.eof() { break; }
459 ret self.error("expecting ',' or '}'");
460 }
461 }
462 }
463
464 ret self.error("EOF while parsing object");
Elly Jonesbd726262011-11-07 19:01:28465 }
466}
467
Erick Tryzelaar012dec52012-02-26 00:39:32468/*
469Function: from_reader
Lenny2226f5a0a32011-12-21 20:36:43470
Erick Tryzelaar012dec52012-02-26 00:39:32471Deserializes a json value from an io::reader.
472*/
473
474fn from_reader(rdr: io::reader) -> result::t<json, error> {
475 let parser = {
476 rdr: rdr,
477 mutable ch: rdr.read_char(),
478 mutable line: 1u,
479 mutable col: 1u,
480 };
481
482 parser.parse()
Elly Jonesbd726262011-11-07 19:01:28483}
484
Elly Jones656a2af2011-11-07 23:24:44485/*
486Function: from_str
487
488Deserializes a json value from a string.
489*/
Erick Tryzelaar012dec52012-02-26 00:39:32490fn from_str(s: str) -> result::t<json, error> {
491 from_reader(io::string_reader(s))
492}
493
494/*
495Function: eq
496
497Test if two json values are equal.
498*/
499fn eq(value0: json, value1: json) -> bool {
500 alt (value0, value1) {
501 (num(f0), num(f1)) { f0 == f1 }
502 (string(s0), string(s1)) { s0 == s1 }
503 (boolean(b0), boolean(b1)) { b0 == b1 }
504 (list(l0), list(l1)) { vec::all2(l0, l1, eq) }
505 (dict(d0), dict(d1)) {
506 if d0.size() == d1.size() {
507 let equal = true;
508 d0.items { |k, v0|
509 alt d1.find(k) {
510 some(v1) {
511 if !eq(v0, v1) { equal = false; } }
512 none { equal = false; }
513 }
514 };
515 equal
516 } else {
517 false
518 }
519 }
520 (null, null) { true }
521 _ { false }
522 }
Elly Jonesbd726262011-11-07 19:01:28523}
Brian Anderson6e27b272012-01-18 03:05:07524
525#[cfg(test)]
526mod tests {
Erick Tryzelaar012dec52012-02-26 00:39:32527 fn mk_dict(items: [(str, json)]) -> json {
528 let d = map::new_str_hash();
529
530 vec::iter(items) { |item|
531 let (key, value) = item;
532 d.insert(key, value);
533 };
534
535 dict(d)
Brian Anderson6e27b272012-01-18 03:05:07536 }
537
538 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32539 fn test_write_null() {
540 assert to_str(null) == "null";
Brian Anderson6e27b272012-01-18 03:05:07541 }
542
543 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32544 fn test_write_num() {
545 assert to_str(num(3f)) == "3";
546 assert to_str(num(3.1f)) == "3.1";
547 assert to_str(num(-1.5f)) == "-1.5";
548 assert to_str(num(0.5f)) == "0.5";
Brian Anderson6e27b272012-01-18 03:05:07549 }
550
551 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32552 fn test_write_str() {
553 assert to_str(string("")) == "\"\"";
554 assert to_str(string("foo")) == "\"foo\"";
Brian Anderson6e27b272012-01-18 03:05:07555 }
556
557 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32558 fn test_write_bool() {
559 assert to_str(boolean(true)) == "true";
560 assert to_str(boolean(false)) == "false";
Brian Anderson6e27b272012-01-18 03:05:07561 }
562
563 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32564 fn test_write_list() {
565 assert to_str(list([])) == "[]";
566 assert to_str(list([boolean(true)])) == "[true]";
567 assert to_str(list([
568 boolean(false),
569 null,
570 list([string("foo\nbar"), num(3.5f)])
571 ])) == "[false, null, [\"foo\\nbar\", 3.5]]";
572 }
573
574 #[test]
575 fn test_write_dict() {
576 assert to_str(mk_dict([])) == "{}";
577 assert to_str(mk_dict([("a", boolean(true))])) == "{ \"a\": true }";
578 assert to_str(mk_dict([
579 ("a", boolean(true)),
580 ("b", list([
581 mk_dict([("c", string("\x0c\r"))]),
582 mk_dict([("d", string(""))])
583 ]))
584 ])) ==
585 "{ " +
586 "\"a\": true, " +
587 "\"b\": [" +
588 "{ \"c\": \"\\f\\r\" }, " +
589 "{ \"d\": \"\" }" +
590 "]" +
591 " }";
592 }
593
594 #[test]
595 fn test_trailing_characters() {
596 assert from_str("nulla") ==
597 err({line: 1u, col: 5u, msg: "trailing characters"});
598 assert from_str("truea") ==
599 err({line: 1u, col: 5u, msg: "trailing characters"});
600 assert from_str("falsea") ==
601 err({line: 1u, col: 6u, msg: "trailing characters"});
602 assert from_str("1a") ==
603 err({line: 1u, col: 2u, msg: "trailing characters"});
604 assert from_str("[]a") ==
605 err({line: 1u, col: 3u, msg: "trailing characters"});
606 assert from_str("{}a") ==
607 err({line: 1u, col: 3u, msg: "trailing characters"});
608 }
609
610 #[test]
611 fn test_read_identifiers() {
612 assert from_str("n") ==
613 err({line: 1u, col: 2u, msg: "invalid syntax"});
614 assert from_str("nul") ==
615 err({line: 1u, col: 4u, msg: "invalid syntax"});
616
617 assert from_str("t") ==
618 err({line: 1u, col: 2u, msg: "invalid syntax"});
619 assert from_str("truz") ==
620 err({line: 1u, col: 4u, msg: "invalid syntax"});
621
622 assert from_str("f") ==
623 err({line: 1u, col: 2u, msg: "invalid syntax"});
624 assert from_str("faz") ==
625 err({line: 1u, col: 3u, msg: "invalid syntax"});
626
627 assert from_str("null") == ok(null);
628 assert from_str("true") == ok(boolean(true));
629 assert from_str("false") == ok(boolean(false));
630 }
631
632 #[test]
633 fn test_read_num() {
634 assert from_str("+") ==
635 err({line: 1u, col: 1u, msg: "invalid syntax"});
636 assert from_str(".") ==
637 err({line: 1u, col: 1u, msg: "invalid syntax"});
638
639 assert from_str("-") ==
640 err({line: 1u, col: 2u, msg: "invalid number"});
641 assert from_str("00") ==
642 err({line: 1u, col: 2u, msg: "invalid number"});
643 assert from_str("1.") ==
644 err({line: 1u, col: 3u, msg: "invalid number"});
645 assert from_str("1e") ==
646 err({line: 1u, col: 3u, msg: "invalid number"});
647 assert from_str("1e+") ==
648 err({line: 1u, col: 4u, msg: "invalid number"});
649
650 assert from_str("3") == ok(num(3f));
651 assert from_str("3.1") == ok(num(3.1f));
652 assert from_str("-1.2") == ok(num(-1.2f));
653 assert from_str("0.4") == ok(num(0.4f));
654 assert from_str("0.4e5") == ok(num(0.4e5f));
655 assert from_str("0.4e+15") == ok(num(0.4e15f));
656 assert from_str("0.4e-01") == ok(num(0.4e-01f));
657 }
658
659 #[test]
660 fn test_read_str() {
661 assert from_str("\"") ==
662 err({line: 1u, col: 2u, msg: "EOF while parsing string"});
663 assert from_str("\"lol") ==
664 err({line: 1u, col: 5u, msg: "EOF while parsing string"});
665
666 assert from_str("\"\"") == ok(string(""));
667 assert from_str("\"foo\"") == ok(string("foo"));
668 assert from_str("\"\\\"\"") == ok(string("\""));
669 assert from_str("\"\\b\"") == ok(string("\x08"));
670 assert from_str("\"\\n\"") == ok(string("\n"));
671 assert from_str("\"\\r\"") == ok(string("\r"));
672 assert from_str("\"\\t\"") == ok(string("\t"));
673 }
674
675 #[test]
676 fn test_read_list() {
677 assert from_str("[") ==
678 err({line: 1u, col: 2u, msg: "EOF while parsing value"});
679 assert from_str("[1") ==
680 err({line: 1u, col: 3u, msg: "EOF while parsing list"});
681 assert from_str("[1,") ==
682 err({line: 1u, col: 4u, msg: "EOF while parsing value"});
683 assert from_str("[1,]") ==
684 err({line: 1u, col: 4u, msg: "invalid syntax"});
685 assert from_str("[6 7]") ==
686 err({line: 1u, col: 4u, msg: "expecting ',' or ']'"});
687
688 assert from_str("[]") == ok(list([]));
689 assert from_str("[ ]") == ok(list([]));
690 assert from_str("[true]") == ok(list([boolean(true)]));
691 assert from_str("[ false ]") == ok(list([boolean(false)]));
692 assert from_str("[null]") == ok(list([null]));
693 assert from_str("[3, 1]") == ok(list([num(3f), num(1f)]));
694 assert from_str("[2, [4, 1]]") ==
695 ok(list([num(2f), list([num(4f), num(1f)])]));
696 }
697
698 #[test]
699 fn test_read_dict() {
700 assert from_str("{") ==
701 err({line: 1u, col: 2u, msg: "EOF while parsing object"});
702 assert from_str("{ ") ==
703 err({line: 1u, col: 3u, msg: "EOF while parsing object"});
704 assert from_str("{1") ==
705 err({line: 1u, col: 2u, msg: "key must be a string"});
706 assert from_str("{ \"a\"") ==
707 err({line: 1u, col: 6u, msg: "EOF while parsing object"});
708 assert from_str("{\"a\"") ==
709 err({line: 1u, col: 5u, msg: "EOF while parsing object"});
710 assert from_str("{\"a\" ") ==
711 err({line: 1u, col: 6u, msg: "EOF while parsing object"});
712
713 assert from_str("{\"a\" 1") ==
714 err({line: 1u, col: 6u, msg: "expecting ':'"});
715 assert from_str("{\"a\":") ==
716 err({line: 1u, col: 6u, msg: "EOF while parsing value"});
717 assert from_str("{\"a\":1") ==
718 err({line: 1u, col: 7u, msg: "EOF while parsing object"});
719 assert from_str("{\"a\":1 1") ==
720 err({line: 1u, col: 8u, msg: "expecting ',' or '}'"});
721 assert from_str("{\"a\":1,") ==
722 err({line: 1u, col: 8u, msg: "EOF while parsing object"});
723
724 assert eq(result::get(from_str("{}")), mk_dict([]));
725 assert eq(result::get(from_str("{\"a\": 3}")),
726 mk_dict([("a", num(3.0f))]));
727
728 assert eq(result::get(from_str("{ \"a\": null, \"b\" : true }")),
729 mk_dict([("a", null), ("b", boolean(true))]));
730 assert eq(result::get(from_str("{\"a\" : 1.0 ,\"b\": [ true ]}")),
731 mk_dict([
732 ("a", num(1.0)),
733 ("b", list([boolean(true)]))
734 ]));
735 assert eq(result::get(from_str(
736 "{" +
737 "\"a\": 1.0, " +
738 "\"b\": [" +
739 "true," +
740 "\"foo\\nbar\", " +
741 "{ \"c\": {\"d\": null} } " +
742 "]" +
743 "}")),
744 mk_dict([
745 ("a", num(1.0f)),
746 ("b", list([
747 boolean(true),
748 string("foo\nbar"),
749 mk_dict([
750 ("c", mk_dict([("d", null)]))
751 ])
752 ]))
753 ]));
754 }
755
756 #[test]
757 fn test_multiline_errors() {
758 assert from_str("{\n \"foo\":\n \"bar\"") ==
759 err({line: 3u, col: 8u, msg: "EOF while parsing object"});
Brian Anderson6e27b272012-01-18 03:05:07760 }
761}