1use crate::Span;
2use std::fmt::{self, Debug, Display};
3
4#[derive(Debug, Clone)]
6pub struct Error {
7 pub kind: ErrorKind,
9 pub span: Span,
13 pub line_info: Option<(usize, usize)>,
15}
16
17impl std::error::Error for Error {}
18
19impl From<(ErrorKind, Span)> for Error {
20 fn from((kind, span): (ErrorKind, Span)) -> Self {
21 Self {
22 kind,
23 span,
24 line_info: None,
25 }
26 }
27}
28
29#[derive(Debug, Clone)]
31pub enum ErrorKind {
32 UnexpectedEof,
34
35 FileTooLarge,
37
38 InvalidCharInString(char),
40
41 InvalidEscape(char),
43
44 InvalidHexEscape(char),
46
47 InvalidEscapeValue(u32),
51
52 Unexpected(char),
55
56 UnterminatedString,
59
60 InvalidNumber,
62
63 OutOfRange(&'static str),
66
67 Wanted {
69 expected: &'static str,
71 found: &'static str,
73 },
74
75 DuplicateTable {
77 name: String,
79 first: Span,
81 },
82
83 DuplicateKey {
85 key: String,
87 first: Span,
89 },
90
91 RedefineAsArray,
93
94 MultilineStringKey,
96
97 Custom(std::borrow::Cow<'static, str>),
100
101 DottedKeyInvalidType {
103 first: Span,
105 },
106
107 UnexpectedKeys {
111 keys: Vec<(String, Span)>,
113 expected: Vec<String>,
115 },
116
117 UnquotedString,
119
120 MissingField(&'static str),
122
123 Deprecated {
125 old: &'static str,
127 new: &'static str,
129 },
130
131 UnexpectedValue {
133 expected: &'static [&'static str],
135 value: Option<String>,
137 },
138}
139
140impl Display for ErrorKind {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 match self {
143 Self::UnexpectedEof => f.write_str("unexpected-eof"),
144 Self::FileTooLarge => f.write_str("file-too-large"),
145 Self::Custom(..) => f.write_str("custom"),
146 Self::DottedKeyInvalidType { .. } => f.write_str("dotted-key-invalid-type"),
147 Self::DuplicateKey { .. } => f.write_str("duplicate-key"),
148 Self::DuplicateTable { .. } => f.write_str("duplicate-table"),
149 Self::UnexpectedKeys { .. } => f.write_str("unexpected-keys"),
150 Self::UnquotedString => f.write_str("unquoted-string"),
151 Self::MultilineStringKey => f.write_str("multiline-string-key"),
152 Self::RedefineAsArray => f.write_str("redefine-as-array"),
153 Self::InvalidCharInString(..) => f.write_str("invalid-char-in-string"),
154 Self::InvalidEscape(..) => f.write_str("invalid-escape"),
155 Self::InvalidEscapeValue(..) => f.write_str("invalid-escape-value"),
156 Self::InvalidHexEscape(..) => f.write_str("invalid-hex-escape"),
157 Self::Unexpected(..) => f.write_str("unexpected"),
158 Self::UnterminatedString => f.write_str("unterminated-string"),
159 Self::InvalidNumber => f.write_str("invalid-number"),
160 Self::OutOfRange(_) => f.write_str("out-of-range"),
161 Self::Wanted { .. } => f.write_str("wanted"),
162 Self::MissingField(..) => f.write_str("missing-field"),
163 Self::Deprecated { .. } => f.write_str("deprecated"),
164 Self::UnexpectedValue { .. } => f.write_str("unexpected-value"),
165 }
166 }
167}
168
169struct Escape(char);
170
171impl fmt::Display for Escape {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 use std::fmt::Write as _;
174
175 if self.0.is_whitespace() {
176 for esc in self.0.escape_default() {
177 f.write_char(esc)?;
178 }
179 Ok(())
180 } else {
181 f.write_char(self.0)
182 }
183 }
184}
185
186impl Display for Error {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 match &self.kind {
189 ErrorKind::UnexpectedEof => f.write_str("unexpected eof encountered")?,
190 ErrorKind::FileTooLarge => f.write_str("file is too large (maximum 4GiB)")?,
191 ErrorKind::InvalidCharInString(c) => {
192 write!(f, "invalid character in string: `{}`", Escape(*c))?;
193 }
194 ErrorKind::InvalidEscape(c) => {
195 write!(f, "invalid escape character in string: `{}`", Escape(*c))?;
196 }
197 ErrorKind::InvalidHexEscape(c) => write!(
198 f,
199 "invalid hex escape character in string: `{}`",
200 Escape(*c)
201 )?,
202 ErrorKind::InvalidEscapeValue(c) => write!(f, "invalid escape value: `{c}`")?,
203 ErrorKind::Unexpected(c) => write!(f, "unexpected character found: `{}`", Escape(*c))?,
204 ErrorKind::UnterminatedString => f.write_str("unterminated string")?,
205 ErrorKind::Wanted { expected, found } => {
206 write!(f, "expected {expected}, found {found}")?;
207 }
208 ErrorKind::InvalidNumber => f.write_str("invalid number")?,
209 ErrorKind::OutOfRange(kind) => write!(f, "out of range of '{kind}'")?,
210 ErrorKind::DuplicateTable { name, .. } => {
211 write!(f, "redefinition of table `{name}`")?;
212 }
213 ErrorKind::DuplicateKey { key, .. } => {
214 write!(f, "duplicate key: `{key}`")?;
215 }
216 ErrorKind::RedefineAsArray => f.write_str("table redefined as array")?,
217 ErrorKind::MultilineStringKey => {
218 f.write_str("multiline strings are not allowed for key")?;
219 }
220 ErrorKind::Custom(message) => f.write_str(message)?,
221 ErrorKind::DottedKeyInvalidType { .. } => {
222 f.write_str("dotted key attempted to extend non-table type")?;
223 }
224 ErrorKind::UnexpectedKeys { keys, expected } => write!(
225 f,
226 "unexpected keys in table: `{keys:?}`\nexpected: {expected:?}"
227 )?,
228 ErrorKind::UnquotedString => {
229 f.write_str("invalid TOML value, did you mean to use a quoted string?")?;
230 }
231 ErrorKind::MissingField(field) => write!(f, "missing field '{field}' in table")?,
232 ErrorKind::Deprecated { old, new } => {
233 write!(f, "field '{old}' is deprecated, '{new}' has replaced it")?;
234 }
235 ErrorKind::UnexpectedValue { expected, .. } => write!(f, "expected '{expected:?}'")?,
236 }
237
238 Ok(())
239 }
240}
241
242#[cfg(feature = "reporting")]
243#[cfg_attr(docsrs, doc(cfg(feature = "reporting")))]
244impl Error {
245 pub fn to_diagnostic<FileId: Copy + PartialEq>(
247 &self,
248 fid: FileId,
249 ) -> codespan_reporting::diagnostic::Diagnostic<FileId> {
250 let diag =
251 codespan_reporting::diagnostic::Diagnostic::error().with_code(self.kind.to_string());
252
253 use codespan_reporting::diagnostic::Label;
254
255 match &self.kind {
256 ErrorKind::DuplicateKey { first, .. } => diag.with_labels(vec![
257 Label::secondary(fid, *first).with_message("first key instance"),
258 Label::primary(fid, self.span).with_message("duplicate key"),
259 ]),
260 ErrorKind::Unexpected(c) => diag.with_labels(vec![
261 Label::primary(fid, self.span)
262 .with_message(format!("unexpected character '{}'", Escape(*c))),
263 ]),
264 ErrorKind::InvalidCharInString(c) => diag.with_labels(vec![
265 Label::primary(fid, self.span)
266 .with_message(format!("invalid character '{}' in string", Escape(*c))),
267 ]),
268 ErrorKind::InvalidEscape(c) => {
269 diag.with_labels(vec![Label::primary(fid, self.span).with_message(format!(
270 "invalid escape character '{}' in string",
271 Escape(*c)
272 ))])
273 }
274 ErrorKind::InvalidEscapeValue(_) => diag.with_labels(vec![
275 Label::primary(fid, self.span).with_message("invalid escape value"),
276 ]),
277 ErrorKind::InvalidNumber => diag.with_labels(vec![
278 Label::primary(fid, self.span).with_message("unable to parse number"),
279 ]),
280 ErrorKind::OutOfRange(kind) => diag
281 .with_message(format!("number is out of range of '{kind}'"))
282 .with_labels(vec![Label::primary(fid, self.span)]),
283 ErrorKind::Wanted { expected, .. } => diag.with_labels(vec![
284 Label::primary(fid, self.span).with_message(format!("expected {expected}")),
285 ]),
286 ErrorKind::MultilineStringKey => diag.with_labels(vec![
287 Label::primary(fid, self.span).with_message("multiline keys are not allowed"),
288 ]),
289 ErrorKind::UnterminatedString => diag.with_labels(vec![
290 Label::primary(fid, self.span).with_message("eof reached before string terminator"),
291 ]),
292 ErrorKind::DuplicateTable { first, .. } => diag.with_labels(vec![
293 Label::secondary(fid, *first).with_message("first table instance"),
294 Label::primary(fid, self.span).with_message("duplicate table"),
295 ]),
296 ErrorKind::InvalidHexEscape(c) => diag.with_labels(vec![
297 Label::primary(fid, self.span)
298 .with_message(format!("invalid hex escape '{}'", Escape(*c))),
299 ]),
300 ErrorKind::UnquotedString => diag.with_labels(vec![
301 Label::primary(fid, self.span).with_message("string is not quoted"),
302 ]),
303 ErrorKind::UnexpectedKeys { keys, expected } => diag
304 .with_message(format!(
305 "found {} unexpected keys, expected: {expected:?}",
306 keys.len()
307 ))
308 .with_labels(
309 keys.iter()
310 .map(|(_name, span)| Label::secondary(fid, *span))
311 .collect(),
312 ),
313 ErrorKind::MissingField(field) => diag
314 .with_message(format!("missing field '{field}'"))
315 .with_labels(vec![
316 Label::primary(fid, self.span).with_message("table with missing field"),
317 ]),
318 ErrorKind::Deprecated { new, .. } => diag
319 .with_message(format!(
320 "deprecated field enountered, '{new}' should be used instead"
321 ))
322 .with_labels(vec![
323 Label::primary(fid, self.span).with_message("deprecated field"),
324 ]),
325 ErrorKind::UnexpectedValue { expected, .. } => diag
326 .with_message(format!("expected '{expected:?}'"))
327 .with_labels(vec![
328 Label::primary(fid, self.span).with_message("unexpected value"),
329 ]),
330 ErrorKind::UnexpectedEof => diag
331 .with_message("unexpected end of file")
332 .with_labels(vec![Label::primary(fid, self.span)]),
333 ErrorKind::DottedKeyInvalidType { first } => {
334 diag.with_message(self.to_string()).with_labels(vec![
335 Label::primary(fid, self.span).with_message("attempted to extend table here"),
336 Label::secondary(fid, *first).with_message("non-table"),
337 ])
338 }
339 ErrorKind::RedefineAsArray => diag
340 .with_message(self.to_string())
341 .with_labels(vec![Label::primary(fid, self.span)]),
342 ErrorKind::Custom(msg) => diag
343 .with_message(msg.to_string())
344 .with_labels(vec![Label::primary(fid, self.span)]),
345 ErrorKind::FileTooLarge => diag
346 .with_message("file is too large (maximum 4GiB)")
347 .with_labels(vec![Label::primary(fid, self.span)]),
348 }
349 }
350}
351
352#[derive(Debug)]
355pub struct DeserError {
356 pub errors: Vec<Error>,
358}
359
360impl DeserError {
361 #[inline]
363 pub fn merge(&mut self, mut other: Self) {
364 self.errors.append(&mut other.errors);
365 }
366}
367
368impl std::error::Error for DeserError {}
369
370impl From<Error> for DeserError {
371 fn from(value: Error) -> Self {
372 Self {
373 errors: vec![value],
374 }
375 }
376}
377
378impl fmt::Display for DeserError {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 for err in &self.errors {
381 writeln!(f, "{err}")?;
382 }
383
384 Ok(())
385 }
386}