1 //! An error type, [`ErrorTree`], designed to retain much more useful 2 //! information about parse failures than the built-in nom error types. 3 4 use std::{ 5 error::Error, 6 fmt::{self, Debug, Display, Formatter, Write}, 7 }; 8 9 use cascade::cascade; 10 use indent_write::fmt::IndentWriter; 11 use joinery::JoinableIterator; 12 use nom::{ 13 error::{ContextError, ErrorKind as NomErrorKind, FromExternalError, ParseError}, 14 ErrorConvert, InputLength, 15 }; 16 17 use crate::final_parser::{ExtractContext, RecreateContext}; 18 use crate::tag::TagError; 19 20 /// Enum for generic things that can be expected by nom parsers 21 /// 22 /// Certain nom parsers (think [`digit1`], [`tag`], or [`space1`]) are "base 23 /// level" in the sense that, rather than combining subparsers, they scan for a 24 /// specific character or specific kind of character. This enum tracks the 25 /// different kinds of things that can be expected by these base parses. 26 /// 27 /// Printing an expectation via [`Display`] will only include the thing that 28 /// was expected, in a form suitable for being prefixed with "expected" or 29 /// suffixed with "was expected". 30 /// 31 /// This enum is non-exhaustive; it is intended to represent everything parse 32 /// errors where we know *specifically* what was expected. For instance, 33 /// [`take_while`] cannot create an [`Expectation`], because it can't 34 /// meaningfully report what its subparser is expecting. 35 /// 36 /// [`digit1`]: nom::character::complete::digit1 37 /// [`tag`]: crate::tag::complete::tag 38 /// [`space1`]: nom::character::complete::space1 39 /// [`take_while`]: nom::bytes::complete::take_while 40 #[non_exhaustive] 41 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 42 pub enum Expectation { 43 /// A string tag was expected. 44 Tag(&'static str), 45 46 /// A specific character was expected. 47 Char(char), 48 49 /// An ASCII letter (`[a-zA-Z]`) was expected. 50 Alpha, 51 52 /// A decimal digit (`[0-9]`) was expected. 53 Digit, 54 55 /// A hexadecimal digit (`[0-9a-fA-F]`) was expected. 56 HexDigit, 57 58 /// An octal digit (`[0-7]`) was expected. 59 OctDigit, 60 61 /// An alphanumeric character (`[0-9a-zA-Z]`) was expected. 62 AlphaNumeric, 63 64 /// A space or tab was expected. 65 Space, 66 67 /// A space, tab, newline, or carriage return was expected. 68 Multispace, 69 70 /// `"\r\n"` was expected. 71 CrLf, 72 73 /// Eof was expected. 74 Eof, 75 76 /// Expected something; ie, not Eof. 77 Something, 78 } 79 80 impl Display for Expectation { fmt(&self, f: &mut Formatter<'_>) -> fmt::Result81 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 82 match *self { 83 Expectation::Tag(tag) => write!(f, "{:?}", tag), 84 Expectation::Char(c) => write!(f, "{:?}", c), 85 Expectation::Alpha => write!(f, "an ascii letter"), 86 Expectation::Digit => write!(f, "an ascii digit"), 87 Expectation::HexDigit => write!(f, "a hexadecimal digit"), 88 Expectation::OctDigit => write!(f, "an octal digit"), 89 Expectation::AlphaNumeric => write!(f, "an ascii alphanumeric character"), 90 Expectation::Space => write!(f, "a space or tab"), 91 Expectation::Multispace => write!(f, "whitespace"), 92 Expectation::Eof => write!(f, "eof"), 93 Expectation::CrLf => write!(f, "CRLF"), 94 Expectation::Something => write!(f, "not eof"), 95 } 96 } 97 } 98 99 /// These are the different specific things that can go wrong at a particular 100 /// location during a nom parse. Many of these are collected into an 101 /// [`ErrorTree`]. 102 #[derive(Debug)] 103 pub enum BaseErrorKind { 104 /// Something specific was expected, such as a specific 105 /// [character][Expectation::Char] or any [digit](Expectation::Digit). 106 /// See [`Expectation`] for details. 107 Expected(Expectation), 108 109 /// A nom parser failed. 110 Kind(NomErrorKind), 111 112 /// An error outside of nom occurred during parsing; for instance, as a 113 /// result of an error during [`map_res`]. 114 /// 115 /// [`map_res`]: crate::parser_ext::ParserExt::map_res 116 // Design note: I've gone back and forth on whether or not to exclude the 117 // ErrorKind from this variant. Right now I'm doing so, because it seems 118 // like in practice it's *always* MapRes. 119 External(Box<dyn Error + Send + Sync + 'static>), 120 } 121 122 impl Display for BaseErrorKind { fmt(&self, f: &mut Formatter<'_>) -> fmt::Result123 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 124 match *self { 125 BaseErrorKind::Expected(expectation) => write!(f, "expected {}", expectation), 126 BaseErrorKind::External(ref err) => { 127 writeln!(f, "external error:")?; 128 let mut f = IndentWriter::new(" ", f); 129 write!(f, "{}", err) 130 } 131 BaseErrorKind::Kind(kind) => write!(f, "error in {:?}", kind), 132 } 133 } 134 } 135 136 /// Context that can appear in a [stack][ErrorTree::Stack], above a base 137 /// [`ErrorTree`]. Stack contexts are attached by parser combinators to errors 138 /// from their subparsers during stack unwinding. 139 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 140 pub enum StackContext { 141 /// A nom combinator attached an [`ErrorKind`][NomErrorKind] as context 142 /// for a subparser error. 143 Kind(NomErrorKind), 144 145 /// The [`context`][crate::parser_ext::ParserExt::context] combinator 146 /// attached a message as context for a subparser error. 147 Context(&'static str), 148 } 149 150 impl Display for StackContext { fmt(&self, f: &mut Formatter<'_>) -> fmt::Result151 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 152 match *self { 153 StackContext::Kind(kind) => write!(f, "while parsing {:?}", kind), 154 StackContext::Context(ctx) => write!(f, "in section {:?}", ctx), 155 } 156 } 157 } 158 159 /// A comprehensive tree of nom errors describing a parse failure. 160 /// 161 /// This Error type is designed to be [`VerboseError`]`++`. While 162 /// [`VerboseError`] can represent a *stack* of errors, this type can represent 163 /// a full tree. In addition to representing a particular specific parse error, 164 /// it can also represent a stack of nested error contexts (for instance, as 165 /// provided by [`context`][nom::error::context]), or a list of alternatives 166 /// that were all tried individually by [`alt`][nom::branch::alt] and all 167 /// failed. 168 /// 169 /// In general, the design goal for this type is to discard as little useful 170 /// information as possible. That being said, many [`ErrorKind`] variants add 171 /// very little useful contextual information to error traces; for example, 172 /// [`ErrorKind::Alt`] doesn't add any interesting context to an 173 /// [`ErrorTree::Alt`], and its presence in a stack precludes merging together 174 /// adjacent sets of [`ErrorTree::Alt`] siblings. 175 /// 176 /// # Examples 177 /// 178 /// ## Base parser errors 179 /// 180 /// An `ErrorTree::Base` is an error that occurred at the "bottom" of the stack, 181 /// from a parser looking for 1 specific kind of thing. 182 /// 183 /// ```rust 184 /// use cool_asserts::assert_matches; 185 /// use nom::{Parser, Err}; 186 /// use nom::character::complete::{digit1, char}; 187 /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 188 /// use nom_supreme::parser_ext::ParserExt; 189 /// 190 /// let err: Err<ErrorTree<&str>> = digit1.parse("abc").unwrap_err(); 191 /// 192 /// assert_matches!(err, Err::Error(ErrorTree::Base{ 193 /// location: "abc", 194 /// kind: BaseErrorKind::Expected(Expectation::Digit), 195 /// })); 196 /// 197 /// let err: Err<ErrorTree<&str>> = char('a').and(char('b')).parse("acb").unwrap_err(); 198 /// 199 /// assert_matches!(err, Err::Error(ErrorTree::Base{ 200 /// location: "cb", 201 /// kind: BaseErrorKind::Expected(Expectation::Char('b')), 202 /// })); 203 /// ``` 204 /// 205 /// ## Stacks 206 /// 207 /// An [`ErrorTree::Stack`] is created when a parser combinator—typically 208 /// [`context`]—attaches additional error context to a subparser error. It can 209 /// have any [`ErrorTree`] at the base of the stack. 210 /// 211 /// ```rust 212 /// use cool_asserts::assert_matches; 213 /// use nom::{Parser, Err}; 214 /// use nom::character::complete::{alpha1, space1, char,}; 215 /// use nom::sequence::{separated_pair, delimited}; 216 /// use nom_supreme::parser_ext::ParserExt; 217 /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 218 /// 219 /// // Parse a single identifier, defined as just a string of letters. 220 /// let identifier = alpha1.context("identifier"); 221 /// 222 /// // Parse a pair of identifiers, separated by whitespace 223 /// let identifier_pair = separated_pair(identifier, space1, identifier) 224 /// .context("identifier pair"); 225 /// 226 /// // Parse a pair of identifiers in parenthesis. 227 /// let mut parenthesized = delimited(char('('), identifier_pair, char(')')) 228 /// .context("parenthesized"); 229 /// 230 /// let err: Err<ErrorTree<&str>> = parenthesized.parse("(abc 123)").unwrap_err(); 231 /// 232 /// assert_matches!(err, Err::Error(ErrorTree::Stack { 233 /// base, 234 /// contexts, 235 /// }) => { 236 /// assert_matches!(*base, ErrorTree::Base { 237 /// location: "123)", 238 /// kind: BaseErrorKind::Expected(Expectation::Alpha) 239 /// }); 240 /// 241 /// assert_eq!(contexts, [ 242 /// ("123)", StackContext::Context("identifier")), 243 /// ("abc 123)", StackContext::Context("identifier pair")), 244 /// ("(abc 123)", StackContext::Context("parenthesized")), 245 /// ]); 246 /// }); 247 /// ``` 248 /// 249 /// ## Alternatives 250 /// 251 /// An [`ErrorTree::Alt`] is created when a series of parsers are all tried, 252 /// and all of them fail. Most commonly this will happen via the 253 /// [`alt`][nom::branch::alt] combinator or the equivalent [`.or`] postfix 254 /// combinator. When all of these subparsers fail, their errors (each 255 /// individually their own `ErrorTree`) are aggregated into an 256 /// [`ErrorTree::Alt`], indicating that "any one of these things were 257 /// expected." 258 /// 259 /// ```rust 260 /// use cool_asserts::assert_matches; 261 /// use nom::{Parser, Err}; 262 /// use nom::branch::alt; 263 /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 264 /// use nom_supreme::parser_ext::ParserExt; 265 /// use nom_supreme::tag::complete::tag; 266 /// 267 /// let parse_bool = alt(( 268 /// tag("true").value(true), 269 /// tag("false").value(false), 270 /// )); 271 /// 272 /// let mut parse_null_bool = alt(( 273 /// parse_bool.map(Some), 274 /// tag("null").value(None), 275 /// )); 276 /// 277 /// assert_eq!(parse_null_bool.parse("true").unwrap(), ("", Some(true))); 278 /// assert_eq!(parse_null_bool.parse("false").unwrap(), ("", Some(false))); 279 /// assert_eq!(parse_null_bool.parse("null").unwrap(), ("", None)); 280 /// 281 /// let err: Err<ErrorTree<&str>> = parse_null_bool.parse("123").unwrap_err(); 282 /// 283 /// // This error communicates to the caller that any one of "true", "false", 284 /// // or "null" was expected at that location. 285 /// assert_matches!(err, Err::Error(ErrorTree::Alt(choices)) => { 286 /// assert_matches!(choices.as_slice(), [ 287 /// ErrorTree::Base { 288 /// location: "123", 289 /// kind: BaseErrorKind::Expected(Expectation::Tag("true"))}, 290 /// ErrorTree::Base { 291 /// location: "123", 292 /// kind: BaseErrorKind::Expected(Expectation::Tag("false"))}, 293 /// ErrorTree::Base { 294 /// location: "123", 295 /// kind: BaseErrorKind::Expected(Expectation::Tag("null"))}, 296 /// ]) 297 /// }); 298 /// ``` 299 /// 300 /// ## Contexts and Alternatives 301 /// 302 /// Because [`Stack`] and [`Alt`] recursively contain [`ErrorTree`] errors from 303 /// subparsers, they can be can combined to create error trees of arbitrary 304 /// complexity. 305 /// 306 /// ```rust 307 /// use cool_asserts::assert_matches; 308 /// use nom::{Parser, Err}; 309 /// use nom::branch::alt; 310 /// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation}; 311 /// use nom_supreme::parser_ext::ParserExt; 312 /// use nom_supreme::tag::complete::tag; 313 /// 314 /// let parse_bool = alt(( 315 /// tag("true").value(true), 316 /// tag("false").value(false), 317 /// )).context("bool"); 318 /// 319 /// let mut parse_null_bool = alt(( 320 /// parse_bool.map(Some), 321 /// tag("null").value(None).context("null"), 322 /// )).context("null or bool"); 323 /// 324 /// assert_eq!(parse_null_bool.parse("true").unwrap(), ("", Some(true))); 325 /// assert_eq!(parse_null_bool.parse("false").unwrap(), ("", Some(false))); 326 /// assert_eq!(parse_null_bool.parse("null").unwrap(), ("", None)); 327 /// 328 /// let err: Err<ErrorTree<&str>> = parse_null_bool.parse("123").unwrap_err(); 329 /// 330 /// assert_matches!(err, Err::Error(ErrorTree::Stack{base, contexts}) => { 331 /// assert_eq!(contexts, [("123", StackContext::Context("null or bool"))]); 332 /// assert_matches!(*base, ErrorTree::Alt(choices) => { 333 /// assert_matches!(&choices[0], ErrorTree::Stack{base, contexts} => { 334 /// assert_eq!(contexts, &[("123", StackContext::Context("bool"))]); 335 /// assert_matches!(&**base, ErrorTree::Alt(choices) => { 336 /// assert_matches!(&choices[0], ErrorTree::Base { 337 /// location: "123", 338 /// kind: BaseErrorKind::Expected(Expectation::Tag("true")) 339 /// }); 340 /// assert_matches!(&choices[1], ErrorTree::Base { 341 /// location: "123", 342 /// kind: BaseErrorKind::Expected(Expectation::Tag("false")) 343 /// }); 344 /// }); 345 /// }); 346 /// assert_matches!(&choices[1], ErrorTree::Stack{base, contexts} => { 347 /// assert_eq!(contexts, &[("123", StackContext::Context("null"))]); 348 /// assert_matches!(&**base, ErrorTree::Base { 349 /// location: "123", 350 /// kind: BaseErrorKind::Expected(Expectation::Tag("null")) 351 /// }); 352 /// }); 353 /// }); 354 /// }); 355 /// ``` 356 /// 357 /// # Display formatting 358 /// 359 /// TODO WRITE THIS SECTION 360 /// 361 /// [`.or`]: nom::Parser::or 362 /// [`Alt`]: ErrorTree::Alt 363 /// [`context`]: nom::error::context 364 /// [`ErrorKind::Alt`]: nom::error::ErrorKind::Alt 365 /// [`ErrorKind`]: nom::error::ErrorKind 366 /// [`Stack`]: ErrorTree::Stack 367 /// [`VerboseError`]: nom::error::VerboseError 368 #[derive(Debug)] 369 pub enum ErrorTree<I> { 370 /// A specific error event at a specific location. Often this will indicate 371 /// that something like a tag or character was expected at that location. 372 /// When used as part of a stack, it indicates some additional context for 373 /// the root error of the stack. 374 Base { 375 /// The location of this error in the input 376 location: I, 377 378 /// The specific error that occurred 379 kind: BaseErrorKind, 380 }, 381 382 /// A stack indicates a chain of error contexts was provided. The stack 383 /// should be read "backwards"; that is, errors *earlier* in the `Vec` 384 /// occurred "sooner" (deeper in the call stack). 385 Stack { 386 /// The original error 387 base: Box<Self>, 388 389 /// The stack of contexts attached to that error 390 contexts: Vec<(I, StackContext)>, 391 }, 392 393 /// A series of parsers were tried in order at the same location (for 394 /// instance, via the [`alt`](nom::branch::alt) combinator) and all of 395 /// them failed. All of the errors in this set are "siblings". 396 Alt(Vec<Self>), 397 // TODO: in a future version of nom-supreme, elaborate on the specific 398 // type combinations here. For instance: 399 // - Alt can only contain Stack or Base 400 // - Stack has a single Base or Alt, followed by a series of contexts 401 // (Context or Kind) 402 } 403 404 impl<I> ErrorTree<I> { 405 /// Helper for `map_locations`. Because it operates recursively, this 406 /// method uses an `&mut impl FnMut`, which can be reborrowed. map_locations_ref<T>(self, convert_location: &mut impl FnMut(I) -> T) -> ErrorTree<T>407 fn map_locations_ref<T>(self, convert_location: &mut impl FnMut(I) -> T) -> ErrorTree<T> { 408 // TODO: does the recursive nature of this function present a potential 409 // security risk? Consider replacing it with a breadth-first algorithm, 410 // or capping the maximum recursion depth. Note, though, that recursion 411 // only happens when alternating between different *kinds* of 412 // ErrorTree; nested groups of Alt or Stack are flattened. 413 match self { 414 ErrorTree::Base { location, kind } => ErrorTree::Base { 415 location: convert_location(location), 416 kind, 417 }, 418 ErrorTree::Stack { base, contexts } => ErrorTree::Stack { 419 base: Box::new(base.map_locations_ref(convert_location)), 420 contexts: contexts 421 .into_iter() 422 .map(|(location, context)| (convert_location(location), context)) 423 .collect(), 424 }, 425 ErrorTree::Alt(siblings) => ErrorTree::Alt( 426 siblings 427 .into_iter() 428 .map(|err| err.map_locations_ref(convert_location)) 429 .collect(), 430 ), 431 } 432 } 433 434 /// Convert all of the locations in this error using some kind of mapping 435 /// function. This is intended to help add additional context that may not 436 /// have been available when the nom parsers were running, such as line 437 /// and column numbers. map_locations<T>(self, mut convert_location: impl FnMut(I) -> T) -> ErrorTree<T>438 pub fn map_locations<T>(self, mut convert_location: impl FnMut(I) -> T) -> ErrorTree<T> { 439 self.map_locations_ref(&mut convert_location) 440 } 441 } 442 443 impl<I: Display> Display for ErrorTree<I> { fmt(&self, f: &mut Formatter<'_>) -> fmt::Result444 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 445 match self { 446 ErrorTree::Base { location, kind } => write!(f, "{} at {:#}", kind, location), 447 ErrorTree::Stack { contexts, base } => { 448 contexts.iter().rev().try_for_each(|(location, context)| { 449 writeln!(f, "{} at {:#},", context, location) 450 })?; 451 452 base.fmt(f) 453 } 454 ErrorTree::Alt(siblings) => { 455 writeln!(f, "one of:")?; 456 let mut f = IndentWriter::new(" ", f); 457 write!(f, "{}", siblings.iter().join_with(", or\n")) 458 } 459 } 460 } 461 } 462 463 impl<I: Display + Debug> Error for ErrorTree<I> {} 464 465 impl<I: InputLength> ParseError<I> for ErrorTree<I> { 466 /// Create a new error at the given position. Interpret `kind` as an 467 /// [`Expectation`] if possible, to give a more informative error message. from_error_kind(location: I, kind: NomErrorKind) -> Self468 fn from_error_kind(location: I, kind: NomErrorKind) -> Self { 469 let kind = match kind { 470 NomErrorKind::Alpha => BaseErrorKind::Expected(Expectation::Alpha), 471 NomErrorKind::Digit => BaseErrorKind::Expected(Expectation::Digit), 472 NomErrorKind::HexDigit => BaseErrorKind::Expected(Expectation::HexDigit), 473 NomErrorKind::OctDigit => BaseErrorKind::Expected(Expectation::OctDigit), 474 NomErrorKind::AlphaNumeric => BaseErrorKind::Expected(Expectation::AlphaNumeric), 475 NomErrorKind::Space => BaseErrorKind::Expected(Expectation::Space), 476 NomErrorKind::MultiSpace => BaseErrorKind::Expected(Expectation::Multispace), 477 NomErrorKind::CrLf => BaseErrorKind::Expected(Expectation::CrLf), 478 479 // Problem: ErrorKind::Eof is used interchangeably by various nom 480 // parsers to mean either "expected Eof" or "expected NOT eof". See 481 // https://github.com/Geal/nom/issues/1259. For now, we examine the 482 // input string to guess what the likely intention is. 483 NomErrorKind::Eof => match location.input_len() { 484 // The input is at Eof, which means that this refers to an 485 // *unexpected* eof. 486 0 => BaseErrorKind::Expected(Expectation::Something), 487 488 // The input is *not* at eof, which means that this refers to 489 // an *expected* eof. 490 _ => BaseErrorKind::Expected(Expectation::Eof), 491 }, 492 kind => BaseErrorKind::Kind(kind), 493 }; 494 495 ErrorTree::Base { location, kind } 496 } 497 498 /// Combine an existing error with a new one. This is how error context is 499 /// accumulated when backtracing. "other" is the original error, and the 500 /// inputs new error from higher in the call stack. 501 /// 502 /// If `other` is already an `ErrorTree::Stack`, the context is added to 503 /// the stack; otherwise, a new stack is created, with `other` at the root. append(location: I, kind: NomErrorKind, other: Self) -> Self504 fn append(location: I, kind: NomErrorKind, other: Self) -> Self { 505 let context = (location, StackContext::Kind(kind)); 506 507 match other { 508 // Don't create a stack of [ErrorKind::Alt, ErrorTree::Alt(..)] 509 alt @ ErrorTree::Alt(..) if kind == NomErrorKind::Alt => alt, 510 511 // This is already a stack, so push on to it 512 ErrorTree::Stack { contexts, base } => ErrorTree::Stack { 513 base, 514 contexts: cascade! { 515 contexts; 516 ..push(context); 517 }, 518 }, 519 520 // This isn't a stack; create a new stack 521 base => ErrorTree::Stack { 522 base: Box::new(base), 523 contexts: vec![context], 524 }, 525 } 526 } 527 528 /// Create an error indicating an expected character at a given position from_char(location: I, character: char) -> Self529 fn from_char(location: I, character: char) -> Self { 530 ErrorTree::Base { 531 location, 532 kind: BaseErrorKind::Expected(Expectation::Char(character)), 533 } 534 } 535 536 /// Combine two errors from branches of alt. If either or both errors are 537 /// already [`ErrorTree::Alt`], the different error sets are merged; 538 /// otherwise, a new [`ErrorTree::Alt`] is created, containing both 539 /// `self` and `other`. or(self, other: Self) -> Self540 fn or(self, other: Self) -> Self { 541 // For now we assume that there's no need to try and preserve 542 // left-to-right ordering of alternatives. 543 let siblings = match (self, other) { 544 (ErrorTree::Alt(siblings1), ErrorTree::Alt(siblings2)) => { 545 match siblings1.capacity() >= siblings2.capacity() { 546 true => cascade! {siblings1; ..extend(siblings2);}, 547 false => cascade! {siblings2; ..extend(siblings1);}, 548 } 549 } 550 (ErrorTree::Alt(siblings), err) | (err, ErrorTree::Alt(siblings)) => cascade! { 551 siblings; 552 ..push(err); 553 }, 554 (err1, err2) => vec![err1, err2], 555 }; 556 557 ErrorTree::Alt(siblings) 558 } 559 } 560 561 impl<I> ContextError<I> for ErrorTree<I> { 562 /// Similar to append: Create a new error with some added context add_context(location: I, ctx: &'static str, other: Self) -> Self563 fn add_context(location: I, ctx: &'static str, other: Self) -> Self { 564 let context = (location, StackContext::Context(ctx)); 565 566 match other { 567 // This is already a stack, so push on to it 568 ErrorTree::Stack { contexts, base } => ErrorTree::Stack { 569 base, 570 contexts: cascade! { 571 contexts; 572 ..push(context); 573 }, 574 }, 575 576 // This isn't a stack, create a new stack 577 base => ErrorTree::Stack { 578 base: Box::new(base), 579 contexts: vec![context], 580 }, 581 } 582 } 583 } 584 585 impl<I, E: Error + Send + Sync + 'static> FromExternalError<I, E> for ErrorTree<I> { 586 /// Create an error from a given external error, such as from FromStr from_external_error(location: I, _kind: NomErrorKind, e: E) -> Self587 fn from_external_error(location: I, _kind: NomErrorKind, e: E) -> Self { 588 ErrorTree::Base { 589 location, 590 kind: BaseErrorKind::External(Box::new(e)), 591 } 592 } 593 } 594 595 impl<I> TagError<I, &'static str> for ErrorTree<I> { from_tag(location: I, tag: &'static str) -> Self596 fn from_tag(location: I, tag: &'static str) -> Self { 597 ErrorTree::Base { 598 location, 599 kind: BaseErrorKind::Expected(Expectation::Tag(tag)), 600 } 601 } 602 } 603 604 impl<I> ErrorConvert<ErrorTree<(I, usize)>> for ErrorTree<I> { convert(self) -> ErrorTree<(I, usize)>605 fn convert(self) -> ErrorTree<(I, usize)> { 606 self.map_locations(|location| (location, 0)) 607 } 608 } 609 610 impl<I> ErrorConvert<ErrorTree<I>> for ErrorTree<(I, usize)> { convert(self) -> ErrorTree<I>611 fn convert(self) -> ErrorTree<I> { 612 self.map_locations(move |(location, _offset)| location) 613 } 614 } 615 616 impl<I, T> ExtractContext<I, ErrorTree<T>> for ErrorTree<I> 617 where 618 I: Clone, 619 T: RecreateContext<I>, 620 { extract_context(self, original_input: I) -> ErrorTree<T>621 fn extract_context(self, original_input: I) -> ErrorTree<T> { 622 self.map_locations(move |location| T::recreate_context(original_input.clone(), location)) 623 } 624 } 625 626 #[cfg(test)] 627 mod tests { 628 use super::*; 629 630 use nom::{ 631 bits::{bits, complete::take}, 632 sequence::tuple, 633 IResult, Parser, 634 }; 635 636 type BitInput<'a> = (&'a [u8], usize); 637 parse_bool_bit(input: (&[u8], usize)) -> IResult<BitInput, bool, ErrorTree<BitInput>>638 fn parse_bool_bit(input: (&[u8], usize)) -> IResult<BitInput, bool, ErrorTree<BitInput>> { 639 take(1usize).map(|bit: u8| bit != 0).parse(input) 640 } 641 642 type Byte = (bool, bool, bool, bool, bool, bool, bool, bool); 643 644 /// Parse 8 bits parse_bits(input: &[u8]) -> IResult<&[u8], Byte, ErrorTree<&[u8]>>645 fn parse_bits(input: &[u8]) -> IResult<&[u8], Byte, ErrorTree<&[u8]>> { 646 bits(tuple(( 647 parse_bool_bit, 648 parse_bool_bit, 649 parse_bool_bit, 650 parse_bool_bit, 651 parse_bool_bit, 652 parse_bool_bit, 653 parse_bool_bit, 654 parse_bool_bit, 655 ))) 656 .parse(input) 657 } 658 659 /// Test that ErrorTree can be used with a bits parser, which requires 660 /// ErrorConvert 661 #[test] error_tree_bits()662 fn error_tree_bits() { 663 let values = [0b1010_1111, 10]; 664 let (tail, result) = parse_bits(&values).unwrap(); 665 666 assert_eq!(tail, &[10]); 667 assert_eq!(result, (true, false, true, false, true, true, true, true)); 668 } 669 } 670