ruby_prism/parse_result/
diagnostics.rs

1//! Diagnostic handling for parse errors and warnings.
2
3use std::ffi::CStr;
4use std::marker::PhantomData;
5
6use ruby_prism_sys::{pm_diagnostic_location, pm_diagnostic_message, pm_diagnostic_t, pm_parser_t};
7
8use super::Location;
9
10/// A diagnostic message that came back from the parser.
11#[derive(Debug)]
12pub struct Diagnostic<'pr> {
13    raw: *const pm_diagnostic_t,
14    parser: *const pm_parser_t,
15    marker: PhantomData<&'pr pm_diagnostic_t>,
16}
17
18impl<'pr> Diagnostic<'pr> {
19    /// Returns the message associated with the diagnostic.
20    ///
21    /// # Panics
22    ///
23    /// Panics if the message is not valid UTF-8.
24    #[must_use]
25    pub fn message(&self) -> &str {
26        unsafe {
27            let message = pm_diagnostic_message(self.raw);
28            CStr::from_ptr(message).to_str().expect("prism allows only UTF-8 for diagnostics.")
29        }
30    }
31
32    /// The location of the diagnostic in the source.
33    #[must_use]
34    pub fn location(&self) -> Location<'pr> {
35        let loc = unsafe { pm_diagnostic_location(self.raw) };
36        Location {
37            parser: self.parser,
38            start: loc.start,
39            length: loc.length,
40            marker: PhantomData,
41        }
42    }
43}
44
45/// An iterator over diagnostics collected from the parse result.
46pub struct Diagnostics<'pr> {
47    ptrs: Vec<*const pm_diagnostic_t>,
48    index: usize,
49    parser: *const pm_parser_t,
50    marker: PhantomData<&'pr pm_diagnostic_t>,
51}
52
53impl Diagnostics<'_> {
54    pub(crate) const fn new(ptrs: Vec<*const pm_diagnostic_t>, parser: *const pm_parser_t) -> Self {
55        Diagnostics { ptrs, index: 0, parser, marker: PhantomData }
56    }
57}
58
59impl<'pr> Iterator for Diagnostics<'pr> {
60    type Item = Diagnostic<'pr>;
61
62    fn next(&mut self) -> Option<Self::Item> {
63        if self.index < self.ptrs.len() {
64            let diagnostic = self.ptrs[self.index];
65            self.index += 1;
66            Some(Diagnostic {
67                raw: diagnostic,
68                parser: self.parser,
69                marker: PhantomData,
70            })
71        } else {
72            None
73        }
74    }
75}