use std::ops::Range;
use std::{fmt, io};
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct TextPosition {
pub line: u64,
pub column: u64,
pub offset: u64,
}
#[derive(Debug, thiserror::Error)]
pub struct TurtleSyntaxError {
location: Range<TextPosition>,
message: String,
}
impl TurtleSyntaxError {
pub(crate) fn new(location: Range<TextPosition>, message: impl Into<String>) -> Self {
Self {
location,
message: message.into(),
}
}
#[inline]
pub fn location(&self) -> Range<TextPosition> {
self.location.clone()
}
#[inline]
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Display for TurtleSyntaxError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.location.start.offset + 1 >= self.location.end.offset {
write!(
f,
"Parser error at line {} column {}: {}",
self.location.start.line + 1,
self.location.start.column + 1,
self.message
)
} else if self.location.start.line == self.location.end.line {
write!(
f,
"Parser error between at line {} between columns {} and column {}: {}",
self.location.start.line + 1,
self.location.start.column + 1,
self.location.end.column + 1,
self.message
)
} else {
write!(
f,
"Parser error between line {} column {} and line {} column {}: {}",
self.location.start.line + 1,
self.location.start.column + 1,
self.location.end.line + 1,
self.location.end.column + 1,
self.message
)
}
}
}
impl From<TurtleSyntaxError> for io::Error {
#[inline]
fn from(error: TurtleSyntaxError) -> Self {
Self::new(io::ErrorKind::InvalidData, error)
}
}
#[derive(Debug, thiserror::Error)]
pub enum TurtleParseError {
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Syntax(#[from] TurtleSyntaxError),
}
impl From<TurtleParseError> for io::Error {
#[inline]
fn from(error: TurtleParseError) -> Self {
match error {
TurtleParseError::Syntax(e) => e.into(),
TurtleParseError::Io(e) => e,
}
}
}