meta_language/translation/
diagnostics.rs1use std::fmt;
9
10use serde::{Deserialize, Serialize};
11
12use super::Span;
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub enum ErrorKind {
17 Syntax,
18 Type,
19 Unsupported,
20}
21
22impl ErrorKind {
23 #[must_use]
24 pub const fn as_str(self) -> &'static str {
25 match self {
26 Self::Syntax => "syntax",
27 Self::Type => "type",
28 Self::Unsupported => "unsupported",
29 }
30 }
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
34pub struct TranslationError {
35 pub kind: ErrorKind,
36 pub reason: String,
38 pub span: Option<Span>,
39 pub construct: Option<String>,
41}
42
43impl TranslationError {
44 #[must_use]
45 pub fn new(kind: ErrorKind, reason: impl Into<String>, span: Option<Span>) -> Self {
46 Self {
47 kind,
48 reason: reason.into(),
49 span,
50 construct: None,
51 }
52 }
53
54 #[must_use]
55 pub fn syntax(reason: impl Into<String>, span: Option<Span>) -> Self {
56 Self::new(ErrorKind::Syntax, reason, span)
57 }
58
59 #[must_use]
61 pub fn message(&self) -> String {
62 self.to_string()
63 }
64}
65
66impl fmt::Display for TranslationError {
67 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
68 match self.span {
69 Some(span) => write!(formatter, "{} at {}..{}", self.reason, span.start, span.end),
70 None => formatter.write_str(&self.reason),
71 }
72 }
73}
74
75impl std::error::Error for TranslationError {}
76
77#[must_use]
79pub fn unsupported(construct: &str, reason: &str, span: Option<Span>) -> TranslationError {
80 TranslationError {
81 kind: ErrorKind::Unsupported,
82 reason: format!("{construct}: {reason}"),
83 span,
84 construct: Some(construct.to_owned()),
85 }
86}
87
88#[must_use]
89pub fn type_error(reason: impl Into<String>, span: Option<Span>) -> TranslationError {
90 TranslationError::new(ErrorKind::Type, reason, span)
91}
92
93pub type Result<T> = std::result::Result<T, TranslationError>;