chumsky/
debug.rs

1//! Utilities for debugging parsers.
2//!
3//! *“He was staring at the instruments with the air of one who is trying to convert Fahrenheit to centigrade in his
4//! head while his house is burning down.”*
5
6use super::*;
7
8use alloc::borrow::Cow;
9use core::panic::Location;
10
11/// Information about a specific parser.
12#[allow(dead_code)]
13pub struct ParserInfo {
14    name: Cow<'static, str>,
15    display: Rc<dyn fmt::Display>,
16    location: Location<'static>,
17}
18
19impl ParserInfo {
20    pub(crate) fn new(
21        name: impl Into<Cow<'static, str>>,
22        display: Rc<dyn fmt::Display>,
23        location: Location<'static>,
24    ) -> Self {
25        Self {
26            name: name.into(),
27            display,
28            location,
29        }
30    }
31}
32
33/// An event that occurred during parsing.
34pub enum ParseEvent {
35    /// Debugging information was emitted.
36    Info(String),
37}
38
39/// A trait implemented by parser debuggers.
40#[deprecated(
41    note = "This trait is excluded from the semver guarantees of chumsky. If you decide to use it, broken builds are your fault."
42)]
43pub trait Debugger {
44    /// Create a new debugging scope.
45    fn scope<R, Info: FnOnce() -> ParserInfo, F: FnOnce(&mut Self) -> R>(
46        &mut self,
47        info: Info,
48        f: F,
49    ) -> R;
50    /// Emit a parse event, if the debugger supports them.
51    fn emit_with<F: FnOnce() -> ParseEvent>(&mut self, f: F);
52    /// Invoke the given parser with a mode specific to this debugger.
53    fn invoke<I: Clone, O, P: Parser<I, O> + ?Sized>(
54        &mut self,
55        parser: &P,
56        stream: &mut StreamOf<I, P::Error>,
57    ) -> PResult<I, O, P::Error>;
58}
59
60/// A verbose debugger that emits debugging messages to the console.
61pub struct Verbose {
62    // TODO: Don't use `Result`, that's silly
63    events: Vec<Result<ParseEvent, (ParserInfo, Self)>>,
64}
65
66impl Verbose {
67    pub(crate) fn new() -> Self {
68        Self { events: Vec::new() }
69    }
70
71    #[allow(unused_variables)]
72    fn print_inner(&self, depth: usize) {
73        // a no-op on no_std!
74        #[cfg(feature = "std")]
75        for event in &self.events {
76            for _ in 0..depth * 4 {
77                print!(" ");
78            }
79            match event {
80                Ok(ParseEvent::Info(s)) => println!("{}", s),
81                Err((info, scope)) => {
82                    println!(
83                        "Entered {} at line {} in {}",
84                        info.display,
85                        info.location.line(),
86                        info.location.file()
87                    );
88                    scope.print_inner(depth + 1);
89                }
90            }
91        }
92    }
93
94    pub(crate) fn print(&self) {
95        self.print_inner(0)
96    }
97}
98
99impl Debugger for Verbose {
100    fn scope<R, Info: FnOnce() -> ParserInfo, F: FnOnce(&mut Self) -> R>(
101        &mut self,
102        info: Info,
103        f: F,
104    ) -> R {
105        let mut verbose = Verbose { events: Vec::new() };
106        let res = f(&mut verbose);
107        self.events.push(Err((info(), verbose)));
108        res
109    }
110
111    fn emit_with<F: FnOnce() -> ParseEvent>(&mut self, f: F) {
112        self.events.push(Ok(f()));
113    }
114
115    fn invoke<I: Clone, O, P: Parser<I, O> + ?Sized>(
116        &mut self,
117        parser: &P,
118        stream: &mut StreamOf<I, P::Error>,
119    ) -> PResult<I, O, P::Error> {
120        parser.parse_inner_verbose(self, stream)
121    }
122}
123
124/// A silent debugger that emits no debugging messages nor collects any debugging data.
125pub struct Silent {
126    phantom: PhantomData<()>,
127}
128
129impl Silent {
130    pub(crate) fn new() -> Self {
131        Self {
132            phantom: PhantomData,
133        }
134    }
135}
136
137impl Debugger for Silent {
138    fn scope<R, Info: FnOnce() -> ParserInfo, F: FnOnce(&mut Self) -> R>(
139        &mut self,
140        _: Info,
141        f: F,
142    ) -> R {
143        f(self)
144    }
145    fn emit_with<F: FnOnce() -> ParseEvent>(&mut self, _: F) {}
146
147    fn invoke<I: Clone, O, P: Parser<I, O> + ?Sized>(
148        &mut self,
149        parser: &P,
150        stream: &mut StreamOf<I, P::Error>,
151    ) -> PResult<I, O, P::Error> {
152        parser.parse_inner_silent(self, stream)
153    }
154}