diff options
Diffstat (limited to 'src/parser.rs')
-rw-r--r-- | src/parser.rs | 93 |
1 files changed, 58 insertions, 35 deletions
diff --git a/src/parser.rs b/src/parser.rs index 808bc62..8cba634 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,32 @@ use std::collections::BTreeMap; +use std::fmt; + +use thiserror::Error; use component::Component; use property::Property; -use error::*; + +#[derive(Debug, Clone, Error)] +pub enum ParseErrorReason { + #[error("trailing data: {}", _0)] + TrailingData(String), + #[error("expected {}, found EOL", _0)] + UnexpectedEol(char), + #[error("expected {}, found {}", _0, _1)] + UnexpectedChar(char, char), + #[error("expected EOL")] + ExpectedEol, + #[error("no property name found")] + NoPropertyName, + #[error("no parameter name found")] + NoParameterName, + #[error("expected BEGIN tag")] + ExpectedBegin, + #[error("mismatched tags: BEGIN:{} vs END:{}", _0, _1)] + MismatchedTag(String, String), +} + +type ParseResult<T> = Result<T, ParseErrorReason>; pub struct Parser<'s> { pub input: &'s str, @@ -55,16 +79,16 @@ impl<'s> Parser<'s> { self.pos >= self.input.len() } - fn assert_char(&self, c: char) -> Result<()> { + fn assert_char(&self, c: char) -> ParseResult<()> { let real_c = match self.peek() { Some((x, _)) => x, None => { - return Err(VObjectErrorKind::ParserError(format!("Expected {}, found EOL", c))) + return Err(ParseErrorReason::UnexpectedEol(c)) } }; if real_c != c { - return Err(VObjectErrorKind::ParserError(format!("Expected {}, found {}", c, real_c))) + return Err(ParseErrorReason::UnexpectedChar(c, real_c)) }; Ok(()) @@ -86,7 +110,7 @@ impl<'s> Parser<'s> { } } - fn consume_eol(&mut self) -> Result<()> { + fn consume_eol(&mut self) -> ParseResult<()> { let start_pos = self.pos; let consumed = match self.consume_char() { @@ -102,13 +126,13 @@ impl<'s> Parser<'s> { Ok(()) } else { self.pos = start_pos; - return Err(VObjectErrorKind::ParserError("Expected EOL.".to_owned())) + return Err(ParseErrorReason::ExpectedEol) } } - fn sloppy_terminate_line(&mut self) -> Result<()> { + fn sloppy_terminate_line(&mut self) -> ParseResult<()> { if !self.eof() { - try!(self.consume_eol()); + self.consume_eol()?; while let Ok(_) = self.consume_eol() {} }; @@ -150,15 +174,15 @@ impl<'s> Parser<'s> { res } - pub fn consume_property(&mut self) -> Result<Property> { + pub fn consume_property(&mut self) -> ParseResult<Property> { let group = self.consume_property_group().ok(); - let name = try!(self.consume_property_name()); + let name = self.consume_property_name()?; let params = self.consume_params(); - try!(self.assert_char(':')); + self.assert_char(':')?; self.consume_char(); - let value = try!(self.consume_property_value()); + let value = self.consume_property_value()?; Ok(Property { name: name, @@ -168,16 +192,16 @@ impl<'s> Parser<'s> { }) } - fn consume_property_name(&mut self) -> Result<String> { + fn consume_property_name(&mut self) -> ParseResult<String> { let rv = self.consume_while(|x| x == '-' || x.is_alphanumeric()); if rv.is_empty() { - Err(VObjectErrorKind::ParserError("No property name found.".to_owned())) + Err(ParseErrorReason::NoPropertyName) } else { Ok(rv) } } - fn consume_property_group(&mut self) -> Result<String> { + fn consume_property_group(&mut self) -> ParseResult<String> { let start_pos = self.pos; let name = self.consume_property_name(); @@ -196,18 +220,18 @@ impl<'s> Parser<'s> { e } - fn consume_property_value(&mut self) -> Result<String> { + fn consume_property_value(&mut self) -> ParseResult<String> { let rv = self.consume_while(|x| x != '\r' && x != '\n'); - try!(self.sloppy_terminate_line()); + self.sloppy_terminate_line()?; Ok(rv) } - fn consume_param_name(&mut self) -> Result<String> { + fn consume_param_name(&mut self) -> ParseResult<String> { self.consume_property_name() - .map_err(|e| VObjectErrorKind::ParserError(format!("No param name found: {}", e))) + .map_err(|_| ParseErrorReason::NoParameterName) } - fn consume_param_value(&mut self) -> Result<String> { + fn consume_param_value(&mut self) -> ParseResult<String> { let qsafe = |x| { x != '"' && x != '\r' && @@ -218,7 +242,7 @@ impl<'s> Parser<'s> { if self.consume_only_char('"') { let rv = self.consume_while(qsafe); - try!(self.assert_char('"')); + self.assert_char('"')?; self.consume_char(); Ok(rv) } else { @@ -226,8 +250,8 @@ impl<'s> Parser<'s> { } } - fn consume_param(&mut self) -> Result<(String, String)> { - let name = try!(self.consume_param_name()); + fn consume_param(&mut self) -> ParseResult<(String, String)> { + let name = self.consume_param_name()?; let start_pos = self.pos; let value = if self.consume_only_char('=') { match self.consume_param_value() { @@ -252,12 +276,12 @@ impl<'s> Parser<'s> { rv } - pub fn consume_component(&mut self) -> Result<Component> { + pub fn consume_component(&mut self) -> ParseResult<Component> { let start_pos = self.pos; - let mut property = try!(self.consume_property()); + let mut property = self.consume_property()?; if property.name != "BEGIN" { self.pos = start_pos; - return Err(VObjectErrorKind::ParserError("Expected BEGIN tag.".to_owned())); + return Err(ParseErrorReason::ExpectedBegin); }; // Create a component with the name of the BEGIN tag's value @@ -265,17 +289,14 @@ impl<'s> Parser<'s> { loop { let previous_pos = self.pos; - property = try!(self.consume_property()); + property = self.consume_property()?; if property.name == "BEGIN" { self.pos = previous_pos; - component.subcomponents.push(try!(self.consume_component())); + component.subcomponents.push(self.consume_component()?); } else if property.name == "END" { if property.raw_value != component.name { self.pos = start_pos; - let s = format!("Mismatched tags: BEGIN:{} vs END:{}", - component.name, - property.raw_value); - return Err(VObjectErrorKind::ParserError(s)); + return Err(ParseErrorReason::MismatchedTag(component.name, property.raw_value)); } break; @@ -290,7 +311,6 @@ impl<'s> Parser<'s> { #[cfg(test)] mod tests { - use error::*; use super::Parser; #[test] @@ -348,7 +368,7 @@ mod tests { // Test for infinite loops as well use std::sync::mpsc::{channel, RecvTimeoutError}; use std::time::Duration; - use error::VObjectErrorKind; + use super::ParseErrorReason; let mut p = Parser {input: "BEGIN:a\nBEGIN:b\nEND:a", pos: 0}; let (tx, rx) = channel(); @@ -358,7 +378,10 @@ mod tests { Err(RecvTimeoutError::Timeout) => assert!(false), Ok(Err(e)) => { match e { - VObjectErrorKind::ParserError { .. } => assert!(true), + ParseErrorReason::MismatchedTag(begin, end) => { + assert_eq!(begin, "b"); + assert_eq!(end, "a"); + }, _ => assert!(false), } }, |