Less clever, lazy evaluation of parser method chain
This commit is contained in:
parent
a2ecaef5ee
commit
e4070abd40
100
src/lib.rs
100
src/lib.rs
@ -79,38 +79,37 @@ impl JSON {
|
||||
}
|
||||
|
||||
/// Parse a `JSONValue` from the current JSON string
|
||||
///
|
||||
/// This is probably an abuse of iterators...but it's still much better than the alternative
|
||||
/// of nested matches.
|
||||
///
|
||||
/// 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 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
|
||||
/// * The first result from the iterator is the first parse method with a non-empty value,
|
||||
/// and should be the value wanted
|
||||
fn parse_value(&mut self) -> Result<JSONValue, ParseError> {
|
||||
self.skip_whitespace();
|
||||
|
||||
let mut value = self
|
||||
.parse_string()?
|
||||
.into_iter()
|
||||
.chain(self.parse_number()?.into_iter())
|
||||
.chain(self.parse_object()?.into_iter())
|
||||
.chain(self.parse_array()?.into_iter())
|
||||
.chain(self.parse_keyword("true", JSONValue::True)?.into_iter())
|
||||
.chain(self.parse_keyword("false", JSONValue::False)?.into_iter())
|
||||
.chain(self.parse_keyword("null", JSONValue::Null)?.into_iter());
|
||||
|
||||
match value.next() {
|
||||
Some(val) => Ok(val),
|
||||
None => Err(ParseError::UnexpectedEndOfInput(String::from(
|
||||
return if let Some(string) = self.parse_string()? {
|
||||
Ok(string)
|
||||
} else if let Some(number) = self.parse_number()? {
|
||||
Ok(number)
|
||||
} else if let Some(object) = self.parse_object()? {
|
||||
Ok(object)
|
||||
} else if let Some(array) = self.parse_array()? {
|
||||
Ok(array)
|
||||
} else if let Some(t) = self.parse_keyword("true", JSONValue::True)? {
|
||||
Ok(t)
|
||||
} else if let Some(f) = self.parse_keyword("false", JSONValue::False)? {
|
||||
Ok(f)
|
||||
} else if let Some(n) = self.parse_keyword("null", JSONValue::Null)? {
|
||||
Ok(n)
|
||||
} else {
|
||||
Err(ParseError::UnexpectedEndOfInput(String::from(
|
||||
"Doesn't seem to be valid JSON",
|
||||
))),
|
||||
}
|
||||
)))
|
||||
};
|
||||
|
||||
// Eagerly evaluated simpler alternative to the original option iterator chain
|
||||
// let value = self.parse_string()?
|
||||
// .or(self.parse_number()?)
|
||||
// .or(self.parse_object()?)
|
||||
// .or(self.parse_array()?)
|
||||
// .or(self.parse_keyword("true", JSONValue::True)?)
|
||||
// .or(self.parse_keyword("false", JSONValue::False)?)
|
||||
// .or(self.parse_keyword("null", JSONValue::Null)?);
|
||||
}
|
||||
|
||||
/// See if there's a `JSONValue::Object` next in the JSON
|
||||
@ -297,11 +296,7 @@ impl JSON {
|
||||
|
||||
// If there are numeric digits attempt to parse the digits as a number
|
||||
if n > start {
|
||||
let mut end = if n < self.chars.len() {
|
||||
n
|
||||
} else {
|
||||
max
|
||||
};
|
||||
let mut end = if n < self.chars.len() { n } else { max };
|
||||
|
||||
// Hack to remove non-number characters
|
||||
if !self.chars[end].is_ascii_digit() {
|
||||
@ -313,8 +308,8 @@ impl JSON {
|
||||
match str.parse::<f64>() {
|
||||
Ok(number) => {
|
||||
self.increment(str.len());
|
||||
return Ok(Some(JSONValue::Number(number)))
|
||||
},
|
||||
return Ok(Some(JSONValue::Number(number)));
|
||||
}
|
||||
Err(e) => Err(ParseError::ExpectedDigit(format!("'{}', {:#?}", str, e))),
|
||||
}
|
||||
} else {
|
||||
@ -488,19 +483,37 @@ mod tests {
|
||||
|
||||
// Number
|
||||
let res = JSON::parse("9.38083151965");
|
||||
assert_eq!(res, Ok(JSONValue::Number(9.38083151965)), "Failed to parse number");
|
||||
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");
|
||||
assert_eq!(
|
||||
res,
|
||||
Ok(JSONValue::String(String::from("/^$/"))),
|
||||
"Failed to parse string"
|
||||
);
|
||||
|
||||
// Number array
|
||||
let res = JSON::parse("[1, 2, 3]");
|
||||
assert_eq!(res, Ok(JSONValue::Array(vec![JSONValue::Number(1f64), JSONValue::Number(2f64), JSONValue::Number(3f64)])));
|
||||
assert_eq!(
|
||||
res,
|
||||
Ok(JSONValue::Array(vec![
|
||||
JSONValue::Number(1f64),
|
||||
JSONValue::Number(2f64),
|
||||
JSONValue::Number(3f64)
|
||||
]))
|
||||
);
|
||||
|
||||
// Object array
|
||||
let result = JSON::parse("[{}]");
|
||||
assert_eq!(result, Ok(JSONValue::Array(vec![JSONValue::Object(HashMap::new())])));
|
||||
assert_eq!(
|
||||
result,
|
||||
Ok(JSONValue::Array(vec![JSONValue::Object(HashMap::new())]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -512,8 +525,10 @@ mod tests {
|
||||
#[test]
|
||||
fn can_parse_arbitrary_json() {
|
||||
let result = JSON::parse(r#"[{ "a": 9.38083151965, "b": 4e3 }]"#);
|
||||
assert!(result.is_ok(), format!("Failed on just number values: {:#?}", result));
|
||||
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
format!("Failed on just number values: {:#?}", result)
|
||||
);
|
||||
|
||||
let result = JSON::parse(
|
||||
r#"[{
|
||||
@ -529,7 +544,8 @@ mod tests {
|
||||
}
|
||||
},
|
||||
"i": ["\"", "\\", "/", "\b", "\f", "\n", "\r", "\t", "\u0001", "\uface"]
|
||||
}]"#);
|
||||
}]"#,
|
||||
);
|
||||
assert!(result.is_ok(), format!("{:#?}", result));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user