Line | Count | Source (jump to first uncovered line) |
1 | | //! Error management |
2 | | //! |
3 | | //! Parsers are generic over their error type, requiring that it implements |
4 | | //! the `error::ParseError<Input>` trait. |
5 | | |
6 | | use crate::internal::{Err, Mode, OutputMode, PResult, Parser}; |
7 | | use crate::lib::std::fmt; |
8 | | |
9 | | #[cfg(feature = "alloc")] |
10 | | use crate::alloc::borrow::ToOwned; |
11 | | |
12 | | #[cfg(feature = "std")] |
13 | | use crate::internal::IResult; |
14 | | |
15 | | /// This trait must be implemented by the error type of a nom parser. |
16 | | /// |
17 | | /// There are already implementations of it for `(Input, ErrorKind)` |
18 | | /// and `Error<Input>`. |
19 | | /// |
20 | | /// It provides methods to create an error from some combinators, |
21 | | /// and combine existing errors in combinators like `alt`. |
22 | | pub trait ParseError<I>: Sized { |
23 | | /// Creates an error from the input position and an [ErrorKind] |
24 | | fn from_error_kind(input: I, kind: ErrorKind) -> Self; |
25 | | |
26 | | /// Combines an existing error with a new one created from the input |
27 | | /// position and an [ErrorKind]. This is useful when backtracking |
28 | | /// through a parse tree, accumulating error context on the way |
29 | | fn append(input: I, kind: ErrorKind, other: Self) -> Self; |
30 | | |
31 | | /// Creates an error from an input position and an expected character |
32 | 37.3k | fn from_char(input: I, _: char) -> Self { |
33 | 37.3k | Self::from_error_kind(input, ErrorKind::Char) |
34 | 37.3k | } <nom::error::Error<&str> as nom::error::ParseError<&str>>::from_char Line | Count | Source | 32 | 37.3k | fn from_char(input: I, _: char) -> Self { | 33 | 37.3k | Self::from_error_kind(input, ErrorKind::Char) | 34 | 37.3k | } |
Unexecuted instantiation: <_ as nom::error::ParseError<_>>::from_char |
35 | | |
36 | | /// Combines two existing errors. This function is used to compare errors |
37 | | /// generated in various branches of `alt`. |
38 | 16.9k | fn or(self, other: Self) -> Self { |
39 | 16.9k | other |
40 | 16.9k | } <nom::error::Error<&str> as nom::error::ParseError<&str>>::or Line | Count | Source | 38 | 16.9k | fn or(self, other: Self) -> Self { | 39 | 16.9k | other | 40 | 16.9k | } |
Unexecuted instantiation: <_ as nom::error::ParseError<_>>::or |
41 | | } |
42 | | |
43 | | /// This trait is required by the `context` combinator to add a static string |
44 | | /// to an existing error |
45 | | pub trait ContextError<I>: Sized { |
46 | | /// Creates a new error from an input position, a static string and an existing error. |
47 | | /// This is used mainly in the [context] combinator, to add user friendly information |
48 | | /// to errors when backtracking through a parse tree |
49 | 0 | fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self { |
50 | 0 | other |
51 | 0 | } |
52 | | } |
53 | | |
54 | | /// This trait is required by the `map_res` combinator to integrate |
55 | | /// error types from external functions, like [std::str::FromStr] |
56 | | pub trait FromExternalError<I, E> { |
57 | | /// Creates a new error from an input position, an [ErrorKind] indicating the |
58 | | /// wrapping parser, and an external error |
59 | | fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self; |
60 | | } |
61 | | |
62 | | /// default error type, only contains the error's location and code |
63 | | #[derive(Clone, Debug, Eq, PartialEq)] |
64 | | pub struct Error<I> { |
65 | | /// position of the error in the input data |
66 | | pub input: I, |
67 | | /// nom error code |
68 | | pub code: ErrorKind, |
69 | | } |
70 | | |
71 | | impl<I> Error<I> { |
72 | | /// creates a new basic error |
73 | 0 | pub fn new(input: I, code: ErrorKind) -> Error<I> { |
74 | 0 | Error { input, code } |
75 | 0 | } Unexecuted instantiation: <nom::error::Error<&str>>::new Unexecuted instantiation: <nom::error::Error<_>>::new |
76 | | } |
77 | | |
78 | | impl<I> ParseError<I> for Error<I> { |
79 | 42.4k | fn from_error_kind(input: I, kind: ErrorKind) -> Self { |
80 | 42.4k | Error { input, code: kind } |
81 | 42.4k | } <nom::error::Error<&str> as nom::error::ParseError<&str>>::from_error_kind Line | Count | Source | 79 | 42.4k | fn from_error_kind(input: I, kind: ErrorKind) -> Self { | 80 | 42.4k | Error { input, code: kind } | 81 | 42.4k | } |
Unexecuted instantiation: <nom::error::Error<_> as nom::error::ParseError<_>>::from_error_kind |
82 | | |
83 | 16.9k | fn append(_: I, _: ErrorKind, other: Self) -> Self { |
84 | 16.9k | other |
85 | 16.9k | } <nom::error::Error<&str> as nom::error::ParseError<&str>>::append Line | Count | Source | 83 | 16.9k | fn append(_: I, _: ErrorKind, other: Self) -> Self { | 84 | 16.9k | other | 85 | 16.9k | } |
Unexecuted instantiation: <nom::error::Error<_> as nom::error::ParseError<_>>::append |
86 | | } |
87 | | |
88 | | impl<I> ContextError<I> for Error<I> {} |
89 | | |
90 | | impl<I, E> FromExternalError<I, E> for Error<I> { |
91 | | /// Create a new error from an input position and an external error |
92 | 2 | fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self { |
93 | 2 | Error { input, code: kind } |
94 | 2 | } <nom::error::Error<&str> as nom::error::FromExternalError<&str, core::num::error::ParseIntError>>::from_external_error Line | Count | Source | 92 | 2 | fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self { | 93 | 2 | Error { input, code: kind } | 94 | 2 | } |
Unexecuted instantiation: <nom::error::Error<_> as nom::error::FromExternalError<_, _>>::from_external_error |
95 | | } |
96 | | |
97 | | /// The Display implementation allows the std::error::Error implementation |
98 | | impl<I: fmt::Display> fmt::Display for Error<I> { |
99 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
100 | 0 | write!(f, "error {:?} at: {}", self.code, self.input) |
101 | 0 | } |
102 | | } |
103 | | |
104 | | #[cfg(feature = "alloc")] |
105 | | impl<I: ToOwned + ?Sized> Error<&I> { |
106 | | /// Converts `Error<&I>` into `Error<I::Owned>` by cloning. |
107 | 0 | pub fn cloned(self) -> Error<I::Owned> { |
108 | 0 | Error { |
109 | 0 | input: self.input.to_owned(), |
110 | 0 | code: self.code, |
111 | 0 | } |
112 | 0 | } |
113 | | } |
114 | | |
115 | | #[cfg(feature = "alloc")] |
116 | | impl<I: ToOwned + ?Sized> Error<&mut I> { |
117 | | /// Converts `Error<&mut I>` into `Error<I::Owned>` by cloning. |
118 | 0 | pub fn cloned(self) -> Error<I::Owned> { |
119 | 0 | Error { |
120 | 0 | input: self.input.to_owned(), |
121 | 0 | code: self.code, |
122 | 0 | } |
123 | 0 | } |
124 | | } |
125 | | |
126 | | impl<I: Copy> Error<&I> { |
127 | | /// Converts `Error<&I>` into `Error<I>` by copying. |
128 | 0 | pub fn copied(self) -> Error<I> { |
129 | 0 | Error { |
130 | 0 | input: *self.input, |
131 | 0 | code: self.code, |
132 | 0 | } |
133 | 0 | } |
134 | | } |
135 | | |
136 | | impl<I: Copy> Error<&mut I> { |
137 | | /// Converts `Error<&mut I>` into `Error<I>` by copying. |
138 | 0 | pub fn copied(self) -> Error<I> { |
139 | 0 | Error { |
140 | 0 | input: *self.input, |
141 | 0 | code: self.code, |
142 | 0 | } |
143 | 0 | } |
144 | | } |
145 | | |
146 | | #[cfg(feature = "std")] |
147 | | impl<I: fmt::Debug + fmt::Display> std::error::Error for Error<I> {} |
148 | | |
149 | | #[cfg(feature = "alloc")] |
150 | | #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] |
151 | | impl From<Error<&[u8]>> for Error<crate::lib::std::vec::Vec<u8>> { |
152 | | fn from(value: Error<&[u8]>) -> Self { |
153 | | Error { |
154 | | input: value.input.to_owned(), |
155 | | code: value.code, |
156 | | } |
157 | | } |
158 | | } |
159 | | |
160 | | #[cfg(feature = "alloc")] |
161 | | #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] |
162 | | impl From<Error<&str>> for Error<crate::lib::std::string::String> { |
163 | | fn from(value: Error<&str>) -> Self { |
164 | | Error { |
165 | | input: value.input.to_owned(), |
166 | | code: value.code, |
167 | | } |
168 | | } |
169 | | } |
170 | | |
171 | | // for backward compatibility, keep those trait implementations |
172 | | // for the previously used error type |
173 | | impl<I> ParseError<I> for (I, ErrorKind) { |
174 | 0 | fn from_error_kind(input: I, kind: ErrorKind) -> Self { |
175 | 0 | (input, kind) |
176 | 0 | } |
177 | | |
178 | 0 | fn append(_: I, _: ErrorKind, other: Self) -> Self { |
179 | 0 | other |
180 | 0 | } |
181 | | } |
182 | | |
183 | | impl<I> ContextError<I> for (I, ErrorKind) {} |
184 | | |
185 | | impl<I, E> FromExternalError<I, E> for (I, ErrorKind) { |
186 | 0 | fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self { |
187 | 0 | (input, kind) |
188 | 0 | } |
189 | | } |
190 | | |
191 | | impl<I> ParseError<I> for () { |
192 | 0 | fn from_error_kind(_: I, _: ErrorKind) -> Self {} |
193 | | |
194 | 0 | fn append(_: I, _: ErrorKind, _: Self) -> Self {} |
195 | | } |
196 | | |
197 | | impl<I> ContextError<I> for () {} |
198 | | |
199 | | impl<I, E> FromExternalError<I, E> for () { |
200 | 0 | fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {} |
201 | | } |
202 | | |
203 | | /// Creates an error from the input position and an [ErrorKind] |
204 | 0 | pub fn make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E { |
205 | 0 | E::from_error_kind(input, kind) |
206 | 0 | } |
207 | | |
208 | | /// Combines an existing error with a new one created from the input |
209 | | /// position and an [ErrorKind]. This is useful when backtracking |
210 | | /// through a parse tree, accumulating error context on the way |
211 | 0 | pub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E { |
212 | 0 | E::append(input, kind, other) |
213 | 0 | } |
214 | | |
215 | | /// Create a new error from an input position, a static string and an existing error. |
216 | | /// This is used mainly in the [context] combinator, to add user friendly information |
217 | | /// to errors when backtracking through a parse tree |
218 | 0 | pub fn context<F>(context: &'static str, parser: F) -> Context<F> { |
219 | 0 | Context { context, parser } |
220 | 0 | } |
221 | | |
222 | | /// Parser implementation for [context] |
223 | | pub struct Context<F> { |
224 | | context: &'static str, |
225 | | parser: F, |
226 | | } |
227 | | |
228 | | impl<I, F> Parser<I> for Context<F> |
229 | | where |
230 | | I: Clone, |
231 | | F: Parser<I>, |
232 | | <F as Parser<I>>::Error: ContextError<I>, |
233 | | { |
234 | | type Output = <F as Parser<I>>::Output; |
235 | | type Error = <F as Parser<I>>::Error; |
236 | | |
237 | 0 | fn process<OM: OutputMode>(&mut self, input: I) -> PResult<OM, I, Self::Output, Self::Error> { |
238 | 0 | match self.parser.process::<OM>(input.clone()) { |
239 | 0 | Err(Err::Error(e)) => Err(Err::Error(OM::Error::map(e, |e| { |
240 | 0 | <F as Parser<I>>::Error::add_context(input, self.context, e) |
241 | 0 | }))), |
242 | 0 | Err(Err::Failure(e)) => Err(Err::Failure(<F as Parser<I>>::Error::add_context( |
243 | 0 | input, |
244 | 0 | self.context, |
245 | 0 | e, |
246 | 0 | ))), |
247 | 0 | x => x, |
248 | | } |
249 | 0 | } |
250 | | } |
251 | | |
252 | | /// Indicates which parser returned an error |
253 | | #[rustfmt::skip] |
254 | | #[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)] |
255 | | #[allow(deprecated,missing_docs)] |
256 | | pub enum ErrorKind { |
257 | | Tag, |
258 | | MapRes, |
259 | | MapOpt, |
260 | | Alt, |
261 | | IsNot, |
262 | | IsA, |
263 | | SeparatedList, |
264 | | SeparatedNonEmptyList, |
265 | | Many0, |
266 | | Many1, |
267 | | ManyTill, |
268 | | Count, |
269 | | TakeUntil, |
270 | | LengthValue, |
271 | | TagClosure, |
272 | | Alpha, |
273 | | Digit, |
274 | | HexDigit, |
275 | | OctDigit, |
276 | | BinDigit, |
277 | | AlphaNumeric, |
278 | | Space, |
279 | | MultiSpace, |
280 | | LengthValueFn, |
281 | | Eof, |
282 | | Switch, |
283 | | TagBits, |
284 | | OneOf, |
285 | | NoneOf, |
286 | | Char, |
287 | | CrLf, |
288 | | RegexpMatch, |
289 | | RegexpMatches, |
290 | | RegexpFind, |
291 | | RegexpCapture, |
292 | | RegexpCaptures, |
293 | | TakeWhile1, |
294 | | Complete, |
295 | | Fix, |
296 | | Escaped, |
297 | | EscapedTransform, |
298 | | NonEmpty, |
299 | | ManyMN, |
300 | | Not, |
301 | | Permutation, |
302 | | Verify, |
303 | | TakeTill1, |
304 | | TakeWhileMN, |
305 | | TooLarge, |
306 | | Many0Count, |
307 | | Many1Count, |
308 | | Float, |
309 | | Satisfy, |
310 | | Fail, |
311 | | Many, |
312 | | Fold, |
313 | | Precedence, |
314 | | } |
315 | | |
316 | | #[rustfmt::skip] |
317 | | #[allow(deprecated)] |
318 | | /// Converts an ErrorKind to a number |
319 | | pub fn error_to_u32(e: &ErrorKind) -> u32 { |
320 | | match *e { |
321 | | ErrorKind::Tag => 1, |
322 | | ErrorKind::MapRes => 2, |
323 | | ErrorKind::MapOpt => 3, |
324 | | ErrorKind::Alt => 4, |
325 | | ErrorKind::IsNot => 5, |
326 | | ErrorKind::IsA => 6, |
327 | | ErrorKind::SeparatedList => 7, |
328 | | ErrorKind::SeparatedNonEmptyList => 8, |
329 | | ErrorKind::Many1 => 9, |
330 | | ErrorKind::Count => 10, |
331 | | ErrorKind::TakeUntil => 12, |
332 | | ErrorKind::LengthValue => 15, |
333 | | ErrorKind::TagClosure => 16, |
334 | | ErrorKind::Alpha => 17, |
335 | | ErrorKind::Digit => 18, |
336 | | ErrorKind::AlphaNumeric => 19, |
337 | | ErrorKind::Space => 20, |
338 | | ErrorKind::MultiSpace => 21, |
339 | | ErrorKind::LengthValueFn => 22, |
340 | | ErrorKind::Eof => 23, |
341 | | ErrorKind::Switch => 27, |
342 | | ErrorKind::TagBits => 28, |
343 | | ErrorKind::OneOf => 29, |
344 | | ErrorKind::NoneOf => 30, |
345 | | ErrorKind::Char => 40, |
346 | | ErrorKind::CrLf => 41, |
347 | | ErrorKind::RegexpMatch => 42, |
348 | | ErrorKind::RegexpMatches => 43, |
349 | | ErrorKind::RegexpFind => 44, |
350 | | ErrorKind::RegexpCapture => 45, |
351 | | ErrorKind::RegexpCaptures => 46, |
352 | | ErrorKind::TakeWhile1 => 47, |
353 | | ErrorKind::Complete => 48, |
354 | | ErrorKind::Fix => 49, |
355 | | ErrorKind::Escaped => 50, |
356 | | ErrorKind::EscapedTransform => 51, |
357 | | ErrorKind::NonEmpty => 56, |
358 | | ErrorKind::ManyMN => 57, |
359 | | ErrorKind::HexDigit => 59, |
360 | | ErrorKind::OctDigit => 61, |
361 | | ErrorKind::Many0 => 62, |
362 | | ErrorKind::Not => 63, |
363 | | ErrorKind::Permutation => 64, |
364 | | ErrorKind::ManyTill => 65, |
365 | | ErrorKind::Verify => 66, |
366 | | ErrorKind::TakeTill1 => 67, |
367 | | ErrorKind::TakeWhileMN => 69, |
368 | | ErrorKind::TooLarge => 70, |
369 | | ErrorKind::Many0Count => 71, |
370 | | ErrorKind::Many1Count => 72, |
371 | | ErrorKind::Float => 73, |
372 | | ErrorKind::Satisfy => 74, |
373 | | ErrorKind::Fail => 75, |
374 | | ErrorKind::Many => 76, |
375 | | ErrorKind::Fold => 77, |
376 | | ErrorKind::BinDigit => 78, |
377 | | ErrorKind::Precedence => 79, |
378 | | } |
379 | | } |
380 | | |
381 | | impl ErrorKind { |
382 | | #[rustfmt::skip] |
383 | | #[allow(deprecated)] |
384 | | /// Converts an ErrorKind to a text description |
385 | | pub fn description(&self) -> &str { |
386 | | match *self { |
387 | | ErrorKind::Tag => "Tag", |
388 | | ErrorKind::MapRes => "Map on Result", |
389 | | ErrorKind::MapOpt => "Map on Option", |
390 | | ErrorKind::Alt => "Alternative", |
391 | | ErrorKind::IsNot => "IsNot", |
392 | | ErrorKind::IsA => "IsA", |
393 | | ErrorKind::SeparatedList => "Separated list", |
394 | | ErrorKind::SeparatedNonEmptyList => "Separated non empty list", |
395 | | ErrorKind::Many0 => "Many0", |
396 | | ErrorKind::Many1 => "Many1", |
397 | | ErrorKind::Count => "Count", |
398 | | ErrorKind::TakeUntil => "Take until", |
399 | | ErrorKind::LengthValue => "Length followed by value", |
400 | | ErrorKind::TagClosure => "Tag closure", |
401 | | ErrorKind::Alpha => "Alphabetic", |
402 | | ErrorKind::Digit => "Digit", |
403 | | ErrorKind::AlphaNumeric => "AlphaNumeric", |
404 | | ErrorKind::Space => "Space", |
405 | | ErrorKind::MultiSpace => "Multiple spaces", |
406 | | ErrorKind::LengthValueFn => "LengthValueFn", |
407 | | ErrorKind::Eof => "End of file", |
408 | | ErrorKind::Switch => "Switch", |
409 | | ErrorKind::TagBits => "Tag on bitstream", |
410 | | ErrorKind::OneOf => "OneOf", |
411 | | ErrorKind::NoneOf => "NoneOf", |
412 | | ErrorKind::Char => "Char", |
413 | | ErrorKind::CrLf => "CrLf", |
414 | | ErrorKind::RegexpMatch => "RegexpMatch", |
415 | | ErrorKind::RegexpMatches => "RegexpMatches", |
416 | | ErrorKind::RegexpFind => "RegexpFind", |
417 | | ErrorKind::RegexpCapture => "RegexpCapture", |
418 | | ErrorKind::RegexpCaptures => "RegexpCaptures", |
419 | | ErrorKind::TakeWhile1 => "TakeWhile1", |
420 | | ErrorKind::Complete => "Complete", |
421 | | ErrorKind::Fix => "Fix", |
422 | | ErrorKind::Escaped => "Escaped", |
423 | | ErrorKind::EscapedTransform => "EscapedTransform", |
424 | | ErrorKind::NonEmpty => "NonEmpty", |
425 | | ErrorKind::ManyMN => "Many(m, n)", |
426 | | ErrorKind::HexDigit => "Hexadecimal Digit", |
427 | | ErrorKind::OctDigit => "Octal digit", |
428 | | ErrorKind::BinDigit => "Binary digit", |
429 | | ErrorKind::Not => "Negation", |
430 | | ErrorKind::Permutation => "Permutation", |
431 | | ErrorKind::ManyTill => "ManyTill", |
432 | | ErrorKind::Verify => "predicate verification", |
433 | | ErrorKind::TakeTill1 => "TakeTill1", |
434 | | ErrorKind::TakeWhileMN => "TakeWhileMN", |
435 | | ErrorKind::TooLarge => "Needed data size is too large", |
436 | | ErrorKind::Many0Count => "Count occurrence of >=0 patterns", |
437 | | ErrorKind::Many1Count => "Count occurrence of >=1 patterns", |
438 | | ErrorKind::Float => "Float", |
439 | | ErrorKind::Satisfy => "Satisfy", |
440 | | ErrorKind::Fail => "Fail", |
441 | | ErrorKind::Many => "Many", |
442 | | ErrorKind::Fold => "Fold", |
443 | | ErrorKind::Precedence => "Precedence", |
444 | | } |
445 | | } |
446 | | } |
447 | | |
448 | | /// Creates a parse error from a `nom::ErrorKind` |
449 | | /// and the position in the input |
450 | | #[allow(unused_variables)] |
451 | | #[macro_export(local_inner_macros)] |
452 | | macro_rules! error_position( |
453 | | ($input:expr, $code:expr $(,)?) => ({ |
454 | | $crate::error::make_error($input, $code) |
455 | | }); |
456 | | ); |
457 | | |
458 | | /// Creates a parse error from a `nom::ErrorKind`, |
459 | | /// the position in the input and the next error in |
460 | | /// the parsing tree |
461 | | #[allow(unused_variables)] |
462 | | #[macro_export(local_inner_macros)] |
463 | | macro_rules! error_node_position( |
464 | | ($input:expr, $code:expr, $next:expr $(,)?) => ({ |
465 | | $crate::error::append_error($input, $code, $next) |
466 | | }); |
467 | | ); |
468 | | |
469 | | /// Prints a message and the input if the parser fails. |
470 | | /// |
471 | | /// The message prints the `Error` or `Incomplete` |
472 | | /// and the parser's calling code. |
473 | | /// |
474 | | /// It also displays the input in hexdump format |
475 | | /// |
476 | | /// ```rust |
477 | | /// use nom::{IResult, error::dbg_dmp, bytes::complete::tag}; |
478 | | /// |
479 | | /// fn f(i: &[u8]) -> IResult<&[u8], &[u8]> { |
480 | | /// dbg_dmp(tag("abcd"), "tag")(i) |
481 | | /// } |
482 | | /// |
483 | | /// let a = &b"efghijkl"[..]; |
484 | | /// |
485 | | /// // Will print the following message: |
486 | | /// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) ' |
487 | | /// // 00000000 65 66 67 68 69 6a 6b 6c efghijkl |
488 | | /// f(a); |
489 | | /// ``` |
490 | | #[cfg(feature = "std")] |
491 | | #[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))] |
492 | 0 | pub fn dbg_dmp<'a, F, O, E: std::fmt::Debug>( |
493 | 0 | f: F, |
494 | 0 | context: &'static str, |
495 | 0 | ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E> |
496 | 0 | where |
497 | 0 | F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>, |
498 | 0 | { |
499 | | use crate::HexDisplay; |
500 | 0 | move |i: &'a [u8]| match f(i) { |
501 | 0 | Err(e) => { |
502 | 0 | println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8)); |
503 | 0 | Err(e) |
504 | | } |
505 | 0 | a => a, |
506 | 0 | } |
507 | 0 | } |
508 | | |
509 | | #[cfg(test)] |
510 | | mod tests { |
511 | | use super::*; |
512 | | |
513 | | #[test] |
514 | | fn context_test() { |
515 | | use crate::{character::char, combinator::cut, internal::Needed}; |
516 | | |
517 | | #[derive(Debug, PartialEq)] |
518 | | struct Error<I> { |
519 | | input: I, |
520 | | ctx: Option<&'static str>, |
521 | | } |
522 | | |
523 | | impl<I> ParseError<I> for Error<I> { |
524 | | fn from_error_kind(input: I, _kind: ErrorKind) -> Self { |
525 | | Self { input, ctx: None } |
526 | | } |
527 | | |
528 | | fn append(input: I, _kind: ErrorKind, other: Self) -> Self { |
529 | | Self { |
530 | | input, |
531 | | ctx: other.ctx, |
532 | | } |
533 | | } |
534 | | } |
535 | | |
536 | | impl<I> ContextError<I> for Error<I> { |
537 | | fn add_context(input: I, ctx: &'static str, _other: Self) -> Self { |
538 | | Self { |
539 | | input, |
540 | | ctx: Some(ctx), |
541 | | } |
542 | | } |
543 | | } |
544 | | |
545 | | assert_eq!( |
546 | | context("ctx", char::<_, Error<_>>('a')).parse("abcd"), |
547 | | Ok(("bcd", 'a')) |
548 | | ); |
549 | | assert_eq!( |
550 | | context("ctx", char::<_, Error<_>>('a')).parse(""), |
551 | | Err(Err::Incomplete(Needed::new(1))) |
552 | | ); |
553 | | assert_eq!( |
554 | | context("ctx", char::<_, Error<_>>('a')).parse_complete(""), |
555 | | Err(Err::Error(Error { |
556 | | input: "", |
557 | | ctx: Some("ctx") |
558 | | })) |
559 | | ); |
560 | | assert_eq!( |
561 | | context("ctx", cut(char::<_, Error<_>>('a'))).parse("bcd"), |
562 | | Err(Err::Failure(Error { |
563 | | input: "bcd", |
564 | | ctx: Some("ctx") |
565 | | })) |
566 | | ); |
567 | | } |
568 | | |
569 | | #[cfg(feature = "alloc")] |
570 | | #[test] |
571 | | fn clone_error() { |
572 | | use crate::lib::std::string::String; |
573 | | let err = Error { |
574 | | code: ErrorKind::Eof, |
575 | | input: "test", |
576 | | }; |
577 | | |
578 | | let _err: Error<String> = err.cloned(); |
579 | | } |
580 | | |
581 | | #[test] |
582 | | fn copy_error() { |
583 | | let err = Error { |
584 | | code: ErrorKind::Eof, |
585 | | input: &0_u8, |
586 | | }; |
587 | | |
588 | | let _err: Error<u8> = err.copied(); |
589 | | } |
590 | | } |
591 | | |
592 | | /* |
593 | | #[cfg(feature = "alloc")] |
594 | | use lib::std::{vec::Vec, collections::HashMap}; |
595 | | |
596 | | #[cfg(feature = "std")] |
597 | | use lib::std::hash::Hash; |
598 | | |
599 | | #[cfg(feature = "std")] |
600 | | pub fn add_error_pattern<'a, I: Clone + Hash + Eq, O, E: Clone + Hash + Eq>( |
601 | | h: &mut HashMap<VerboseError<I>, &'a str>, |
602 | | e: VerboseError<I>, |
603 | | message: &'a str, |
604 | | ) -> bool { |
605 | | h.insert(e, message); |
606 | | true |
607 | | } |
608 | | |
609 | | pub fn slice_to_offsets(input: &[u8], s: &[u8]) -> (usize, usize) { |
610 | | let start = input.as_ptr(); |
611 | | let off1 = s.as_ptr() as usize - start as usize; |
612 | | let off2 = off1 + s.len(); |
613 | | (off1, off2) |
614 | | } |
615 | | |
616 | | #[cfg(feature = "std")] |
617 | | pub fn prepare_errors<O, E: Clone>(input: &[u8], e: VerboseError<&[u8]>) -> Option<Vec<(ErrorKind, usize, usize)>> { |
618 | | let mut v: Vec<(ErrorKind, usize, usize)> = Vec::new(); |
619 | | |
620 | | for (p, kind) in e.errors.drain(..) { |
621 | | let (o1, o2) = slice_to_offsets(input, p); |
622 | | v.push((kind, o1, o2)); |
623 | | } |
624 | | |
625 | | v.reverse(); |
626 | | Some(v) |
627 | | } |
628 | | |
629 | | #[cfg(feature = "std")] |
630 | | pub fn print_error<O, E: Clone>(input: &[u8], res: VerboseError<&[u8]>) { |
631 | | if let Some(v) = prepare_errors(input, res) { |
632 | | let colors = generate_colors(&v); |
633 | | println!("parser codes: {}", print_codes(&colors, &HashMap::new())); |
634 | | println!("{}", print_offsets(input, 0, &v)); |
635 | | } else { |
636 | | println!("not an error"); |
637 | | } |
638 | | } |
639 | | |
640 | | #[cfg(feature = "std")] |
641 | | pub fn generate_colors<E>(v: &[(ErrorKind, usize, usize)]) -> HashMap<u32, u8> { |
642 | | let mut h: HashMap<u32, u8> = HashMap::new(); |
643 | | let mut color = 0; |
644 | | |
645 | | for &(ref c, _, _) in v.iter() { |
646 | | h.insert(error_to_u32(c), color + 31); |
647 | | color = color + 1 % 7; |
648 | | } |
649 | | |
650 | | h |
651 | | } |
652 | | |
653 | | pub fn code_from_offset(v: &[(ErrorKind, usize, usize)], offset: usize) -> Option<u32> { |
654 | | let mut acc: Option<(u32, usize, usize)> = None; |
655 | | for &(ref ek, s, e) in v.iter() { |
656 | | let c = error_to_u32(ek); |
657 | | if s <= offset && offset <= e { |
658 | | if let Some((_, start, end)) = acc { |
659 | | if start <= s && e <= end { |
660 | | acc = Some((c, s, e)); |
661 | | } |
662 | | } else { |
663 | | acc = Some((c, s, e)); |
664 | | } |
665 | | } |
666 | | } |
667 | | if let Some((code, _, _)) = acc { |
668 | | return Some(code); |
669 | | } else { |
670 | | return None; |
671 | | } |
672 | | } |
673 | | |
674 | | #[cfg(feature = "alloc")] |
675 | | pub fn reset_color(v: &mut Vec<u8>) { |
676 | | v.push(0x1B); |
677 | | v.push(b'['); |
678 | | v.push(0); |
679 | | v.push(b'm'); |
680 | | } |
681 | | |
682 | | #[cfg(feature = "alloc")] |
683 | | pub fn write_color(v: &mut Vec<u8>, color: u8) { |
684 | | v.push(0x1B); |
685 | | v.push(b'['); |
686 | | v.push(1); |
687 | | v.push(b';'); |
688 | | let s = color.to_string(); |
689 | | let bytes = s.as_bytes(); |
690 | | v.extend(bytes.iter().cloned()); |
691 | | v.push(b'm'); |
692 | | } |
693 | | |
694 | | #[cfg(feature = "std")] |
695 | | #[cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))] |
696 | | pub fn print_codes(colors: &HashMap<u32, u8>, names: &HashMap<u32, &str>) -> String { |
697 | | let mut v = Vec::new(); |
698 | | for (code, &color) in colors { |
699 | | if let Some(&s) = names.get(code) { |
700 | | let bytes = s.as_bytes(); |
701 | | write_color(&mut v, color); |
702 | | v.extend(bytes.iter().cloned()); |
703 | | } else { |
704 | | let s = code.to_string(); |
705 | | let bytes = s.as_bytes(); |
706 | | write_color(&mut v, color); |
707 | | v.extend(bytes.iter().cloned()); |
708 | | } |
709 | | reset_color(&mut v); |
710 | | v.push(b' '); |
711 | | } |
712 | | reset_color(&mut v); |
713 | | |
714 | | String::from_utf8_lossy(&v[..]).into_owned() |
715 | | } |
716 | | |
717 | | #[cfg(feature = "std")] |
718 | | pub fn print_offsets(input: &[u8], from: usize, offsets: &[(ErrorKind, usize, usize)]) -> String { |
719 | | let mut v = Vec::with_capacity(input.len() * 3); |
720 | | let mut i = from; |
721 | | let chunk_size = 8; |
722 | | let mut current_code: Option<u32> = None; |
723 | | let mut current_code2: Option<u32> = None; |
724 | | |
725 | | let colors = generate_colors(&offsets); |
726 | | |
727 | | for chunk in input.chunks(chunk_size) { |
728 | | let s = format!("{:08x}", i); |
729 | | for &ch in s.as_bytes().iter() { |
730 | | v.push(ch); |
731 | | } |
732 | | v.push(b'\t'); |
733 | | |
734 | | let mut k = i; |
735 | | let mut l = i; |
736 | | for &byte in chunk { |
737 | | if let Some(code) = code_from_offset(&offsets, k) { |
738 | | if let Some(current) = current_code { |
739 | | if current != code { |
740 | | reset_color(&mut v); |
741 | | current_code = Some(code); |
742 | | if let Some(&color) = colors.get(&code) { |
743 | | write_color(&mut v, color); |
744 | | } |
745 | | } |
746 | | } else { |
747 | | current_code = Some(code); |
748 | | if let Some(&color) = colors.get(&code) { |
749 | | write_color(&mut v, color); |
750 | | } |
751 | | } |
752 | | } |
753 | | v.push(CHARS[(byte >> 4) as usize]); |
754 | | v.push(CHARS[(byte & 0xf) as usize]); |
755 | | v.push(b' '); |
756 | | k = k + 1; |
757 | | } |
758 | | |
759 | | reset_color(&mut v); |
760 | | |
761 | | if chunk_size > chunk.len() { |
762 | | for _ in 0..(chunk_size - chunk.len()) { |
763 | | v.push(b' '); |
764 | | v.push(b' '); |
765 | | v.push(b' '); |
766 | | } |
767 | | } |
768 | | v.push(b'\t'); |
769 | | |
770 | | for &byte in chunk { |
771 | | if let Some(code) = code_from_offset(&offsets, l) { |
772 | | if let Some(current) = current_code2 { |
773 | | if current != code { |
774 | | reset_color(&mut v); |
775 | | current_code2 = Some(code); |
776 | | if let Some(&color) = colors.get(&code) { |
777 | | write_color(&mut v, color); |
778 | | } |
779 | | } |
780 | | } else { |
781 | | current_code2 = Some(code); |
782 | | if let Some(&color) = colors.get(&code) { |
783 | | write_color(&mut v, color); |
784 | | } |
785 | | } |
786 | | } |
787 | | if (byte >= 32 && byte <= 126) || byte >= 128 { |
788 | | v.push(byte); |
789 | | } else { |
790 | | v.push(b'.'); |
791 | | } |
792 | | l = l + 1; |
793 | | } |
794 | | reset_color(&mut v); |
795 | | |
796 | | v.push(b'\n'); |
797 | | i = i + chunk_size; |
798 | | } |
799 | | |
800 | | String::from_utf8_lossy(&v[..]).into_owned() |
801 | | } |
802 | | */ |