use std::fmt;
use serde::{Deserialize, Serialize};
use super::Span;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ErrorKind {
Syntax,
Type,
Unsupported,
}
impl ErrorKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Syntax => "syntax",
Self::Type => "type",
Self::Unsupported => "unsupported",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TranslationError {
pub kind: ErrorKind,
pub reason: String,
pub span: Option<Span>,
pub construct: Option<String>,
}
impl TranslationError {
#[must_use]
pub fn new(kind: ErrorKind, reason: impl Into<String>, span: Option<Span>) -> Self {
Self {
kind,
reason: reason.into(),
span,
construct: None,
}
}
#[must_use]
pub fn syntax(reason: impl Into<String>, span: Option<Span>) -> Self {
Self::new(ErrorKind::Syntax, reason, span)
}
#[must_use]
pub fn message(&self) -> String {
self.to_string()
}
}
impl fmt::Display for TranslationError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.span {
Some(span) => write!(formatter, "{} at {}..{}", self.reason, span.start, span.end),
None => formatter.write_str(&self.reason),
}
}
}
impl std::error::Error for TranslationError {}
#[must_use]
pub fn unsupported(construct: &str, reason: &str, span: Option<Span>) -> TranslationError {
TranslationError {
kind: ErrorKind::Unsupported,
reason: format!("{construct}: {reason}"),
span,
construct: Some(construct.to_owned()),
}
}
#[must_use]
pub fn type_error(reason: impl Into<String>, span: Option<Span>) -> TranslationError {
TranslationError::new(ErrorKind::Type, reason, span)
}
pub type Result<T> = std::result::Result<T, TranslationError>;