ruby_prism/parse_result/
comments.rs

1//! Comment handling for the prism parser.
2
3use std::marker::PhantomData;
4
5use ruby_prism_sys::{pm_comment_location, pm_comment_t, pm_comment_type, pm_comment_type_t, pm_magic_comment_key, pm_magic_comment_t, pm_magic_comment_value, pm_parser_start, pm_parser_t};
6
7use super::Location;
8
9/// The type of the comment
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum CommentType {
12    /// `InlineComment` corresponds to comments that start with #.
13    InlineComment,
14    /// `EmbDocComment` corresponds to comments that are surrounded by =begin and =end.
15    EmbDocComment,
16}
17
18/// A comment that was found during parsing.
19#[derive(Debug)]
20pub struct Comment<'pr> {
21    raw: *const pm_comment_t,
22    parser: *const pm_parser_t,
23    marker: PhantomData<&'pr pm_comment_t>,
24}
25
26impl<'pr> Comment<'pr> {
27    /// Returns the text of the comment.
28    #[must_use]
29    pub fn text(&self) -> &[u8] {
30        self.location().as_slice()
31    }
32
33    /// Returns the type of the comment.
34    #[must_use]
35    pub fn type_(&self) -> CommentType {
36        let type_ = unsafe { pm_comment_type(self.raw) };
37        if type_ == pm_comment_type_t::PM_COMMENT_EMBDOC {
38            CommentType::EmbDocComment
39        } else {
40            CommentType::InlineComment
41        }
42    }
43
44    /// The location of the comment in the source.
45    #[must_use]
46    pub fn location(&self) -> Location<'pr> {
47        let loc = unsafe { pm_comment_location(self.raw) };
48        Location {
49            parser: self.parser,
50            start: loc.start,
51            length: loc.length,
52            marker: PhantomData,
53        }
54    }
55}
56
57/// An iterator over comments collected from the parse result.
58pub struct Comments<'pr> {
59    ptrs: Vec<*const pm_comment_t>,
60    index: usize,
61    parser: *const pm_parser_t,
62    marker: PhantomData<&'pr pm_comment_t>,
63}
64
65impl Comments<'_> {
66    pub(crate) const fn new(ptrs: Vec<*const pm_comment_t>, parser: *const pm_parser_t) -> Self {
67        Comments { ptrs, index: 0, parser, marker: PhantomData }
68    }
69}
70
71impl<'pr> Iterator for Comments<'pr> {
72    type Item = Comment<'pr>;
73
74    fn next(&mut self) -> Option<Self::Item> {
75        if self.index < self.ptrs.len() {
76            let comment = self.ptrs[self.index];
77            self.index += 1;
78            Some(Comment { raw: comment, parser: self.parser, marker: PhantomData })
79        } else {
80            None
81        }
82    }
83}
84
85/// A magic comment that was found during parsing.
86#[derive(Debug)]
87pub struct MagicComment<'pr> {
88    parser: *const pm_parser_t,
89    raw: *const pm_magic_comment_t,
90    marker: PhantomData<&'pr pm_magic_comment_t>,
91}
92
93impl MagicComment<'_> {
94    /// Returns the text of the comment's key.
95    #[must_use]
96    pub fn key(&self) -> &[u8] {
97        unsafe {
98            let loc = pm_magic_comment_key(self.raw);
99            let start = pm_parser_start(self.parser).add(loc.start as usize);
100            std::slice::from_raw_parts(start, loc.length as usize)
101        }
102    }
103
104    /// Returns the text of the comment's value.
105    #[must_use]
106    pub fn value(&self) -> &[u8] {
107        unsafe {
108            let loc = pm_magic_comment_value(self.raw);
109            let start = pm_parser_start(self.parser).add(loc.start as usize);
110            std::slice::from_raw_parts(start, loc.length as usize)
111        }
112    }
113}
114
115/// An iterator over magic comments collected from the parse result.
116pub struct MagicComments<'pr> {
117    ptrs: Vec<*const pm_magic_comment_t>,
118    index: usize,
119    parser: *const pm_parser_t,
120    marker: PhantomData<&'pr pm_magic_comment_t>,
121}
122
123impl MagicComments<'_> {
124    pub(crate) const fn new(ptrs: Vec<*const pm_magic_comment_t>, parser: *const pm_parser_t) -> Self {
125        MagicComments { ptrs, index: 0, parser, marker: PhantomData }
126    }
127}
128
129impl<'pr> Iterator for MagicComments<'pr> {
130    type Item = MagicComment<'pr>;
131
132    fn next(&mut self) -> Option<Self::Item> {
133        if self.index < self.ptrs.len() {
134            let comment = self.ptrs[self.index];
135            self.index += 1;
136            Some(MagicComment { parser: self.parser, raw: comment, marker: PhantomData })
137        } else {
138            None
139        }
140    }
141}