1use alloc::{string::String, vec, vec::Vec};
2
3use super::{DeclarationContext, ParsingContext, Result};
4use crate::{
5 front::glsl::{
6 ast::{
7 GlobalLookup, GlobalLookupKind, Precision, QualifierKey, QualifierValue,
8 StorageQualifier, StructLayout, TypeQualifiers,
9 },
10 context::{Context, ExprPos},
11 error::ExpectedToken,
12 offset,
13 token::{Token, TokenValue},
14 types::scalar_components,
15 variables::{GlobalOrConstant, VarDeclaration},
16 Error, ErrorKind, Frontend, Span,
17 },
18 proc::Alignment,
19 AddressSpace, Expression, FunctionResult, Handle, Scalar, ScalarKind, Statement, StructMember,
20 Type, TypeInner,
21};
22
23fn element_or_member_type(
32 ty: Handle<Type>,
33 i: usize,
34 types: &mut crate::UniqueArena<Type>,
35) -> Handle<Type> {
36 match types[ty].inner {
37 TypeInner::Vector { scalar, .. } => types.insert(
39 Type {
40 name: None,
41 inner: TypeInner::Scalar(scalar),
42 },
43 Default::default(),
44 ),
45 TypeInner::Matrix { rows, scalar, .. } => types.insert(
48 Type {
49 name: None,
50 inner: TypeInner::Vector { size: rows, scalar },
51 },
52 Default::default(),
53 ),
54 TypeInner::Array { base, .. } => base,
56 TypeInner::Struct { ref members, .. } => {
61 members.get(i).map(|member| member.ty).unwrap_or(ty)
62 }
63 _ => ty,
65 }
66}
67
68impl ParsingContext<'_> {
69 pub fn parse_external_declaration(
70 &mut self,
71 frontend: &mut Frontend,
72 global_ctx: &mut Context,
73 ) -> Result<()> {
74 if self
75 .parse_declaration(frontend, global_ctx, true, false)?
76 .is_none()
77 {
78 let token = self.bump(frontend)?;
79 match token.value {
80 TokenValue::Semicolon if frontend.meta.version == 460 => Ok(()),
81 _ => {
82 let expected = match frontend.meta.version {
83 460 => vec![TokenValue::Semicolon.into(), ExpectedToken::Eof],
84 _ => vec![ExpectedToken::Eof],
85 };
86 Err(Error {
87 kind: ErrorKind::InvalidToken(token.value, expected),
88 meta: token.meta,
89 })
90 }
91 }
92 } else {
93 Ok(())
94 }
95 }
96
97 pub fn parse_initializer(
98 &mut self,
99 frontend: &mut Frontend,
100 ty: Handle<Type>,
101 ctx: &mut Context,
102 ) -> Result<(Handle<Expression>, Span)> {
103 if let Some(Token { mut meta, .. }) = self.bump_if(frontend, TokenValue::LeftBrace) {
112 let mut components = Vec::new();
114 loop {
115 let new_ty = element_or_member_type(ty, components.len(), &mut ctx.module.types);
117
118 components.push(self.parse_initializer(frontend, new_ty, ctx)?.0);
119
120 let token = self.bump(frontend)?;
121 match token.value {
122 TokenValue::Comma => {
123 if let Some(Token { meta: end_meta, .. }) =
124 self.bump_if(frontend, TokenValue::RightBrace)
125 {
126 meta.subsume(end_meta);
127 break;
128 }
129 }
130 TokenValue::RightBrace => {
131 meta.subsume(token.meta);
132 break;
133 }
134 _ => {
135 return Err(Error {
136 kind: ErrorKind::InvalidToken(
137 token.value,
138 vec![TokenValue::Comma.into(), TokenValue::RightBrace.into()],
139 ),
140 meta: token.meta,
141 })
142 }
143 }
144 }
145
146 Ok((
147 ctx.add_expression(Expression::Compose { ty, components }, meta)?,
148 meta,
149 ))
150 } else {
151 let mut stmt = ctx.stmt_ctx();
152 let expr = self.parse_assignment(frontend, ctx, &mut stmt)?;
153 let (mut init, init_meta) = ctx.lower_expect(stmt, frontend, expr, ExprPos::Rhs)?;
154
155 let scalar_components = scalar_components(&ctx.module.types[ty].inner);
156 if let Some(scalar) = scalar_components {
157 ctx.implicit_conversion(&mut init, init_meta, scalar)?;
158 }
159
160 Ok((init, init_meta))
161 }
162 }
163
164 pub fn parse_init_declarator_list(
168 &mut self,
169 frontend: &mut Frontend,
170 mut ty: Handle<Type>,
171 ctx: &mut DeclarationContext,
172 ) -> Result<()> {
173 if self
189 .peek(frontend)
190 .is_some_and(|t| t.value == TokenValue::Comma)
191 {
192 self.next(frontend);
193 }
194
195 loop {
196 let token = self.bump(frontend)?;
197 let name = match token.value {
198 TokenValue::Semicolon => break,
199 TokenValue::Identifier(name) => name,
200 _ => {
201 return Err(Error {
202 kind: ErrorKind::InvalidToken(
203 token.value,
204 vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()],
205 ),
206 meta: token.meta,
207 })
208 }
209 };
210 let mut meta = token.meta;
211
212 self.parse_array_specifier(frontend, ctx.ctx, &mut meta, &mut ty)?;
220
221 let is_global_const =
222 ctx.qualifiers.storage.0 == StorageQualifier::Const && ctx.external;
223
224 let init = self
225 .bump_if(frontend, TokenValue::Assign)
226 .map::<Result<_>, _>(|_| {
227 let prev_const = ctx.ctx.is_const;
228 ctx.ctx.is_const = is_global_const;
229
230 let (mut expr, init_meta) = self.parse_initializer(frontend, ty, ctx.ctx)?;
231
232 let scalar_components = scalar_components(&ctx.ctx.module.types[ty].inner);
233 if let Some(scalar) = scalar_components {
234 ctx.ctx.implicit_conversion(&mut expr, init_meta, scalar)?;
235 }
236
237 ctx.ctx.is_const = prev_const;
238
239 meta.subsume(init_meta);
240
241 Ok(expr)
242 })
243 .transpose()?;
244
245 let decl_initializer;
246 let late_initializer;
247 if is_global_const {
248 decl_initializer = init;
249 late_initializer = None;
250 } else if ctx.external {
251 decl_initializer =
252 init.and_then(|expr| ctx.ctx.lift_up_const_expression(expr).ok());
253 late_initializer = None;
254 } else if let Some(init) = init {
255 if ctx.is_inside_loop || !ctx.ctx.local_expression_kind_tracker.is_const(init) {
256 decl_initializer = None;
257 late_initializer = Some(init);
258 } else {
259 decl_initializer = Some(init);
260 late_initializer = None;
261 }
262 } else {
263 decl_initializer = None;
264 late_initializer = None;
265 };
266
267 let pointer = ctx.add_var(frontend, ty, name, decl_initializer, meta)?;
268
269 if let Some(value) = late_initializer {
270 ctx.ctx.emit_restart();
271 ctx.ctx.body.push(Statement::Store { pointer, value }, meta);
272 }
273
274 let token = self.bump(frontend)?;
275 match token.value {
276 TokenValue::Semicolon => break,
277 TokenValue::Comma => {}
278 _ => {
279 return Err(Error {
280 kind: ErrorKind::InvalidToken(
281 token.value,
282 vec![TokenValue::Comma.into(), TokenValue::Semicolon.into()],
283 ),
284 meta: token.meta,
285 })
286 }
287 }
288 }
289
290 Ok(())
291 }
292
293 pub fn parse_declaration(
295 &mut self,
296 frontend: &mut Frontend,
297 ctx: &mut Context,
298 external: bool,
299 is_inside_loop: bool,
300 ) -> Result<Option<Span>> {
301 if self.peek_type_qualifier(frontend) || self.peek_type_name(frontend) {
314 let mut qualifiers = self.parse_type_qualifiers(frontend, ctx)?;
315
316 if self.peek_type_name(frontend) {
317 let (ty, mut meta) = self.parse_type(frontend, ctx)?;
320
321 let token = self.bump(frontend)?;
322 let token_fallthrough = match token.value {
323 TokenValue::Identifier(name) => match self.expect_peek(frontend)?.value {
324 TokenValue::LeftParen => {
325 self.bump(frontend)?;
327
328 let result = ty.map(|ty| FunctionResult { ty, binding: None });
329
330 let mut context = Context::new(
331 frontend,
332 ctx.module,
333 false,
334 ctx.global_expression_kind_tracker,
335 )?;
336
337 self.parse_function_args(frontend, &mut context)?;
338
339 let end_meta = self.expect(frontend, TokenValue::RightParen)?.meta;
340 meta.subsume(end_meta);
341
342 let token = self.bump(frontend)?;
343 return match token.value {
344 TokenValue::Semicolon => {
345 frontend.add_prototype(context, name, result, meta);
347
348 Ok(Some(meta))
349 }
350 TokenValue::LeftBrace if external => {
351 self.parse_compound_statement(
357 token.meta,
358 frontend,
359 &mut context,
360 &mut None,
361 false,
362 )?;
363
364 frontend.add_function(context, name, result, meta);
365
366 Ok(Some(meta))
367 }
368 _ if external => Err(Error {
369 kind: ErrorKind::InvalidToken(
370 token.value,
371 vec![
372 TokenValue::LeftBrace.into(),
373 TokenValue::Semicolon.into(),
374 ],
375 ),
376 meta: token.meta,
377 }),
378 _ => Err(Error {
379 kind: ErrorKind::InvalidToken(
380 token.value,
381 vec![TokenValue::Semicolon.into()],
382 ),
383 meta: token.meta,
384 }),
385 };
386 }
387 _ => Token {
389 value: TokenValue::Identifier(name),
390 meta: token.meta,
391 },
392 },
393 _ => token,
395 };
396
397 if let Some(ty) = ty {
401 let mut ctx = DeclarationContext {
402 qualifiers,
403 external,
404 is_inside_loop,
405 ctx,
406 };
407
408 self.backtrack(token_fallthrough)?;
409 self.parse_init_declarator_list(frontend, ty, &mut ctx)?;
410 } else {
411 frontend.errors.push(Error {
412 kind: ErrorKind::SemanticError("Declaration cannot have void type".into()),
413 meta,
414 })
415 }
416
417 Ok(Some(meta))
418 } else {
419 let token = self.bump(frontend)?;
424 match token.value {
425 TokenValue::Identifier(ty_name) => {
426 if self.bump_if(frontend, TokenValue::LeftBrace).is_some() {
427 self.parse_block_declaration(
428 frontend,
429 ctx,
430 &mut qualifiers,
431 ty_name,
432 token.meta,
433 )
434 .map(Some)
435 } else {
436 if qualifiers.invariant.take().is_some() {
437 frontend.make_variable_invariant(ctx, &ty_name, token.meta)?;
438
439 qualifiers.unused_errors(&mut frontend.errors);
440 self.expect(frontend, TokenValue::Semicolon)?;
441 return Ok(Some(qualifiers.span));
442 }
443
444 Err(Error {
448 kind: ErrorKind::NotImplemented("variable qualifier"),
449 meta: token.meta,
450 })
451 }
452 }
453 TokenValue::Semicolon => {
454 if let Some(value) =
455 qualifiers.uint_layout_qualifier("local_size_x", &mut frontend.errors)
456 {
457 frontend.meta.workgroup_size[0] = value;
458 }
459 if let Some(value) =
460 qualifiers.uint_layout_qualifier("local_size_y", &mut frontend.errors)
461 {
462 frontend.meta.workgroup_size[1] = value;
463 }
464 if let Some(value) =
465 qualifiers.uint_layout_qualifier("local_size_z", &mut frontend.errors)
466 {
467 frontend.meta.workgroup_size[2] = value;
468 }
469
470 frontend.meta.early_fragment_tests |= qualifiers
471 .none_layout_qualifier("early_fragment_tests", &mut frontend.errors);
472
473 qualifiers.unused_errors(&mut frontend.errors);
474
475 Ok(Some(qualifiers.span))
476 }
477 _ => Err(Error {
478 kind: ErrorKind::InvalidToken(
479 token.value,
480 vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()],
481 ),
482 meta: token.meta,
483 }),
484 }
485 }
486 } else {
487 match self.peek(frontend).map(|t| &t.value) {
488 Some(&TokenValue::Precision) => {
489 self.bump(frontend)?;
491
492 let token = self.bump(frontend)?;
493 let _ = match token.value {
494 TokenValue::PrecisionQualifier(p) => p,
495 _ => {
496 return Err(Error {
497 kind: ErrorKind::InvalidToken(
498 token.value,
499 vec![
500 TokenValue::PrecisionQualifier(Precision::High).into(),
501 TokenValue::PrecisionQualifier(Precision::Medium).into(),
502 TokenValue::PrecisionQualifier(Precision::Low).into(),
503 ],
504 ),
505 meta: token.meta,
506 })
507 }
508 };
509
510 let (ty, meta) = self.parse_type_non_void(frontend, ctx)?;
511
512 match ctx.module.types[ty].inner {
513 TypeInner::Scalar(Scalar {
514 kind: ScalarKind::Float | ScalarKind::Sint,
515 ..
516 }) => {}
517 _ => frontend.errors.push(Error {
518 kind: ErrorKind::SemanticError(
519 "Precision statement can only work on floats and ints".into(),
520 ),
521 meta,
522 }),
523 }
524
525 self.expect(frontend, TokenValue::Semicolon)?;
526
527 Ok(Some(meta))
528 }
529 _ => Ok(None),
530 }
531 }
532 }
533
534 pub fn parse_block_declaration(
535 &mut self,
536 frontend: &mut Frontend,
537 ctx: &mut Context,
538 qualifiers: &mut TypeQualifiers,
539 ty_name: String,
540 mut meta: Span,
541 ) -> Result<Span> {
542 let layout = match qualifiers.layout_qualifiers.remove(&QualifierKey::Layout) {
543 Some((QualifierValue::Layout(l), _)) => l,
544 None => {
545 if let StorageQualifier::AddressSpace(AddressSpace::Storage { .. }) =
546 qualifiers.storage.0
547 {
548 StructLayout::Std430
549 } else {
550 StructLayout::Std140
551 }
552 }
553 _ => unreachable!(),
554 };
555
556 let mut members = Vec::new();
557 let span = self.parse_struct_declaration_list(frontend, ctx, &mut members, layout)?;
558 self.expect(frontend, TokenValue::RightBrace)?;
559
560 let mut ty = ctx.module.types.insert(
561 Type {
562 name: Some(ty_name),
563 inner: TypeInner::Struct {
564 members: members.clone(),
565 span,
566 },
567 },
568 Default::default(),
569 );
570
571 let token = self.bump(frontend)?;
572 let name = match token.value {
573 TokenValue::Semicolon => None,
574 TokenValue::Identifier(name) => {
575 self.parse_array_specifier(frontend, ctx, &mut meta, &mut ty)?;
576
577 self.expect(frontend, TokenValue::Semicolon)?;
578
579 Some(name)
580 }
581 _ => {
582 return Err(Error {
583 kind: ErrorKind::InvalidToken(
584 token.value,
585 vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()],
586 ),
587 meta: token.meta,
588 })
589 }
590 };
591
592 let global = frontend.add_global_var(
593 ctx,
594 VarDeclaration {
595 qualifiers,
596 ty,
597 name,
598 init: None,
599 meta,
600 },
601 )?;
602
603 for (i, k, ty) in members.into_iter().enumerate().filter_map(|(i, m)| {
604 let ty = m.ty;
605 m.name.map(|s| (i as u32, s, ty))
606 }) {
607 let lookup = GlobalLookup {
608 kind: match global {
609 GlobalOrConstant::Global(handle) => GlobalLookupKind::BlockSelect(handle, i),
610 GlobalOrConstant::Constant(handle) => GlobalLookupKind::Constant(handle, ty),
611 },
612 entry_arg: None,
613 mutable: true,
614 };
615 ctx.add_global(&k, lookup)?;
616
617 frontend.global_variables.push((k, lookup));
618 }
619
620 Ok(meta)
621 }
622
623 pub fn parse_struct_declaration_list(
625 &mut self,
626 frontend: &mut Frontend,
627 ctx: &mut Context,
628 members: &mut Vec<StructMember>,
629 layout: StructLayout,
630 ) -> Result<u32> {
631 let mut span = 0;
632 let mut align = Alignment::ONE;
633
634 loop {
635 let (base_ty, mut meta) = self.parse_type_non_void(frontend, ctx)?;
638
639 loop {
640 let (name, name_meta) = self.expect_ident(frontend)?;
641 let mut ty = base_ty;
642 self.parse_array_specifier(frontend, ctx, &mut meta, &mut ty)?;
643
644 meta.subsume(name_meta);
645
646 let info = offset::calculate_offset(
647 ty,
648 meta,
649 layout,
650 &mut ctx.module.types,
651 &mut frontend.errors,
652 );
653
654 let member_alignment = info.align;
655 span = member_alignment.round_up(span);
656 align = member_alignment.max(align);
657
658 members.push(StructMember {
659 name: Some(name),
660 ty: info.ty,
661 binding: None,
662 offset: span,
663 });
664
665 span += info.span;
666
667 if self.bump_if(frontend, TokenValue::Comma).is_none() {
668 break;
669 }
670 }
671
672 self.expect(frontend, TokenValue::Semicolon)?;
673
674 if let TokenValue::RightBrace = self.expect_peek(frontend)?.value {
675 break;
676 }
677 }
678
679 span = align.round_up(span);
680
681 Ok(span)
682 }
683}