1use gramatika::{ParseStreamer, Spanned, SpannedError, Substr, Token as _, TokenCtor};
2
3use crate::{
4 comment::Comment,
5 token::{Lexer, Token},
6 TokenKind,
7};
8
9#[cfg(test)]
10use crate::utils::{WithComments, WithErrors, WithTokens};
11
12pub(crate) trait ErrorRecoveringParseStream: ParseStreamer {
14 fn push_error(&mut self, error: SpannedError);
15
16 fn parse_seq_separated<P>(
17 &mut self,
18 separator: Self::Token,
19 loop_condition: impl Fn(&mut Self) -> bool,
20 ) -> gramatika::Result<Vec<P>>
21 where
22 P: gramatika::Parse<Stream = Self>,
23 {
24 self.__parse_seq_impl(&loop_condition, |input, parsed| {
25 if loop_condition(input) {
26 input.consume(separator.clone())?;
27 }
28 Ok(parsed)
29 })
30 }
31
32 fn parse_seq_with_finisher<P, R>(
33 &mut self,
34 loop_condition: impl Fn(&mut Self) -> bool,
35 finish: impl Fn(&mut Self, P) -> gramatika::Result<R>,
36 ) -> gramatika::Result<Vec<R>>
37 where
38 P: gramatika::Parse<Stream = Self>,
39 {
40 self.__parse_seq_impl(&loop_condition, finish)
41 }
42
43 fn parse_seq<P>(&mut self, loop_condition: impl Fn(&mut Self) -> bool) -> Vec<P>
44 where P: gramatika::Parse<Stream = Self> {
45 self.__parse_seq_impl(&loop_condition, |_, parsed| Ok(parsed))
46 .unwrap()
47 }
48
49 #[inline]
50 #[doc(hidden)]
51 fn __parse_seq_impl<P, R>(
52 &mut self,
53 loop_condition: &impl Fn(&mut Self) -> bool,
54 finish: impl Fn(&mut Self, P) -> gramatika::Result<R>,
55 ) -> gramatika::Result<Vec<R>>
56 where
57 P: gramatika::Parse<Stream = Self>,
58 {
59 let mut results = vec![];
60 let mut recovering = false;
61
62 while !self.is_empty() && loop_condition(self) {
63 match self.parse::<P>() {
64 Ok(parsed) => {
65 if recovering {
66 recovering = false;
67 }
68
69 results.push(finish(self, parsed)?);
70 }
71 Err(err) => {
72 if recovering {
73 let needs_discard = self
74 .peek()
75 .and_then(|next_token| Some(err.span?.contains(next_token.span())));
76
77 if matches!(needs_discard, Some(true)) {
78 self.discard();
79 }
80 } else {
81 self.push_error(err);
82 recovering = true;
83 }
84 }
85 }
86 }
87
88 Ok(results)
89 }
90}
91
92pub struct ParseStream {
93 inner: gramatika::ParseStream<Token, Lexer>,
94 comments: Vec<Comment>,
95 parsing_comment: bool,
96 pub(crate) errors: Vec<SpannedError>,
97}
98
99pub struct ParseResult {
100 pub source: Substr,
101 pub tokens: Vec<Token>,
102 pub comments: Vec<Comment>,
103 pub errors: Vec<SpannedError>,
104}
105
106impl ParseStream {
107 pub fn new(lexer: Lexer) -> Self {
108 Self {
109 inner: gramatika::ParseStream::new(lexer),
110 comments: vec![],
111 parsing_comment: false,
112 errors: vec![],
113 }
114 }
115
116 pub fn source(&self) -> Substr {
117 self.inner.source()
118 }
119
120 pub fn into_inner(self) -> ParseResult {
121 let (source, tokens) = self.inner.into_inner();
122 ParseResult {
123 source,
124 tokens,
125 comments: self.comments,
126 errors: self.errors,
127 }
128 }
129
130 pub fn split_next(
131 &mut self,
132 split_at: usize,
133 ctors: (TokenCtor<Token>, TokenCtor<Token>),
134 ) -> gramatika::Result<Token> {
135 self.inner.split_next(split_at, ctors)
136 }
137
138 fn did_parse_comment(&mut self) -> bool {
139 let Some(token) = self.inner.peek() else {
140 return false;
141 };
142
143 match token.kind() {
144 TokenKind::CommentStart => {
145 self.parsing_comment = true;
146
147 match self.parse::<Comment>() {
148 Ok(comment) => {
149 self.comments.push(comment);
150 self.parsing_comment = false;
151 true
152 }
153 Err(error) => {
154 self.errors.push(error);
155 self.parsing_comment = false;
156 true
157 }
158 }
159 }
160 _ => false,
161 }
162 }
163}
164
165impl ErrorRecoveringParseStream for ParseStream {
166 fn push_error(&mut self, error: SpannedError) {
167 self.errors.push(error);
168 }
169}
170
171impl<S> From<S> for ParseStream
172where S: Into<Substr>
173{
174 fn from(value: S) -> Self {
175 Self {
176 inner: gramatika::ParseStream::from(value),
177 comments: vec![],
178 parsing_comment: false,
179 errors: vec![],
180 }
181 }
182}
183
184impl ParseStreamer for ParseStream {
185 type Token = Token;
186
187 fn is_empty(&mut self) -> bool {
188 self.peek().is_none()
189 }
190
191 fn peek(&mut self) -> Option<&Token> {
192 if !self.parsing_comment && self.did_parse_comment() {
193 self.peek()
194 } else {
195 self.inner.peek()
196 }
197 }
198
199 fn prev(&mut self) -> Option<&Token> {
200 self.inner.prev()
201 }
202
203 fn check_kind(&mut self, kind: TokenKind) -> bool {
204 if !self.parsing_comment && self.did_parse_comment() {
205 self.check_kind(kind)
206 } else {
207 self.inner.check_kind(kind)
208 }
209 }
210
211 fn check(&mut self, compare: Token) -> bool {
212 if !self.parsing_comment && self.did_parse_comment() {
213 self.check(compare)
214 } else {
215 self.inner.check(compare)
216 }
217 }
218
219 fn consume(&mut self, compare: Token) -> gramatika::Result<Token> {
220 if !self.parsing_comment && self.did_parse_comment() {
221 self.consume(compare)
222 } else {
223 self.inner.consume(compare)
224 }
225 }
226
227 fn consume_kind(&mut self, kind: TokenKind) -> gramatika::Result<Token> {
228 if !self.parsing_comment && self.did_parse_comment() {
229 self.consume_kind(kind)
230 } else {
231 self.inner.consume_kind(kind)
232 }
233 }
234
235 fn consume_as(
236 &mut self,
237 kind: TokenKind,
238 convert: TokenCtor<Token>,
239 ) -> gramatika::Result<Token> {
240 if !self.parsing_comment && self.did_parse_comment() {
241 self.consume_as(kind, convert)
242 } else {
243 self.inner.consume_as(kind, convert)
244 }
245 }
246
247 fn upgrade_last(
248 &mut self,
249 kind: TokenKind,
250 convert: TokenCtor<Token>,
251 ) -> gramatika::Result<Token> {
252 self.inner.upgrade_last(kind, convert)
253 }
254
255 fn upgrade(
256 &mut self,
257 token: Self::Token,
258 convert: TokenCtor<Token>,
259 ) -> gramatika::Result<Token> {
260 self.inner.upgrade(token, convert)
261 }
262
263 fn discard(&mut self) {
264 self.inner.discard();
265 }
266}
267
268impl Iterator for ParseStream {
269 type Item = Token;
270
271 fn next(&mut self) -> Option<Token> {
272 self.inner.next()
273 }
274}
275
276#[cfg(test)]
277impl WithErrors for ParseStream {
278 type Output = SpannedError;
279
280 fn get(&self) -> &[Self::Output] {
281 &self.errors
282 }
283}
284
285#[cfg(test)]
286impl WithComments for ParseStream {
287 type Output = Comment;
288
289 fn get(&self) -> &[Self::Output] {
290 &self.comments
291 }
292}
293
294#[cfg(test)]
295impl WithTokens for ParseStream {
296 type Output = Token;
297
298 fn into(self) -> Vec<Self::Output> {
299 let ParseResult { tokens, .. } = self.into_inner();
300 tokens
301 }
302}