1use crate::lossless::{Deb822, ParseError, PositionedParseError};
4use rowan::ast::AstNode;
5use rowan::{GreenNode, SyntaxNode};
6use std::marker::PhantomData;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Parse<T> {
14 green: GreenNode,
15 errors: Vec<String>,
16 positioned_errors: Vec<PositionedParseError>,
17 _ty: PhantomData<T>,
18}
19
20impl<T> Parse<T> {
21 pub fn new(green: GreenNode, errors: Vec<String>) -> Self {
23 Parse {
24 green,
25 errors,
26 positioned_errors: Vec::new(),
27 _ty: PhantomData,
28 }
29 }
30
31 pub fn new_with_positioned_errors(
33 green: GreenNode,
34 errors: Vec<String>,
35 positioned_errors: Vec<PositionedParseError>,
36 ) -> Self {
37 Parse {
38 green,
39 errors,
40 positioned_errors,
41 _ty: PhantomData,
42 }
43 }
44
45 pub fn green(&self) -> &GreenNode {
47 &self.green
48 }
49
50 pub fn errors(&self) -> &[String] {
52 &self.errors
53 }
54
55 pub fn positioned_errors(&self) -> &[PositionedParseError] {
57 &self.positioned_errors
58 }
59
60 pub fn error_messages(&self) -> Vec<String> {
62 self.positioned_errors
63 .iter()
64 .map(|e| e.message.clone())
65 .collect()
66 }
67
68 pub fn ok(&self) -> bool {
70 self.errors.is_empty()
71 }
72
73 pub fn to_result(self) -> Result<T, ParseError>
75 where
76 T: AstNode<Language = crate::lossless::Lang>,
77 {
78 if self.errors.is_empty() {
79 let node = SyntaxNode::new_root_mut(self.green);
80 Ok(T::cast(node).expect("root node has wrong type"))
81 } else {
82 Err(ParseError(self.errors))
83 }
84 }
85
86 pub fn tree(&self) -> T
92 where
93 T: AstNode<Language = crate::lossless::Lang>,
94 {
95 let node = SyntaxNode::new_root_mut(self.green.clone());
96 T::cast(node).expect("root node has wrong type")
97 }
98
99 pub fn syntax_node(&self) -> SyntaxNode<crate::lossless::Lang> {
101 SyntaxNode::new_root(self.green.clone())
102 }
103}
104
105unsafe impl<T> Send for Parse<T> {}
107unsafe impl<T> Sync for Parse<T> {}
108
109impl Parse<Deb822> {
110 pub fn parse_deb822(text: &str) -> Self {
112 let parsed = crate::lossless::parse(text);
113 Parse::new_with_positioned_errors(
114 parsed.green_node,
115 parsed.errors,
116 parsed.positioned_errors,
117 )
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_positioned_errors_api() {
127 let input = "Invalid field without colon\nBroken: field: extra colon\n";
128 let parsed = Parse::<Deb822>::parse_deb822(input);
129
130 let positioned_errors = parsed.positioned_errors();
132 assert!(!positioned_errors.is_empty());
133
134 let string_errors = parsed.errors();
136 assert!(!string_errors.is_empty());
137
138 let error_messages = parsed.error_messages();
140 assert_eq!(error_messages.len(), positioned_errors.len());
141
142 for (i, positioned_error) in positioned_errors.iter().enumerate() {
143 assert_eq!(positioned_error.message, error_messages[i]);
144 assert!(positioned_error.range.start() <= positioned_error.range.end());
145 }
146 }
147
148 #[test]
149 fn test_positioned_errors_example() {
150 let input = "Invalid: field\nBroken field without colon";
152 let parsed = Parse::<Deb822>::parse_deb822(input);
153
154 let positioned_errors = parsed.positioned_errors();
155 assert!(!positioned_errors.is_empty());
156
157 for error in positioned_errors {
159 let start_offset: u32 = error.range.start().into();
160 let end_offset: u32 = error.range.end().into();
161 println!(
162 "Error at {:?} ({}..{}): {}",
163 error.range, start_offset, end_offset, error.message
164 );
165
166 if end_offset <= input.len() as u32 {
168 let error_text = &input[start_offset as usize..end_offset as usize];
169 assert!(!error_text.is_empty());
170 }
171 }
172 }
173
174 #[test]
175 fn test_tree_with_errors_does_not_panic() {
176 let input = "Invalid field without colon\nBroken: field: extra colon\n";
179 let parsed = Parse::<Deb822>::parse_deb822(input);
180
181 assert!(!parsed.errors().is_empty());
183
184 let tree = parsed.tree();
186
187 assert!(tree.syntax().text().to_string() == input);
189 }
190}