From a480e5a096baa30886d2b679fd76981c7c0ecf58 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Mon, 10 Feb 2020 12:26:54 -0500 Subject: [PATCH] Make more tests pass...but still fail on the full JSON --- src/lib.rs | 69 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bf1873b..b7b9af4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,7 +86,7 @@ impl JSON { /// In order to determine the type of JSON value, each parse method is tried, until one /// matches, or a parse error happens. /// - /// * `Option`s implement IntoIterator, which returns an iterator of -1 or 1 items: the + /// * `Option`s implement IntoIterator, which returns an iterator of 0 or 1 items: the /// transferred (not borrowed) Some() value. /// * The `chain` method of iterators allows you to link iterators together, /// to act as one iterator @@ -119,7 +119,7 @@ impl JSON { return Ok(None); } - self.i += 1; + self.increment(1); self.skip_whitespace(); @@ -153,7 +153,7 @@ impl JSON { } // Move to the next character: '}' - self.i += 1; + self.increment(1); Ok(Some(JSONValue::Object(result))) } @@ -164,7 +164,7 @@ impl JSON { return Ok(None); } - self.i += 1; + self.increment(1); self.skip_whitespace(); let mut result: Vec = vec![]; @@ -180,7 +180,7 @@ impl JSON { } // move to next character: ']' - self.i += 1; + self.increment(1); Ok(Some(JSONValue::Array(result))) } @@ -191,10 +191,10 @@ impl JSON { return Ok(None); } - self.i += 1; + self.increment(1); let mut result = String::new(); - while self.chars[self.i] != '"' { + while self.chars[self.i] != '"' && self.i < self.chars.len() - 1 { // All the escape sequences... if self.chars[self.i] == '\\' { let ch = self.chars[self.i + 1]; @@ -202,7 +202,7 @@ impl JSON { let escaped = ch.escape_default().next().unwrap_or(ch); result.push(escaped); - self.i += 1; + self.increment(1); } else if ['b', 'f', 'n', 'r', 't'].contains(&ch) { let ch = match ch { 'b' => '\u{8}', @@ -213,7 +213,7 @@ impl JSON { _ => panic!("Shouldn't be possible!"), }; result.push(ch); - self.i += 1; + self.increment(1); } else if ch == 'u' && self.chars[self.i + 2].is_ascii_hexdigit() && self.chars[self.i + 3].is_ascii_hexdigit() @@ -229,22 +229,25 @@ impl JSON { result.push_str(&string); - self.i += 5; + self.increment(5); } } else { result.push(self.chars[self.i]); } - self.i += 1; + self.increment(1); } - self.i += 1; + self.increment(1); Ok(Some(JSONValue::String(result))) } /// See if there's a `JSONValue::Number` next in the JSON fn parse_number(&mut self) -> Result, ParseError> { - self.skip_whitespace(); + // If it doesn't start with 0-9 or a minus sign, it's probably not a number + if ! (self.chars[self.i].is_ascii_digit() || self.chars[self.i] == '-') { + return Ok(None); + } // All this looping basically just counts the number of characters in the number let start = self.i; @@ -259,8 +262,7 @@ impl JSON { n += 1; } else if self.chars[n] >= '1' && self.chars[n] <= '9' && n < max { n += 1; - while self.chars[n].is_ascii_digit() { - // && n < max { + while self.chars[n].is_ascii_digit() && n < max { n += 1; } } @@ -292,6 +294,7 @@ impl JSON { }; let str = String::from_iter(&self.chars[start..=end]); + self.i += str.len() - 1; match str.parse::() { Ok(n) => Ok(Some(JSONValue::Number(n))), @@ -328,7 +331,7 @@ impl JSON { /// Increment the internal index until the next character is not a whitespace character fn skip_whitespace(&mut self) { while self.chars[self.i].is_ascii_whitespace() { - self.i += 1; + self.increment(1); } } @@ -343,11 +346,20 @@ impl JSON { return Err(ParseError::ExpectedToken(msg)); } - self.i += 1; + self.increment(1); Ok(()) } + fn increment(&mut self, amount: usize) { + let current = self.i; + if current + amount >= self.chars.len() { + self.i = self.chars.len() - 1; + } else { + self.i += amount; + } + } + /// Convert a `&str` containing JSON into a `Result` pub fn parse(json: &str) -> Result { JSON::new(json).parse_value() @@ -396,6 +408,10 @@ mod tests { #[test] fn parse_number() { + let mut parser = JSON::new(r#""foo""#); + let res = JSON::parse_number(&mut parser); + assert_eq!(res, Ok(None)); + let mut parser = JSON::new("3.14159"); let res = JSON::parse_number(&mut parser); assert_eq!(res, Ok(Some(JSONValue::Number(3.14159f64)))); @@ -419,6 +435,25 @@ mod tests { ); } + #[test] + fn parse_json_types() { + // Boolean / Null + let res = JSON::parse("true"); + assert_eq!(res, Ok(JSONValue::True)); + let res = JSON::parse("false"); + assert_eq!(res, Ok(JSONValue::False)); + let res = JSON::parse("null"); + assert_eq!(res, Ok(JSONValue::Null)); + + // Number + let res = JSON::parse("9.38083151965"); + assert_eq!(res, Ok(JSONValue::Number(9.38083151965)), "Failed to parse number"); + + // String + let res = JSON::parse(r#""/^$/""#); + assert_eq!(res, Ok(JSONValue::String(String::from("/^$/"))), "Failed to parse string"); + } + #[test] fn can_parse_arbitrary_json() { let result = JSON::parse(