blob: 785afa392b40e233e7ac6189f67c1c148e6f49dd [file] [log] [blame]
use combine::easy::Errors as ParseError;
use combine::stream::easy::Error;
use combine::stream::position::SourcePosition;
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result};
/// Type representing a TOML parse error
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TomlError {
message: String,
}
impl TomlError {
pub(crate) fn new(error: ParseError<char, &str, SourcePosition>, input: &str) -> Self {
Self {
message: format!("{}", FancyError::new(error, input)),
}
}
pub(crate) fn from_unparsed(pos: SourcePosition, input: &str) -> Self {
Self::new(
ParseError::new(pos, CustomError::UnparsedLine.into()),
input,
)
}
}
/// Displays a TOML parse error
///
/// # Example
///
/// TOML parse error at line 1, column 10
/// |
/// 1 | 00:32:00.a999999
/// | ^
/// Unexpected `a`
/// Expected `digit`
/// While parsing a Time
/// While parsing a Date-Time
impl Display for TomlError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{}", self.message)
}
}
impl StdError for TomlError {
fn description(&self) -> &'static str {
"TOML parse error"
}
}
#[derive(Debug)]
pub(crate) struct FancyError<'a> {
error: ParseError<char, &'a str, SourcePosition>,
input: &'a str,
}
impl<'a> FancyError<'a> {
pub(crate) fn new(error: ParseError<char, &'a str, SourcePosition>, input: &'a str) -> Self {
Self { error, input }
}
}
impl<'a> Display for FancyError<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let SourcePosition { line, column } = self.error.position;
let offset = line.to_string().len();
let content = self
.input
.split('\n')
.nth((line - 1) as usize)
.expect("line");
writeln!(f, "TOML parse error at line {}, column {}", line, column)?;
// |
for _ in 0..=offset {
write!(f, " ")?;
}
writeln!(f, "|")?;
// 1 | 00:32:00.a999999
write!(f, "{} | ", line)?;
writeln!(f, "{}", content)?;
// | ^
for _ in 0..=offset {
write!(f, " ")?;
}
write!(f, "|")?;
for _ in 0..column {
write!(f, " ")?;
}
writeln!(f, "^")?;
Error::fmt_errors(self.error.errors.as_ref(), f)
}
}
#[derive(Debug, Clone)]
pub enum CustomError {
MixedArrayType { got: String, expected: String },
DuplicateKey { key: String, table: String },
InvalidHexEscape(u32),
UnparsedLine,
}
impl StdError for CustomError {
fn description(&self) -> &'static str {
"TOML parse error"
}
}
impl Display for CustomError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match *self {
CustomError::MixedArrayType {
ref got,
ref expected,
} => {
writeln!(f, "Mixed types in array: {} and {}", expected, got)
}
CustomError::DuplicateKey { ref key, ref table } => {
writeln!(f, "Duplicate key `{}` in `{}` table", key, table)
}
CustomError::InvalidHexEscape(ref h) => {
writeln!(f, "Invalid hex escape code: {:x} ", h)
}
CustomError::UnparsedLine => writeln!(f, "Could not parse the line"),
}
}
}