diff --git a/src/front/glsl/ast.rs b/src/front/glsl/ast.rs index 94ef4c173a..453c31a418 100644 --- a/src/front/glsl/ast.rs +++ b/src/front/glsl/ast.rs @@ -1,15 +1,16 @@ use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind, TokenMetadata}; use crate::{ - proc::ResolveContext, Arena, ArraySize, BinaryOperator, Block, BuiltIn, Constant, Expression, - FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, - Module, RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, - Type, TypeInner, UnaryOperator, + proc::ResolveContext, Arena, BinaryOperator, Block, BuiltIn, Constant, Expression, FastHashMap, + Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module, + RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type, + TypeInner, UnaryOperator, }; #[derive(Debug)] pub enum GlobalLookup { Variable(Handle), - Select(u32), + InOutSelect(u32), + BlockSelect(Handle, u32), } #[derive(Debug, PartialEq, Eq, Hash)] @@ -162,52 +163,6 @@ impl<'a> Program<'a> { vec![ParameterQualifier::In], ) } - - #[allow(dead_code)] // FIXME: Remove after implementing structs - pub fn type_size(&self, ty: Handle) -> Result { - Ok(match self.module.types[ty].inner { - crate::TypeInner::Scalar { width, .. } => width, - crate::TypeInner::Vector { size, width, .. } => size as u8 * width, - crate::TypeInner::Matrix { - columns, - rows, - width, - } => columns as u8 * rows as u8 * width, - crate::TypeInner::Pointer { .. } => { - return Err(ErrorKind::NotImplemented("type size of pointer")) - } - crate::TypeInner::ValuePointer { .. } => { - return Err(ErrorKind::NotImplemented("type size of value pointer")) - } - crate::TypeInner::Array { size, stride, .. } => { - stride as u8 - * match size { - ArraySize::Dynamic => { - return Err(ErrorKind::NotImplemented("type size of dynamic array")) - } - ArraySize::Constant(constant) => { - match self.module.constants[constant].inner { - crate::ConstantInner::Scalar { width, .. } => width, - crate::ConstantInner::Composite { .. } => { - return Err(ErrorKind::NotImplemented( - "type size of array with composite item size", - )) - } - } - } - } - } - crate::TypeInner::Struct { .. } => { - return Err(ErrorKind::NotImplemented("type size of struct")) - } - crate::TypeInner::Image { .. } => { - return Err(ErrorKind::NotImplemented("type size of image")) - } - crate::TypeInner::Sampler { .. } => { - return Err(ErrorKind::NotImplemented("type size of sampler")) - } - }) - } } #[derive(Debug)] @@ -265,9 +220,14 @@ impl<'function> Context<'function> { self.lookup_global_var_exps.get(name).cloned().or_else(|| { let expr = match *program.lookup_global_variables.get(name)? { GlobalLookup::Variable(v) => Expression::GlobalVariable(v), - GlobalLookup::Select(index) => { + GlobalLookup::InOutSelect(index) => { let base = self.expressions.append(Expression::FunctionArgument(0)); + Expression::AccessIndex { base, index } + } + GlobalLookup::BlockSelect(handle, index) => { + let base = self.expressions.append(Expression::GlobalVariable(handle)); + Expression::AccessIndex { base, index } } }; diff --git a/src/front/glsl/parser.rs b/src/front/glsl/parser.rs index 28b1540d27..22275873dc 100644 --- a/src/front/glsl/parser.rs +++ b/src/front/glsl/parser.rs @@ -1,7 +1,7 @@ use super::{ ast::{ - Context, Expr, ExprKind, FunctionCall, FunctionCallKind, ParameterQualifier, Profile, - StorageQualifier, StructLayout, TypeQualifier, + Context, Expr, ExprKind, FunctionCall, FunctionCallKind, GlobalLookup, ParameterQualifier, + Profile, StorageQualifier, StructLayout, TypeQualifier, }, error::ErrorKind, lex::Lexer, @@ -10,8 +10,8 @@ use super::{ }; use crate::{ arena::Handle, Arena, ArraySize, BinaryOperator, Block, Constant, ConstantInner, Expression, - Function, FunctionResult, ResourceBinding, ScalarValue, Statement, StorageClass, SwitchCase, - Type, TypeInner, UnaryOperator, + Function, FunctionResult, GlobalVariable, ResourceBinding, ScalarValue, Statement, + StorageAccess, StorageClass, StructMember, SwitchCase, Type, TypeInner, UnaryOperator, }; use core::convert::TryFrom; use std::{iter::Peekable, mem}; @@ -627,7 +627,16 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { // ``` let token = self.bump()?; match token.value { - TokenValue::Identifier(_) => todo!(), + TokenValue::Identifier(ty_name) => { + if self.bump_if(TokenValue::LeftBrace).is_some() { + self.parse_block_declaration(&qualifiers, ty_name) + } else { + //TODO: declaration + // type_qualifier IDENTIFIER SEMICOLON + // type_qualifier IDENTIFIER identifier_list SEMICOLON + todo!() + } + } TokenValue::Semicolon => Ok(true), _ => Err(ErrorKind::InvalidToken(token)), } @@ -638,6 +647,147 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { } } + fn parse_block_declaration( + &mut self, + qualifiers: &[TypeQualifier], + ty_name: String, + ) -> Result { + let mut class = StorageClass::Function; + let mut binding = None; + let mut layout = None; + + for qualifier in qualifiers { + match *qualifier { + TypeQualifier::StorageQualifier(StorageQualifier::StorageClass(c)) => { + if StorageClass::Function != class { + return Err(ErrorKind::SemanticError( + "Cannot use more than one storage qualifier per declaration".into(), + )); + } + + class = c; + } + TypeQualifier::ResourceBinding(ref r) => { + if binding.is_some() { + return Err(ErrorKind::SemanticError( + "Cannot use more than one storage qualifier per declaration".into(), + )); + } + + binding = Some(r.clone()); + } + TypeQualifier::Layout(ref l) => { + if layout.is_some() { + return Err(ErrorKind::SemanticError( + "Cannot use more than one storage qualifier per declaration".into(), + )); + } + + layout = Some(l); + } + _ => { + return Err(ErrorKind::SemanticError( + "Qualifier not supported in block declarations".into(), + )); + } + } + } + + let mut members = Vec::new(); + let span = self.parse_struct_declaration_list(&mut members)?; + self.expect(TokenValue::RightBrace)?; + + let mut ty = self.program.module.types.append(Type { + name: Some(ty_name), + inner: TypeInner::Struct { + top_level: true, + members: members.clone(), + span, + }, + }); + + let token = self.bump()?; + let name = match token.value { + TokenValue::Semicolon => None, + TokenValue::Identifier(name) => { + if let Some(size) = self.parse_array_specifier()? { + ty = self.program.module.types.append(Type { + name: None, + inner: TypeInner::Array { + base: ty, + size, + stride: self.program.module.types[ty] + .inner + .span(&self.program.module.constants), + }, + }); + } + + self.expect(TokenValue::Semicolon)?; + + Some(name) + } + _ => return Err(ErrorKind::InvalidToken(token)), + }; + + let handle = self.program.module.global_variables.append(GlobalVariable { + name: name.clone(), + class, + binding, + ty, + init: None, + // TODO + storage_access: StorageAccess::all(), + }); + + if let Some(k) = name { + self.program + .lookup_global_variables + .insert(k, GlobalLookup::Variable(handle)); + } + + for (i, k) in members + .into_iter() + .enumerate() + .filter_map(|(i, m)| m.name.map(|s| (i as u32, s))) + { + self.program + .lookup_global_variables + .insert(k, GlobalLookup::BlockSelect(handle, i)); + } + + Ok(true) + } + + // TODO: Accept layout arguments + fn parse_struct_declaration_list(&mut self, members: &mut Vec) -> Result { + let mut span = 0; + + loop { + // TODO: type_qualifier + if !self.peek_type_name() { + break; + } + + let ty = self.parse_type_non_void()?; + let name = self.expect_ident()?.0; + self.expect(TokenValue::Semicolon)?; + + members.push(StructMember { + name: Some(name), + ty, + binding: None, + offset: span, + }); + + span = self.program.module.types[ty] + .inner + .span(&self.program.module.constants); + } + + Ok(span) + } + fn parse_primary(&mut self, ctx: &mut Context) -> Result { let mut token = self.bump()?; diff --git a/src/front/glsl/parser_tests.rs b/src/front/glsl/parser_tests.rs index 4f74348bf7..a9e22fa7c8 100644 --- a/src/front/glsl/parser_tests.rs +++ b/src/front/glsl/parser_tests.rs @@ -187,20 +187,37 @@ fn declarations() { ) .unwrap(); - // TODO: Reenable tests later - // let _program = parse_program( - // r#" - // #version 450 - // layout(std140, set = 2, binding = 0) - // uniform u_locals { - // vec3 model_offs; - // float load_time; - // ivec4 atlas_offs; - // }; - // "#, - // &entry_points, - // ) - // .unwrap(); + let _program = parse_program( + r#" + #version 450 + layout(std140, set = 2, binding = 0) + uniform u_locals { + vec3 model_offs; + float load_time; + ivec4 atlas_offs; + }; + "#, + &entry_points, + ) + .unwrap(); + + let _program = parse_program( + r#" + #version 450 + layout(std140, set = 2, binding = 0) + uniform u_locals { + vec3 model_offs; + float load_time; + } block_var; + + void main() { + load_time * model_offs; + block_var.load_time * block_var.model_offs; + } + "#, + &entry_points, + ) + .unwrap(); } #[test] diff --git a/src/front/glsl/variables.rs b/src/front/glsl/variables.rs index 6b629aed38..12def04225 100644 --- a/src/front/glsl/variables.rs +++ b/src/front/glsl/variables.rs @@ -301,7 +301,7 @@ impl Program<'_> { ); self.lookup_global_variables - .insert(name, GlobalLookup::Select(index)); + .insert(name, GlobalLookup::InOutSelect(index)); let base = ctx.expressions.append(Expression::FunctionArgument(0)); return Ok(ctx