Skip to main content

nargo_types/errors/
mod.rs

1use crate::Span;
2use std::fmt;
3
4#[derive(Debug)]
5pub struct Error {
6    pub kind: Box<ErrorKind>,
7}
8
9#[derive(Debug)]
10pub enum ErrorKind {
11    Io(std::io::Error),
12    Regex(regex::Error),
13    Dialoguer(dialoguer::Error),
14    Parse { message: String, span: Span },
15    UnexpectedChar { character: char, span: Span },
16    ExpectedChar { expected: char, found: char, span: Span },
17    ExpectedString { expected: String, found: String, span: Span },
18    ExpectedOneOf { expected: Vec<String>, found: String, span: Span },
19    ExpectedClosingTag { expected: String, found: String, span: Span },
20    InvalidI18n { format: String, span: Span },
21    UnsupportedI18nFormat { format: String, span: Span },
22    NotImplemented { feature: String, span: Span },
23    ParseFloatError { source: String, span: Span },
24    UnexpectedContent { message: String, span: Span },
25    TrailingContent { span: Span },
26    ExternalError { source: String, details: String, span: Span },
27    Codegen { message: String, span: Span },
28}
29
30impl Error {
31    pub fn new(kind: ErrorKind) -> Self {
32        Self { kind: Box::new(kind) }
33    }
34
35    pub fn io_error(err: std::io::Error) -> Self {
36        Self::new(ErrorKind::Io(err))
37    }
38
39    pub fn unexpected_char(character: char, span: Span) -> Self {
40        Self::new(ErrorKind::UnexpectedChar { character, span })
41    }
42
43    pub fn expected_char(expected: char, found: char, span: Span) -> Self {
44        Self::new(ErrorKind::ExpectedChar { expected, found, span })
45    }
46
47    pub fn expected_string(expected: String, found: String, span: Span) -> Self {
48        Self::new(ErrorKind::ExpectedString { expected, found, span })
49    }
50
51    pub fn expected_one_of(expected: Vec<String>, found: String, span: Span) -> Self {
52        Self::new(ErrorKind::ExpectedOneOf { expected, found, span })
53    }
54
55    pub fn expected_closing_tag(expected: String, found: String, span: Span) -> Self {
56        Self::new(ErrorKind::ExpectedClosingTag { expected, found, span })
57    }
58
59    pub fn invalid_i18n(format: String, span: Span) -> Self {
60        Self::new(ErrorKind::InvalidI18n { format, span })
61    }
62
63    pub fn unsupported_i18n_format(format: String, span: Span) -> Self {
64        Self::new(ErrorKind::UnsupportedI18nFormat { format, span })
65    }
66
67    pub fn not_implemented(feature: String, span: Span) -> Self {
68        Self::new(ErrorKind::NotImplemented { feature, span })
69    }
70
71    pub fn parse_error(message: String, span: Span) -> Self {
72        Self::new(ErrorKind::Parse { message, span })
73    }
74
75    pub fn parse_float_error(source: String, span: Span) -> Self {
76        Self::new(ErrorKind::ParseFloatError { source, span })
77    }
78
79    pub fn trailing_content(span: Span) -> Self {
80        Self::new(ErrorKind::TrailingContent { span })
81    }
82
83    pub fn external_error(source: String, details: String, span: Span) -> Self {
84        Self::new(ErrorKind::ExternalError { source, details, span })
85    }
86
87    pub fn codegen_error(message: String, span: Span) -> Self {
88        Self::new(ErrorKind::Codegen { message, span })
89    }
90
91    pub fn regex_error(err: regex::Error) -> Self {
92        Self::new(ErrorKind::Regex(err))
93    }
94
95    pub fn dialoguer_error(err: dialoguer::Error) -> Self {
96        Self::new(ErrorKind::Dialoguer(err))
97    }
98
99    pub fn span(&self) -> Span {
100        self.kind.span()
101    }
102}
103
104impl ErrorKind {
105    pub fn span(&self) -> Span {
106        match self {
107            ErrorKind::Io(_) => Span::unknown(),
108            ErrorKind::Regex(_) => Span::unknown(),
109            ErrorKind::Dialoguer(_) => Span::unknown(),
110            ErrorKind::Parse { span, .. } => *span,
111            ErrorKind::UnexpectedChar { span, .. } => *span,
112            ErrorKind::ExpectedChar { span, .. } => *span,
113            ErrorKind::ExpectedString { span, .. } => *span,
114            ErrorKind::ExpectedOneOf { span, .. } => *span,
115            ErrorKind::ExpectedClosingTag { span, .. } => *span,
116            ErrorKind::InvalidI18n { span, .. } => *span,
117            ErrorKind::UnsupportedI18nFormat { span, .. } => *span,
118            ErrorKind::NotImplemented { span, .. } => *span,
119            ErrorKind::ParseFloatError { span, .. } => *span,
120            ErrorKind::UnexpectedContent { span, .. } => *span,
121            ErrorKind::TrailingContent { span, .. } => *span,
122            ErrorKind::ExternalError { span, .. } => *span,
123            ErrorKind::Codegen { span, .. } => *span,
124        }
125    }
126}
127
128impl fmt::Display for Error {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        match &*self.kind {
131            ErrorKind::Io(err) => write!(f, "IO error: {}", err),
132            ErrorKind::Regex(err) => write!(f, "Regex error: {}", err),
133            ErrorKind::Dialoguer(err) => write!(f, "Dialoguer error: {}", err),
134            ErrorKind::Parse { message, span } => {
135                write!(f, "Parse error: {}", message)?;
136                if !span.is_unknown() {
137                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
138                }
139                Ok(())
140            }
141            ErrorKind::UnexpectedChar { character, span } => {
142                write!(f, "Unexpected character '{}'", character)?;
143                if !span.is_unknown() {
144                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
145                }
146                Ok(())
147            }
148            ErrorKind::ExpectedChar { expected, found, span } => {
149                write!(f, "Expected '{}', found '{}'", expected, found)?;
150                if !span.is_unknown() {
151                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
152                }
153                Ok(())
154            }
155            ErrorKind::ExpectedString { expected, found, span } => {
156                write!(f, "Expected '{}', found '{}'", expected, found)?;
157                if !span.is_unknown() {
158                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
159                }
160                Ok(())
161            }
162            ErrorKind::ExpectedOneOf { expected, found, span } => {
163                write!(f, "Expected one of {:?}, found '{}'", expected, found)?;
164                if !span.is_unknown() {
165                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
166                }
167                Ok(())
168            }
169            ErrorKind::ExpectedClosingTag { expected, found, span } => {
170                write!(f, "Expected closing tag </{}>, found </{}>", expected, found)?;
171                if !span.is_unknown() {
172                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
173                }
174                Ok(())
175            }
176            ErrorKind::InvalidI18n { format, span } => {
177                write!(f, "Invalid i18n {}", format)?;
178                if !span.is_unknown() {
179                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
180                }
181                Ok(())
182            }
183            ErrorKind::UnsupportedI18nFormat { format, span } => {
184                write!(f, "Unsupported i18n format: {}", format)?;
185                if !span.is_unknown() {
186                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
187                }
188                Ok(())
189            }
190            ErrorKind::NotImplemented { feature, span } => {
191                write!(f, "{} not yet implemented", feature)?;
192                if !span.is_unknown() {
193                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
194                }
195                Ok(())
196            }
197            ErrorKind::ParseFloatError { source, span } => {
198                write!(f, "Failed to parse float: '{}'", source)?;
199                if !span.is_unknown() {
200                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
201                }
202                Ok(())
203            }
204            ErrorKind::UnexpectedContent { message, span } => {
205                write!(f, "Unexpected content: {}", message)?;
206                if !span.is_unknown() {
207                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
208                }
209                Ok(())
210            }
211            ErrorKind::TrailingContent { span } => {
212                write!(f, "Unexpected trailing content")?;
213                if !span.is_unknown() {
214                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
215                }
216                Ok(())
217            }
218            ErrorKind::ExternalError { source, details, span } => {
219                write!(f, "Error in {}: {}", source, details)?;
220                if !span.is_unknown() {
221                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
222                }
223                Ok(())
224            }
225            ErrorKind::Codegen { message, span } => {
226                write!(f, "Codegen error: {}", message)?;
227                if !span.is_unknown() {
228                    write!(f, " at {}:{}", span.start.line, span.start.column)?;
229                }
230                Ok(())
231            }
232        }
233    }
234}
235
236impl std::error::Error for Error {
237    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
238        match &*self.kind {
239            ErrorKind::Io(err) => Some(err),
240            ErrorKind::Regex(err) => Some(err),
241            ErrorKind::Dialoguer(err) => Some(err),
242            _ => None,
243        }
244    }
245}
246
247impl From<std::io::Error> for Error {
248    fn from(err: std::io::Error) -> Self {
249        Error::new(ErrorKind::Io(err))
250    }
251}
252
253impl From<regex::Error> for Error {
254    fn from(err: regex::Error) -> Self {
255        Error::new(ErrorKind::Regex(err))
256    }
257}
258
259impl From<dialoguer::Error> for Error {
260    fn from(err: dialoguer::Error) -> Self {
261        Error::new(ErrorKind::Dialoguer(err))
262    }
263}
264
265impl From<serde_json::Error> for Error {
266    fn from(err: serde_json::Error) -> Self {
267        Error::new(ErrorKind::ExternalError { source: "serde_json".to_string(), details: err.to_string(), span: Span::unknown() })
268    }
269}
270
271pub type Result<T> = std::result::Result<T, Error>;