1use alloc::{vec, vec::Vec};
2
3use crate::front::glsl::context::ExprPos;
4use crate::front::glsl::Span;
5use crate::Literal;
6use crate::{
7 front::glsl::{
8 ast::ParameterQualifier,
9 context::Context,
10 parser::ParsingContext,
11 token::{Token, TokenValue},
12 variables::VarDeclaration,
13 Error, ErrorKind, Frontend, Result,
14 },
15 Block, Expression, Statement, SwitchCase, UnaryOperator,
16};
17
18impl ParsingContext<'_> {
19 pub fn peek_parameter_qualifier(&mut self, frontend: &mut Frontend) -> bool {
20 self.peek(frontend).is_some_and(|t| match t.value {
21 TokenValue::In | TokenValue::Out | TokenValue::InOut | TokenValue::Const => true,
22 _ => false,
23 })
24 }
25
26 pub fn parse_parameter_qualifier(&mut self, frontend: &mut Frontend) -> ParameterQualifier {
28 if self.peek_parameter_qualifier(frontend) {
29 match self.bump(frontend).unwrap().value {
30 TokenValue::In => ParameterQualifier::In,
31 TokenValue::Out => ParameterQualifier::Out,
32 TokenValue::InOut => ParameterQualifier::InOut,
33 TokenValue::Const => ParameterQualifier::Const,
34 _ => unreachable!(),
35 }
36 } else {
37 ParameterQualifier::In
38 }
39 }
40
41 pub fn parse_statement(
42 &mut self,
43 frontend: &mut Frontend,
44 ctx: &mut Context,
45 terminator: &mut Option<usize>,
46 is_inside_loop: bool,
47 ) -> Result<Option<Span>> {
48 if self.peek_type_qualifier(frontend) {
50 return self.parse_declaration(frontend, ctx, false, is_inside_loop);
51 }
52
53 if self.peek_type_name(frontend) {
56 let token = self.bump(frontend)?;
58 let declaration = TokenValue::LeftParen != self.expect_peek(frontend)?.value;
62
63 self.backtrack(token)?;
64
65 if declaration {
66 return self.parse_declaration(frontend, ctx, false, is_inside_loop);
67 }
68 }
69
70 let new_break = || {
71 let mut block = Block::new();
72 block.push(Statement::Break, Span::default());
73 block
74 };
75
76 let &Token {
77 ref value,
78 mut meta,
79 } = self.expect_peek(frontend)?;
80
81 let meta_rest = match *value {
82 TokenValue::Continue => {
83 let meta = self.bump(frontend)?.meta;
84 ctx.body.push(Statement::Continue, meta);
85 terminator.get_or_insert(ctx.body.len());
86 self.expect(frontend, TokenValue::Semicolon)?.meta
87 }
88 TokenValue::Break => {
89 let meta = self.bump(frontend)?.meta;
90 ctx.body.push(Statement::Break, meta);
91 terminator.get_or_insert(ctx.body.len());
92 self.expect(frontend, TokenValue::Semicolon)?.meta
93 }
94 TokenValue::Return => {
95 self.bump(frontend)?;
96 let (value, meta) = match self.expect_peek(frontend)?.value {
97 TokenValue::Semicolon => (None, self.bump(frontend)?.meta),
98 _ => {
99 let mut stmt = ctx.stmt_ctx();
101 let expr = self.parse_expression(frontend, ctx, &mut stmt)?;
102 self.expect(frontend, TokenValue::Semicolon)?;
103 let (handle, meta) =
104 ctx.lower_expect(stmt, frontend, expr, ExprPos::Rhs)?;
105 (Some(handle), meta)
106 }
107 };
108
109 ctx.emit_restart();
110
111 ctx.body.push(Statement::Return { value }, meta);
112 terminator.get_or_insert(ctx.body.len());
113
114 meta
115 }
116 TokenValue::Discard => {
117 let meta = self.bump(frontend)?.meta;
118 ctx.body.push(Statement::Kill, meta);
119 terminator.get_or_insert(ctx.body.len());
120
121 self.expect(frontend, TokenValue::Semicolon)?.meta
122 }
123 TokenValue::If => {
124 let mut meta = self.bump(frontend)?.meta;
125
126 self.expect(frontend, TokenValue::LeftParen)?;
127 let condition = {
128 let mut stmt = ctx.stmt_ctx();
129 let expr = self.parse_expression(frontend, ctx, &mut stmt)?;
130 let (handle, more_meta) =
131 ctx.lower_expect(stmt, frontend, expr, ExprPos::Rhs)?;
132 meta.subsume(more_meta);
133 handle
134 };
135 self.expect(frontend, TokenValue::RightParen)?;
136
137 let accept = ctx.new_body(|ctx| {
138 if let Some(more_meta) =
139 self.parse_statement(frontend, ctx, &mut None, is_inside_loop)?
140 {
141 meta.subsume(more_meta);
142 }
143 Ok(())
144 })?;
145
146 let reject = ctx.new_body(|ctx| {
147 if self.bump_if(frontend, TokenValue::Else).is_some() {
148 if let Some(more_meta) =
149 self.parse_statement(frontend, ctx, &mut None, is_inside_loop)?
150 {
151 meta.subsume(more_meta);
152 }
153 }
154 Ok(())
155 })?;
156
157 ctx.body.push(
158 Statement::If {
159 condition,
160 accept,
161 reject,
162 },
163 meta,
164 );
165
166 meta
167 }
168 TokenValue::Switch => {
169 let mut meta = self.bump(frontend)?.meta;
170 let end_meta;
171
172 self.expect(frontend, TokenValue::LeftParen)?;
173
174 let (selector, uint) = {
175 let mut stmt = ctx.stmt_ctx();
176 let expr = self.parse_expression(frontend, ctx, &mut stmt)?;
177 let (root, meta) = ctx.lower_expect(stmt, frontend, expr, ExprPos::Rhs)?;
178 let uint = ctx.resolve_type(root, meta)?.scalar_kind()
179 == Some(crate::ScalarKind::Uint);
180 (root, uint)
181 };
182
183 self.expect(frontend, TokenValue::RightParen)?;
184
185 ctx.emit_restart();
186
187 let mut cases = Vec::new();
188 let mut default_present = false;
190
191 self.expect(frontend, TokenValue::LeftBrace)?;
192 loop {
193 let value = match self.expect_peek(frontend)?.value {
194 TokenValue::Case => {
195 self.bump(frontend)?;
196
197 let (const_expr, meta) = self.parse_constant_expression(
198 frontend,
199 ctx.module,
200 ctx.global_expression_kind_tracker,
201 )?;
202
203 match ctx.module.global_expressions[const_expr] {
204 Expression::Literal(Literal::I32(value)) => match uint {
205 true => crate::SwitchValue::U32(value as u32),
211 false => crate::SwitchValue::I32(value),
212 },
213 Expression::Literal(Literal::U32(value)) => {
214 crate::SwitchValue::U32(value)
215 }
216 _ => {
217 frontend.errors.push(Error {
218 kind: ErrorKind::SemanticError(
219 "Case values can only be integers".into(),
220 ),
221 meta,
222 });
223
224 crate::SwitchValue::I32(0)
225 }
226 }
227 }
228 TokenValue::Default => {
229 self.bump(frontend)?;
230 default_present = true;
231 crate::SwitchValue::Default
232 }
233 TokenValue::RightBrace => {
234 end_meta = self.bump(frontend)?.meta;
235 break;
236 }
237 _ => {
238 let Token { value, meta } = self.bump(frontend)?;
239 return Err(Error {
240 kind: ErrorKind::InvalidToken(
241 value,
242 vec![
243 TokenValue::Case.into(),
244 TokenValue::Default.into(),
245 TokenValue::RightBrace.into(),
246 ],
247 ),
248 meta,
249 });
250 }
251 };
252
253 self.expect(frontend, TokenValue::Colon)?;
254
255 let mut fall_through = true;
256
257 let body = ctx.new_body(|ctx| {
258 let mut case_terminator = None;
259 loop {
260 match self.expect_peek(frontend)?.value {
261 TokenValue::Case | TokenValue::Default | TokenValue::RightBrace => {
262 break
263 }
264 _ => {
265 self.parse_statement(
266 frontend,
267 ctx,
268 &mut case_terminator,
269 is_inside_loop,
270 )?;
271 }
272 }
273 }
274
275 if let Some(mut idx) = case_terminator {
276 if let Statement::Break = ctx.body[idx - 1] {
277 fall_through = false;
278 idx -= 1;
279 }
280
281 ctx.body.cull(idx..)
282 }
283
284 Ok(())
285 })?;
286
287 cases.push(SwitchCase {
288 value,
289 body,
290 fall_through,
291 })
292 }
293
294 meta.subsume(end_meta);
295
296 if let Some(case) = cases.last_mut() {
299 if case.body.is_empty() && case.fall_through {
304 frontend.errors.push(Error {
305 kind: ErrorKind::SemanticError(
306 "last case/default label must be followed by statements".into(),
307 ),
308 meta,
309 })
310 }
311
312 case.fall_through = false;
317 }
318
319 if !default_present {
323 cases.push(SwitchCase {
324 value: crate::SwitchValue::Default,
325 body: Block::new(),
326 fall_through: false,
327 })
328 }
329
330 ctx.body.push(Statement::Switch { selector, cases }, meta);
331
332 meta
333 }
334 TokenValue::While => {
335 let mut meta = self.bump(frontend)?.meta;
336
337 let loop_body = ctx.new_body(|ctx| {
338 let mut stmt = ctx.stmt_ctx();
339 self.expect(frontend, TokenValue::LeftParen)?;
340 let root = self.parse_expression(frontend, ctx, &mut stmt)?;
341 meta.subsume(self.expect(frontend, TokenValue::RightParen)?.meta);
342
343 let (expr, expr_meta) = ctx.lower_expect(stmt, frontend, root, ExprPos::Rhs)?;
344 let condition = ctx.add_expression(
345 Expression::Unary {
346 op: UnaryOperator::LogicalNot,
347 expr,
348 },
349 expr_meta,
350 )?;
351
352 ctx.emit_restart();
353
354 ctx.body.push(
355 Statement::If {
356 condition,
357 accept: new_break(),
358 reject: Block::new(),
359 },
360 Span::default(),
361 );
362
363 meta.subsume(expr_meta);
364
365 if let Some(body_meta) = self.parse_statement(frontend, ctx, &mut None, true)? {
366 meta.subsume(body_meta);
367 }
368 Ok(())
369 })?;
370
371 ctx.body.push(
372 Statement::Loop {
373 body: loop_body,
374 continuing: Block::new(),
375 break_if: None,
376 },
377 meta,
378 );
379
380 meta
381 }
382 TokenValue::Do => {
383 let mut meta = self.bump(frontend)?.meta;
384
385 let loop_body = ctx.new_body(|ctx| {
386 let mut terminator = None;
387 self.parse_statement(frontend, ctx, &mut terminator, true)?;
388
389 let mut stmt = ctx.stmt_ctx();
390
391 self.expect(frontend, TokenValue::While)?;
392 self.expect(frontend, TokenValue::LeftParen)?;
393 let root = self.parse_expression(frontend, ctx, &mut stmt)?;
394 let end_meta = self.expect(frontend, TokenValue::RightParen)?.meta;
395
396 meta.subsume(end_meta);
397
398 let (expr, expr_meta) = ctx.lower_expect(stmt, frontend, root, ExprPos::Rhs)?;
399 let condition = ctx.add_expression(
400 Expression::Unary {
401 op: UnaryOperator::LogicalNot,
402 expr,
403 },
404 expr_meta,
405 )?;
406
407 ctx.emit_restart();
408
409 ctx.body.push(
410 Statement::If {
411 condition,
412 accept: new_break(),
413 reject: Block::new(),
414 },
415 Span::default(),
416 );
417
418 if let Some(idx) = terminator {
419 ctx.body.cull(idx..)
420 }
421 Ok(())
422 })?;
423
424 ctx.body.push(
425 Statement::Loop {
426 body: loop_body,
427 continuing: Block::new(),
428 break_if: None,
429 },
430 meta,
431 );
432
433 meta
434 }
435 TokenValue::For => {
436 let mut meta = self.bump(frontend)?.meta;
437
438 ctx.symbol_table.push_scope();
439 self.expect(frontend, TokenValue::LeftParen)?;
440
441 if self.bump_if(frontend, TokenValue::Semicolon).is_none() {
442 if self.peek_type_name(frontend) || self.peek_type_qualifier(frontend) {
443 self.parse_declaration(frontend, ctx, false, is_inside_loop)?;
444 } else {
445 let mut stmt = ctx.stmt_ctx();
446 let expr = self.parse_expression(frontend, ctx, &mut stmt)?;
447 ctx.lower(stmt, frontend, expr, ExprPos::Rhs)?;
448 self.expect(frontend, TokenValue::Semicolon)?;
449 }
450 }
451
452 let loop_body = ctx.new_body(|ctx| {
453 if self.bump_if(frontend, TokenValue::Semicolon).is_none() {
454 let (expr, expr_meta) = if self.peek_type_name(frontend)
455 || self.peek_type_qualifier(frontend)
456 {
457 let mut qualifiers = self.parse_type_qualifiers(frontend, ctx)?;
458 let (ty, mut meta) = self.parse_type_non_void(frontend, ctx)?;
459 let name = self.expect_ident(frontend)?.0;
460
461 self.expect(frontend, TokenValue::Assign)?;
462
463 let (value, end_meta) = self.parse_initializer(frontend, ty, ctx)?;
464 meta.subsume(end_meta);
465
466 let decl = VarDeclaration {
467 qualifiers: &mut qualifiers,
468 ty,
469 name: Some(name),
470 init: None,
471 meta,
472 };
473
474 let pointer = frontend.add_local_var(ctx, decl)?;
475
476 ctx.emit_restart();
477
478 ctx.body.push(Statement::Store { pointer, value }, meta);
479
480 (value, end_meta)
481 } else {
482 let mut stmt = ctx.stmt_ctx();
483 let root = self.parse_expression(frontend, ctx, &mut stmt)?;
484 ctx.lower_expect(stmt, frontend, root, ExprPos::Rhs)?
485 };
486
487 let condition = ctx.add_expression(
488 Expression::Unary {
489 op: UnaryOperator::LogicalNot,
490 expr,
491 },
492 expr_meta,
493 )?;
494
495 ctx.emit_restart();
496
497 ctx.body.push(
498 Statement::If {
499 condition,
500 accept: new_break(),
501 reject: Block::new(),
502 },
503 Span::default(),
504 );
505
506 self.expect(frontend, TokenValue::Semicolon)?;
507 }
508 Ok(())
509 })?;
510
511 let continuing = ctx.new_body(|ctx| {
512 match self.expect_peek(frontend)?.value {
513 TokenValue::RightParen => {}
514 _ => {
515 let mut stmt = ctx.stmt_ctx();
516 let rest = self.parse_expression(frontend, ctx, &mut stmt)?;
517 ctx.lower(stmt, frontend, rest, ExprPos::Rhs)?;
518 }
519 }
520 Ok(())
521 })?;
522
523 meta.subsume(self.expect(frontend, TokenValue::RightParen)?.meta);
524
525 let loop_body = ctx.with_body(loop_body, |ctx| {
526 if let Some(stmt_meta) = self.parse_statement(frontend, ctx, &mut None, true)? {
527 meta.subsume(stmt_meta);
528 }
529 Ok(())
530 })?;
531
532 ctx.body.push(
533 Statement::Loop {
534 body: loop_body,
535 continuing,
536 break_if: None,
537 },
538 meta,
539 );
540
541 ctx.symbol_table.pop_scope();
542
543 meta
544 }
545 TokenValue::LeftBrace => {
546 let mut meta = self.bump(frontend)?.meta;
547
548 let mut block_terminator = None;
549
550 let block = ctx.new_body(|ctx| {
551 let block_meta = self.parse_compound_statement(
552 meta,
553 frontend,
554 ctx,
555 &mut block_terminator,
556 is_inside_loop,
557 )?;
558 meta.subsume(block_meta);
559 Ok(())
560 })?;
561
562 ctx.body.push(Statement::Block(block), meta);
563 if block_terminator.is_some() {
564 terminator.get_or_insert(ctx.body.len());
565 }
566
567 meta
568 }
569 TokenValue::Semicolon => self.bump(frontend)?.meta,
570 _ => {
571 let mut stmt = ctx.stmt_ctx();
575 let expr = self.parse_expression(frontend, ctx, &mut stmt)?;
576 ctx.lower(stmt, frontend, expr, ExprPos::Rhs)?;
577 self.expect(frontend, TokenValue::Semicolon)?.meta
578 }
579 };
580
581 meta.subsume(meta_rest);
582 Ok(Some(meta))
583 }
584
585 pub fn parse_compound_statement(
586 &mut self,
587 mut meta: Span,
588 frontend: &mut Frontend,
589 ctx: &mut Context,
590 terminator: &mut Option<usize>,
591 is_inside_loop: bool,
592 ) -> Result<Span> {
593 ctx.symbol_table.push_scope();
594
595 loop {
596 if let Some(Token {
597 meta: brace_meta, ..
598 }) = self.bump_if(frontend, TokenValue::RightBrace)
599 {
600 meta.subsume(brace_meta);
601 break;
602 }
603
604 let stmt = self.parse_statement(frontend, ctx, terminator, is_inside_loop)?;
605
606 if let Some(stmt_meta) = stmt {
607 meta.subsume(stmt_meta);
608 }
609 }
610
611 if let Some(idx) = *terminator {
612 ctx.body.cull(idx..)
613 }
614
615 ctx.symbol_table.pop_scope();
616
617 Ok(meta)
618 }
619
620 pub fn parse_function_args(
621 &mut self,
622 frontend: &mut Frontend,
623 ctx: &mut Context,
624 ) -> Result<()> {
625 if self.bump_if(frontend, TokenValue::Void).is_some() {
626 return Ok(());
627 }
628
629 loop {
630 if self.peek_type_name(frontend) || self.peek_parameter_qualifier(frontend) {
631 let qualifier = self.parse_parameter_qualifier(frontend);
632 let mut ty = self.parse_type_non_void(frontend, ctx)?.0;
633
634 match self.expect_peek(frontend)?.value {
635 TokenValue::Comma => {
636 self.bump(frontend)?;
637 ctx.add_function_arg(None, ty, qualifier)?;
638 continue;
639 }
640 TokenValue::Identifier(_) => {
641 let mut name = self.expect_ident(frontend)?;
642 self.parse_array_specifier(frontend, ctx, &mut name.1, &mut ty)?;
643
644 ctx.add_function_arg(Some(name), ty, qualifier)?;
645
646 if self.bump_if(frontend, TokenValue::Comma).is_some() {
647 continue;
648 }
649
650 break;
651 }
652 _ => break,
653 }
654 }
655
656 break;
657 }
658
659 Ok(())
660 }
661}