use std; use std::io;
use std::result;
use std::fmt::{ self, Display, Formatter };
use std::cell::{ BorrowError, BorrowMutError };
use util::{ Diagnostic, DiagnosticKind };
use lexer::Range;
macro_rules! unreachable_error {
($msg: expr) => {
Error::Unreachable {
message: $msg,
file: file!(),
line: line!() as usize,
}
}
}
macro_rules! bug {
($msg: expr) => {
Err(unreachable_error!($msg.to_owned()))
};
($fmt: expr, $($args: tt)*) => {
Err(unreachable_error!(format!($fmt, $($args)*)))
};
}
macro_rules! lazy_bug {
($msg: expr) => {
|| unreachable_error!($msg.to_owned())
};
($fmt: expr, $($args: tt)*) => {
|| unreachable_error!(format!($fmt, $($args)*))
};
}
#[derive(Debug)]
pub enum Error {
IO(io::Error),
Borrow(BorrowError),
BorrowMut(BorrowMutError),
Strongify,
Unreachable {
message: String,
file: &'static str,
line: usize,
},
Syntax {
message: String,
range: Range,
},
Semantic {
message: String,
range: Option<Range>,
},
}
pub type Result<T> = result::Result<T, Error>;
impl Error {
pub fn pretty_print<P: AsRef<str>>(&self, wr: &mut io::Write, sources: &[P]) -> io::Result<()> {
let range = match *self {
Error::IO(_) => None,
Error::Borrow(_) => None,
Error::BorrowMut(_) => None,
Error::Strongify => None,
Error::Unreachable { .. } => None,
Error::Syntax { range, .. } => range.into(),
Error::Semantic { range, .. } => range,
};
if let Some(r) = range {
write!(
wr,
"\n\n In file {}, near {}:\n",
Diagnostic::new(sources[r.start.src_idx].as_ref(), DiagnosticKind::Highlight),
Diagnostic::new(r, DiagnosticKind::Highlight),
)?;
} else {
write!(wr, "\n\n")?;
}
write!(wr, " {}\n\n", Diagnostic::new(self, DiagnosticKind::Error))
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::IO(ref err) => err.description(),
Error::Borrow(ref err) => err.description(),
Error::BorrowMut(ref err) => err.description(),
Error::Strongify => "No strong pointer backing weak",
Error::Unreachable { ref message, .. } => message,
Error::Syntax { ref message, .. } => message,
Error::Semantic { ref message, .. } => message,
}
}
fn cause(&self) -> Option<&std::error::Error> {
match *self {
Error::IO(ref err) => Some(err),
Error::Borrow(ref err) => Some(err),
Error::BorrowMut(ref err) => Some(err),
Error::Strongify => None,
Error::Unreachable { .. } => None,
Error::Syntax { .. } => None,
Error::Semantic { .. } => None,
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Error::IO(ref err) => write!(f, "I/O error: {}", err),
Error::Borrow(ref err) => write!(
f,
"Internal Compiler Error: {}. This is a bug.",
err,
),
Error::BorrowMut(ref err) => write!(
f,
"Internal Compiler Error: {}. This is a bug.",
err,
),
Error::Strongify => write!(
f,
"Internal Compiler Error: No strong pointer backing weak. This is a bug.",
),
Error::Unreachable { ref message, file, line } => write!(
f,
"Internal Compiler Error: Reached unreachable code: {}, in file {}, line {}. This is a bug.",
message,
file,
line,
),
Error::Syntax { ref message, .. } => write!(
f, "Syntax Error: {}", message
),
Error::Semantic { ref message, .. } => write!(
f, "Semantic Error: {}", message
),
}
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Error::IO(error)
}
}
impl From<BorrowError> for Error {
fn from(error: BorrowError) -> Self {
Error::Borrow(error)
}
}
impl From<BorrowMutError> for Error {
fn from(error: BorrowMutError) -> Self {
Error::BorrowMut(error)
}
}