Skip to main content

workshop_rs/
error.rs

1//! Structured errors for the Workshop language model.
2
3use crate::catalog::Locale;
4use crate::source::Span;
5
6/// A structured Workshop-language error.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum WorkshopError {
9    /// Catalog data is malformed or fails validation.
10    Catalog(CatalogError),
11    /// A localized spelling is unknown or ambiguous.
12    Unknown {
13        kind: &'static str,
14        spelling: String,
15        locale: Locale,
16        span: Option<Span>,
17    },
18    /// A canonical builtin has no spelling mapped for the target locale.
19    ///
20    /// Missing target-locale mappings fail explicitly (never a guess, never a
21    /// silent passthrough of another locale's spelling); fallback is opt-in
22    /// ([`crate::emitter::EmitOptions`], [`crate::convert::ConvertOptions`]).
23    MissingMapping {
24        kind: &'static str,
25        id: String,
26        locale: Locale,
27    },
28    /// The input is syntactically malformed.
29    Malformed { message: String, span: Option<Span> },
30    /// A construct is recognized but outside the supported surface.
31    Unsupported { message: String, span: Option<Span> },
32}
33
34/// Catalog-specific error.
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct CatalogError {
37    pub code: &'static str,
38    pub message: String,
39}
40
41impl CatalogError {
42    pub(crate) fn malformed(message: String) -> WorkshopError {
43        WorkshopError::Catalog(CatalogError {
44            code: "malformed-catalog",
45            message,
46        })
47    }
48
49    pub(crate) fn validation(message: String) -> WorkshopError {
50        WorkshopError::Catalog(CatalogError {
51            code: "invalid-catalog",
52            message,
53        })
54    }
55}
56
57/// A crate-wide result alias.
58pub(crate) type Result<T> = std::result::Result<T, WorkshopError>;
59
60impl std::fmt::Display for WorkshopError {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        match self {
63            WorkshopError::Catalog(error) => write!(f, "{}: {}", error.code, error.message),
64            WorkshopError::Unknown {
65                kind,
66                spelling,
67                locale,
68                ..
69            } => {
70                write!(
71                    f,
72                    "unknown {kind} spelling '{spelling}' for locale '{locale}'"
73                )
74            }
75            WorkshopError::MissingMapping { kind, id, locale } => {
76                write!(f, "missing {kind} mapping for locale '{locale}': '{id}'")
77            }
78            WorkshopError::Malformed { message, .. } => write!(f, "malformed: {message}"),
79            WorkshopError::Unsupported { message, .. } => write!(f, "unsupported: {message}"),
80        }
81    }
82}