Make more tests pass...but still fail on the full JSON
This commit is contained in:
parent
b0c2eb7e08
commit
a480e5a096
69
src/lib.rs
69
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
|
/// In order to determine the type of JSON value, each parse method is tried, until one
|
||||||
/// matches, or a parse error happens.
|
/// 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.
|
/// transferred (not borrowed) Some() value.
|
||||||
/// * The `chain` method of iterators allows you to link iterators together,
|
/// * The `chain` method of iterators allows you to link iterators together,
|
||||||
/// to act as one iterator
|
/// to act as one iterator
|
||||||
@ -119,7 +119,7 @@ impl JSON {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
|
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ impl JSON {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Move to the next character: '}'
|
// Move to the next character: '}'
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
|
|
||||||
Ok(Some(JSONValue::Object(result)))
|
Ok(Some(JSONValue::Object(result)))
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ impl JSON {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
|
|
||||||
let mut result: Vec<JSONValue> = vec![];
|
let mut result: Vec<JSONValue> = vec![];
|
||||||
@ -180,7 +180,7 @@ impl JSON {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// move to next character: ']'
|
// move to next character: ']'
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
|
|
||||||
Ok(Some(JSONValue::Array(result)))
|
Ok(Some(JSONValue::Array(result)))
|
||||||
}
|
}
|
||||||
@ -191,10 +191,10 @@ impl JSON {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
let mut result = String::new();
|
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...
|
// All the escape sequences...
|
||||||
if self.chars[self.i] == '\\' {
|
if self.chars[self.i] == '\\' {
|
||||||
let ch = self.chars[self.i + 1];
|
let ch = self.chars[self.i + 1];
|
||||||
@ -202,7 +202,7 @@ impl JSON {
|
|||||||
let escaped = ch.escape_default().next().unwrap_or(ch);
|
let escaped = ch.escape_default().next().unwrap_or(ch);
|
||||||
|
|
||||||
result.push(escaped);
|
result.push(escaped);
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
} else if ['b', 'f', 'n', 'r', 't'].contains(&ch) {
|
} else if ['b', 'f', 'n', 'r', 't'].contains(&ch) {
|
||||||
let ch = match ch {
|
let ch = match ch {
|
||||||
'b' => '\u{8}',
|
'b' => '\u{8}',
|
||||||
@ -213,7 +213,7 @@ impl JSON {
|
|||||||
_ => panic!("Shouldn't be possible!"),
|
_ => panic!("Shouldn't be possible!"),
|
||||||
};
|
};
|
||||||
result.push(ch);
|
result.push(ch);
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
} else if ch == 'u'
|
} else if ch == 'u'
|
||||||
&& self.chars[self.i + 2].is_ascii_hexdigit()
|
&& self.chars[self.i + 2].is_ascii_hexdigit()
|
||||||
&& self.chars[self.i + 3].is_ascii_hexdigit()
|
&& self.chars[self.i + 3].is_ascii_hexdigit()
|
||||||
@ -229,22 +229,25 @@ impl JSON {
|
|||||||
|
|
||||||
result.push_str(&string);
|
result.push_str(&string);
|
||||||
|
|
||||||
self.i += 5;
|
self.increment(5);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.push(self.chars[self.i]);
|
result.push(self.chars[self.i]);
|
||||||
}
|
}
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
|
|
||||||
Ok(Some(JSONValue::String(result)))
|
Ok(Some(JSONValue::String(result)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See if there's a `JSONValue::Number` next in the JSON
|
/// See if there's a `JSONValue::Number` next in the JSON
|
||||||
fn parse_number(&mut self) -> Result<Option<JSONValue>, ParseError> {
|
fn parse_number(&mut self) -> Result<Option<JSONValue>, 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
|
// All this looping basically just counts the number of characters in the number
|
||||||
let start = self.i;
|
let start = self.i;
|
||||||
@ -259,8 +262,7 @@ impl JSON {
|
|||||||
n += 1;
|
n += 1;
|
||||||
} else if self.chars[n] >= '1' && self.chars[n] <= '9' && n < max {
|
} else if self.chars[n] >= '1' && self.chars[n] <= '9' && n < max {
|
||||||
n += 1;
|
n += 1;
|
||||||
while self.chars[n].is_ascii_digit() {
|
while self.chars[n].is_ascii_digit() && n < max {
|
||||||
// && n < max {
|
|
||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,6 +294,7 @@ impl JSON {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let str = String::from_iter(&self.chars[start..=end]);
|
let str = String::from_iter(&self.chars[start..=end]);
|
||||||
|
self.i += str.len() - 1;
|
||||||
|
|
||||||
match str.parse::<f64>() {
|
match str.parse::<f64>() {
|
||||||
Ok(n) => Ok(Some(JSONValue::Number(n))),
|
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
|
/// Increment the internal index until the next character is not a whitespace character
|
||||||
fn skip_whitespace(&mut self) {
|
fn skip_whitespace(&mut self) {
|
||||||
while self.chars[self.i].is_ascii_whitespace() {
|
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));
|
return Err(ParseError::ExpectedToken(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.i += 1;
|
self.increment(1);
|
||||||
|
|
||||||
Ok(())
|
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<JSONValue, ParseError>`
|
/// Convert a `&str` containing JSON into a `Result<JSONValue, ParseError>`
|
||||||
pub fn parse(json: &str) -> Result<JSONValue, ParseError> {
|
pub fn parse(json: &str) -> Result<JSONValue, ParseError> {
|
||||||
JSON::new(json).parse_value()
|
JSON::new(json).parse_value()
|
||||||
@ -396,6 +408,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_number() {
|
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 mut parser = JSON::new("3.14159");
|
||||||
let res = JSON::parse_number(&mut parser);
|
let res = JSON::parse_number(&mut parser);
|
||||||
assert_eq!(res, Ok(Some(JSONValue::Number(3.14159f64))));
|
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]
|
#[test]
|
||||||
fn can_parse_arbitrary_json() {
|
fn can_parse_arbitrary_json() {
|
||||||
let result = JSON::parse(
|
let result = JSON::parse(
|
||||||
|
Loading…
Reference in New Issue
Block a user