use std::error::Error; #[derive(Debug, Clone, Copy)] pub struct Location<'a> { pub line: usize, pub col: usize, pub file: Option<&'a str>, } #[derive(Debug, Clone)] pub struct OwnedLocation { pub line: usize, pub col: usize, pub file: Option, } impl<'a> From> for OwnedLocation { fn from(l: Location<'a>) -> OwnedLocation { OwnedLocation { line: l.line, col: l.col, file: l.file.map(|v| v.to_string()), } } } impl<'a> From<&'a OwnedLocation> for Location<'a> { fn from(l: &'a OwnedLocation) -> Location<'a> { Location { line: l.line, col: l.col, file: l.file.as_deref(), } } } pub trait ErrorWithLocation: Error { fn get_location(&self) -> Location; } #[derive(Debug)] pub struct ErrorLocationWrapper { pub inner: T, location: OwnedLocation, } impl ErrorLocationWrapper { pub fn new(inner: T, location: OwnedLocation) -> Self { Self { inner, location } } } impl ErrorWithLocation for ErrorLocationWrapper { fn get_location(&self) -> Location { (&self.location).into() } } impl std::fmt::Display for ErrorLocationWrapper { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "An error occured: {} \n On line: {}, col: {}", self.inner, self.location.line, self.location.col ) } } impl Error for ErrorLocationWrapper { fn cause(&self) -> Option<&dyn Error> { Some(&self.inner) } } impl<'a> Location<'a> { pub fn wrap(self, err: T) -> ErrorLocationWrapper { ErrorLocationWrapper::new(err, self.into()) } }