1use std::borrow::Borrow;
2use std::rc::Rc;
3
4use snafu::{OptionExt, Snafu};
5use strum::EnumMessage;
6
7use crate::diagnostics::DiagnosticError;
8use crate::location::{FileLocation, Uri};
9use crate::parser::Rule;
10
11#[derive(Clone, Debug, PartialEq, strum::EnumMessage, Snafu)]
13#[snafu(visibility(pub))]
14pub enum Error {
15 Exhausted { loc: FileLocation },
17 MissingRule { rule: Rule, loc: FileLocation },
19 UnexpectedRule { rule: Rule, loc: FileLocation },
21}
22impl Error {
23 pub fn as_location(&self) -> FileLocation {
25 match self {
26 Self::Exhausted { loc } => loc.clone(),
27 Self::MissingRule { rule: _, loc } => loc.clone(),
28 Self::UnexpectedRule { rule: _, loc } => loc.clone(),
29 }
30 }
31 pub fn as_documentation(&self) -> String {
33 self.get_documentation().unwrap_or_default().into()
34 }
35 pub fn as_related_information(&self) -> Vec<lsp_types::DiagnosticRelatedInformation> {
37 let mut info = vec![];
38 let location: lsp_types::Location = self.as_location().into();
39 info.push(lsp_types::DiagnosticRelatedInformation {
40 message: format!("Builder error: {}", self.as_documentation()),
41 location: location.clone(),
42 });
43 match self {
44 Self::MissingRule { loc: _, rule } => {
45 info.push(lsp_types::DiagnosticRelatedInformation {
46 message: format!("Missing rule: {:?}", rule),
47 location,
48 })
49 }
50 Self::UnexpectedRule { loc: _, rule } => {
51 info.push(lsp_types::DiagnosticRelatedInformation {
52 message: format!("Unexpected rule: {:?}", rule),
53 location,
54 })
55 }
56 _ => (),
57 };
58 info
59 }
60 pub fn as_diagnostic(&self) -> lsp_types::Diagnostic {
62 match self {
63 Self::UnexpectedRule { rule, loc } => {
64 if rule == &Rule::syntax_error {
65 DiagnosticError::Syntax.diagnostic(loc.range, None)
66 } else {
67 DiagnosticError::Internal.diagnostic(
68 self.as_location().range,
69 Some(self.as_related_information()),
70 )
71 }
72 }
73 _ => DiagnosticError::Internal.diagnostic(
74 self.as_location().range,
75 Some(self.as_related_information()),
76 ),
77 }
78 }
79}
80impl MissingRuleSnafu<Rule, FileLocation> {
81 pub fn from<'a, T: Borrow<Cursors<'a>>>(cs: T, rule: Rule) -> Self {
82 let cs = cs.borrow();
83 MissingRuleSnafu {
84 rule,
85 loc: cs.as_location(),
86 }
87 }
88}
89impl<'a, T: Borrow<Cursor<'a>>> From<T> for ExhaustedSnafu<FileLocation> {
90 fn from(value: T) -> Self {
91 let value = value.borrow();
92 ExhaustedSnafu {
93 loc: value.as_location(),
94 }
95 }
96}
97impl<'a, T: Borrow<Cursor<'a>>> From<T> for UnexpectedRuleSnafu<Rule, FileLocation> {
98 fn from(value: T) -> Self {
99 let value = value.borrow();
100 UnexpectedRuleSnafu {
101 rule: value.as_rule(),
102 loc: value.as_location(),
103 }
104 }
105}
106
107#[derive(Clone, Debug, PartialEq)]
109pub struct Cursors<'a> {
110 pairs: pest::iterators::Pairs<'a, Rule>,
112 range: lsp_types::Range,
114 uri: Uri,
116}
117impl<'a> Cursors<'a> {
118 pub fn new(cursor: Cursor<'a>) -> Self {
120 Self {
121 range: cursor.as_range(),
122 pairs: cursor.pair.into_inner(),
123 uri: cursor.uri,
124 }
125 }
126 pub fn as_location(&self) -> FileLocation {
128 FileLocation {
129 range: self.range,
130 uri: Rc::clone(&self.uri),
131 }
132 }
133 pub fn req_next(&mut self) -> Result<Cursor<'a>, Error> {
135 self.next().with_context(|| ExhaustedSnafu {
136 loc: self.as_location(),
137 })
138 }
139 pub fn find_first(&mut self, rule: Rule) -> Option<Cursor<'a>> {
141 self.pairs
142 .find(|p| p.as_rule() == rule)
143 .map(|p| Cursor::new(p, Rc::clone(&self.uri)))
144 }
145 pub fn contains(&mut self, rule: Rule) -> bool {
147 self.find_first(rule).is_some()
148 }
149 pub fn req_first(&mut self, rule: Rule) -> Result<Cursor<'a>, Error> {
151 self.find_first(rule)
152 .with_context(|| MissingRuleSnafu::from(self, rule))
153 }
154 pub fn get_all(self, rule: Rule) -> impl Iterator<Item = Cursor<'a>> {
156 self.pairs
157 .filter(move |p| p.as_rule() == rule)
158 .map(move |p| Cursor::new(p, Rc::clone(&self.uri)))
159 }
160}
161impl<'a> From<Cursor<'a>> for Cursors<'a> {
162 fn from(value: Cursor<'a>) -> Self {
163 value.into_inner()
164 }
165}
166impl<'a> ExactSizeIterator for Cursors<'a> {
167 #[inline]
168 fn len(&self) -> usize {
169 self.pairs.len()
170 }
171}
172impl<'a> Iterator for Cursors<'a> {
173 type Item = Cursor<'a>;
174 fn next(&mut self) -> Option<Self::Item> {
175 for p in self.pairs.by_ref() {
176 if matches!(p.as_rule(), Rule::COMMENT | Rule::EOI) {
177 continue;
178 }
179 return Some(Cursor::new(p, Rc::clone(&self.uri)));
180 }
181 None
182 }
183 fn size_hint(&self) -> (usize, Option<usize>) {
184 let len = <Self as ExactSizeIterator>::len(self);
185 (len, Some(len))
186 }
187}
188
189#[derive(Clone, Debug, PartialEq)]
191pub struct Cursor<'a> {
192 pair: pest::iterators::Pair<'a, Rule>,
194 uri: Uri,
196}
197impl<'a> Cursor<'a> {
198 pub fn new(pair: pest::iterators::Pair<'a, Rule>, uri: Uri) -> Self {
200 Self { pair, uri }
201 }
202 pub fn into_inner(self) -> Cursors<'a> {
204 Cursors::new(self)
205 }
206 pub fn as_range(&self) -> lsp_types::Range {
208 let span = self.pair.as_span();
209 let start = span.start_pos().line_col();
210 let end = span.end_pos().line_col();
211 lsp_types::Range::new(
212 lsp_types::Position::new(start.0 as u32 - 1, start.1 as u32 - 1),
213 lsp_types::Position::new(end.0 as u32 - 1, end.1 as u32 - 1),
214 )
215 }
216 pub fn as_rule(&self) -> Rule {
218 self.pair.as_rule()
219 }
220 pub fn as_location(&self) -> FileLocation {
222 FileLocation {
223 range: self.as_range(),
224 uri: Rc::clone(&self.uri),
225 }
226 }
227 pub fn as_str(&self) -> &str {
229 self.pair.as_str()
230 }
231}
232
233#[derive(Clone, Debug, PartialEq)]
235pub struct Token {
236 pub loc: FileLocation,
238 pub text: Rc<str>,
240}
241impl Default for Token {
242 fn default() -> Self {
243 let text = "".into();
244 Token {
245 loc: Default::default(),
246 text,
247 }
248 }
249}
250impl<'a> From<Cursor<'a>> for Token {
251 fn from(value: Cursor<'a>) -> Self {
252 let text = value.pair.as_str().into();
253 let loc = value.as_location();
254 Self { text, loc }
255 }
256}
257impl std::fmt::Display for Token {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 write!(f, "{}", self.text)
260 }
261}