From b0c2eb7e08b35a8132707c25b26e4cb5b1614b1d Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Fri, 7 Feb 2020 23:51:49 -0500 Subject: [PATCH] Mostly done, parse_number needs some more work --- src/lib.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f498b55..bf1873b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -244,7 +244,62 @@ impl JSON { /// See if there's a `JSONValue::Number` next in the JSON fn parse_number(&mut self) -> Result, ParseError> { - todo!(); + self.skip_whitespace(); + + // All this looping basically just counts the number of characters in the number + let start = self.i; + let max = self.chars.len() - 1; + let mut n = start; + + if self.chars[n] == '-' && n < max { + n += 1; + } + + if self.chars[n] == '0' && n < max { + 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 { + n += 1; + } + } + + if self.chars[n] == '.' && n < max { + n += 1; + while self.chars[n].is_ascii_digit() && n < max { + n += 1; + } + } + + if self.chars[n] == 'e' || self.chars[n] == 'E' && n < max { + n += 1; + + if self.chars[n] == '-' || self.chars[n] == '+' && n < max { + n += 1; + } + + while self.chars[n].is_ascii_digit() && n < max { + n += 1; + } + } + + if n > start { + let end = if n < self.chars.len() { + n + } else { + self.chars.len() + }; + + let str = String::from_iter(&self.chars[start..=end]); + + match str.parse::() { + Ok(n) => Ok(Some(JSONValue::Number(n))), + Err(e) => Err(ParseError::ExpectedDigit(format!("{:#?}", (str, e)))), + } + } else { + Ok(None) + } } /// See if there's a `JSONValue::True`, `JSONValue::False`, or a `JSONValue::Null` next in the JSON @@ -284,7 +339,7 @@ impl JSON { /// error is returned fn eat(&mut self, ch: char) -> Result<(), ParseError> { if self.chars[self.i] != ch { - let msg = format!(r#"Expected "{}"."#, ch); + let msg = format!("Expected '{}'.", ch); return Err(ParseError::ExpectedToken(msg)); } @@ -339,6 +394,17 @@ mod tests { assert_eq!(res, Ok(JSONValue::Array(vec![]))); } + #[test] + fn parse_number() { + let mut parser = JSON::new("3.14159"); + let res = JSON::parse_number(&mut parser); + assert_eq!(res, Ok(Some(JSONValue::Number(3.14159f64)))); + + let mut parser = JSON::new("3e4"); + let res = JSON::parse_number(&mut parser); + assert_eq!(res, Ok(Some(JSONValue::Number(3e4f64)))); + } + #[test] fn can_parse_array_of_keywords() { let result = JSON::parse("[true,false,null]"); @@ -352,4 +418,26 @@ mod tests { ])) ); } + + #[test] + fn can_parse_arbitrary_json() { + let result = JSON::parse( + r#"[{ + "a": 9.38083151965, + "b": 4e3, + "c": [1, 2, 3], + "d": "foo", + "e": { + "f": { + "g": { + "h": null + } + } + }, + "i": ["\"", "\\", "/", "\b", "\f", "\n", "\r", "\t", "\u0001", "\uface"] +}]"#, + ); + // let msg = format!("{:#?}", result); + assert!(result.is_ok(), format!("{:#?}", result)); + } }