use std::fmt::Write;
use combine::primitives::{ParseError as CombineError, Error};
use regex;
use tokenizer::TokenStream;
use {Pos};
quick_error! {
#[derive(Debug)]
pub enum ParseError wraps pub ParseErrorEnum {
InvalidSyntax(position: Pos, error: String) {
description("error parsing template")
display("{}:{}: {}", position.line, position.column, error.trim())
}
InvalidSyntaxDirective {
description("Invalid syntax directive")
}
DuplicateSyntaxDirective {
description("duplicate syntax directive")
}
UnsupportedSyntax {
description("Template must start with `## syntax: indent`")
display("Template must start with `## syntax: indent`")
}
BadRegexValidator(value: String, err: regex::Error) {
description("Validator regexp is invalid")
display("Validator regex {:?} is invalid: {}", value, err)
}
BadFilter(value: String) {
display("Filter {:?} is unknown", value)
}
}
}
impl<'a> From<CombineError<TokenStream<'a>>> for ParseError {
fn from(e: CombineError<TokenStream<'a>>) -> ParseError {
let mut buf = String::with_capacity(100);
let unexpected = e.errors.iter()
.filter(|e| {
match **e {
Error::Unexpected(_) => true,
_ => false,
}
});
for error in unexpected {
writeln!(&mut buf, "{}", error).unwrap();
}
let iter = || {
e.errors.iter()
.filter_map(|e| {
match *e {
Error::Expected(ref err) => Some(err),
_ => None,
}
})
};
let expected_count = iter().count();
for (i, message) in iter().enumerate() {
let s = match i {
0 => "Expected",
_ if i < expected_count - 1 => ",",
_ => " or",
};
write!(&mut buf, " {} `{}`", s, message).unwrap();
}
if expected_count != 0 {
writeln!(&mut buf, "").unwrap();
}
let messages = e.errors.iter()
.filter(|e| {
match **e {
Error::Message(_) |
Error::Other(_) => true,
_ => false,
}
});
for error in messages {
writeln!(&mut buf, " {}", error).unwrap();
}
ParseErrorEnum::InvalidSyntax(e.position, buf).into()
}
}