blob: 5d9427c72b8603be0aa70f571a64e3f4b44a1718 [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),
Patrick Walton194d8e32012-01-20 01:55:3431 string(str),
Patrick Walton194d8e32012-01-20 01:55:3432 boolean(bool),
Erick Tryzelaar012dec52012-02-26 00:39:3233 list([json]),
Patrick Waltonc9375fe2012-03-08 00:48:5734 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,
41 msg: str,
42};
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) {
49 wr.write_char('"');
Niko Matsakis6b358752012-03-14 18:03:5650 let mut escaped = "";
Erick Tryzelaar012dec52012-02-26 00:39:3251 str::chars_iter(s) { |c|
52 alt c {
53 '"' { escaped += "\\\""; }
54 '\\' { escaped += "\\\\"; }
55 '\x08' { escaped += "\\b"; }
56 '\x0c' { escaped += "\\f"; }
57 '\n' { escaped += "\\n"; }
58 '\r' { escaped += "\\r"; }
59 '\t' { escaped += "\\t"; }
60 _ { escaped += str::from_char(c); }
61 }
62 };
63 wr.write_str(escaped);
64 wr.write_char('"');
65 }
66 boolean(b) {
67 wr.write_str(if b { "true" } else { "false" });
68 }
69 list(v) {
70 wr.write_char('[');
Niko Matsakis6b358752012-03-14 18:03:5671 let mut first = true;
Erick Tryzelaar012dec52012-02-26 00:39:3272 vec::iter(v) { |item|
73 if !first {
74 wr.write_str(", ");
75 }
76 first = false;
77 to_writer(wr, item);
78 };
79 wr.write_char(']');
80 }
81 dict(d) {
82 if d.size() == 0u {
83 wr.write_str("{}");
84 ret;
85 }
86
87 wr.write_str("{ ");
Niko Matsakis6b358752012-03-14 18:03:5688 let mut first = true;
Marijn Haverbeke9053f542012-04-23 11:42:1589 for d.each { |key, value|
Erick Tryzelaar012dec52012-02-26 00:39:3290 if !first {
91 wr.write_str(", ");
92 }
93 first = false;
94 to_writer(wr, string(key));
95 wr.write_str(": ");
96 to_writer(wr, value);
97 };
98 wr.write_str(" }");
99 }
100 null {
101 wr.write_str("null");
102 }
103 }
104}
105
Brian Anderson95521c42012-03-08 02:17:30106#[doc = "Serializes a json value into a string"]
Elly Jones656a2af2011-11-07 23:24:44107fn to_str(j: json) -> str {
Erick Tryzelaar012dec52012-02-26 00:39:32108 io::with_str_writer { |wr| to_writer(wr, j) }
Elly Jonesbd726262011-11-07 19:01:28109}
110
Erick Tryzelaar012dec52012-02-26 00:39:32111type parser = {
112 rdr: io::reader,
Graydon Hoare6e6798c2012-03-27 01:35:18113 mut ch: char,
114 mut line: uint,
115 mut col: uint,
Erick Tryzelaar012dec52012-02-26 00:39:32116};
Elly Jonesbd726262011-11-07 19:01:28117
Erick Tryzelaar012dec52012-02-26 00:39:32118impl parser for parser {
119 fn eof() -> bool { self.ch == -1 as char }
Elly Jonesbd726262011-11-07 19:01:28120
Erick Tryzelaar012dec52012-02-26 00:39:32121 fn bump() {
122 self.ch = self.rdr.read_char();
123
124 if self.ch == '\n' {
125 self.line += 1u;
126 self.col = 1u;
127 } else {
128 self.col += 1u;
129 }
Elly Jonesbd726262011-11-07 19:01:28130 }
131
Erick Tryzelaar012dec52012-02-26 00:39:32132 fn next_char() -> char {
133 self.bump();
134 self.ch
Elly Jonesbd726262011-11-07 19:01:28135 }
136
Brian Andersonb968c8e2012-03-13 21:39:28137 fn error<T>(msg: str) -> result<T, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32138 err({ line: self.line, col: self.col, msg: msg })
Elly Jonesbd726262011-11-07 19:01:28139 }
Elly Jonesbd726262011-11-07 19:01:28140
Brian Andersonb968c8e2012-03-13 21:39:28141 fn parse() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32142 alt self.parse_value() {
143 ok(value) {
Tycho Sciecf87c32012-02-29 08:47:17144 // Skip trailing whitespaces.
145 self.parse_whitespace();
Erick Tryzelaar012dec52012-02-26 00:39:32146 // Make sure there is no trailing characters.
147 if self.eof() {
148 ok(value)
149 } else {
150 self.error("trailing characters")
151 }
152 }
153 e { e }
Elly Jonesbd726262011-11-07 19:01:28154 }
Elly Jonesbd726262011-11-07 19:01:28155 }
Elly Jonesbd726262011-11-07 19:01:28156
Brian Andersonb968c8e2012-03-13 21:39:28157 fn parse_value() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32158 self.parse_whitespace();
Elly Jonesbd726262011-11-07 19:01:28159
Erick Tryzelaar012dec52012-02-26 00:39:32160 if self.eof() { ret self.error("EOF while parsing value"); }
161
162 alt self.ch {
163 'n' { self.parse_ident("ull", null) }
164 't' { self.parse_ident("rue", boolean(true)) }
165 'f' { self.parse_ident("alse", boolean(false)) }
166 '0' to '9' | '-' { self.parse_number() }
167 '"' {
168 alt self.parse_str() {
169 ok(s) { ok(string(s)) }
170 err(e) { err(e) }
171 }
172 }
173 '[' { self.parse_list() }
174 '{' { self.parse_object() }
175 _ { self.error("invalid syntax") }
176 }
177 }
178
179 fn parse_whitespace() {
180 while char::is_whitespace(self.ch) { self.bump(); }
181 }
182
Brian Andersonb968c8e2012-03-13 21:39:28183 fn parse_ident(ident: str, value: json) -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32184 if str::all(ident, { |c| c == self.next_char() }) {
185 self.bump();
186 ok(value)
187 } else {
188 self.error("invalid syntax")
189 }
190 }
191
Brian Andersonb968c8e2012-03-13 21:39:28192 fn parse_number() -> result<json, error> {
Niko Matsakis6b358752012-03-14 18:03:56193 let mut neg = 1f;
Erick Tryzelaar012dec52012-02-26 00:39:32194
195 if self.ch == '-' {
196 self.bump();
Marijn Haverbeke4f826d82011-12-16 09:11:00197 neg = -1f;
Elly Jonesbd726262011-11-07 19:01:28198 }
Elly Jonesbd726262011-11-07 19:01:28199
Niko Matsakis6b358752012-03-14 18:03:56200 let mut res = alt self.parse_integer() {
Erick Tryzelaar012dec52012-02-26 00:39:32201 ok(res) { res }
202 err(e) { ret err(e); }
203 };
204
205 if self.ch == '.' {
206 alt self.parse_decimal(res) {
207 ok(r) { res = r; }
208 err(e) { ret err(e); }
Elly Jonesbd726262011-11-07 19:01:28209 }
Elly Jonesbd726262011-11-07 19:01:28210 }
Erick Tryzelaar012dec52012-02-26 00:39:32211
212 if self.ch == 'e' || self.ch == 'E' {
213 alt self.parse_exponent(res) {
214 ok(r) { res = r; }
215 err(e) { ret err(e); }
216 }
217 }
218
219 ok(num(neg * res))
Elly Jonesbd726262011-11-07 19:01:28220 }
221
Brian Andersonb968c8e2012-03-13 21:39:28222 fn parse_integer() -> result<float, error> {
Niko Matsakis6b358752012-03-14 18:03:56223 let mut res = 0f;
Erick Tryzelaar012dec52012-02-26 00:39:32224
225 alt self.ch {
226 '0' {
227 self.bump();
228
229 // There can be only one leading '0'.
230 alt self.ch {
231 '0' to '9' { ret self.error("invalid number"); }
232 _ {}
233 }
234 }
235 '1' to '9' {
236 while !self.eof() {
237 alt self.ch {
238 '0' to '9' {
239 res *= 10f;
240 res += ((self.ch as int) - ('0' as int)) as float;
241
242 self.bump();
243 }
244 _ { break; }
245 }
246 }
247 }
248 _ { ret self.error("invalid number"); }
249 }
250
251 ok(res)
Elly Jonesbd726262011-11-07 19:01:28252 }
253
Brian Andersonb968c8e2012-03-13 21:39:28254 fn parse_decimal(res: float) -> result<float, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32255 self.bump();
256
257 // Make sure a digit follows the decimal place.
258 alt self.ch {
259 '0' to '9' {}
260 _ { ret self.error("invalid number"); }
261 }
262
Niko Matsakis6b358752012-03-14 18:03:56263 let mut res = res;
264 let mut dec = 1f;
Erick Tryzelaar012dec52012-02-26 00:39:32265 while !self.eof() {
266 alt self.ch {
267 '0' to '9' {
Marijn Haverbeke4f826d82011-12-16 09:11:00268 dec /= 10f;
Erick Tryzelaar012dec52012-02-26 00:39:32269 res += (((self.ch as int) - ('0' as int)) as float) * dec;
270
271 self.bump();
272 }
273 _ { break; }
Elly Jonesbd726262011-11-07 19:01:28274 }
Elly Jonesbd726262011-11-07 19:01:28275 }
Elly Jonesbd726262011-11-07 19:01:28276
Erick Tryzelaar012dec52012-02-26 00:39:32277 ok(res)
278 }
279
Brian Andersonb968c8e2012-03-13 21:39:28280 fn parse_exponent(res: float) -> result<float, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32281 self.bump();
282
Niko Matsakis6b358752012-03-14 18:03:56283 let mut res = res;
284 let mut exp = 0u;
285 let mut neg_exp = false;
Erick Tryzelaar012dec52012-02-26 00:39:32286
287 alt self.ch {
288 '+' { self.bump(); }
289 '-' { self.bump(); neg_exp = true; }
290 _ {}
291 }
292
293 // Make sure a digit follows the exponent place.
294 alt self.ch {
295 '0' to '9' {}
296 _ { ret self.error("invalid number"); }
297 }
298
299 while !self.eof() {
300 alt self.ch {
301 '0' to '9' {
302 exp *= 10u;
303 exp += (self.ch as uint) - ('0' as uint);
304
305 self.bump();
306 }
307 _ { break; }
308 }
309 }
310
311 let exp = float::pow_with_uint(10u, exp);
312 if neg_exp {
313 res /= exp;
314 } else {
315 res *= exp;
316 }
317
318 ok(res)
319 }
320
Brian Andersonb968c8e2012-03-13 21:39:28321 fn parse_str() -> result<str, error> {
Niko Matsakis6b358752012-03-14 18:03:56322 let mut escape = false;
323 let mut res = "";
Erick Tryzelaar012dec52012-02-26 00:39:32324
325 while !self.eof() {
326 self.bump();
327
328 if (escape) {
329 alt self.ch {
330 '"' { str::push_char(res, '"'); }
331 '\\' { str::push_char(res, '\\'); }
332 '/' { str::push_char(res, '/'); }
333 'b' { str::push_char(res, '\x08'); }
334 'f' { str::push_char(res, '\x0c'); }
335 'n' { str::push_char(res, '\n'); }
336 'r' { str::push_char(res, '\r'); }
337 't' { str::push_char(res, '\t'); }
338 'u' {
339 // Parse \u1234.
Niko Matsakis6b358752012-03-14 18:03:56340 let mut i = 0u;
341 let mut n = 0u;
Erick Tryzelaar012dec52012-02-26 00:39:32342 while i < 4u {
343 alt self.next_char() {
344 '0' to '9' {
345 n = n * 10u +
346 (self.ch as uint) - ('0' as uint);
347 }
348 _ { ret self.error("invalid \\u escape"); }
349 }
Niko Matsakis6b358752012-03-14 18:03:56350 i += 1u;
Erick Tryzelaar012dec52012-02-26 00:39:32351 }
352
353 // Error out if we didn't parse 4 digits.
354 if i != 4u {
355 ret self.error("invalid \\u escape");
356 }
357
358 str::push_char(res, n as char);
359 }
360 _ { ret self.error("invalid escape"); }
361 }
362 escape = false;
363 } else if self.ch == '\\' {
364 escape = true;
365 } else {
366 if self.ch == '"' {
367 self.bump();
368 ret ok(res);
369 }
370 str::push_char(res, self.ch);
371 }
372 }
373
374 self.error("EOF while parsing string")
375 }
376
Brian Andersonb968c8e2012-03-13 21:39:28377 fn parse_list() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32378 self.bump();
379 self.parse_whitespace();
380
Niko Matsakis6b358752012-03-14 18:03:56381 let mut values = [];
Erick Tryzelaar012dec52012-02-26 00:39:32382
383 if self.ch == ']' {
384 self.bump();
385 ret ok(list(values));
386 }
387
Tim Chevalier35400e12012-03-11 04:34:17388 loop {
Erick Tryzelaar012dec52012-02-26 00:39:32389 alt self.parse_value() {
390 ok(v) { vec::push(values, v); }
391 e { ret e; }
392 }
393
394 self.parse_whitespace();
Tim Chevalier35400e12012-03-11 04:34:17395 if self.eof() {
396 ret self.error("EOF while parsing list");
397 }
Erick Tryzelaar012dec52012-02-26 00:39:32398
399 alt self.ch {
400 ',' { self.bump(); }
Tycho Sciecf87c32012-02-29 08:47:17401 ']' { self.bump(); ret ok(list(values)); }
Erick Tryzelaar012dec52012-02-26 00:39:32402 _ { ret self.error("expecting ',' or ']'"); }
403 }
Tim Chevalier35400e12012-03-11 04:34:17404 };
Erick Tryzelaar012dec52012-02-26 00:39:32405 }
406
Brian Andersonb968c8e2012-03-13 21:39:28407 fn parse_object() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32408 self.bump();
409 self.parse_whitespace();
410
Brian Anderson3864d6d2012-03-14 19:07:23411 let values = map::str_hash();
Erick Tryzelaar012dec52012-02-26 00:39:32412
413 if self.ch == '}' {
414 self.bump();
415 ret ok(dict(values));
416 }
417
418 while !self.eof() {
419 self.parse_whitespace();
420
421 if self.ch != '"' {
422 ret self.error("key must be a string");
423 }
424
425 let key = alt self.parse_str() {
426 ok(key) { key }
427 err(e) { ret err(e); }
428 };
429
430 self.parse_whitespace();
431
432 if self.ch != ':' {
433 if self.eof() { break; }
434 ret self.error("expecting ':'");
435 }
436 self.bump();
437
438 alt self.parse_value() {
439 ok(value) { values.insert(key, value); }
440 e { ret e; }
441 }
442 self.parse_whitespace();
443
444 alt self.ch {
445 ',' { self.bump(); }
Tycho Sciecf87c32012-02-29 08:47:17446 '}' { self.bump(); ret ok(dict(values)); }
Erick Tryzelaar012dec52012-02-26 00:39:32447 _ {
448 if self.eof() { break; }
449 ret self.error("expecting ',' or '}'");
450 }
451 }
452 }
453
454 ret self.error("EOF while parsing object");
Elly Jonesbd726262011-11-07 19:01:28455 }
456}
457
Brian Anderson95521c42012-03-08 02:17:30458#[doc = "Deserializes a json value from an io::reader"]
Brian Andersonb968c8e2012-03-13 21:39:28459fn from_reader(rdr: io::reader) -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32460 let parser = {
461 rdr: rdr,
Graydon Hoare6e6798c2012-03-27 01:35:18462 mut ch: rdr.read_char(),
463 mut line: 1u,
464 mut col: 1u,
Erick Tryzelaar012dec52012-02-26 00:39:32465 };
466
467 parser.parse()
Elly Jonesbd726262011-11-07 19:01:28468}
469
Brian Anderson95521c42012-03-08 02:17:30470#[doc = "Deserializes a json value from a string"]
Brian Andersonb968c8e2012-03-13 21:39:28471fn from_str(s: str) -> result<json, error> {
Erick Tryzelaar1404a862012-02-29 18:48:57472 io::with_str_reader(s, from_reader)
Erick Tryzelaar012dec52012-02-26 00:39:32473}
474
Brian Anderson95521c42012-03-08 02:17:30475#[doc = "Test if two json values are equal"]
Erick Tryzelaar012dec52012-02-26 00:39:32476fn eq(value0: json, value1: json) -> bool {
477 alt (value0, value1) {
478 (num(f0), num(f1)) { f0 == f1 }
479 (string(s0), string(s1)) { s0 == s1 }
480 (boolean(b0), boolean(b1)) { b0 == b1 }
481 (list(l0), list(l1)) { vec::all2(l0, l1, eq) }
482 (dict(d0), dict(d1)) {
483 if d0.size() == d1.size() {
Niko Matsakis6b358752012-03-14 18:03:56484 let mut equal = true;
Marijn Haverbeke9053f542012-04-23 11:42:15485 for d0.each { |k, v0|
Erick Tryzelaar012dec52012-02-26 00:39:32486 alt d1.find(k) {
487 some(v1) {
488 if !eq(v0, v1) { equal = false; } }
489 none { equal = false; }
490 }
491 };
492 equal
493 } else {
494 false
495 }
496 }
497 (null, null) { true }
498 _ { false }
499 }
Elly Jonesbd726262011-11-07 19:01:28500}
Brian Anderson6e27b272012-01-18 03:05:07501
Erick Tryzelaared5af702012-05-28 19:10:32502iface to_json { fn to_json() -> json; }
503
504impl of to_json for json {
505 fn to_json() -> json { self }
506}
507
508impl of to_json for i8 {
509 fn to_json() -> json { num(self as float) }
510}
511
512impl of to_json for i16 {
513 fn to_json() -> json { num(self as float) }
514}
515
516impl of to_json for i32 {
517 fn to_json() -> json { num(self as float) }
518}
519
520impl of to_json for i64 {
521 fn to_json() -> json { num(self as float) }
522}
523
524impl of to_json for u8 {
525 fn to_json() -> json { num(self as float) }
526}
527
528impl of to_json for u16 {
529 fn to_json() -> json { num(self as float) }
530}
531
532impl of to_json for u32 {
533 fn to_json() -> json { num(self as float) }
534}
535
536impl of to_json for u64 {
537 fn to_json() -> json { num(self as float) }
538}
539
540impl of to_json for float {
541 fn to_json() -> json { num(self) }
542}
543
544impl of to_json for f32 {
545 fn to_json() -> json { num(self as float) }
546}
547
548impl of to_json for f64 {
549 fn to_json() -> json { num(self as float) }
550}
551
552impl of to_json for () {
553 fn to_json() -> json { null }
554}
555
556impl of to_json for bool {
557 fn to_json() -> json { boolean(self) }
558}
559
560impl of to_json for str {
561 fn to_json() -> json { string(self) }
562}
563
564impl <A: to_json copy, B: to_json copy> of to_json for (A, B) {
565 fn to_json() -> json {
566 let (a, b) = self;
567 list([a.to_json(), b.to_json()])
568 }
569}
570
571impl <A: to_json copy, B: to_json copy, C: to_json copy>
572 of to_json for (A, B, C) {
573 fn to_json() -> json {
574 let (a, b, c) = self;
575 list([a.to_json(), b.to_json(), c.to_json()])
576 }
577}
578
579impl <A: to_json> of to_json for [A] {
580 fn to_json() -> json { list(self.map { |elt| elt.to_json() }) }
581}
582
583impl <A: to_json copy> of to_json for hashmap<str, A> {
584 fn to_json() -> json {
585 let d = map::str_hash();
586 for self.each() { |key, value|
587 d.insert(key, value.to_json());
588 }
589 dict(d)
590 }
591}
592
593impl <A: to_json> of to_json for option<A> {
594 fn to_json() -> json {
595 alt self {
596 none { null }
597 some(value) { value.to_json() }
598 }
599 }
600}
601
602impl of to_str::to_str for json {
603 fn to_str() -> str { to_str(self) }
604}
605
Brian Anderson6e27b272012-01-18 03:05:07606#[cfg(test)]
607mod tests {
Erick Tryzelaar012dec52012-02-26 00:39:32608 fn mk_dict(items: [(str, json)]) -> json {
Brian Anderson3864d6d2012-03-14 19:07:23609 let d = map::str_hash();
Erick Tryzelaar012dec52012-02-26 00:39:32610
611 vec::iter(items) { |item|
612 let (key, value) = item;
613 d.insert(key, value);
614 };
615
616 dict(d)
Brian Anderson6e27b272012-01-18 03:05:07617 }
618
619 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32620 fn test_write_null() {
621 assert to_str(null) == "null";
Brian Anderson6e27b272012-01-18 03:05:07622 }
623
624 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32625 fn test_write_num() {
626 assert to_str(num(3f)) == "3";
627 assert to_str(num(3.1f)) == "3.1";
628 assert to_str(num(-1.5f)) == "-1.5";
629 assert to_str(num(0.5f)) == "0.5";
Brian Anderson6e27b272012-01-18 03:05:07630 }
631
632 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32633 fn test_write_str() {
634 assert to_str(string("")) == "\"\"";
635 assert to_str(string("foo")) == "\"foo\"";
Brian Anderson6e27b272012-01-18 03:05:07636 }
637
638 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32639 fn test_write_bool() {
640 assert to_str(boolean(true)) == "true";
641 assert to_str(boolean(false)) == "false";
Brian Anderson6e27b272012-01-18 03:05:07642 }
643
644 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32645 fn test_write_list() {
646 assert to_str(list([])) == "[]";
647 assert to_str(list([boolean(true)])) == "[true]";
648 assert to_str(list([
649 boolean(false),
650 null,
651 list([string("foo\nbar"), num(3.5f)])
652 ])) == "[false, null, [\"foo\\nbar\", 3.5]]";
653 }
654
655 #[test]
656 fn test_write_dict() {
657 assert to_str(mk_dict([])) == "{}";
658 assert to_str(mk_dict([("a", boolean(true))])) == "{ \"a\": true }";
659 assert to_str(mk_dict([
660 ("a", boolean(true)),
661 ("b", list([
662 mk_dict([("c", string("\x0c\r"))]),
663 mk_dict([("d", string(""))])
664 ]))
665 ])) ==
666 "{ " +
667 "\"a\": true, " +
668 "\"b\": [" +
669 "{ \"c\": \"\\f\\r\" }, " +
670 "{ \"d\": \"\" }" +
671 "]" +
672 " }";
673 }
674
675 #[test]
676 fn test_trailing_characters() {
677 assert from_str("nulla") ==
678 err({line: 1u, col: 5u, msg: "trailing characters"});
679 assert from_str("truea") ==
680 err({line: 1u, col: 5u, msg: "trailing characters"});
681 assert from_str("falsea") ==
682 err({line: 1u, col: 6u, msg: "trailing characters"});
683 assert from_str("1a") ==
684 err({line: 1u, col: 2u, msg: "trailing characters"});
685 assert from_str("[]a") ==
686 err({line: 1u, col: 3u, msg: "trailing characters"});
687 assert from_str("{}a") ==
688 err({line: 1u, col: 3u, msg: "trailing characters"});
689 }
690
691 #[test]
692 fn test_read_identifiers() {
693 assert from_str("n") ==
694 err({line: 1u, col: 2u, msg: "invalid syntax"});
695 assert from_str("nul") ==
696 err({line: 1u, col: 4u, msg: "invalid syntax"});
697
698 assert from_str("t") ==
699 err({line: 1u, col: 2u, msg: "invalid syntax"});
700 assert from_str("truz") ==
701 err({line: 1u, col: 4u, msg: "invalid syntax"});
702
703 assert from_str("f") ==
704 err({line: 1u, col: 2u, msg: "invalid syntax"});
705 assert from_str("faz") ==
706 err({line: 1u, col: 3u, msg: "invalid syntax"});
707
708 assert from_str("null") == ok(null);
709 assert from_str("true") == ok(boolean(true));
710 assert from_str("false") == ok(boolean(false));
Tycho Sciecf87c32012-02-29 08:47:17711 assert from_str(" null ") == ok(null);
712 assert from_str(" true ") == ok(boolean(true));
713 assert from_str(" false ") == ok(boolean(false));
Erick Tryzelaar012dec52012-02-26 00:39:32714 }
715
716 #[test]
717 fn test_read_num() {
718 assert from_str("+") ==
719 err({line: 1u, col: 1u, msg: "invalid syntax"});
720 assert from_str(".") ==
721 err({line: 1u, col: 1u, msg: "invalid syntax"});
722
723 assert from_str("-") ==
724 err({line: 1u, col: 2u, msg: "invalid number"});
725 assert from_str("00") ==
726 err({line: 1u, col: 2u, msg: "invalid number"});
727 assert from_str("1.") ==
728 err({line: 1u, col: 3u, msg: "invalid number"});
729 assert from_str("1e") ==
730 err({line: 1u, col: 3u, msg: "invalid number"});
731 assert from_str("1e+") ==
732 err({line: 1u, col: 4u, msg: "invalid number"});
733
734 assert from_str("3") == ok(num(3f));
735 assert from_str("3.1") == ok(num(3.1f));
736 assert from_str("-1.2") == ok(num(-1.2f));
737 assert from_str("0.4") == ok(num(0.4f));
738 assert from_str("0.4e5") == ok(num(0.4e5f));
739 assert from_str("0.4e+15") == ok(num(0.4e15f));
740 assert from_str("0.4e-01") == ok(num(0.4e-01f));
Tycho Sciecf87c32012-02-29 08:47:17741 assert from_str(" 3 ") == ok(num(3f));
Erick Tryzelaar012dec52012-02-26 00:39:32742 }
743
744 #[test]
745 fn test_read_str() {
746 assert from_str("\"") ==
747 err({line: 1u, col: 2u, msg: "EOF while parsing string"});
748 assert from_str("\"lol") ==
749 err({line: 1u, col: 5u, msg: "EOF while parsing string"});
750
751 assert from_str("\"\"") == ok(string(""));
752 assert from_str("\"foo\"") == ok(string("foo"));
753 assert from_str("\"\\\"\"") == ok(string("\""));
754 assert from_str("\"\\b\"") == ok(string("\x08"));
755 assert from_str("\"\\n\"") == ok(string("\n"));
756 assert from_str("\"\\r\"") == ok(string("\r"));
757 assert from_str("\"\\t\"") == ok(string("\t"));
Tycho Sciecf87c32012-02-29 08:47:17758 assert from_str(" \"foo\" ") == ok(string("foo"));
Erick Tryzelaar012dec52012-02-26 00:39:32759 }
760
761 #[test]
762 fn test_read_list() {
763 assert from_str("[") ==
764 err({line: 1u, col: 2u, msg: "EOF while parsing value"});
765 assert from_str("[1") ==
766 err({line: 1u, col: 3u, msg: "EOF while parsing list"});
767 assert from_str("[1,") ==
768 err({line: 1u, col: 4u, msg: "EOF while parsing value"});
769 assert from_str("[1,]") ==
770 err({line: 1u, col: 4u, msg: "invalid syntax"});
771 assert from_str("[6 7]") ==
772 err({line: 1u, col: 4u, msg: "expecting ',' or ']'"});
773
774 assert from_str("[]") == ok(list([]));
775 assert from_str("[ ]") == ok(list([]));
776 assert from_str("[true]") == ok(list([boolean(true)]));
777 assert from_str("[ false ]") == ok(list([boolean(false)]));
778 assert from_str("[null]") == ok(list([null]));
779 assert from_str("[3, 1]") == ok(list([num(3f), num(1f)]));
Tycho Sci0465d522012-02-29 07:14:43780 assert from_str("\n[3, 2]\n") == ok(list([num(3f), num(2f)]));
Erick Tryzelaar012dec52012-02-26 00:39:32781 assert from_str("[2, [4, 1]]") ==
782 ok(list([num(2f), list([num(4f), num(1f)])]));
783 }
784
785 #[test]
786 fn test_read_dict() {
787 assert from_str("{") ==
788 err({line: 1u, col: 2u, msg: "EOF while parsing object"});
789 assert from_str("{ ") ==
790 err({line: 1u, col: 3u, msg: "EOF while parsing object"});
791 assert from_str("{1") ==
792 err({line: 1u, col: 2u, msg: "key must be a string"});
793 assert from_str("{ \"a\"") ==
794 err({line: 1u, col: 6u, msg: "EOF while parsing object"});
795 assert from_str("{\"a\"") ==
796 err({line: 1u, col: 5u, msg: "EOF while parsing object"});
797 assert from_str("{\"a\" ") ==
798 err({line: 1u, col: 6u, msg: "EOF while parsing object"});
799
800 assert from_str("{\"a\" 1") ==
801 err({line: 1u, col: 6u, msg: "expecting ':'"});
802 assert from_str("{\"a\":") ==
803 err({line: 1u, col: 6u, msg: "EOF while parsing value"});
804 assert from_str("{\"a\":1") ==
805 err({line: 1u, col: 7u, msg: "EOF while parsing object"});
806 assert from_str("{\"a\":1 1") ==
807 err({line: 1u, col: 8u, msg: "expecting ',' or '}'"});
808 assert from_str("{\"a\":1,") ==
809 err({line: 1u, col: 8u, msg: "EOF while parsing object"});
810
811 assert eq(result::get(from_str("{}")), mk_dict([]));
812 assert eq(result::get(from_str("{\"a\": 3}")),
813 mk_dict([("a", num(3.0f))]));
814
815 assert eq(result::get(from_str("{ \"a\": null, \"b\" : true }")),
816 mk_dict([("a", null), ("b", boolean(true))]));
Tycho Sci0465d522012-02-29 07:14:43817 assert eq(result::get(from_str("\n{ \"a\": null, \"b\" : true }\n")),
818 mk_dict([("a", null), ("b", boolean(true))]));
Erick Tryzelaar012dec52012-02-26 00:39:32819 assert eq(result::get(from_str("{\"a\" : 1.0 ,\"b\": [ true ]}")),
820 mk_dict([
821 ("a", num(1.0)),
822 ("b", list([boolean(true)]))
823 ]));
824 assert eq(result::get(from_str(
825 "{" +
826 "\"a\": 1.0, " +
827 "\"b\": [" +
828 "true," +
829 "\"foo\\nbar\", " +
830 "{ \"c\": {\"d\": null} } " +
831 "]" +
832 "}")),
833 mk_dict([
834 ("a", num(1.0f)),
835 ("b", list([
836 boolean(true),
837 string("foo\nbar"),
838 mk_dict([
839 ("c", mk_dict([("d", null)]))
840 ])
841 ]))
842 ]));
843 }
844
845 #[test]
846 fn test_multiline_errors() {
847 assert from_str("{\n \"foo\":\n \"bar\"") ==
848 err({line: 3u, col: 8u, msg: "EOF while parsing object"});
Brian Anderson6e27b272012-01-18 03:05:07849 }
850}