use std::result;
#[cfg(feature = "unstable")]
use proc_macro::{Diagnostic, Level};
use proc_macro2::Span;
#[cfg(not(feature = "unstable"))]
use quote::Tokens;
#[derive(Debug)]
pub struct Error {
pub code: Option<String>,
pub children: Vec<Error>,
pub kind: ErrorType, pub message: String,
pub position: Span,
}
#[derive(Debug)]
pub enum ErrorType {
Error,
Help,
Note,
Warning,
}
pub type Result<T> = result::Result<T, Vec<Error>>;
impl Error {
pub fn new(message: &str, position: Span) -> Self {
Self {
code: None,
children: vec![],
kind: ErrorType::Error,
message: message.to_string(),
position,
}
}
pub fn add_help(&mut self, message: &str) {
self.children.push(Self {
code: None,
children: vec![],
kind: ErrorType::Help,
message: message.to_string(),
position: Span::call_site(),
});
}
pub fn add_note(&mut self, message: &str) {
self.children.push(Self {
code: None,
children: vec![],
kind: ErrorType::Note,
message: message.to_string(),
position: Span::call_site(),
});
}
pub fn new_warning(message: &str, position: Span) -> Self {
Self {
code: None,
children: vec![],
kind: ErrorType::Warning,
message: message.to_string(),
position,
}
}
pub fn new_with_code(message: &str, position: Span, code: &str) -> Self {
Self {
code: Some(code.to_string()),
children: vec![],
kind: ErrorType::Error,
message: message.to_string(),
position,
}
}
#[cfg(feature = "unstable")]
pub fn emit_diagnostic(self) {
let span = self.position.unstable();
let mut diagnostic = Diagnostic::spanned(span, self.kind.into(), self.message);
for child in self.children {
let func =
match child.kind {
ErrorType::Error => Diagnostic::error,
ErrorType::Help => Diagnostic::help,
ErrorType::Note => Diagnostic::note,
ErrorType::Warning => Diagnostic::warning,
};
diagnostic = func(diagnostic, child.message);
}
diagnostic.emit();
}
#[cfg(not(feature = "unstable"))]
fn to_string(&self) -> String {
let kind =
match self.kind {
ErrorType::Error => "",
ErrorType::Help => "help: ",
ErrorType::Note => "note: ",
ErrorType::Warning => "warning: ",
};
let mut messages = format!("{}{}", kind, self.message);
for child in &self.children {
messages += &format!("\n{}", child.to_string());
}
messages
}
}
pub fn res<T>(result: T, errors: Vec<Error>) -> Result<T> {
if !errors.is_empty() {
Err(errors)
}
else {
Ok(result)
}
}
#[cfg(not(feature = "unstable"))]
pub fn compiler_error(msg: &Error) -> Tokens {
let msg = msg.to_string();
quote! {
compile_error!(#msg);
}
}
#[cfg(feature = "unstable")]
impl From<ErrorType> for Level {
fn from(error_type: ErrorType) -> Self {
match error_type {
ErrorType::Error => Level::Error,
ErrorType::Help => Level::Help,
ErrorType::Note => Level::Note,
ErrorType::Warning => Level::Warning,
}
}
}