diff --git a/src/lib.rs b/src/lib.rs index f3009be..496314d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ +//! # Naive JSON Parser use std::collections::HashMap; use std::iter::FromIterator; -use crate::ParseError::UnexpectedEndOfInput; #[derive(Debug, PartialEq)] pub enum JSONValue { @@ -13,7 +13,7 @@ pub enum JSONValue { Null, } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum ParseError { UnexpectedEndOfInput(String), ExpectedEndOfInput(String), @@ -25,7 +25,7 @@ pub enum ParseError { ExpectedUnicodeEscape(String), } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct JSON { chars: Vec, i: usize @@ -55,7 +55,7 @@ impl JSON { match types.next() { Some(val) => Ok(val), - None => Err(UnexpectedEndOfInput(String::new())) + None => Err(ParseError::UnexpectedEndOfInput(String::new())) } } @@ -76,7 +76,7 @@ impl JSON { // we take the path of string -> whitespace -> ':' -> value -> ... while self.chars[self.i] != '}' { if initial == false { - self.eat_char(',')?; + self.eat(',')?; self.skip_whitespace(); } @@ -89,7 +89,7 @@ impl JSON { }; self.skip_whitespace(); - self.eat_char(':')?; + self.eat(':')?; let value = self.parse_value()?; result.insert(key, value); @@ -116,7 +116,7 @@ impl JSON { while self.chars[self.i] != ']' { if initial == false { - self.eat_char(',')?; + self.eat(',')?; } let value = self.parse_value()?; result.push(value); @@ -130,15 +130,22 @@ impl JSON { } fn parse_string(&mut self) -> PartialResult { - todo!(); + Ok(None) } fn parse_number(&mut self) -> PartialResult { - todo!(); + Ok(None) } fn parse_keyword(&mut self, search: &str, value: JSONValue) -> PartialResult { - let slice = &String::from_iter(&self.chars[self.i..self.i+search.len()]); + let start = self.i; + let end = if self.i + search.len() > self.chars.len() { + self.chars.len() + } else { + self.i + search.len() + }; + + let slice = &String::from_iter(&self.chars[start..end]); if slice == search { self.i += search.len(); @@ -154,7 +161,7 @@ impl JSON { } } - fn eat_char(&mut self, ch: char) -> Result<(), ParseError> { + fn eat(&mut self, ch: char) -> Result<(), ParseError> { if self.chars[self.i] != ch { let msg = format!(r#"Expected "{}"."#, ch); return Err(ParseError::ExpectedToken(msg)); @@ -165,6 +172,7 @@ impl JSON { Ok(()) } + /// Convert a `&str` containing JSON into a `Result` pub fn parse(json: &str) -> JSONResult { JSON::new(json).parse_value() } @@ -177,7 +185,34 @@ mod tests { use super::*; #[test] - fn it_works() { - assert_eq!(2 + 2, 4); + fn parse_keyword() { + let mut parser = JSON::new(r#""foobarbaz""#); + let res = JSON::parse_keyword(&mut parser, "true", JSONValue::True); + assert_eq!(res, Ok(None)); + + let mut parser = JSON::new("true"); + let res = JSON::parse_keyword(&mut parser, "true", JSONValue::True); + assert_eq!(res, Ok(Some(JSONValue::True))); + } + + #[test] + fn skip_whitespace() { + let mut parser = JSON::new(" \t\r\nx"); + parser.skip_whitespace(); + assert_eq!('x', parser.chars[parser.i]); + } + + #[test] + fn parse_empty_array() { + let mut parser = JSON::new("[]"); + let res = JSON::parse_value(&mut parser); + assert_eq!(res, Ok(JSONValue::Array(vec![]))); + } + + #[test] + fn can_parse_array_of_keywords() { + let result = JSON::parse("[true,false,null]"); + + assert_eq!(result, Ok(JSONValue::Array(vec![JSONValue::True, JSONValue::False, JSONValue::Null]))); } }