wgsl_parser/
parser.rs

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
12// TODO: Upstream to Gramatika
13pub(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}