Use a macro to cut down on the if statement boilerplate

This commit is contained in:
Timothy Warren 2020-02-11 14:06:08 -05:00
parent a3b16acb13
commit 695219de02

View File

@ -69,6 +69,19 @@ pub struct JSON {
i: usize, i: usize,
} }
/// Cut down the if boilerplate
///
/// Thanks to `uwaterloodudette` on reddit
macro_rules! try_parse {
($( $e:expr ),* ) => {
$(
if let Some(v) = $e? {
return Ok(v);
}
)*
};
}
impl JSON { impl JSON {
/// Private constructor /// Private constructor
fn new(json: &str) -> Self { fn new(json: &str) -> Self {
@ -82,34 +95,22 @@ impl JSON {
fn parse_value(&mut self) -> Result<JSONValue, ParseError> { fn parse_value(&mut self) -> Result<JSONValue, ParseError> {
self.skip_whitespace(); self.skip_whitespace();
return if let Some(string) = self.parse_string()? { // Go through the parser methods, until you find
Ok(string) // one that doesn't return a `None`
} else if let Some(number) = self.parse_number()? { try_parse!(
Ok(number) self.parse_string(),
} else if let Some(object) = self.parse_object()? { self.parse_number(),
Ok(object) self.parse_object(),
} else if let Some(array) = self.parse_array()? { self.parse_array(),
Ok(array) self.parse_keyword("true", JSONValue::True),
} else if let Some(t) = self.parse_keyword("true", JSONValue::True)? { self.parse_keyword("false", JSONValue::False),
Ok(t) self.parse_keyword("null", JSONValue::Null)
} else if let Some(f) = self.parse_keyword("false", JSONValue::False)? { );
Ok(f)
} else if let Some(n) = self.parse_keyword("null", JSONValue::Null)? { // Every parser failed, so the syntax is probably incorrect
Ok(n)
} else {
Err(ParseError::UnexpectedEndOfInput(String::from( Err(ParseError::UnexpectedEndOfInput(String::from(
"Doesn't seem to be valid JSON", "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 /// See if there's a `JSONValue::Object` next in the JSON
@ -143,7 +144,7 @@ impl JSON {
JSONValue::String(s) => s, JSONValue::String(s) => s,
_ => panic!("parse_string returned non-string value"), _ => panic!("parse_string returned non-string value"),
}, },
None => panic!("Missing object key"), None => String::new(),
}; };
self.skip_whitespace(); self.skip_whitespace();