summaryrefslogtreecommitdiffstats
path: root/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs93
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),
}
},