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
1 changed files with 29 additions and 28 deletions

View File

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