Skip to main content

xsd_schema/compiler/
error.rs

1//! Error types for NFA compilation
2//!
3//! All errors include source locations when available for developer-friendly messages.
4
5use crate::parser::location::SourceRef;
6use thiserror::Error;
7
8/// Result type for NFA compilation operations
9pub type NfaCompileResult<T> = Result<T, NfaCompileError>;
10
11/// Errors that can occur during NFA compilation
12#[derive(Error, Debug, Clone)]
13pub enum NfaCompileError {
14    /// Group reference could not be resolved
15    #[error("unresolved group reference: {name}")]
16    UnresolvedGroupRef {
17        name: String,
18        location: Option<SourceRef>,
19    },
20
21    /// Element reference could not be resolved
22    #[error("unresolved element reference: {name}")]
23    UnresolvedElementRef {
24        name: String,
25        location: Option<SourceRef>,
26    },
27
28    /// Invalid occurrence constraint (minOccurs > maxOccurs)
29    #[error("invalid occurrence: minOccurs ({min}) > maxOccurs ({max})")]
30    InvalidOccurrence {
31        min: u32,
32        max: u32,
33        location: Option<SourceRef>,
34    },
35
36    /// All-group contains invalid content (XSD 1.0 restriction)
37    #[error("xs:all group can only contain element particles in XSD 1.0")]
38    InvalidAllGroupContent { location: Option<SourceRef> },
39
40    /// All-group has invalid occurrence constraints (XSD 1.0 restriction)
41    #[error("invalid xs:all occurrence constraint: {reason}")]
42    InvalidAllGroupOccurs {
43        reason: String,
44        location: Option<SourceRef>,
45    },
46
47    /// Recursion limit exceeded during compilation
48    #[error("recursion limit exceeded while compiling content model")]
49    RecursionLimitExceeded { location: Option<SourceRef> },
50
51    /// Empty content model (no particles to compile)
52    #[error("empty content model")]
53    EmptyContentModel { location: Option<SourceRef> },
54}
55
56impl NfaCompileError {
57    /// Create an unresolved group reference error
58    pub fn unresolved_group(name: impl Into<String>, location: Option<SourceRef>) -> Self {
59        NfaCompileError::UnresolvedGroupRef {
60            name: name.into(),
61            location,
62        }
63    }
64
65    /// Create an unresolved element reference error
66    pub fn unresolved_element(name: impl Into<String>, location: Option<SourceRef>) -> Self {
67        NfaCompileError::UnresolvedElementRef {
68            name: name.into(),
69            location,
70        }
71    }
72
73    /// Create an invalid occurrence error
74    pub fn invalid_occurrence(min: u32, max: u32, location: Option<SourceRef>) -> Self {
75        NfaCompileError::InvalidOccurrence { min, max, location }
76    }
77
78    /// Create an invalid all-group content error
79    pub fn invalid_all_group(location: Option<SourceRef>) -> Self {
80        NfaCompileError::InvalidAllGroupContent { location }
81    }
82
83    /// Create an invalid all-group occurrence error
84    pub fn invalid_all_group_occurs(
85        reason: impl Into<String>,
86        location: Option<SourceRef>,
87    ) -> Self {
88        NfaCompileError::InvalidAllGroupOccurs {
89            reason: reason.into(),
90            location,
91        }
92    }
93
94    /// Create a recursion limit exceeded error
95    pub fn recursion_exceeded(location: Option<SourceRef>) -> Self {
96        NfaCompileError::RecursionLimitExceeded { location }
97    }
98
99    /// Create an empty content model error
100    pub fn empty_content(location: Option<SourceRef>) -> Self {
101        NfaCompileError::EmptyContentModel { location }
102    }
103
104    /// Get the source location if available
105    pub fn location(&self) -> Option<&SourceRef> {
106        match self {
107            NfaCompileError::UnresolvedGroupRef { location, .. } => location.as_ref(),
108            NfaCompileError::UnresolvedElementRef { location, .. } => location.as_ref(),
109            NfaCompileError::InvalidOccurrence { location, .. } => location.as_ref(),
110            NfaCompileError::InvalidAllGroupContent { location } => location.as_ref(),
111            NfaCompileError::InvalidAllGroupOccurs { location, .. } => location.as_ref(),
112            NfaCompileError::RecursionLimitExceeded { location } => location.as_ref(),
113            NfaCompileError::EmptyContentModel { location } => location.as_ref(),
114        }
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_error_messages() {
124        let err = NfaCompileError::unresolved_group("myGroup", None);
125        assert!(err.to_string().contains("myGroup"));
126
127        let err = NfaCompileError::invalid_occurrence(5, 3, None);
128        assert!(err.to_string().contains("5"));
129        assert!(err.to_string().contains("3"));
130    }
131
132    #[test]
133    fn test_location_accessor() {
134        let err = NfaCompileError::unresolved_element("elem", None);
135        assert!(err.location().is_none());
136    }
137}