1use alloc::{string::String, vec};
2use core::iter::Peekable;
3
4use pp_rs::token::{PreprocessorError, Token as PPToken, TokenValue as PPTokenValue};
5
6use super::{
7 ast::{FunctionKind, Profile, TypeQualifiers},
8 context::{Context, ExprPos},
9 error::ExpectedToken,
10 error::{Error, ErrorKind},
11 lex::{Lexer, LexerResultKind},
12 token::{Directive, DirectiveKind},
13 token::{Token, TokenValue},
14 variables::{GlobalOrConstant, VarDeclaration},
15 Frontend, Result,
16};
17use crate::{arena::Handle, proc::U32EvalError, Expression, Module, Span, Type};
18
19mod declarations;
20mod expressions;
21mod functions;
22mod types;
23
24pub struct ParsingContext<'source> {
25 lexer: Peekable<Lexer<'source>>,
26 backtracked_token: Option<Token>,
28 last_meta: Span,
29}
30
31impl<'source> ParsingContext<'source> {
32 pub fn new(lexer: Lexer<'source>) -> Self {
33 ParsingContext {
34 lexer: lexer.peekable(),
35 backtracked_token: None,
36 last_meta: Span::default(),
37 }
38 }
39
40 pub fn backtrack(&mut self, token: Token) -> Result<()> {
48 if let Some(ref prev_token) = self.backtracked_token {
50 return Err(Error {
51 kind: ErrorKind::InternalError("The parser tried to backtrack twice in a row"),
52 meta: prev_token.meta,
53 });
54 }
55
56 self.backtracked_token = Some(token);
57
58 Ok(())
59 }
60
61 pub fn expect_ident(&mut self, frontend: &mut Frontend) -> Result<(String, Span)> {
62 let token = self.bump(frontend)?;
63
64 match token.value {
65 TokenValue::Identifier(name) => Ok((name, token.meta)),
66 _ => Err(Error {
67 kind: ErrorKind::InvalidToken(token.value, vec![ExpectedToken::Identifier]),
68 meta: token.meta,
69 }),
70 }
71 }
72
73 pub fn expect(&mut self, frontend: &mut Frontend, value: TokenValue) -> Result<Token> {
74 let token = self.bump(frontend)?;
75
76 if token.value != value {
77 Err(Error {
78 kind: ErrorKind::InvalidToken(token.value, vec![value.into()]),
79 meta: token.meta,
80 })
81 } else {
82 Ok(token)
83 }
84 }
85
86 pub fn next(&mut self, frontend: &mut Frontend) -> Option<Token> {
87 loop {
88 if let Some(token) = self.backtracked_token.take() {
89 self.last_meta = token.meta;
90 break Some(token);
91 }
92
93 let res = self.lexer.next()?;
94
95 match res.kind {
96 LexerResultKind::Token(token) => {
97 self.last_meta = token.meta;
98 break Some(token);
99 }
100 LexerResultKind::Directive(directive) => {
101 frontend.handle_directive(directive, res.meta)
102 }
103 LexerResultKind::Error(error) => frontend.errors.push(Error {
104 kind: ErrorKind::PreprocessorError(error),
105 meta: res.meta,
106 }),
107 }
108 }
109 }
110
111 pub fn bump(&mut self, frontend: &mut Frontend) -> Result<Token> {
112 self.next(frontend).ok_or(Error {
113 kind: ErrorKind::EndOfFile,
114 meta: self.last_meta,
115 })
116 }
117
118 pub fn bump_if(&mut self, frontend: &mut Frontend, value: TokenValue) -> Option<Token> {
120 if self.peek(frontend).filter(|t| t.value == value).is_some() {
121 self.bump(frontend).ok()
122 } else {
123 None
124 }
125 }
126
127 pub fn peek(&mut self, frontend: &mut Frontend) -> Option<&Token> {
128 loop {
129 if let Some(ref token) = self.backtracked_token {
130 break Some(token);
131 }
132
133 match self.lexer.peek()?.kind {
134 LexerResultKind::Token(_) => {
135 let res = self.lexer.peek()?;
136
137 match res.kind {
138 LexerResultKind::Token(ref token) => break Some(token),
139 _ => unreachable!(),
140 }
141 }
142 LexerResultKind::Error(_) | LexerResultKind::Directive(_) => {
143 let res = self.lexer.next()?;
144
145 match res.kind {
146 LexerResultKind::Directive(directive) => {
147 frontend.handle_directive(directive, res.meta)
148 }
149 LexerResultKind::Error(error) => frontend.errors.push(Error {
150 kind: ErrorKind::PreprocessorError(error),
151 meta: res.meta,
152 }),
153 LexerResultKind::Token(_) => unreachable!(),
154 }
155 }
156 }
157 }
158 }
159
160 pub fn expect_peek(&mut self, frontend: &mut Frontend) -> Result<&Token> {
161 let meta = self.last_meta;
162 self.peek(frontend).ok_or(Error {
163 kind: ErrorKind::EndOfFile,
164 meta,
165 })
166 }
167
168 pub fn parse(&mut self, frontend: &mut Frontend) -> Result<Module> {
169 let mut module = Module::default();
170 let mut global_expression_kind_tracker = crate::proc::ExpressionKindTracker::new();
171
172 let mut ctx = Context::new(
174 frontend,
175 &mut module,
176 false,
177 &mut global_expression_kind_tracker,
178 )?;
179
180 while self.peek(frontend).is_some() {
181 self.parse_external_declaration(frontend, &mut ctx)?;
182 }
183
184 if let Some(declaration) = frontend.lookup_function.get("main") {
187 for decl in declaration.overloads.iter() {
188 if let FunctionKind::Call(handle) = decl.kind {
189 if decl.defined && decl.parameters.is_empty() {
190 frontend.add_entry_point(handle, ctx)?;
191 return Ok(module);
192 }
193 }
194 }
195 }
196
197 Err(Error {
198 kind: ErrorKind::SemanticError("Missing entry point".into()),
199 meta: Span::default(),
200 })
201 }
202
203 fn parse_uint_constant(
204 &mut self,
205 frontend: &mut Frontend,
206 ctx: &mut Context,
207 ) -> Result<(u32, Span)> {
208 let (const_expr, meta) = self.parse_constant_expression(
209 frontend,
210 ctx.module,
211 ctx.global_expression_kind_tracker,
212 )?;
213
214 let res = ctx.module.to_ctx().eval_expr_to_u32(const_expr);
215
216 let int = match res {
217 Ok(value) => Ok(value),
218 Err(U32EvalError::Negative) => Err(Error {
219 kind: ErrorKind::SemanticError("int constant overflows".into()),
220 meta,
221 }),
222 Err(U32EvalError::NonConst) => Err(Error {
223 kind: ErrorKind::SemanticError("Expected a uint constant".into()),
224 meta,
225 }),
226 }?;
227
228 Ok((int, meta))
229 }
230
231 fn parse_constant_expression(
232 &mut self,
233 frontend: &mut Frontend,
234 module: &mut Module,
235 global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker,
236 ) -> Result<(Handle<Expression>, Span)> {
237 let mut ctx = Context::new(frontend, module, true, global_expression_kind_tracker)?;
238
239 let mut stmt_ctx = ctx.stmt_ctx();
240 let expr = self.parse_conditional(frontend, &mut ctx, &mut stmt_ctx, None)?;
241 let (root, meta) = ctx.lower_expect(stmt_ctx, frontend, expr, ExprPos::Rhs)?;
242
243 Ok((root, meta))
244 }
245}
246
247impl Frontend {
248 fn handle_directive(&mut self, directive: Directive, meta: Span) {
249 let mut tokens = directive.tokens.into_iter();
250
251 match directive.kind {
252 DirectiveKind::Version { is_first_directive } => {
253 if !is_first_directive {
254 self.errors.push(Error {
255 kind: ErrorKind::SemanticError(
256 "#version must occur first in shader".into(),
257 ),
258 meta,
259 })
260 }
261
262 match tokens.next() {
263 Some(PPToken {
264 value: PPTokenValue::Integer(int),
265 location,
266 }) => match int.value {
267 440 | 450 | 460 => self.meta.version = int.value as u16,
268 _ => self.errors.push(Error {
269 kind: ErrorKind::InvalidVersion(int.value),
270 meta: location.into(),
271 }),
272 },
273 Some(PPToken { value, location }) => self.errors.push(Error {
274 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
275 value,
276 )),
277 meta: location.into(),
278 }),
279 None => self.errors.push(Error {
280 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedNewLine),
281 meta,
282 }),
283 };
284
285 match tokens.next() {
286 Some(PPToken {
287 value: PPTokenValue::Ident(name),
288 location,
289 }) => match name.as_str() {
290 "core" => self.meta.profile = Profile::Core,
291 _ => self.errors.push(Error {
292 kind: ErrorKind::InvalidProfile(name),
293 meta: location.into(),
294 }),
295 },
296 Some(PPToken { value, location }) => self.errors.push(Error {
297 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
298 value,
299 )),
300 meta: location.into(),
301 }),
302 None => {}
303 };
304
305 if let Some(PPToken { value, location }) = tokens.next() {
306 self.errors.push(Error {
307 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
308 value,
309 )),
310 meta: location.into(),
311 })
312 }
313 }
314 DirectiveKind::Extension => {
315 let name = match tokens.next() {
320 Some(PPToken {
321 value: PPTokenValue::Ident(name),
322 ..
323 }) => Some(name),
324 Some(PPToken { value, location }) => {
325 self.errors.push(Error {
326 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
327 value,
328 )),
329 meta: location.into(),
330 });
331
332 None
333 }
334 None => {
335 self.errors.push(Error {
336 kind: ErrorKind::PreprocessorError(
337 PreprocessorError::UnexpectedNewLine,
338 ),
339 meta,
340 });
341
342 None
343 }
344 };
345
346 match tokens.next() {
347 Some(PPToken {
348 value: PPTokenValue::Punct(pp_rs::token::Punct::Colon),
349 ..
350 }) => {}
351 Some(PPToken { value, location }) => self.errors.push(Error {
352 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
353 value,
354 )),
355 meta: location.into(),
356 }),
357 None => self.errors.push(Error {
358 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedNewLine),
359 meta,
360 }),
361 };
362
363 match tokens.next() {
364 Some(PPToken {
365 value: PPTokenValue::Ident(behavior),
366 location,
367 }) => match behavior.as_str() {
368 "require" | "enable" | "warn" | "disable" => {
369 if let Some(name) = name {
370 self.meta.extensions.insert(name);
371 }
372 }
373 _ => self.errors.push(Error {
374 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
375 PPTokenValue::Ident(behavior),
376 )),
377 meta: location.into(),
378 }),
379 },
380 Some(PPToken { value, location }) => self.errors.push(Error {
381 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
382 value,
383 )),
384 meta: location.into(),
385 }),
386 None => self.errors.push(Error {
387 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedNewLine),
388 meta,
389 }),
390 }
391
392 if let Some(PPToken { value, location }) = tokens.next() {
393 self.errors.push(Error {
394 kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken(
395 value,
396 )),
397 meta: location.into(),
398 })
399 }
400 }
401 DirectiveKind::Pragma => {
402 }
404 }
405 }
406}
407
408pub struct DeclarationContext<'ctx, 'qualifiers, 'a> {
409 qualifiers: TypeQualifiers<'qualifiers>,
410 external: bool,
412 is_inside_loop: bool,
413 ctx: &'ctx mut Context<'a>,
414}
415
416impl DeclarationContext<'_, '_, '_> {
417 fn add_var(
418 &mut self,
419 frontend: &mut Frontend,
420 ty: Handle<Type>,
421 name: String,
422 init: Option<Handle<Expression>>,
423 meta: Span,
424 ) -> Result<Handle<Expression>> {
425 let decl = VarDeclaration {
426 qualifiers: &mut self.qualifiers,
427 ty,
428 name: Some(name),
429 init,
430 meta,
431 };
432
433 match self.external {
434 true => {
435 let global = frontend.add_global_var(self.ctx, decl)?;
436 let expr = match global {
437 GlobalOrConstant::Global(handle) => Expression::GlobalVariable(handle),
438 GlobalOrConstant::Constant(handle) => Expression::Constant(handle),
439 };
440 Ok(self.ctx.add_expression(expr, meta)?)
441 }
442 false => frontend.add_local_var(self.ctx, decl),
443 }
444 }
445}