ruby_prism/parse_result/
mod.rs1mod comments;
7mod diagnostics;
8
9use std::ptr::NonNull;
10
11use ruby_prism_sys::{pm_comment_t, pm_diagnostic_t, pm_location_t, pm_magic_comment_t, pm_node_destroy, pm_node_t, pm_parser_free, pm_parser_t};
12
13pub use self::comments::{Comment, CommentType, Comments, MagicComment, MagicComments};
14pub use self::diagnostics::{Diagnostic, Diagnostics};
15
16use crate::Node;
17
18pub struct Location<'pr> {
20 pub(crate) parser: NonNull<pm_parser_t>,
21 pub(crate) start: u32,
22 pub(crate) length: u32,
23 marker: std::marker::PhantomData<&'pr [u8]>,
24}
25
26impl<'pr> Location<'pr> {
27 #[must_use]
29 pub fn as_slice(&self) -> &'pr [u8] {
30 unsafe {
31 let parser_start = (*self.parser.as_ptr()).start;
32 std::slice::from_raw_parts(parser_start.add(self.start as usize), self.length as usize)
33 }
34 }
35
36 #[must_use]
38 pub(crate) const fn new(parser: NonNull<pm_parser_t>, location: &'pr pm_location_t) -> Self {
39 Location {
40 parser,
41 start: location.start,
42 length: location.length,
43 marker: std::marker::PhantomData,
44 }
45 }
46
47 #[must_use]
49 pub const fn end(&self) -> u32 {
50 self.start + self.length
51 }
52
53 #[must_use]
57 pub fn join(&self, other: &Self) -> Option<Self> {
58 if self.parser != other.parser || self.start > other.start {
59 None
60 } else {
61 Some(Location {
62 parser: self.parser,
63 start: self.start,
64 length: other.end() - self.start,
65 marker: std::marker::PhantomData,
66 })
67 }
68 }
69}
70
71impl std::fmt::Debug for Location<'_> {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 let slice: &[u8] = self.as_slice();
74
75 let mut visible = String::new();
76 visible.push('"');
77
78 for &byte in slice {
79 let part: Vec<u8> = std::ascii::escape_default(byte).collect();
80 visible.push_str(std::str::from_utf8(&part).unwrap());
81 }
82
83 visible.push('"');
84 write!(f, "{visible}")
85 }
86}
87
88#[derive(Debug)]
90pub struct ParseResult<'pr> {
91 source: &'pr [u8],
92 parser: NonNull<pm_parser_t>,
93 node: NonNull<pm_node_t>,
94}
95
96impl<'pr> ParseResult<'pr> {
97 pub(crate) const unsafe fn new(source: &'pr [u8], parser: NonNull<pm_parser_t>, node: NonNull<pm_node_t>) -> Self {
98 ParseResult { source, parser, node }
99 }
100
101 #[must_use]
103 pub const fn source(&self) -> &'pr [u8] {
104 self.source
105 }
106
107 #[must_use]
109 pub fn frozen_string_literals(&self) -> bool {
110 unsafe { (*self.parser.as_ptr()).frozen_string_literal == 1 }
111 }
112
113 #[must_use]
116 pub fn as_slice(&self, location: &Location<'pr>) -> &'pr [u8] {
117 let start = location.start as usize;
118 let end = start + location.length as usize;
119 &self.source[start..end]
120 }
121
122 #[must_use]
125 pub fn errors(&self) -> Diagnostics<'_> {
126 unsafe {
127 let list = &mut (*self.parser.as_ptr()).error_list;
128 Diagnostics::new(list.head.cast::<pm_diagnostic_t>(), self.parser)
129 }
130 }
131
132 #[must_use]
135 pub fn warnings(&self) -> Diagnostics<'_> {
136 unsafe {
137 let list = &mut (*self.parser.as_ptr()).warning_list;
138 Diagnostics::new(list.head.cast::<pm_diagnostic_t>(), self.parser)
139 }
140 }
141
142 #[must_use]
145 pub fn comments(&self) -> Comments<'_> {
146 unsafe {
147 let list = &mut (*self.parser.as_ptr()).comment_list;
148 Comments::new(list.head.cast::<pm_comment_t>(), self.parser)
149 }
150 }
151
152 #[must_use]
155 pub fn magic_comments(&self) -> MagicComments<'_> {
156 unsafe {
157 let list = &mut (*self.parser.as_ptr()).magic_comment_list;
158 MagicComments::new(self.parser, list.head.cast::<pm_magic_comment_t>())
159 }
160 }
161
162 #[must_use]
164 pub fn data_loc(&self) -> Option<Location<'_>> {
165 let location = unsafe { &(*self.parser.as_ptr()).data_loc };
166 if location.length == 0 {
167 None
168 } else {
169 Some(Location::new(self.parser, location))
170 }
171 }
172
173 #[must_use]
175 pub fn node(&self) -> Node<'_> {
176 Node::new(self.parser, self.node.as_ptr())
177 }
178}
179
180impl Drop for ParseResult<'_> {
181 fn drop(&mut self) {
182 unsafe {
183 pm_node_destroy(self.parser.as_ptr(), self.node.as_ptr());
184 pm_parser_free(self.parser.as_ptr());
185 drop(Box::from_raw(self.parser.as_ptr()));
186 }
187 }
188}