1use std::io;
10use std::fmt;
11use std::error;
12use std::result;
13use std::collections::BTreeMap;
14use super::value::Value;
15use std::f64::{NAN, INFINITY};
16
17
18#[derive(Clone, PartialEq)]
19pub enum ErrorCode {
20 ExpectedDictKey,
21 ExpectedSeparator,
22 InvalidBoolValue,
23 InvalidNumberValue,
24 InvalidEscapeSequence,
25 InvalidUtf8Sequence,
26 UnexpectedEOF,
27 UnterminatedMessage,
28 UnterminatedString,
29 UnterminatedList,
30 UnterminatedDict,
31}
32
33
34impl fmt::Debug for ErrorCode {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 (match *self {
37 ErrorCode::ExpectedDictKey => "Dictionary key expected",
38 ErrorCode::ExpectedSeparator => "Separator expected",
39 ErrorCode::InvalidBoolValue => "Invalid boolean value",
40 ErrorCode::InvalidNumberValue => "Invalid numeric value",
41 ErrorCode::InvalidEscapeSequence => "Invalid escape sequence",
42 ErrorCode::InvalidUtf8Sequence => "Invalid UTF-8 sequence",
43 ErrorCode::UnexpectedEOF => "Unexpected end of file",
44 ErrorCode::UnterminatedMessage => "Unterminated message",
45 ErrorCode::UnterminatedString => "Unterminated string",
46 ErrorCode::UnterminatedList => "Unterminated list",
47 ErrorCode::UnterminatedDict => "Unterminated dictionary",
48 }).fmt(f)
49 }
50}
51
52
53#[derive(Debug)]
54pub enum Error {
55 SyntaxError(ErrorCode, usize, usize), IoError(io::Error),
57}
58
59
60impl error::Error for Error {
61 fn description(&self) -> &str {
62 match *self {
63 Error::SyntaxError(..) => "syntax error",
64 Error::IoError(ref error) => error::Error::description(error),
65 }
66 }
67
68 fn cause(&self) -> Option<&error::Error> {
69 match *self {
70 Error::IoError(ref error) => Some(error),
71 _ => None,
72 }
73 }
74}
75
76
77impl fmt::Display for Error {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 match *self {
80 Error::SyntaxError(ref code, line, column) =>
81 write!(f, "{:?} at line {} column {}", code, line, column),
82 Error::IoError(ref error) =>
83 fmt::Display::fmt(error, f),
84 }
85 }
86}
87
88
89impl From<io::Error> for Error {
90 fn from(error: io::Error) -> Error {
91 Error::IoError(error)
92 }
93}
94
95
96pub type Result<T> = result::Result<T, Error>;
97
98
99#[inline]
100fn is_whitespace_character(ch: u8) -> bool {
101 match ch { 0x09 | 0x0A | 0x0D | 0x20 => true,
106 _ => false,
107 }
108}
109
110
111#[inline]
112fn is_key_character(ch: u8) -> bool {
113 match ch {
114 b'[' | b']' | b'{' | b'}' | b':' | b',' => false, _ => !is_whitespace_character(ch),
116 }
117}
118
119
120#[inline]
121fn is_xdigit_character(ch: u8) -> bool {
122 match ch { b'0'...b'9'
123 | b'a'...b'f'
124 | b'A'...b'F'
125 => true,
126 _ => false,
127 }
128}
129
130
131#[inline]
132fn xdigit_to_int(ch: u8) -> u8 {
133 match ch {
134 b'0' => 0,
135 b'1' => 1,
136 b'2' => 2,
137 b'3' => 3,
138 b'4' => 4,
139 b'5' => 5,
140 b'6' => 6,
141 b'7' => 7,
142 b'8' => 8,
143 b'9' => 9,
144 b'a' | b'A' => 0xA,
145 b'b' | b'B' => 0xB,
146 b'c' | b'C' => 0xC,
147 b'd' | b'D' => 0xD,
148 b'e' | b'E' => 0xE,
149 b'f' | b'F' => 0xF,
150 _ => panic!("Invalid input {}", ch),
151 }
152}
153
154
155#[inline]
156fn is_octal_character(ch: u8) -> bool {
157 match ch {
158 b'0'...b'7' => true,
159 _ => false,
160 }
161}
162
163
164pub struct Parser<Iter: Iterator<Item=io::Result<u8>>> {
165 input : Iter,
166 line : usize,
167 column: usize,
168 look : Option<u8>,
169}
170
171
172macro_rules! try_no_eof {
173 ($obj:expr, $e:expr) => {
174 (match try!($e) {
175 None => return $obj.parse_error(ErrorCode::UnexpectedEOF),
176 Some(v) => v,
177 })
178 }
179}
180
181macro_rules! peek_no_eof {
182 ($e:expr) => {
183 match try!($e.peek()) {
184 None => return $e.parse_error(ErrorCode::UnexpectedEOF),
185 Some(v) => v,
186 }
187 }
188}
189
190macro_rules! getc_no_eof {
191 ($e:expr) => {
192 match $e.nextchar_raw() {
193 None => return $e.parse_error(ErrorCode::UnexpectedEOF),
194 Some(Err(error)) => return Err(Error::IoError(error)),
195 Some(Ok(ch)) => ch,
196 }
197 }
198}
199
200macro_rules! parse_digits {
201 ($e:expr, $base:expr, $check_digit:expr, $negative:expr) => {{
202 if !$check_digit(peek_no_eof!($e)) {
203 return $e.parse_error(ErrorCode::InvalidNumberValue);
204 }
205 let mut result = 0i64;
206 loop {
207 result = result * $base + match try!($e.peek()) {
208 Some(ch) if $check_digit(ch) => xdigit_to_int(ch) as i64,
209 Some(_) | None => break,
210 };
211 $e.advance();
212 }
213 if $negative {
214 result = -result;
215 }
216 Ok(Value::Integer(result))
217 }}
218}
219
220macro_rules! match_any {
221 ($e:expr, $error:ident, $($item:expr),+) => {
222 match peek_no_eof!($e) {
223 $(
224 $item => $e.advance(),
225 )*
226 _ => { return $e.parse_error(ErrorCode::$error); },
227 }
228 }
229}
230
231impl<Iter> Parser<Iter>
232 where Iter: Iterator<Item=io::Result<u8>>
233{
234 pub fn new(input: Iter) -> Self {
235 Parser {
236 input : input,
237 line : 1,
238 column: 0,
239 look : None,
240 }
241 }
242
243 fn nextchar_raw(&mut self) -> Option<io::Result<u8>> {
244 match self.input.next() {
245 Some(Ok(b'\n')) => {
246 self.line += 1;
247 self.column = 0;
248 Some(Ok(b'\n'))
249 }
250 Some(Ok(c)) => {
251 self.column += 1;
252 Some(Ok(c))
253 }
254 x => x,
255 }
256 }
257
258 fn nextchar(&mut self) -> Option<io::Result<u8>> {
259 match self.nextchar_raw() {
260 Some(Ok(b'#')) => loop {
261 match self.nextchar_raw() {
262 None => return None,
263 Some(Ok(b'\n')) => return self.nextchar(),
264 Some(Ok(..)) => continue,
265 Some(Err(x)) => return Some(Err(x)),
266 }
267 },
268 x => return x,
269 }
270 }
271
272 fn peek(&mut self) -> Result<Option<u8>> {
273 match self.look {
274 Some(ch) => Ok(Some(ch)),
275 None => {
276 match self.nextchar() {
277 Some(Err(error)) => Err(Error::IoError(error)),
278 Some(Ok(ch)) => {
279 self.look = Some(ch);
280 Ok(self.look)
281 },
282 None => Ok(None),
283 }
284 }
285 }
286 }
287
288 fn advance(&mut self) {
289 self.look = None;
290 }
291
292 fn parse_whitespace(&mut self) -> Result<()> {
293 match self.peek() {
294 Err(t) => Err(t),
295 Ok(None) => Ok(()),
296 Ok(Some(ch)) if is_whitespace_character(ch) => {
297 self.advance();
298 self.parse_whitespace()
299 },
300 Ok(Some(ch)) => {
301 self.look = Some(ch);
302 return Ok(())
303 },
304 }
305 }
306
307 fn parse_error<T>(&self, code : ErrorCode) -> Result<T> {
308 Err(Error::SyntaxError(code, self.line, self.column))
309 }
310
311 fn parse_value(&mut self) -> Result<Value> {
312 match peek_no_eof!(self) {
313 b'"' => self.parse_string(),
314 b'[' => self.parse_list(),
315 b'{' => self.parse_dict(),
316 b'T' | b't' | b'F' | b'f' => self.parse_bool(),
317 _ => self.parse_number(),
318 }
319 }
320
321 fn match_char(&mut self, expected: u8, code: ErrorCode) -> Result<()> {
322 if peek_no_eof!(self) == expected {
323 self.advance();
324 Ok(())
325 } else {
326 self.parse_error(code)
327 }
328 }
329
330 fn parse_string(&mut self) -> Result<Value> {
331 try!(self.match_char(b'"', ErrorCode::UnterminatedString));
332 let mut value = Vec::new();
333 loop {
334 match getc_no_eof!(self) {
335 b'"' => break,
336 b'\\' => match getc_no_eof!(self) {
337 b'"' => value.push(b'"'),
338 b'\\' => value.push(b'\\'),
339 b'n' => value.push(b'\n'),
340 b'r' => value.push(b'\r'),
341 b't' => value.push(b'\t'),
342 c if is_xdigit_character(c) => {
343 let x = match getc_no_eof!(self) {
345 ch if is_xdigit_character(ch) => ch,
346 _ => return self.parse_error(ErrorCode::InvalidEscapeSequence),
347 };
348 value.push(xdigit_to_int(c) * 16 + xdigit_to_int(x));
349 },
350 _ => return self.parse_error(ErrorCode::InvalidEscapeSequence),
351 },
352 ch => value.push(ch),
353 }
354 }
355
356 match String::from_utf8(value) {
357 Err(_) => self.parse_error(ErrorCode::InvalidUtf8Sequence),
358 Ok(x) => Ok(Value::String(x)),
359 }
360 }
361
362 fn parse_list(&mut self) -> Result<Value> {
363 try!(self.match_char(b'[', ErrorCode::UnterminatedList));
364 try!(self.parse_whitespace());
365
366 let mut list = Vec::new();
367 while peek_no_eof!(self) != b']' {
368 list.push(try!(self.parse_value()));
370
371 let got_whitespace = is_whitespace_character(peek_no_eof!(self));
373 try!(self.parse_whitespace());
374 if peek_no_eof!(self) == b',' {
375 self.advance();
376 } else if !got_whitespace && !is_whitespace_character(peek_no_eof!(self)) {
377 break;
378 }
379 try!(self.parse_whitespace());
380 }
381
382 try!(self.match_char(b']', ErrorCode::UnterminatedList));
383 Ok(Value::List(list))
384 }
385
386 fn parse_key(&mut self) -> Result<String> {
387 let mut key = Vec::new();
388 while is_key_character(peek_no_eof!(self)) {
389 key.push(peek_no_eof!(self));
390 self.advance();
391 }
392
393 if key.len() == 0 {
394 self.parse_error(ErrorCode::ExpectedDictKey)
395 } else {
396 match String::from_utf8(key) {
397 Err(_) => self.parse_error(ErrorCode::InvalidUtf8Sequence),
398 Ok(x) => Ok(x),
399 }
400 }
401 }
402
403 fn parse_keyval_items(&mut self, delim: Option<u8>) -> Result<Value> {
404 let mut items = BTreeMap::new();
405 while try!(self.peek()) != delim {
406 let key = try!(self.parse_key());
407 let mut got_separator = false;
408 if is_whitespace_character(peek_no_eof!(self)) {
409 try!(self.parse_whitespace());
410 got_separator = true;
411 }
412
413 match peek_no_eof!(self) {
414 b':' => {
415 self.advance();
416 try!(self.parse_whitespace());
417 got_separator = true;
418 },
419 b'{' | b'[' => {
420 got_separator = true;
421 },
422 _ => (),
423 }
424 if !got_separator {
425 return self.parse_error(ErrorCode::ExpectedSeparator);
426 }
427
428 items.insert(key, try!(self.parse_value()));
429
430 match try!(self.peek()) {
431 Some(b',') => self.advance(),
432 Some(ch) if Some(ch) != delim =>
433 if !is_whitespace_character(ch) {
434 break;
435 },
436 None if None != delim =>
437 return self.parse_error(ErrorCode::UnexpectedEOF),
438 _ => (),
439 }
440
441 try!(self.parse_whitespace());
442 }
443 Ok(Value::Dict(items))
444 }
445
446 fn parse_dict(&mut self) -> Result<Value> {
447 try!(self.match_char(b'{', ErrorCode::UnterminatedDict));
448 try!(self.parse_whitespace());
449 let result = try!(self.parse_keyval_items(Some(b'}')));
450 try!(self.match_char(b'}', ErrorCode::UnterminatedDict));
451 Ok(result)
452 }
453
454 fn parse_bool_rest(&mut self, result: bool) -> Result<Value> {
455 self.advance();
456 let remaining : &[u8] = { if result { b"rue" } else { b"alse" } };
457 for byte in remaining {
458 if peek_no_eof!(self) != *byte {
459 return self.parse_error(ErrorCode::InvalidBoolValue);
460 }
461 self.advance();
462 }
463 Ok(Value::Bool(result))
464 }
465
466 fn parse_bool(&mut self) -> Result<Value> {
467 match peek_no_eof!(self) {
468 b'T' | b't' => self.parse_bool_rest(true),
469 b'F' | b'f' => self.parse_bool_rest(false),
470 _ => self.parse_error(ErrorCode::InvalidBoolValue),
471 }
472 }
473
474 fn parse_number(&mut self) -> Result<Value> {
475 let mut buffer = Vec::new();
476
477 let negative = match peek_no_eof!(self) {
479 b'-' => { self.advance(); true },
480 b'+' => { self.advance(); false },
481 _ => false,
482 };
483
484 match peek_no_eof!(self) {
486 b'0' => {
487 buffer.push(b'0');
488 self.advance();
489 match try!(self.peek()) {
490 None => (),
491 Some(b'x') | Some(b'X') => {
492 buffer.push(b'x');
493 self.advance();
494 return parse_digits!(self, 16, is_xdigit_character, negative)
495 },
496 Some(ch) if is_octal_character(ch) =>
497 return parse_digits!(self, 8, is_octal_character, negative),
498 Some(_) => (),
499 }
500 },
501 b'N' | b'n' => {
502 self.advance();
503 match_any!(self, InvalidNumberValue, b'a', b'A');
504 match_any!(self, InvalidNumberValue, b'n', b'N');
505 return Ok(Value::Float(if negative { -NAN } else { NAN }));
506 },
507 b'I' | b'i' => {
508 self.advance();
509 match_any!(self, InvalidNumberValue, b'n', b'N');
510 match_any!(self, InvalidNumberValue, b'f', b'F');
511 match try!(self.peek()) {
512 Some(b'i') | Some(b'I') => {
513 self.advance();
514 match_any!(self, InvalidNumberValue, b'n', b'N');
515 match_any!(self, InvalidNumberValue, b'i', b'I');
516 match_any!(self, InvalidNumberValue, b't', b'T');
517 match_any!(self, InvalidNumberValue, b'y', b'Y');
518 }
519 _ => (),
520 }
521 return Ok(Value::Float(if negative { -INFINITY } else { INFINITY }));
522 },
523 _ => (),
524 }
525
526 let mut dot_seen = false;
527 let mut exp_seen = false;
528 loop {
529 match try!(self.peek()) {
530 None => break,
531 Some(b'e') | Some(b'E') => {
532 if exp_seen {
533 return self.parse_error(ErrorCode::InvalidNumberValue);
534 }
535 exp_seen = true;
536 buffer.push(b'e');
537 self.advance();
538 match peek_no_eof!(self) {
540 ch @b'-' | ch @b'+' => {
541 buffer.push(ch);
542 self.advance();
543 },
544 _ => (),
545 }
546 },
547 Some(b'.') => {
548 if dot_seen {
549 return self.parse_error(ErrorCode::InvalidNumberValue);
550 }
551 dot_seen = true;
552 buffer.push(b'.');
553 self.advance();
554 },
555 Some(ch @b'0'...b'9') => {
556 buffer.push(ch);
557 self.advance();
558 },
559 Some(_) =>
560 return self.parse_error(ErrorCode::InvalidNumberValue),
561 }
562 }
563
564 if buffer.len() == 0 {
565 return self.parse_error(ErrorCode::InvalidNumberValue);
566 }
567
568 let string_value = match String::from_utf8(buffer) {
569 Err(_) => return self.parse_error(ErrorCode::InvalidUtf8Sequence),
570 Ok(value) => value,
571 };
572
573 if dot_seen || exp_seen {
574 match string_value.parse::<f64>() {
575 Ok(value) => Ok(Value::Float(if negative { -value } else { value })),
576 Err(_) => self.parse_error(ErrorCode::InvalidNumberValue),
577 }
578 } else {
579 match string_value.parse::<i64>() {
580 Ok(value) => Ok(Value::Integer(if negative { -value } else { value })),
581 Err(_) => self.parse_error(ErrorCode::InvalidNumberValue),
582 }
583 }
584 }
585
586 pub fn parse_message(&mut self) -> Result<Value> {
587 try!(self.parse_whitespace());
588 match try!(self.peek()) {
589 None => Ok(Value::Dict(BTreeMap::new())),
590 Some(b'{') => {
591 self.advance();
592 try!(self.parse_whitespace());
593 let result = try!(self.parse_keyval_items(Some(b'}')));
594 try!(self.match_char(b'}', ErrorCode::UnterminatedMessage));
595 Ok(result)
596 },
597 _ => self.parse_keyval_items(None),
598 }
599 }
600}
601
602
603#[cfg(test)]
604mod tests {
605 use super::*;
606 use super::super::value::Value;
607 use std::io::{Cursor, Read};
608
609 #[test]
610 fn peek_input() {
611 let input = Cursor::new("Hello, world".as_bytes());
612 let mut p = Parser::new(input.bytes());
613 assert_eq!(Some(b'H'), p.peek().unwrap());
614 }
615
616 #[test]
617 fn ignore_comment() {
618 let input = Cursor::new("# Comment\nFoo".as_bytes());
619 let mut p = Parser::new(input.bytes());
620 assert_eq!(Some(b'F'), p.peek().unwrap());
621 }
622
623 #[test]
624 fn ignore_consecutive_comments() {
625 let input = Cursor::new("# Comment 1\n#Comment 2\nBar".as_bytes());
626 let mut p = Parser::new(input.bytes());
627 assert_eq!(Some(b'B'), p.peek().unwrap());
628 }
629
630 #[test]
631 fn skip_whitespace() {
632 let input = Cursor::new(" Whitespace".as_bytes());
633 let mut p = Parser::new(input.bytes());
634 p.parse_whitespace().unwrap();
635 assert_eq!(Some(b'W'), p.peek().unwrap());
636 }
637
638 #[test]
639 fn advance_input() {
640 let hello = "Hello, world";
641 let mut check = hello.bytes();
642 let input = Cursor::new(hello.as_bytes());
643 let mut p = Parser::new(input.bytes());
644 loop {
645 match p.peek().unwrap() {
646 Some(ch) => assert_eq!(check.next().unwrap(), ch),
647 None => break,
648 }
649 p.advance();
650 }
651 }
652
653 macro_rules! make_fail_tests {
654 ($($name:ident, $str:expr),+) => {
655 $(
656 #[test] #[should_panic]
657 fn $name() {
658 let input = Cursor::new($str.as_bytes());
659 let mut p = Parser::new(input.bytes());
660 p.parse_list().unwrap().as_list();
661 }
662 )*
663 }
664 }
665
666 macro_rules! make_bool_tests {
667 ($expected:expr, $($name:ident, $str:expr),+) => {
668 $(
669 #[test]
670 fn $name() {
671 let input = Cursor::new($str.as_bytes());
672 let mut p = Parser::new(input.bytes());
673 assert_eq!(Some($expected), p.parse_bool().unwrap().as_bool());
674 }
675 )*
676 }
677 }
678
679 make_bool_tests!(true,
680 parse_true, "true",
681 parse_true_upper, "True");
682 make_bool_tests!(false,
683 parse_false, "false",
684 parse_false_upper, "False");
685 make_fail_tests!(parse_true_allupper, "TRUE",
686 parse_false_allupper, "FALSE");
687
688
689 macro_rules! make_list_test {
690 ($name:ident, $value:ident, $str:expr, $block:block) => {
691 #[test]
692 fn $name() {
693 let input = Cursor::new($str.as_bytes());
694 let mut p = Parser::new(input.bytes());
695 if let Some($value) = p.parse_list().unwrap().as_list() {
696 $block
697 } else {
698 panic!("Parsing did not return a value");
699 }
700 }
701 }
702 }
703
704 make_list_test!(list_empty, value, "[]", {
705 assert_eq!(0, value.len());
706 });
707
708 make_list_test!(list_empty_space, value, "[ ]", {
709 assert_eq!(0, value.len());
710 });
711
712 make_list_test!(list_one_item, value, "[true]", {
713 assert_eq!(1, value.len());
714 assert_eq!(Some(true), value[0].as_bool());
715 });
716
717 make_list_test!(list_two_items_comma, value, "[true,false]", {
718 assert_eq!(2, value.len());
719 assert_eq!(Some(true), value[0].as_bool());
720 assert_eq!(Some(false), value[1].as_bool());
721 });
722
723 make_list_test!(list_two_items_space, value, "[true false]", {
724 assert_eq!(2, value.len());
725 assert_eq!(Some(true), value[0].as_bool());
726 assert_eq!(Some(false), value[1].as_bool());
727 });
728
729 make_list_test!(list_two_items_commaspace, value, "[true, false]", {
730 assert_eq!(2, value.len());
731 assert_eq!(Some(true), value[0].as_bool());
732 assert_eq!(Some(false), value[1].as_bool());
733 });
734
735 make_list_test!(list_two_items_spacecommaspace, value, "[true , false]", {
736 assert_eq!(2, value.len());
737 assert_eq!(Some(true), value[0].as_bool());
738 assert_eq!(Some(false), value[1].as_bool());
739 });
740
741 make_fail_tests!(list_unterminated, "[",
742 list_unterminated_space, "[ ",
743 list_unterminated_one_item, "[true",
744 list_unterminated_one_item_space, "[true ",
745 list_unterminated_one_item_comma, "[true,",
746 list_unterminated_one_item_commaspace, "[true, ",
747 list_unterminated_one_item_spacecommaspace, "[true , ");
748
749
750 macro_rules! make_dict_test {
751 ($name:ident, $value:ident, $str:expr, $block:block) => {
752 #[test]
753 fn $name() {
754 let input = Cursor::new($str.as_bytes());
755 let mut p = Parser::new(input.bytes());
756 if let Some($value) = p.parse_dict().unwrap().as_dict() {
757 $block
758 } else {
759 panic!("Parsing did not return a value");
760 }
761 }
762 }
763 }
764
765 make_dict_test!(dict_empty, value, "{}", {
766 assert_eq!(0, value.len());
767 });
768 make_dict_test!(dict_empty_space, value, "{ }", {
769 assert_eq!(0, value.len());
770 });
771 make_dict_test!(dict_one_item, value, "{ a: True }", {
772 assert_eq!(1, value.len());
773 assert!(value.contains_key("a"));
774 assert_eq!(Some(true), value.get("a").unwrap().as_bool());
775 });
776 make_dict_test!(dict_one_item_space, value, "{a False}", {
777 assert_eq!(1, value.len());
778 assert!(value.contains_key("a"));
779 assert_eq!(Some(false), value.get("a").unwrap().as_bool());
780 });
781 make_dict_test!(dict_two_items, value, "{a:true,b:false}", {
782 assert_eq!(2, value.len());
783 assert_eq!(true, value.get("a").unwrap().as_bool().unwrap());
784 assert_eq!(false, value.get("b").unwrap().as_bool().unwrap());
785 });
786 make_dict_test!(dict_two_items_space, value, "{a:true b:false}", {
787 assert_eq!(2, value.len());
788 assert_eq!(true, value.get("a").unwrap().as_bool().unwrap());
789 assert_eq!(false, value.get("b").unwrap().as_bool().unwrap());
790 });
791 make_dict_test!(dict_two_items_commaspace, value, "{a:true, b:false}", {
792 assert_eq!(2, value.len());
793 assert_eq!(true, value.get("a").unwrap().as_bool().unwrap());
794 assert_eq!(false, value.get("b").unwrap().as_bool().unwrap());
795 });
796
797 make_fail_tests!(dict_unterminated, "{",
798 dict_unterminated_with_key, "{ key",
799 dict_unterminated_with_key_space, "{ key ",
800 dict_unterminated_with_key_colon, "{ key:",
801 dict_unterminated_with_key_colonspace, "{ key: ",
802 dict_missing_value, "{ key }",
803 dict_missing_value_colon, "{ key: }");
804
805
806 macro_rules! make_string_tests {
807 ($($name:ident, $str:expr, $expected:expr),+) => {
808 $(
809 #[test]
810 fn $name() {
811 let input = Cursor::new($str.as_bytes());
812 let mut p = Parser::new(input.bytes());
813 assert_eq!($expected, p.parse_string().unwrap().as_string().unwrap());
814 }
815 )*
816 }
817 }
818
819 make_string_tests!(string_empty, "\"\"", "",
820 string_foo_bar, "\"foo bar\"", "foo bar",
821 string_unicode, "\"☺\"", "☺");
822
823 macro_rules! make_number_tests {
824 ($t:ident, $($name:ident, $str:expr, $expected:expr),+) => {
825 $(
826 #[test]
827 fn $name() {
828 let mut p = Parser::new(Cursor::new($str.as_bytes()).bytes());
829 match p.parse_number().unwrap() {
830 Value::$t(value) => assert_eq!($expected, value),
831 _ => panic!("{} decoded into in incorrect type", stringify!($t)),
832 }
833 }
834 )*
835 }
836 }
837
838 make_number_tests!(Integer,
839 integer_zero, "0", 0,
840 integer_zero_octal, "00", 0,
841 integer_zero_hex, "0x0", 0,
842 integer_negative, "-42", -42,
843 integer_signed, "+42", 42,
844 integer_hex, "0xCAFE", 0xCAFE,
845 integer_octal, "01744", 0o1744,
846 integer_negative_oct, "-0644", -0o644);
847
848 make_number_tests!(Float,
849 float_zero, "0.0", 0f64,
850 float_zero_exp, "0e0", 0f64,
851 float_zero_negative, "-0.0", -0f64,
852 float_exp_negative, "1e-0", 1e-0_f64,
853 float_negative_exp_negative, "-1e-0", -1e0_f64);
854
855 macro_rules! make_exotic_float_tests {
856 ($check:ident, $name:ident, $($str:expr),+) => {
857 #[test]
858 fn $name() {
859 $({
860 println!($str);
861 let mut p = Parser::new(Cursor::new($str.as_bytes()).bytes());
862 assert!(p.parse_number().unwrap().as_float().unwrap().$check());
863 })*
864 }
865 }
866 }
867
868 make_exotic_float_tests!(is_nan, float_nan, "NaN", "nan", "NAN", "nAn", "nAN", "Nan");
869 make_exotic_float_tests!(is_infinite, float_inf, "Inf", "inf", "iNf", "iNF",
870 "Infinity", "infinity", "iNfInItY", "iNFiniTy");
871}