use super::loc::Loc;
use std::error;
use std::fmt;
pub type ParseResult<A> = Result<A, ParseError>;
#[derive(Debug)]
pub enum ParseError {
Internal {
loc: Loc,
msg: String,
},
Unimplemented {
loc: Loc,
thing: String,
},
Io {
loc: Loc,
cause: std::io::Error,
},
Syntax {
loc: Loc,
msg: String,
},
Unexpected {
loc: Loc,
expected: String,
found: String,
},
Error {
loc: Loc,
cause: Box<dyn std::error::Error>,
},
NotFound {
loc: Loc,
what: String,
},
}
impl ParseError {
pub fn loc(&self) -> &Loc {
match self {
ParseError::Error { loc, .. } => loc,
ParseError::Internal { loc, .. } => loc,
ParseError::Io { loc, .. } => loc,
ParseError::NotFound { loc, .. } => loc,
ParseError::Syntax { loc, .. } => loc,
ParseError::Unexpected { loc, .. } => loc,
ParseError::Unimplemented { loc, .. } => loc,
}
}
}
impl error::Error for ParseError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
Self::Io { ref cause, .. } => Some(cause),
_ => None,
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, form: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Internal { loc, msg } => {
write!(form, "{}: Internal Error: {}", loc, msg)
}
Self::Unimplemented { loc, thing } => {
write!(form, "{}: Not Implemented: {}", loc, thing)
}
Self::Io { loc, cause } => {
write!(form, "{}: I/O Error: {}", loc, cause)
}
Self::Syntax { loc, msg } => {
write!(form, "{}: Syntax Error: {}", loc, msg)
}
Self::Unexpected {
loc,
expected,
found,
} => {
write!(form, "{}: Expected {}, but found {}", loc, expected, found)
}
Self::Error { loc, cause: err } => {
write!(form, "{}: {}", loc, err)
}
Self::NotFound { loc, what } => {
write!(form, "{}: Could not find {}", loc, what)
}
}
}
}
pub fn unexpected_eof_error(loc: Loc) -> ParseError {
let ioe = std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "Unexpected end of file");
ParseError::Io { loc, cause: ioe }
}
pub fn syntax_error(loc: Loc, msg: &str) -> ParseError {
ParseError::Syntax {
msg: msg.to_string(),
loc,
}
}
pub fn unexpected_text_error(loc: Loc, expected: &str, found: &str) -> ParseError {
ParseError::Unexpected {
loc,
expected: expected.to_owned(),
found: found.to_owned(),
}
}
pub fn unexpected_character_error(loc: Loc, expected: &str, found: char) -> ParseError {
ParseError::Unexpected {
loc,
expected: expected.to_owned(),
found: format!("'{}'", found),
}
}
pub fn internal_error(loc: Loc, msg: &str) -> ParseError {
ParseError::Internal {
msg: msg.to_owned(),
loc,
}
}
pub fn not_found_error(loc: Loc, what: &str) -> ParseError {
ParseError::NotFound {
loc,
what: what.to_owned(),
}
}
pub fn io_error(loc: Loc, cause: std::io::Error) -> ParseError {
ParseError::Io { loc, cause }
}
pub fn unimplemented_error(loc: Loc, thing: &str) -> ParseError {
ParseError::Unimplemented {
loc,
thing: thing.to_owned(),
}
}
pub fn error<E>(loc: Loc, err: E) -> ParseError
where
E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
let err = std::io::Error::new(std::io::ErrorKind::Other, err);
ParseError::Error {
loc,
cause: Box::new(err),
}
}