| 1 | #![cfg_attr (feature = "debug" , allow(clippy::std_instead_of_core))] |
| 2 | |
| 3 | #[cfg (feature = "debug" )] |
| 4 | mod internals; |
| 5 | |
| 6 | use crate::error::ErrMode; |
| 7 | use crate::stream::Stream; |
| 8 | use crate::Parser; |
| 9 | |
| 10 | #[cfg (all(feature = "debug" , not(feature = "std" )))] |
| 11 | compile_error!("`debug` requires `std`" ); |
| 12 | |
| 13 | /// Trace the execution of the parser |
| 14 | /// |
| 15 | /// Note that [`Parser::context`] also provides high level trace information. |
| 16 | /// |
| 17 | /// See [tutorial][crate::_tutorial::chapter_8] for more details. |
| 18 | /// |
| 19 | /// # Example |
| 20 | /// |
| 21 | /// ```rust |
| 22 | /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; |
| 23 | /// # use winnow::token::take_while; |
| 24 | /// # use winnow::stream::AsChar; |
| 25 | /// # use winnow::prelude::*; |
| 26 | /// use winnow::combinator::trace; |
| 27 | /// |
| 28 | /// fn short_alpha<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> { |
| 29 | /// trace("short_alpha" , |
| 30 | /// take_while(3..=6, AsChar::is_alpha) |
| 31 | /// ).parse_next(s) |
| 32 | /// } |
| 33 | /// |
| 34 | /// assert_eq!(short_alpha.parse_peek(b"latin123" ), Ok((&b"123" [..], &b"latin" [..]))); |
| 35 | /// assert_eq!(short_alpha.parse_peek(b"lengthy" ), Ok((&b"y" [..], &b"length" [..]))); |
| 36 | /// assert_eq!(short_alpha.parse_peek(b"latin" ), Ok((&b"" [..], &b"latin" [..]))); |
| 37 | /// assert_eq!(short_alpha.parse_peek(b"ed" ), Err(ErrMode::Backtrack(InputError::new(&b"ed" [..], ErrorKind::Slice)))); |
| 38 | /// assert_eq!(short_alpha.parse_peek(b"12345" ), Err(ErrMode::Backtrack(InputError::new(&b"12345" [..], ErrorKind::Slice)))); |
| 39 | /// ``` |
| 40 | #[cfg_attr (not(feature = "debug" ), allow(unused_variables))] |
| 41 | #[cfg_attr (not(feature = "debug" ), allow(unused_mut))] |
| 42 | #[cfg_attr (not(feature = "debug" ), inline(always))] |
| 43 | pub fn trace<I: Stream, O, E>( |
| 44 | name: impl crate::lib::std::fmt::Display, |
| 45 | parser: impl Parser<I, O, E>, |
| 46 | ) -> impl Parser<I, O, E> { |
| 47 | #[cfg (feature = "debug" )] |
| 48 | { |
| 49 | internals::Trace::new(parser, name) |
| 50 | } |
| 51 | #[cfg (not(feature = "debug" ))] |
| 52 | { |
| 53 | parser |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | #[cfg_attr (not(feature = "debug" ), allow(unused_variables))] |
| 58 | pub(crate) fn trace_result<T, E>( |
| 59 | name: impl crate::lib::std::fmt::Display, |
| 60 | res: &Result<T, ErrMode<E>>, |
| 61 | ) { |
| 62 | #[cfg (feature = "debug" )] |
| 63 | { |
| 64 | let depth = internals::Depth::existing(); |
| 65 | let severity = internals::Severity::with_result(res); |
| 66 | internals::result(*depth, &name, severity); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | #[test ] |
| 71 | #[cfg (feature = "std" )] |
| 72 | #[cfg_attr (miri, ignore)] |
| 73 | #[cfg (unix)] |
| 74 | #[cfg (feature = "debug" )] |
| 75 | fn example() { |
| 76 | use term_transcript::{test::TestConfig, ShellOptions}; |
| 77 | |
| 78 | let path = snapbox::cmd::compile_example("string" , ["--features=debug" ]).unwrap(); |
| 79 | |
| 80 | let current_dir = path.parent().unwrap(); |
| 81 | let cmd = path.file_name().unwrap(); |
| 82 | // HACK: term_transcript doesn't allow non-UTF8 paths |
| 83 | let cmd = format!("./{}" , cmd.to_string_lossy()); |
| 84 | |
| 85 | TestConfig::new( |
| 86 | ShellOptions::default() |
| 87 | .with_current_dir(current_dir) |
| 88 | .with_env("CLICOLOR_FORCE" , "1" ), |
| 89 | ) |
| 90 | .test("assets/trace.svg" , [cmd.as_str()]); |
| 91 | } |
| 92 | |