From 1aaf77489b44bc4b56ea294de0209b8926855c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Capucho?= Date: Sun, 8 Aug 2021 00:10:56 +0100 Subject: [PATCH] [glsl-in] Improve error api and make more errors deferred --- cli/src/main.rs | 15 +- src/front/glsl/ast.rs | 5 +- src/front/glsl/context.rs | 70 +++--- src/front/glsl/error.rs | 99 ++++---- src/front/glsl/functions.rs | 177 ++++++++------- src/front/glsl/mod.rs | 12 +- src/front/glsl/offset.rs | 22 +- src/front/glsl/parser.rs | 213 ++++++++++-------- src/front/glsl/parser/declarations.rs | 145 +++++++----- src/front/glsl/parser/expressions.rs | 43 ++-- src/front/glsl/parser/functions.rs | 41 ++-- src/front/glsl/parser/types.rs | 143 ++++++------ src/front/glsl/parser_tests.rs | 83 ++++--- src/front/glsl/token.rs | 12 +- src/front/glsl/types.rs | 18 +- src/front/glsl/variables.rs | 208 +++++++++++------ tests/in/glsl/800-out-of-bounds-panic.vert | 3 +- .../wgsl/800-out-of-bounds-panic-vert.wgsl | 3 + 18 files changed, 720 insertions(+), 592 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index 0aa384c45d..d5ef5ccc4f 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -409,22 +409,15 @@ use codespan_reporting::{ }, }; -pub fn emit_glsl_parser_error( - errors: Vec, - filename: &str, - source: &str, -) { +pub fn emit_glsl_parser_error(errors: Vec, filename: &str, source: &str) { let files = SimpleFile::new(filename, source); let config = codespan_reporting::term::Config::default(); let writer = StandardStream::stderr(ColorChoice::Auto); for err in errors { - let diagnostic = match err.kind.metadata() { - Some(metadata) => Diagnostic::error() - .with_message(err.kind.to_string()) - .with_labels(vec![Label::primary((), metadata.start..metadata.end)]), - None => Diagnostic::error().with_message(err.kind.to_string()), - }; + let diagnostic = Diagnostic::error() + .with_message(err.kind.to_string()) + .with_labels(vec![Label::primary((), err.meta.start..err.meta.end)]); term::emit(&mut writer.lock(), &config, &files, &diagnostic).expect("cannot write error"); } diff --git a/src/front/glsl/ast.rs b/src/front/glsl/ast.rs index 751fb4d67a..c5e46a96ba 100644 --- a/src/front/glsl/ast.rs +++ b/src/front/glsl/ast.rs @@ -1,7 +1,7 @@ use super::SourceMetadata; use crate::{ BinaryOperator, Binding, Constant, Expression, Function, GlobalVariable, Handle, Interpolation, - ResourceBinding, Sampling, StorageAccess, StorageClass, Type, UnaryOperator, + Sampling, StorageAccess, StorageClass, Type, UnaryOperator, }; #[derive(Debug, Clone, Copy)] @@ -102,7 +102,8 @@ pub enum HirExprKind { pub enum TypeQualifier { StorageQualifier(StorageQualifier), Interpolation(Interpolation), - ResourceBinding(ResourceBinding), + Set(u32), + Binding(u32), Location(u32), WorkGroupSize(usize, u32), Sampling(Sampling), diff --git a/src/front/glsl/context.rs b/src/front/glsl/context.rs index b756bb08da..74053f0fdd 100644 --- a/src/front/glsl/context.rs +++ b/src/front/glsl/context.rs @@ -5,9 +5,9 @@ use crate::{ GlobalLookup, GlobalLookupKind, HirExpr, HirExprKind, ParameterInfo, ParameterQualifier, VariableReference, }, - error::ErrorKind, + error::{Error, ErrorKind}, types::{scalar_components, type_power}, - Parser, SourceMetadata, + Parser, Result, SourceMetadata, }, Emitter, Typifier, }, @@ -288,16 +288,16 @@ impl Context { expr: Handle, lhs: bool, body: &mut Block, - ) -> Result<(Handle, SourceMetadata), ErrorKind> { + ) -> Result<(Handle, SourceMetadata)> { let (maybe_expr, meta) = self.lower(parser, expr, lhs, body)?; let expr = match maybe_expr { Some(e) => e, None => { - return Err(ErrorKind::SemanticError( + return Err(Error { + kind: ErrorKind::SemanticError("Expression returns void".into()), meta, - "Expression returns void".into(), - )) + }) } }; @@ -310,7 +310,7 @@ impl Context { expr: Handle, lhs: bool, body: &mut Block, - ) -> Result<(Option>, SourceMetadata), ErrorKind> { + ) -> Result<(Option>, SourceMetadata)> { let HirExpr { kind, meta } = self.hir_exprs[expr].clone(); let handle = match kind { @@ -448,10 +448,12 @@ impl Context { HirExprKind::Variable(var) => { if lhs { if !var.mutable { - return Err(ErrorKind::SemanticError( + parser.errors.push(Error { + kind: ErrorKind::SemanticError( + "Variable cannot be used in LHS position".into(), + ), meta, - "Variable cannot be used in LHS position".into(), - )); + }) } var.expr @@ -567,23 +569,18 @@ impl Context { let pointer = self.lower_expect(parser, expr, true, body)?.0; let left = self.add_expression(Expression::Load { pointer }, body); - let uint = if let Some(kind) = parser.resolve_type(self, left, meta)?.scalar_kind() - { - match kind { - ScalarKind::Sint => false, - ScalarKind::Uint => true, - _ => { - return Err(ErrorKind::SemanticError( - meta, + let uint = match parser.resolve_type(self, left, meta)?.scalar_kind() { + Some(ScalarKind::Sint) => false, + Some(ScalarKind::Uint) => true, + _ => { + parser.errors.push(Error { + kind: ErrorKind::SemanticError( "Increment/decrement operations must operate in integers".into(), - )) - } + ), + meta, + }); + true } - } else { - return Err(ErrorKind::SemanticError( - meta, - "Increment/decrement operations must operate in integers".into(), - )); }; let one = parser.module.constants.append(Constant { @@ -644,10 +641,13 @@ impl Context { } } _ => { - return Err(ErrorKind::SemanticError( + return Err(Error { + kind: ErrorKind::SemanticError( + format!("{:?} cannot be in the left hand side", self.hir_exprs[expr]) + .into(), + ), meta, - format!("{:?} cannot be in the left hand side", self.hir_exprs[expr]).into(), - )) + }) } }; @@ -659,7 +659,7 @@ impl Context { parser: &mut Parser, expr: Handle, meta: SourceMetadata, - ) -> Result, ErrorKind> { + ) -> Result> { let ty = parser.resolve_type(self, expr, meta)?; Ok(scalar_components(ty)) } @@ -669,16 +669,12 @@ impl Context { parser: &mut Parser, expr: Handle, meta: SourceMetadata, - ) -> Result, ErrorKind> { + ) -> Result> { Ok(self .expr_scalar_components(parser, expr, meta)? .and_then(|(kind, _)| type_power(kind))) } - pub fn get_expression(&self, expr: Handle) -> &Expression { - &self.expressions[expr] - } - pub fn implicit_conversion( &mut self, parser: &mut Parser, @@ -686,7 +682,7 @@ impl Context { meta: SourceMetadata, kind: ScalarKind, width: crate::Bytes, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { if let (Some(tgt_power), Some(expr_power)) = (type_power(kind), self.expr_power(parser, *expr, meta)?) { @@ -709,7 +705,7 @@ impl Context { left_meta: SourceMetadata, right: &mut Handle, right_meta: SourceMetadata, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { let left_components = self.expr_scalar_components(parser, *left, left_meta)?; let right_components = self.expr_scalar_components(parser, *right, right_meta)?; @@ -749,7 +745,7 @@ impl Context { expr: &mut Handle, meta: SourceMetadata, vector_size: Option, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { let expr_type = parser.resolve_type(self, *expr, meta)?; if let (&TypeInner::Scalar { .. }, Some(size)) = (expr_type, vector_size) { diff --git a/src/front/glsl/error.rs b/src/front/glsl/error.rs index eb9f5395e2..f6ce380118 100644 --- a/src/front/glsl/error.rs +++ b/src/front/glsl/error.rs @@ -1,6 +1,6 @@ use super::{ constants::ConstantSolvingError, - token::{SourceMetadata, Token, TokenValue}, + token::{SourceMetadata, TokenValue}, }; use pp_rs::token::PreprocessorError; use std::borrow::Cow; @@ -53,49 +53,46 @@ impl std::fmt::Display for ExpectedToken { pub enum ErrorKind { #[error("Unexpected end of file")] EndOfFile, - #[error("Invalid profile: {1}")] - InvalidProfile(SourceMetadata, String), - #[error("Invalid version: {1}")] - InvalidVersion(SourceMetadata, u64), - #[error("Expected {}, found {0}", join_with_comma(.1))] - InvalidToken(Token, Vec), - #[error("Not implemented: {1}")] - NotImplemented(SourceMetadata, &'static str), - #[error("Unknown variable: {1}")] - UnknownVariable(SourceMetadata, String), - #[error("Unknown type: {1}")] - UnknownType(SourceMetadata, String), - #[error("Unknown field: {1}")] - UnknownField(SourceMetadata, String), - #[error("Unknown layout qualifier: {1}")] - UnknownLayoutQualifier(SourceMetadata, String), + #[error("Invalid profile: {0}")] + InvalidProfile(String), + #[error("Invalid version: {0}")] + InvalidVersion(u64), + #[error("Expected {}, found {0:?}", join_with_comma(.1))] + InvalidToken(TokenValue, Vec), + #[error("Not implemented: {0}")] + NotImplemented(&'static str), + #[error("Unknown variable: {0}")] + UnknownVariable(String), + #[error("Unknown type: {0}")] + UnknownType(String), + #[error("Unknown field: {0}")] + UnknownField(String), + #[error("Unknown layout qualifier: {0}")] + UnknownLayoutQualifier(String), #[cfg(feature = "glsl-validate")] - #[error("Variable already declared: {1}")] - VariableAlreadyDeclared(SourceMetadata, String), - #[error("{1}")] - SemanticError(SourceMetadata, Cow<'static, str>), - #[error("{1:?}")] - PreprocessorError(SourceMetadata, PreprocessorError), + #[error("Variable already declared: {0}")] + VariableAlreadyDeclared(String), + #[error("{0}")] + SemanticError(Cow<'static, str>), + #[error("{0:?}")] + PreprocessorError(PreprocessorError), } -impl ErrorKind { - /// Returns the TokenMetadata if available - pub fn metadata(&self) -> Option { - match *self { - ErrorKind::UnknownVariable(metadata, _) - | ErrorKind::InvalidProfile(metadata, _) - | ErrorKind::InvalidVersion(metadata, _) - | ErrorKind::NotImplemented(metadata, _) - | ErrorKind::UnknownLayoutQualifier(metadata, _) - | ErrorKind::SemanticError(metadata, _) - | ErrorKind::UnknownField(metadata, _) => Some(metadata), - #[cfg(feature = "glsl-validate")] - ErrorKind::VariableAlreadyDeclared(metadata, _) => Some(metadata), - ErrorKind::InvalidToken(ref token, _) => Some(token.meta), - _ => None, - } +impl From for ErrorKind { + fn from(err: ConstantSolvingError) -> Self { + ErrorKind::SemanticError(err.to_string().into()) } +} +#[derive(Debug, Error)] +#[error("{kind}")] +#[cfg_attr(test, derive(PartialEq))] +pub struct Error { + pub kind: ErrorKind, + pub meta: SourceMetadata, +} + +impl Error { pub(crate) fn wrong_function_args( name: String, expected: usize, @@ -107,25 +104,9 @@ impl ErrorKind { name, expected, got ); - ErrorKind::SemanticError(meta, msg.into()) - } -} - -impl From<(SourceMetadata, ConstantSolvingError)> for ErrorKind { - fn from((meta, err): (SourceMetadata, ConstantSolvingError)) -> Self { - ErrorKind::SemanticError(meta, err.to_string().into()) - } -} - -#[derive(Debug, Error)] -#[error("{kind}")] -#[cfg_attr(test, derive(PartialEq))] -pub struct ParseError { - pub kind: ErrorKind, -} - -impl From for ParseError { - fn from(kind: ErrorKind) -> Self { - ParseError { kind } + Error { + kind: ErrorKind::SemanticError(msg.into()), + meta, + } } } diff --git a/src/front/glsl/functions.rs b/src/front/glsl/functions.rs index 3d3ab3932c..bc7ec3b1bf 100644 --- a/src/front/glsl/functions.rs +++ b/src/front/glsl/functions.rs @@ -2,9 +2,9 @@ use crate::{ front::glsl::{ ast::*, context::Context, - error::ErrorKind, + error::{Error, ErrorKind}, types::{scalar_components, type_power}, - Parser, SourceMetadata, + Parser, Result, SourceMetadata, }, proc::ensure_block_returns, Arena, BinaryOperator, Block, Constant, ConstantInner, EntryPoint, Expression, FastHashMap, @@ -46,11 +46,11 @@ impl Parser { fc: FunctionCallKind, raw_args: &[Handle], meta: SourceMetadata, - ) -> Result>, ErrorKind> { + ) -> Result>> { let args: Vec<_> = raw_args .iter() .map(|e| ctx.lower_expect(self, *e, false, body)) - .collect::>()?; + .collect::>()?; match fc { FunctionCallKind::TypeConstructor(ty) => { @@ -226,7 +226,14 @@ impl Parser { }, body, ), - _ => return Err(ErrorKind::SemanticError(meta, "Bad cast".into())), + _ => { + self.errors.push(Error { + kind: ErrorKind::SemanticError("Bad cast".into()), + meta, + }); + + args[0].0 + } } } else { let mut components = Vec::with_capacity(args.len()); @@ -314,12 +321,12 @@ impl Parser { mut args: Vec<(Handle, SourceMetadata)>, raw_args: &[Handle], meta: SourceMetadata, - ) -> Result>, ErrorKind> { + ) -> Result>> { match name.as_str() { "sampler1D" | "sampler1DArray" | "sampler2D" | "sampler2DArray" | "sampler2DMS" | "sampler2DMSArray" | "sampler3D" | "samplerCube" | "samplerCubeArray" => { if args.len() != 2 { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } ctx.samplers.insert(args[0].0, args[1].0); Ok(Some(args[0].0)) @@ -331,16 +338,16 @@ impl Parser { | "samplerCubeShadow" | "samplerCubeArrayShadow" => { if args.len() != 2 { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } - sampled_to_depth(&mut self.module, ctx, args[0])?; + sampled_to_depth(&mut self.module, ctx, args[0], &mut self.errors)?; self.invalidate_expression(ctx, args[0].0, args[0].1)?; ctx.samplers.insert(args[0].0, args[1].0); Ok(Some(args[0].0)) } "texture" => { if !(2..=3).contains(&args.len()) { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } let arg_1 = &mut args[1]; ctx.implicit_conversion(self, &mut arg_1.0, arg_1.1, ScalarKind::Float, 4)?; @@ -366,12 +373,15 @@ impl Parser { ), )) } else { - Err(ErrorKind::SemanticError(meta, "Bad call to texture".into())) + Err(Error { + kind: ErrorKind::SemanticError("Bad call to texture".into()), + meta, + }) } } "textureLod" => { if args.len() != 3 { - return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); + return Err(Error::wrong_function_args(name, 3, args.len(), meta)); } let arg_1 = &mut args[1]; ctx.implicit_conversion(self, &mut arg_1.0, arg_1.1, ScalarKind::Float, 4)?; @@ -392,15 +402,15 @@ impl Parser { body, ))) } else { - Err(ErrorKind::SemanticError( + Err(Error { + kind: ErrorKind::SemanticError("Bad call to textureLod".into()), meta, - "Bad call to textureLod".into(), - )) + }) } } "textureProj" => { if !(2..=3).contains(&args.len()) { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } let arg_1 = &mut args[1]; ctx.implicit_conversion(self, &mut arg_1.0, arg_1.1, ScalarKind::Float, 4)?; @@ -413,10 +423,10 @@ impl Parser { let size = match *self.resolve_type(ctx, args[1].0, args[1].1)? { TypeInner::Vector { size, .. } => size, _ => { - return Err(ErrorKind::SemanticError( + return Err(Error { + kind: ErrorKind::SemanticError("Bad call to textureProj".into()), meta, - "Bad call to textureProj".into(), - )) + }) } }; let (base, base_meta) = args[1]; @@ -460,15 +470,15 @@ impl Parser { body, ))) } else { - Err(ErrorKind::SemanticError( + Err(Error { + kind: ErrorKind::SemanticError("Bad call to textureProj".into()), meta, - "Bad call to textureProj".into(), - )) + }) } } "textureGrad" => { if args.len() != 4 { - return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); + return Err(Error::wrong_function_args(name, 3, args.len(), meta)); } let arg_1 = &mut args[1]; ctx.implicit_conversion(self, &mut arg_1.0, arg_1.1, ScalarKind::Float, 4)?; @@ -494,15 +504,15 @@ impl Parser { body, ))) } else { - Err(ErrorKind::SemanticError( + Err(Error { + kind: ErrorKind::SemanticError("Bad call to textureGrad".into()), meta, - "Bad call to textureGrad".into(), - )) + }) } } "textureSize" => { if !(1..=2).contains(&args.len()) { - return Err(ErrorKind::wrong_function_args(name, 1, args.len(), meta)); + return Err(Error::wrong_function_args(name, 1, args.len(), meta)); } if let Some(&mut (ref mut expr, meta)) = args.get_mut(1) { ctx.implicit_conversion(self, expr, meta, ScalarKind::Sint, 4)?; @@ -519,7 +529,7 @@ impl Parser { } "texelFetch" => { if args.len() != 3 { - return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); + return Err(Error::wrong_function_args(name, 3, args.len(), meta)); } let arg_1 = &mut args[1]; ctx.implicit_conversion(self, &mut arg_1.0, arg_1.1, ScalarKind::Sint, 4)?; @@ -537,10 +547,10 @@ impl Parser { body, ))) } else { - Err(ErrorKind::SemanticError( + Err(Error { + kind: ErrorKind::SemanticError("Bad call to texelFetch".into()), meta, - "Bad call to texelFetch".into(), - )) + }) } } "ceil" | "round" | "floor" | "fract" | "trunc" | "sin" | "abs" | "sqrt" @@ -548,7 +558,7 @@ impl Parser { | "sinh" | "cos" | "cosh" | "tan" | "tanh" | "acos" | "asin" | "log" | "log2" | "length" | "determinant" | "bitCount" | "bitfieldReverse" => { if args.len() != 1 { - return Err(ErrorKind::wrong_function_args(name, 1, args.len(), meta)); + return Err(Error::wrong_function_args(name, 1, args.len(), meta)); } Ok(Some(ctx.add_expression( Expression::Math { @@ -604,13 +614,13 @@ impl Parser { arg1: Some(args[1].0), arg2: None, }, - _ => return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)), + _ => return Err(Error::wrong_function_args(name, 2, args.len(), meta)), }; Ok(Some(ctx.add_expression(expr, body))) } "mod" => { if args.len() != 2 { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } let (mut left, left_meta) = args[0]; @@ -629,7 +639,7 @@ impl Parser { } "min" | "max" => { if args.len() != 2 { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } let (mut arg0, arg0_meta) = args[0]; @@ -661,7 +671,7 @@ impl Parser { "pow" | "dot" | "reflect" | "cross" | "outerProduct" | "distance" | "step" | "modf" | "frexp" | "ldexp" => { if args.len() != 2 { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } let (mut arg0, arg0_meta) = args[0]; @@ -693,7 +703,7 @@ impl Parser { } "mix" => { if args.len() != 3 { - return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); + return Err(Error::wrong_function_args(name, 3, args.len(), meta)); } let (mut arg, arg_meta) = args[0]; @@ -763,7 +773,7 @@ impl Parser { } "clamp" => { if args.len() != 3 { - return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); + return Err(Error::wrong_function_args(name, 3, args.len(), meta)); } let (mut arg0, arg0_meta) = args[0]; @@ -794,7 +804,7 @@ impl Parser { } "faceforward" | "refract" | "fma" | "smoothstep" => { if args.len() != 3 { - return Err(ErrorKind::wrong_function_args(name, 3, args.len(), meta)); + return Err(Error::wrong_function_args(name, 3, args.len(), meta)); } Ok(Some(ctx.add_expression( Expression::Math { @@ -815,7 +825,7 @@ impl Parser { "lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal" | "notEqual" => { if args.len() != 2 { - return Err(ErrorKind::wrong_function_args(name, 2, args.len(), meta)); + return Err(Error::wrong_function_args(name, 2, args.len(), meta)); } Ok(Some(ctx.add_expression( Expression::Binary { @@ -848,8 +858,9 @@ impl Parser { )) } _ => { - let declarations = self.lookup_function.get(&name).ok_or_else(|| { - ErrorKind::SemanticError(meta, format!("Unknown function '{}'", name).into()) + let declarations = self.lookup_function.get(&name).ok_or_else(|| Error { + kind: ErrorKind::SemanticError(format!("Unknown function '{}'", name).into()), + meta, })?; let mut maybe_decl = None; @@ -866,7 +877,7 @@ impl Parser { decl.parameters.iter().enumerate().zip(args.iter()) { if decl.parameters_info[i].depth { - sampled_to_depth(&mut self.module, ctx, *call_arg)?; + sampled_to_depth(&mut self.module, ctx, *call_arg, &mut self.errors)?; self.invalidate_expression(ctx, call_arg.0, call_arg.1)? } @@ -935,14 +946,17 @@ impl Parser { } if ambiguous { - return Err(ErrorKind::SemanticError( + self.errors.push(Error { + kind: ErrorKind::SemanticError( + format!("Ambiguous best function for '{}'", name).into(), + ), meta, - format!("Ambiguous best function for '{}'", name).into(), - )); + }) } - let decl = maybe_decl.ok_or_else(|| { - ErrorKind::SemanticError(meta, format!("Unknown function '{}'", name).into()) + let decl = maybe_decl.ok_or_else(|| Error { + kind: ErrorKind::SemanticError(format!("Unknown function '{}'", name).into()), + meta, })?; let parameters_info = decl.parameters_info.clone(); @@ -963,7 +977,7 @@ impl Parser { *self.resolve_type(ctx, handle, meta)? { if parameter_info.qualifier.is_lhs() - && matches!(*ctx.get_expression(handle), Expression::Swizzle { .. }) + && matches!(ctx[handle], Expression::Swizzle { .. }) { let ty = self.module.types.fetch_or_append(Type { name: None, @@ -1047,9 +1061,9 @@ impl Parser { args: &[(Handle, SourceMetadata)], fun: RelationalFunction, meta: SourceMetadata, - ) -> Result, ErrorKind> { + ) -> Result> { if args.len() != 1 { - return Err(ErrorKind::wrong_function_args(name, 1, args.len(), meta)); + return Err(Error::wrong_function_args(name, 1, args.len(), meta)); } Ok(ctx.add_expression( @@ -1068,7 +1082,7 @@ impl Parser { result: Option, mut body: Block, meta: SourceMetadata, - ) -> Result<(), ErrorKind> { + ) { ensure_block_returns(&mut body); let void = result.is_none(); @@ -1113,16 +1127,16 @@ impl Parser { } if decl.defined { - return Err(ErrorKind::SemanticError( + return self.errors.push(Error { + kind: ErrorKind::SemanticError("Function already defined".into()), meta, - "Function already defined".into(), - )); + }); } decl.defined = true; decl.parameters_info = parameters_info; *self.module.functions.get_mut(decl.handle) = function; - return Ok(()); + return; } let handle = module.functions.append(function); @@ -1133,8 +1147,6 @@ impl Parser { defined: true, void, }); - - Ok(()) } pub fn add_prototype( @@ -1143,7 +1155,7 @@ impl Parser { name: String, result: Option, meta: SourceMetadata, - ) -> Result<(), ErrorKind> { + ) { let void = result.is_none(); let &mut Parser { @@ -1181,10 +1193,10 @@ impl Parser { } } - return Err(ErrorKind::SemanticError( + return self.errors.push(Error { + kind: ErrorKind::SemanticError("Prototype already defined".into()), meta, - "Prototype already defined".into(), - )); + }); } let handle = module.functions.append(function); @@ -1195,8 +1207,6 @@ impl Parser { defined: false, void, }); - - Ok(()) } pub fn add_entry_point( @@ -1204,7 +1214,7 @@ impl Parser { function: Handle, mut global_init_body: Block, mut expressions: Arena, - ) -> Result<(), ErrorKind> { + ) { let mut arguments = Vec::new(); let mut body = Block::with_capacity( // global init body @@ -1305,8 +1315,6 @@ impl Parser { ..Default::default() }, }); - - Ok(()) } /// Helper function for texture calls, splits the vector argument into it's components @@ -1316,7 +1324,7 @@ impl Parser { (image, image_meta): (Handle, SourceMetadata), (coord, coord_meta): (Handle, SourceMetadata), body: &mut Block, - ) -> Result { + ) -> Result { if let TypeInner::Image { dim, arrayed, @@ -1377,10 +1385,16 @@ impl Parser { array_index, }) } else { - Err(ErrorKind::SemanticError( - image_meta, - "Type is not an image".into(), - )) + self.errors.push(Error { + kind: ErrorKind::SemanticError("Type is not an image".into()), + meta: image_meta, + }); + + Ok(CoordComponents { + coordinate: coord, + depth_ref: None, + array_index: None, + }) } } } @@ -1391,7 +1405,8 @@ fn sampled_to_depth( module: &mut Module, ctx: &mut Context, (image, meta): (Handle, SourceMetadata), -) -> Result<(), ErrorKind> { + errors: &mut Vec, +) -> Result<()> { let ty = match ctx[image] { Expression::GlobalVariable(handle) => &mut module.global_variables.get_mut(handle).ty, Expression::FunctionArgument(i) => { @@ -1399,10 +1414,10 @@ fn sampled_to_depth( &mut ctx.arguments[i as usize].ty } _ => { - return Err(ErrorKind::SemanticError( + return Err(Error { + kind: ErrorKind::SemanticError("Not a valid texture expression".into()), meta, - "Not a valid texture expression".into(), - )) + }) } }; match module.types[*ty].inner { @@ -1422,9 +1437,15 @@ fn sampled_to_depth( }) } ImageClass::Depth { .. } => {} - _ => return Err(ErrorKind::SemanticError(meta, "Not a texture".into())), + _ => errors.push(Error { + kind: ErrorKind::SemanticError("Not a texture".into()), + meta, + }), }, - _ => return Err(ErrorKind::SemanticError(meta, "Not a texture".into())), + _ => errors.push(Error { + kind: ErrorKind::SemanticError("Not a texture".into()), + meta, + }), }; Ok(()) diff --git a/src/front/glsl/mod.rs b/src/front/glsl/mod.rs index 2d9f0725d9..9e68f68f6f 100644 --- a/src/front/glsl/mod.rs +++ b/src/front/glsl/mod.rs @@ -1,5 +1,5 @@ pub use ast::Profile; -pub use error::{ErrorKind, ParseError}; +pub use error::{Error, ErrorKind}; pub use token::{SourceMetadata, Token}; use crate::{FastHashMap, FastHashSet, Handle, Module, ShaderStage, Type}; @@ -20,7 +20,7 @@ mod token; mod types; mod variables; -type Result = std::result::Result; +type Result = std::result::Result; pub struct Options { pub stage: ShaderStage, @@ -74,7 +74,7 @@ pub struct Parser { entry_args: Vec, - errors: Vec, + errors: Vec, module: Module, } @@ -97,14 +97,14 @@ impl Parser { &mut self, options: &Options, source: &str, - ) -> std::result::Result> { + ) -> std::result::Result> { self.reset(options.stage); let lexer = lex::Lexer::new(source, &options.defines); let mut ctx = ParsingContext::new(lexer); - if let Err(kind) = ctx.parse(self) { - self.errors.push(ParseError { kind }); + if let Err(e) = ctx.parse(self) { + self.errors.push(e); } if self.errors.is_empty() { diff --git a/src/front/glsl/offset.rs b/src/front/glsl/offset.rs index 72aa9570d3..698aeab35f 100644 --- a/src/front/glsl/offset.rs +++ b/src/front/glsl/offset.rs @@ -8,7 +8,11 @@ //! The OpenGl spec (the layout rules are defined by the OpenGl spec in section //! 7.6.2.2 as opposed to the GLSL spec) uses the term basic machine units which are //! equivalent to bytes. -use super::{ast::StructLayout, error::ErrorKind, SourceMetadata}; +use super::{ + ast::StructLayout, + error::{Error, ErrorKind}, + SourceMetadata, +}; use crate::{Arena, Constant, Handle, Type, TypeInner}; /// Struct with information needed for defining a struct member. @@ -37,7 +41,8 @@ pub fn calculate_offset( layout: StructLayout, types: &mut Arena, constants: &Arena, -) -> Result { + errors: &mut Vec, +) -> TypeAlignSpan { // When using the std430 storage layout, shader storage blocks will be laid out in buffer storage // identically to uniform and shader storage blocks using the std140 layout, except // that the base alignment and stride of arrays of scalars and vectors in rule 4 and of @@ -60,7 +65,7 @@ pub fn calculate_offset( // to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. // TODO: Matrices array TypeInner::Array { base, size, .. } => { - let info = calculate_offset(base, meta, layout, types, constants)?; + let info = calculate_offset(base, meta, layout, types, constants, errors); let name = types[ty].name.clone(); let mut align = info.align; @@ -122,7 +127,7 @@ pub fn calculate_offset( let name = types[ty].name.clone(); for member in members.iter_mut() { - let info = calculate_offset(member.ty, meta, layout, types, constants)?; + let info = calculate_offset(member.ty, meta, layout, types, constants, errors); span = align_up(span, info.align); align = align.max(info.align); @@ -145,14 +150,15 @@ pub fn calculate_offset( (align, span) } _ => { - return Err(ErrorKind::SemanticError( + errors.push(Error { + kind: ErrorKind::SemanticError("Invalid struct member type".into()), meta, - "Invalid struct member type".into(), - )) + }); + (0, 0) } }; - Ok(TypeAlignSpan { ty, align, span }) + TypeAlignSpan { ty, align, span } } /// Helper function used for aligning `value` to the next multiple of `align` diff --git a/src/front/glsl/parser.rs b/src/front/glsl/parser.rs index 09752df984..cde62531e4 100644 --- a/src/front/glsl/parser.rs +++ b/src/front/glsl/parser.rs @@ -9,7 +9,7 @@ use crate::{ token::{Directive, DirectiveKind}, token::{SourceMetadata, Token, TokenValue}, variables::{GlobalOrConstant, VarDeclaration}, - ParseError, Parser, Result, + Error, Parser, Result, }, Block, Constant, ConstantInner, Expression, ScalarValue, Type, }; @@ -24,12 +24,14 @@ mod types; pub struct ParsingContext<'source> { lexer: Peekable>, + last_meta: SourceMetadata, } impl<'source> ParsingContext<'source> { pub fn new(lexer: Lexer<'source>) -> Self { ParsingContext { lexer: lexer.peekable(), + last_meta: SourceMetadata::none(), } } @@ -38,10 +40,10 @@ impl<'source> ParsingContext<'source> { match token.value { TokenValue::Identifier(name) => Ok((name, token.meta)), - _ => Err(ErrorKind::InvalidToken( - token, - vec![ExpectedToken::Identifier], - )), + _ => Err(Error { + kind: ErrorKind::InvalidToken(token.value, vec![ExpectedToken::Identifier]), + meta: token.meta, + }), } } @@ -49,7 +51,10 @@ impl<'source> ParsingContext<'source> { let token = self.bump(parser)?; if token.value != value { - Err(ErrorKind::InvalidToken(token, vec![value.into()])) + Err(Error { + kind: ErrorKind::InvalidToken(token.value, vec![value.into()]), + meta: token.meta, + }) } else { Ok(token) } @@ -60,19 +65,26 @@ impl<'source> ParsingContext<'source> { let res = self.lexer.next()?; match res.kind { - LexerResultKind::Token(token) => break Some(token), + LexerResultKind::Token(token) => { + self.last_meta = token.meta; + break Some(token); + } LexerResultKind::Directive(directive) => { parser.handle_directive(directive, res.meta) } - LexerResultKind::Error(error) => parser.errors.push(ParseError { - kind: ErrorKind::PreprocessorError(res.meta, error), + LexerResultKind::Error(error) => parser.errors.push(Error { + kind: ErrorKind::PreprocessorError(error), + meta: res.meta, }), } } } pub fn bump(&mut self, parser: &mut Parser) -> Result { - self.next(parser).ok_or(ErrorKind::EndOfFile) + self.next(parser).ok_or(Error { + kind: ErrorKind::EndOfFile, + meta: self.last_meta, + }) } /// Returns None on the end of the file rather than an error like other methods @@ -101,8 +113,9 @@ impl<'source> ParsingContext<'source> { LexerResultKind::Directive(directive) => { parser.handle_directive(directive, res.meta) } - LexerResultKind::Error(error) => parser.errors.push(ParseError { - kind: ErrorKind::PreprocessorError(res.meta, error), + LexerResultKind::Error(error) => parser.errors.push(Error { + kind: ErrorKind::PreprocessorError(error), + meta: res.meta, }), _ => unreachable!(), } @@ -113,7 +126,11 @@ impl<'source> ParsingContext<'source> { } pub fn expect_peek(&mut self, parser: &mut Parser) -> Result<&Token> { - self.peek(parser).ok_or(ErrorKind::EndOfFile) + let meta = self.last_meta; + self.peek(parser).ok_or(Error { + kind: ErrorKind::EndOfFile, + meta, + }) } pub fn parse(&mut self, parser: &mut Parser) -> Result<()> { @@ -125,20 +142,18 @@ impl<'source> ParsingContext<'source> { self.parse_external_declaration(parser, &mut ctx, &mut body)?; } - let handle = parser - .lookup_function - .get("main") - .and_then(|declarations| { - declarations - .iter() - .find(|decl| decl.defined && decl.parameters.is_empty()) - .map(|decl| decl.handle) - }) - .ok_or_else(|| { - ErrorKind::SemanticError(SourceMetadata::default(), "Missing entry point".into()) - })?; - - parser.add_entry_point(handle, body, ctx.expressions)?; + match parser.lookup_function.get("main").and_then(|declarations| { + declarations + .iter() + .find(|decl| decl.defined && decl.parameters.is_empty()) + .map(|decl| decl.handle) + }) { + Some(handle) => parser.add_entry_point(handle, body, ctx.expressions), + None => parser.errors.push(Error { + kind: ErrorKind::SemanticError("Missing entry point".into()), + meta: SourceMetadata::none(), + }), + } Ok(()) } @@ -150,18 +165,24 @@ impl<'source> ParsingContext<'source> { ConstantInner::Scalar { value: ScalarValue::Uint(int), .. - } => u32::try_from(int) - .map_err(|_| ErrorKind::SemanticError(meta, "int constant overflows".into())), + } => u32::try_from(int).map_err(|_| Error { + kind: ErrorKind::SemanticError("int constant overflows".into()), + meta, + })?, ConstantInner::Scalar { value: ScalarValue::Sint(int), .. - } => u32::try_from(int) - .map_err(|_| ErrorKind::SemanticError(meta, "int constant overflows".into())), - _ => Err(ErrorKind::SemanticError( + } => u32::try_from(int).map_err(|_| Error { + kind: ErrorKind::SemanticError("int constant overflows".into()), meta, - "Expected a uint constant".into(), - )), - }?; + })?, + _ => { + return Err(Error { + kind: ErrorKind::SemanticError("Expected a uint constant".into()), + meta, + }) + } + }; Ok((int, meta)) } @@ -188,11 +209,11 @@ impl Parser { match directive.kind { DirectiveKind::Version { is_first_directive } => { if !is_first_directive { - self.errors.push(ParseError { + self.errors.push(Error { kind: ErrorKind::SemanticError( - meta, "#version must occur first in shader".into(), ), + meta, }) } @@ -202,21 +223,20 @@ impl Parser { location, }) => match int.value { 440 | 450 | 460 => self.meta.version = int.value as u16, - _ => self.errors.push(ParseError { - kind: ErrorKind::InvalidVersion(location.into(), int.value), + _ => self.errors.push(Error { + kind: ErrorKind::InvalidVersion(int.value), + meta: location.into(), }), }, - Some(PPToken { value, location }) => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(value), - ), + Some(PPToken { value, location }) => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + value, + )), + meta: location.into(), }), - None => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - meta, - PreprocessorError::UnexpectedNewLine, - ), + None => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedNewLine), + meta, }), }; @@ -226,25 +246,26 @@ impl Parser { location, }) => match name.as_str() { "core" => self.meta.profile = Profile::Core, - _ => self.errors.push(ParseError { - kind: ErrorKind::InvalidProfile(location.into(), name), + _ => self.errors.push(Error { + kind: ErrorKind::InvalidProfile(name), + meta: location.into(), }), }, - Some(PPToken { value, location }) => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(value), - ), + Some(PPToken { value, location }) => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + value, + )), + meta: location.into(), }), None => {} }; if let Some(PPToken { value, location }) = tokens.next() { - self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(value), - ), + self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + value, + )), + meta: location.into(), }) } } @@ -259,21 +280,21 @@ impl Parser { .. }) => Some(name), Some(PPToken { value, location }) => { - self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(value), - ), + self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + value, + )), + meta: location.into(), }); None } None => { - self.errors.push(ParseError { + self.errors.push(Error { kind: ErrorKind::PreprocessorError( - meta, PreprocessorError::UnexpectedNewLine, ), + meta, }); None @@ -285,17 +306,15 @@ impl Parser { value: PPTokenValue::Punct(pp_rs::token::Punct::Colon), .. }) => {} - Some(PPToken { value, location }) => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(value), - ), + Some(PPToken { value, location }) => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + value, + )), + meta: location.into(), }), - None => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - meta, - PreprocessorError::UnexpectedNewLine, - ), + None => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedNewLine), + meta, }), }; @@ -309,33 +328,31 @@ impl Parser { self.meta.extensions.insert(name); } } - _ => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(PPTokenValue::Ident(behavior)), - ), + _ => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + PPTokenValue::Ident(behavior), + )), + meta: location.into(), }), }, - Some(PPToken { value, location }) => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(value), - ), + Some(PPToken { value, location }) => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + value, + )), + meta: location.into(), }), - None => self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - meta, - PreprocessorError::UnexpectedNewLine, - ), + None => self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedNewLine), + meta, }), } if let Some(PPToken { value, location }) = tokens.next() { - self.errors.push(ParseError { - kind: ErrorKind::PreprocessorError( - location.into(), - PreprocessorError::UnexpectedToken(value), - ), + self.errors.push(Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedToken( + value, + )), + meta: location.into(), }) } } diff --git a/src/front/glsl/parser/declarations.rs b/src/front/glsl/parser/declarations.rs index f74cd15ae3..6e543c4310 100644 --- a/src/front/glsl/parser/declarations.rs +++ b/src/front/glsl/parser/declarations.rs @@ -10,7 +10,7 @@ use crate::{ token::TokenValue, types::scalar_components, variables::{GlobalOrConstant, VarDeclaration}, - ErrorKind, Parser, SourceMetadata, Token, + Error, ErrorKind, Parser, SourceMetadata, Token, }, Block, Expression, FunctionResult, Handle, ScalarKind, Statement, StorageClass, StructMember, Type, TypeInner, @@ -34,7 +34,10 @@ impl<'source> ParsingContext<'source> { 460 => vec![TokenValue::Semicolon.into(), ExpectedToken::Eof], _ => vec![ExpectedToken::Eof], }; - Err(ErrorKind::InvalidToken(token, expected)) + Err(Error { + kind: ErrorKind::InvalidToken(token.value, expected), + meta: token.meta, + }) } } } else { @@ -79,10 +82,13 @@ impl<'source> ParsingContext<'source> { break; } _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![TokenValue::Comma.into(), TokenValue::RightBrace.into()], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![TokenValue::Comma.into(), TokenValue::RightBrace.into()], + ), + meta: token.meta, + }) } } } @@ -147,10 +153,13 @@ impl<'source> ParsingContext<'source> { TokenValue::Semicolon => break, TokenValue::Identifier(name) => name, _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()], + ), + meta: token.meta, + }) } }; let mut meta = token.meta; @@ -201,10 +210,13 @@ impl<'source> ParsingContext<'source> { TokenValue::Semicolon => break, TokenValue::Comma => {} _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![TokenValue::Comma.into(), TokenValue::Semicolon.into()], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![TokenValue::Comma.into(), TokenValue::Semicolon.into()], + ), + meta: token.meta, + }) } } } @@ -261,7 +273,7 @@ impl<'source> ParsingContext<'source> { return match token.value { TokenValue::Semicolon => { // This branch handles function prototypes - parser.add_prototype(context, name, result, meta)?; + parser.add_prototype(context, name, result, meta); Ok(true) } @@ -273,21 +285,27 @@ impl<'source> ParsingContext<'source> { // parse the body self.parse_compound_statement(parser, &mut context, &mut body)?; - parser.add_function(context, name, result, body, meta)?; + parser.add_function(context, name, result, body, meta); Ok(true) } - _ if external => Err(ErrorKind::InvalidToken( - token, - vec![ - TokenValue::LeftBrace.into(), - TokenValue::Semicolon.into(), - ], - )), - _ => Err(ErrorKind::InvalidToken( - token, - vec![TokenValue::Semicolon.into()], - )), + _ if external => Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![ + TokenValue::LeftBrace.into(), + TokenValue::Semicolon.into(), + ], + ), + meta: token.meta, + }), + _ => Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![TokenValue::Semicolon.into()], + ), + meta: token.meta, + }), }; } // Pass the token to the init_declator_list parser @@ -313,10 +331,10 @@ impl<'source> ParsingContext<'source> { self.parse_init_declarator_list(parser, ty, Some(token_fallthrough), &mut ctx)?; } else { - return Err(ErrorKind::SemanticError( + parser.errors.push(Error { + kind: ErrorKind::SemanticError("Declaration cannot have void type".into()), meta, - "Declaration cannot have void type".into(), - )); + }) } Ok(true) @@ -341,7 +359,10 @@ impl<'source> ParsingContext<'source> { //TODO: declaration // type_qualifier IDENTIFIER SEMICOLON // type_qualifier IDENTIFIER identifier_list SEMICOLON - Err(ErrorKind::NotImplemented(token.meta, "variable qualifier")) + Err(Error { + kind: ErrorKind::NotImplemented("variable qualifier"), + meta: token.meta, + }) } } TokenValue::Semicolon => { @@ -359,20 +380,25 @@ impl<'source> ParsingContext<'source> { // layout(early_fragment_tests) in; } _ => { - return Err(ErrorKind::SemanticError( + parser.errors.push(Error { + kind: ErrorKind::SemanticError( + "Qualifier not supported as standalone".into(), + ), meta, - "Qualifier not supported as standalone".into(), - )); + }); } } } Ok(true) } - _ => Err(ErrorKind::InvalidToken( - token, - vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()], - )), + _ => Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()], + ), + meta: token.meta, + }), } } } else { @@ -385,14 +411,17 @@ impl<'source> ParsingContext<'source> { let _ = match token.value { TokenValue::PrecisionQualifier(p) => p, _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![ - TokenValue::PrecisionQualifier(Precision::High).into(), - TokenValue::PrecisionQualifier(Precision::Medium).into(), - TokenValue::PrecisionQualifier(Precision::Low).into(), - ], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![ + TokenValue::PrecisionQualifier(Precision::High).into(), + TokenValue::PrecisionQualifier(Precision::Medium).into(), + TokenValue::PrecisionQualifier(Precision::Low).into(), + ], + ), + meta: token.meta, + }) } }; @@ -407,12 +436,12 @@ impl<'source> ParsingContext<'source> { kind: ScalarKind::Sint, .. } => {} - _ => { - return Err(ErrorKind::SemanticError( - meta, + _ => parser.errors.push(Error { + kind: ErrorKind::SemanticError( "Precision statement can only work on floats and ints".into(), - )) - } + ), + meta, + }), } self.expect(parser, TokenValue::Semicolon)?; @@ -485,10 +514,13 @@ impl<'source> ParsingContext<'source> { Some(name) } _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![ExpectedToken::Identifier, TokenValue::Semicolon.into()], + ), + meta: token.meta, + }) } }; meta = meta.union(&token.meta); @@ -555,7 +587,8 @@ impl<'source> ParsingContext<'source> { layout, &mut parser.module.types, &parser.module.constants, - )?; + &mut parser.errors, + ); span = offset::align_up(span, info.align); align = align.max(info.align); diff --git a/src/front/glsl/parser/expressions.rs b/src/front/glsl/parser/expressions.rs index 8f119eaaae..f0d98dd2ae 100644 --- a/src/front/glsl/parser/expressions.rs +++ b/src/front/glsl/parser/expressions.rs @@ -5,7 +5,7 @@ use crate::{ error::{ErrorKind, ExpectedToken}, parser::ParsingContext, token::{Token, TokenValue}, - Parser, Result, SourceMetadata, + Error, Parser, Result, SourceMetadata, }, ArraySize, BinaryOperator, Block, Constant, ConstantInner, Handle, ScalarValue, Type, TypeInner, UnaryOperator, @@ -43,15 +43,18 @@ impl<'source> ParsingContext<'source> { return Ok(expr); } _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![ - TokenValue::LeftParen.into(), - ExpectedToken::IntLiteral, - ExpectedToken::FloatLiteral, - ExpectedToken::BoolLiteral, - ], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![ + TokenValue::LeftParen.into(), + ExpectedToken::IntLiteral, + ExpectedToken::FloatLiteral, + ExpectedToken::BoolLiteral, + ], + ), + meta: token.meta, + }); } }; @@ -89,10 +92,13 @@ impl<'source> ParsingContext<'source> { break; } _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![TokenValue::Comma.into(), TokenValue::RightParen.into()], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![TokenValue::Comma.into(), TokenValue::RightParen.into()], + ), + meta: token.meta, + }); } } } @@ -124,9 +130,14 @@ impl<'source> ParsingContext<'source> { meta, } } else { - let var = match parser.lookup_variable(ctx, body, &name)? { + let var = match parser.lookup_variable(ctx, body, &name) { Some(var) => var, - None => return Err(ErrorKind::UnknownVariable(meta, name)), + None => { + return Err(Error { + kind: ErrorKind::UnknownVariable(name), + meta, + }) + } }; HirExpr { diff --git a/src/front/glsl/parser/functions.rs b/src/front/glsl/parser/functions.rs index 9e1db2b89e..31bd585a10 100644 --- a/src/front/glsl/parser/functions.rs +++ b/src/front/glsl/parser/functions.rs @@ -1,7 +1,7 @@ use crate::{ front::glsl::{ ast::ParameterQualifier, context::Context, parser::ParsingContext, token::TokenValue, - variables::VarDeclaration, ErrorKind, Parser, Result, Token, + variables::VarDeclaration, Error, ErrorKind, Parser, Result, Token, }, Block, ConstantInner, Expression, ScalarValue, Statement, SwitchCase, UnaryOperator, }; @@ -147,10 +147,14 @@ impl<'source> ParsingContext<'source> { .. } => int as i32, _ => { - return Err(ErrorKind::SemanticError( + parser.errors.push(Error { + kind: ErrorKind::SemanticError( + "Case values can only be integers".into(), + ), meta, - "Case values can only be integers".into(), - )) + }); + + 0 } } }; @@ -189,10 +193,13 @@ impl<'source> ParsingContext<'source> { self.expect(parser, TokenValue::Colon)?; if !default.is_empty() { - return Err(ErrorKind::SemanticError( + parser.errors.push(Error { + kind: ErrorKind::SemanticError( + "Can only have one default case per switch statement" + .into(), + ), meta, - "Can only have one default case per switch statement".into(), - )); + }); } loop { @@ -214,14 +221,18 @@ impl<'source> ParsingContext<'source> { break; } _ => { - return Err(ErrorKind::InvalidToken( - self.bump(parser)?, - vec![ - TokenValue::Case.into(), - TokenValue::Default.into(), - TokenValue::RightBrace.into(), - ], - )) + let Token { value, meta } = self.bump(parser)?; + return Err(Error { + kind: ErrorKind::InvalidToken( + value, + vec![ + TokenValue::Case.into(), + TokenValue::Default.into(), + TokenValue::RightBrace.into(), + ], + ), + meta, + }); } } } diff --git a/src/front/glsl/parser/types.rs b/src/front/glsl/parser/types.rs index 9ee12a0f00..a575f5cb8d 100644 --- a/src/front/glsl/parser/types.rs +++ b/src/front/glsl/parser/types.rs @@ -4,9 +4,9 @@ use crate::{ error::ExpectedToken, parser::ParsingContext, token::{SourceMetadata, TokenValue}, - ErrorKind, Parser, Result, + Error, ErrorKind, Parser, Result, }, - ArraySize, Handle, ResourceBinding, StorageClass, Type, TypeInner, + ArraySize, Handle, StorageClass, Type, TypeInner, }; impl<'source> ParsingContext<'source> { @@ -55,17 +55,25 @@ impl<'source> ParsingContext<'source> { } TokenValue::Identifier(ident) => match parser.lookup_type.get(&ident) { Some(ty) => Some(*ty), - None => return Err(ErrorKind::UnknownType(token.meta, ident)), + None => { + return Err(Error { + kind: ErrorKind::UnknownType(ident), + meta: token.meta, + }) + } }, _ => { - return Err(ErrorKind::InvalidToken( - token, - vec![ - TokenValue::Void.into(), - TokenValue::Struct.into(), - ExpectedToken::TypeName, - ], - )) + return Err(Error { + kind: ErrorKind::InvalidToken( + token.value, + vec![ + TokenValue::Void.into(), + TokenValue::Struct.into(), + ExpectedToken::TypeName, + ], + ), + meta: token.meta, + }); } }; @@ -78,8 +86,10 @@ impl<'source> ParsingContext<'source> { parser: &mut Parser, ) -> Result<(Handle, SourceMetadata)> { let (maybe_ty, meta) = self.parse_type(parser)?; - let ty = - maybe_ty.ok_or_else(|| ErrorKind::SemanticError(meta, "Type can't be void".into()))?; + let ty = maybe_ty.ok_or_else(|| Error { + kind: ErrorKind::SemanticError("Type can't be void".into()), + meta, + })?; Ok((ty, meta)) } @@ -148,13 +158,9 @@ impl<'source> ParsingContext<'source> { parser: &mut Parser, qualifiers: &mut Vec<(TypeQualifier, SourceMetadata)>, ) -> Result<()> { - // We need both of these to produce a ResourceBinding - let mut group = None; - let mut binding = None; - self.expect(parser, TokenValue::LeftParen)?; loop { - self.parse_layout_qualifier_id(parser, qualifiers, &mut group, &mut binding)?; + self.parse_layout_qualifier_id(parser, qualifiers)?; if self.bump_if(parser, TokenValue::Comma).is_some() { continue; @@ -164,27 +170,6 @@ impl<'source> ParsingContext<'source> { } self.expect(parser, TokenValue::RightParen)?; - match (group, binding) { - (Some((group, group_meta)), Some((binding, binding_meta))) => qualifiers.push(( - TypeQualifier::ResourceBinding(ResourceBinding { group, binding }), - group_meta.union(&binding_meta), - )), - // Produce an error if we have one of group or binding but not the other - (Some((_, meta)), None) => { - return Err(ErrorKind::SemanticError( - meta, - "set specified with no binding".into(), - )) - } - (None, Some((_, meta))) => { - return Err(ErrorKind::SemanticError( - meta, - "binding specified with no set".into(), - )) - } - (None, None) => (), - } - Ok(()) } @@ -192,8 +177,6 @@ impl<'source> ParsingContext<'source> { &mut self, parser: &mut Parser, qualifiers: &mut Vec<(TypeQualifier, SourceMetadata)>, - group: &mut Option<(u32, SourceMetadata)>, - binding: &mut Option<(u32, SourceMetadata)>, ) -> Result<()> { // layout_qualifier_id: // IDENTIFIER @@ -209,52 +192,60 @@ impl<'source> ParsingContext<'source> { qualifiers.push(( match name.as_str() { "location" => TypeQualifier::Location(value), - "set" => { - *group = Some((value, end_meta)); - return Ok(()); - } - "binding" => { - *binding = Some((value, end_meta)); - return Ok(()); - } + "set" => TypeQualifier::Set(value), + "binding" => TypeQualifier::Binding(value), "local_size_x" => TypeQualifier::WorkGroupSize(0, value), "local_size_y" => TypeQualifier::WorkGroupSize(1, value), "local_size_z" => TypeQualifier::WorkGroupSize(2, value), - _ => return Err(ErrorKind::UnknownLayoutQualifier(token.meta, name)), + _ => { + parser.errors.push(Error { + kind: ErrorKind::UnknownLayoutQualifier(name), + meta: token.meta, + }); + return Ok(()); + } }, token.meta, )) } else { - match name.as_str() { - "push_constant" => { - qualifiers.push(( - TypeQualifier::StorageQualifier(StorageQualifier::StorageClass( - StorageClass::PushConstant, - )), - token.meta, - )); - qualifiers - .push((TypeQualifier::Layout(StructLayout::Std430), token.meta)); - } - "std140" => qualifiers - .push((TypeQualifier::Layout(StructLayout::Std140), token.meta)), - "std430" => qualifiers - .push((TypeQualifier::Layout(StructLayout::Std430), token.meta)), - "early_fragment_tests" => { - qualifiers.push((TypeQualifier::EarlyFragmentTests, token.meta)) - } - _ => return Err(ErrorKind::UnknownLayoutQualifier(token.meta, name)), - } + qualifiers.push(( + match name.as_str() { + "push_constant" => { + qualifiers.push(( + TypeQualifier::Layout(StructLayout::Std430), + token.meta, + )); + qualifiers.push(( + TypeQualifier::StorageQualifier( + StorageQualifier::StorageClass(StorageClass::PushConstant), + ), + token.meta, + )); + return Ok(()); + } + "std140" => TypeQualifier::Layout(StructLayout::Std140), + "std430" => TypeQualifier::Layout(StructLayout::Std430), + "early_fragment_tests" => TypeQualifier::EarlyFragmentTests, + _ => { + parser.errors.push(Error { + kind: ErrorKind::UnknownLayoutQualifier(name), + meta: token.meta, + }); + return Ok(()); + } + }, + token.meta, + )); }; - - Ok(()) } // TODO: handle Shared? - _ => Err(ErrorKind::InvalidToken( - token, - vec![ExpectedToken::Identifier], - )), + _ => parser.errors.push(Error { + kind: ErrorKind::InvalidToken(token.value, vec![ExpectedToken::Identifier]), + meta: token.meta, + }), } + + Ok(()) } pub fn peek_type_name(&mut self, parser: &mut Parser) -> bool { diff --git a/src/front/glsl/parser_tests.rs b/src/front/glsl/parser_tests.rs index 282f0c0424..29ea1900c5 100644 --- a/src/front/glsl/parser_tests.rs +++ b/src/front/glsl/parser_tests.rs @@ -2,15 +2,15 @@ use crate::{ front::glsl::{ ast::Profile, error::ExpectedToken, - error::{ErrorKind, ParseError}, + error::{Error, ErrorKind}, token::TokenValue, - Options, Parser, SourceMetadata, Token, + Options, Parser, SourceMetadata, }, Module, ShaderStage, }; use pp_rs::token::PreprocessorError; -fn parse(parser: &mut Parser, source: &str, stage: ShaderStage) -> Result> { +fn parse(parser: &mut Parser, source: &str, stage: ShaderStage) -> Result> { let defines = crate::FastHashMap::default(); parser.parse(&Options { stage, defines }, source) @@ -29,8 +29,9 @@ fn version() { ) .err() .unwrap(), - vec![ParseError { - kind: ErrorKind::InvalidVersion(SourceMetadata { start: 9, end: 14 }, 99000) + vec![Error { + kind: ErrorKind::InvalidVersion(99000), + meta: SourceMetadata { start: 9, end: 14 } }], ); @@ -42,8 +43,9 @@ fn version() { ) .err() .unwrap(), - vec![ParseError { - kind: ErrorKind::InvalidVersion(SourceMetadata { start: 9, end: 12 }, 449) + vec![Error { + kind: ErrorKind::InvalidVersion(449), + meta: SourceMetadata { start: 9, end: 12 } }] ); @@ -55,8 +57,9 @@ fn version() { ) .err() .unwrap(), - vec![ParseError { - kind: ErrorKind::InvalidProfile(SourceMetadata { start: 13, end: 18 }, "smart".into()) + vec![Error { + kind: ErrorKind::InvalidProfile("smart".into()), + meta: SourceMetadata { start: 13, end: 18 }, }] ); @@ -69,20 +72,16 @@ fn version() { .err() .unwrap(), vec![ - ParseError { - kind: ErrorKind::PreprocessorError( - SourceMetadata { start: 27, end: 28 }, - PreprocessorError::UnexpectedHash, - ) + Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,), + meta: SourceMetadata { start: 27, end: 28 }, }, - ParseError { + Error { kind: ErrorKind::InvalidToken( - Token { - value: TokenValue::Identifier("version".into()), - meta: SourceMetadata { start: 28, end: 35 } - }, + TokenValue::Identifier("version".into()), vec![ExpectedToken::Eof] - ) + ), + meta: SourceMetadata { start: 28, end: 35 } } ] ); @@ -256,7 +255,7 @@ fn declarations() { &mut parser, r#" #version 450 - layout(push_constant, set = 2, binding = 0) + layout(push_constant) uniform u_locals { vec3 model_offs; float load_time; @@ -455,14 +454,12 @@ fn functions() { ) .err() .unwrap(), - vec![ParseError { - kind: ErrorKind::SemanticError( - SourceMetadata { - start: 134, - end: 152 - }, - "Function already defined".into() - ) + vec![Error { + kind: ErrorKind::SemanticError("Function already defined".into()), + meta: SourceMetadata { + start: 134, + end: 152 + }, }] ); @@ -616,14 +613,12 @@ fn implicit_conversions() { ) .err() .unwrap(), - vec![ParseError { - kind: ErrorKind::SemanticError( - SourceMetadata { - start: 156, - end: 165 - }, - "Unknown function \'test\'".into() - ) + vec![Error { + kind: ErrorKind::SemanticError("Unknown function \'test\'".into()), + meta: SourceMetadata { + start: 156, + end: 165 + }, }] ); @@ -643,14 +638,12 @@ fn implicit_conversions() { ) .err() .unwrap(), - vec![ParseError { - kind: ErrorKind::SemanticError( - SourceMetadata { - start: 158, - end: 165 - }, - "Ambiguous best function for \'test\'".into() - ) + vec![Error { + kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()), + meta: SourceMetadata { + start: 158, + end: 165 + }, }] ); } diff --git a/src/front/glsl/token.rs b/src/front/glsl/token.rs index bcff732f93..23caa4b022 100644 --- a/src/front/glsl/token.rs +++ b/src/front/glsl/token.rs @@ -3,7 +3,7 @@ pub use pp_rs::token::{Float, Integer, PreprocessorError, Token as PPToken}; use super::ast::Precision; use crate::{Interpolation, Sampling, Type}; -use std::{fmt, ops::Range}; +use std::ops::Range; #[derive(Debug, Clone, Copy, Default)] #[cfg_attr(test, derive(PartialEq))] @@ -22,6 +22,10 @@ impl SourceMetadata { end: self.end.max(other.end), } } + + pub fn none() -> Self { + SourceMetadata::default() + } } impl From for SourceMetadata { @@ -141,12 +145,6 @@ pub enum TokenValue { Question, } -impl fmt::Display for Token { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.value) - } -} - #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub struct Directive { diff --git a/src/front/glsl/types.rs b/src/front/glsl/types.rs index cac9137929..b829b4628b 100644 --- a/src/front/glsl/types.rs +++ b/src/front/glsl/types.rs @@ -1,6 +1,7 @@ use crate::{ front::glsl::{ - constants::ConstantSolver, context::Context, ErrorKind, Parser, Result, SourceMetadata, + constants::ConstantSolver, context::Context, Error, ErrorKind, Parser, Result, + SourceMetadata, }, proc::ResolveContext, ArraySize, Constant, Expression, Handle, ImageClass, ImageDimension, ScalarKind, Type, @@ -197,8 +198,9 @@ impl Parser { ctx.typifier .grow(handle, &ctx.expressions, &resolve_ctx) - .map_err(|error| { - ErrorKind::SemanticError(meta, format!("Can't resolve type: {:?}", error).into()) + .map_err(|error| Error { + kind: ErrorKind::SemanticError(format!("Can't resolve type: {:?}", error).into()), + meta, }) } @@ -230,8 +232,9 @@ impl Parser { ctx.typifier .invalidate(handle, &ctx.expressions, &resolve_ctx) - .map_err(|error| { - ErrorKind::SemanticError(meta, format!("Can't resolve type: {:?}", error).into()) + .map_err(|error| Error { + kind: ErrorKind::SemanticError(format!("Can't resolve type: {:?}", error).into()), + meta, }) } @@ -247,7 +250,10 @@ impl Parser { constants: &mut self.module.constants, }; - solver.solve(root).map_err(|e| (meta, e).into()) + solver.solve(root).map_err(|e| Error { + kind: e.into(), + meta, + }) } pub fn maybe_array(&mut self, base: Handle, size: Option) -> Handle { diff --git a/src/front/glsl/variables.rs b/src/front/glsl/variables.rs index 3057cbd7d0..11df1cd7e2 100644 --- a/src/front/glsl/variables.rs +++ b/src/front/glsl/variables.rs @@ -1,14 +1,22 @@ use crate::{ - front::glsl::{ast::*, context::Context, error::ErrorKind, Parser, SourceMetadata}, + front::glsl::{ + ast::*, + context::Context, + error::{Error, ErrorKind}, + Parser, Result, SourceMetadata, + }, Binding, Block, BuiltIn, Constant, Expression, GlobalVariable, Handle, Interpolation, - LocalVariable, ScalarKind, StorageAccess, StorageClass, SwizzleComponent, Type, TypeInner, - VectorSize, + LocalVariable, ResourceBinding, ScalarKind, StorageAccess, StorageClass, SwizzleComponent, + Type, TypeInner, VectorSize, }; macro_rules! qualifier_arm { - ($src:expr, $tgt:expr, $meta:expr, $msg:literal $(,)?) => {{ + ($src:expr, $tgt:expr, $meta:expr, $msg:literal, $errors:expr $(,)?) => {{ if $tgt.is_some() { - return Err(ErrorKind::SemanticError($meta, $msg.into())); + $errors.push(Error { + kind: ErrorKind::SemanticError($msg.into()), + meta: $meta, + }) } $tgt = Some($src); @@ -34,12 +42,12 @@ impl Parser { ctx: &mut Context, body: &mut Block, name: &str, - ) -> Result, ErrorKind> { + ) -> Option { if let Some(local_var) = ctx.lookup_local_var(name) { - return Ok(Some(local_var)); + return Some(local_var); } if let Some(global_var) = ctx.lookup_global_var(name) { - return Ok(Some(global_var)); + return Some(global_var); } let mut add_builtin = |inner, builtin, mutable, storage| { @@ -84,7 +92,7 @@ impl Parser { }, ); - Ok(ctx.lookup_global_var(name)) + ctx.lookup_global_var(name) }; match name { "gl_Position" => add_builtin( @@ -162,7 +170,7 @@ impl Parser { false, StorageQualifier::Input, ), - _ => Ok(None), + _ => None, } } @@ -174,7 +182,7 @@ impl Parser { expression: Handle, name: &str, meta: SourceMetadata, - ) -> Result, ErrorKind> { + ) -> Result> { let (ty, is_pointer) = match *self.resolve_type(ctx, expression, meta)? { TypeInner::Pointer { base, .. } => (&self.module.types[base].inner, true), ref ty => (ty, false), @@ -184,7 +192,10 @@ impl Parser { let index = members .iter() .position(|m| m.name == Some(name.into())) - .ok_or_else(|| ErrorKind::UnknownField(meta, name.into()))?; + .ok_or_else(|| Error { + kind: ErrorKind::UnknownField(name.into()), + meta, + })?; Ok(ctx.add_expression( Expression::AccessIndex { base: expression, @@ -215,14 +226,17 @@ impl Parser { let not_unique = (1..components.len()) .any(|i| components[i..].contains(&components[i - 1])); if not_unique { - return Err(ErrorKind::SemanticError( - meta, + self.errors.push(Error { + kind: + ErrorKind::SemanticError( format!( "swizzle cannot have duplicate components in left-hand-side expression for \"{:?}\"", name ) .into(), - )); + ), + meta , + }) } } @@ -237,7 +251,7 @@ impl Parser { size: _, vector, pattern: ref src_pattern, - } = *ctx.get_expression(expression) + } = ctx[expression] { expression = vector; for pat in &mut pattern { @@ -250,9 +264,7 @@ impl Parser { // only single element swizzle, like pos.y, just return that component. if lhs { // Because of possible nested swizzles, like pos.xy.x, we have to unwrap the potential load expr. - if let Expression::Load { ref pointer } = - *ctx.get_expression(expression) - { + if let Expression::Load { ref pointer } = ctx[expression] { expression = *pointer; } } @@ -268,10 +280,14 @@ impl Parser { 3 => VectorSize::Tri, 4 => VectorSize::Quad, _ => { - return Err(ErrorKind::SemanticError( + self.errors.push(Error { + kind: ErrorKind::SemanticError( + format!("Bad swizzle size for \"{:?}\"", name).into(), + ), meta, - format!("Bad swizzle size for \"{:?}\"", name).into(), - )); + }); + + VectorSize::Quad } }; @@ -296,16 +312,20 @@ impl Parser { body, )) } else { - Err(ErrorKind::SemanticError( + Err(Error { + kind: ErrorKind::SemanticError( + format!("Invalid swizzle for vector \"{}\"", name).into(), + ), meta, - format!("Invalid swizzle for vector \"{}\"", name).into(), - )) + }) } } - _ => Err(ErrorKind::SemanticError( + _ => Err(Error { + kind: ErrorKind::SemanticError( + format!("Can't lookup field on this type \"{}\"", name).into(), + ), meta, - format!("Can't lookup field on this type \"{}\"", name).into(), - )), + }), } } @@ -320,9 +340,10 @@ impl Parser { init, meta, }: VarDeclaration, - ) -> Result { + ) -> Result { let mut storage = StorageQualifier::StorageClass(StorageClass::Private); let mut interpolation = None; + let mut set = None; let mut binding = None; let mut location = None; let mut sampling = None; @@ -339,10 +360,12 @@ impl Parser { // Ignore the Uniform qualifier if the class was already set to PushConstant continue; } else if StorageQualifier::StorageClass(StorageClass::Private) != storage { - return Err(ErrorKind::SemanticError( + self.errors.push(Error { + kind: ErrorKind::SemanticError( + "Cannot use more than one storage qualifier per declaration".into(), + ), meta, - "Cannot use more than one storage qualifier per declaration".into(), - )); + }); } storage = s; @@ -351,67 +374,103 @@ impl Parser { i, interpolation, meta, - "Cannot use more than one interpolation qualifier per declaration" + "Cannot use more than one interpolation qualifier per declaration", + self.errors ), - TypeQualifier::ResourceBinding(ref r) => qualifier_arm!( - r.clone(), + TypeQualifier::Binding(r) => qualifier_arm!( + r, binding, meta, - "Cannot use more than one binding per declaration" + "Cannot use more than one binding per declaration", + self.errors + ), + TypeQualifier::Set(s) => qualifier_arm!( + s, + set, + meta, + "Cannot use more than one binding per declaration", + self.errors ), TypeQualifier::Location(l) => qualifier_arm!( l, location, meta, - "Cannot use more than one binding per declaration" + "Cannot use more than one binding per declaration", + self.errors ), TypeQualifier::Sampling(s) => qualifier_arm!( s, sampling, meta, - "Cannot use more than one sampling qualifier per declaration" + "Cannot use more than one sampling qualifier per declaration", + self.errors ), TypeQualifier::Layout(ref l) => qualifier_arm!( l, layout, meta, - "Cannot use more than one layout qualifier per declaration" + "Cannot use more than one layout qualifier per declaration", + self.errors ), TypeQualifier::Precision(ref p) => qualifier_arm!( p, precision, meta, - "Cannot use more than one precision qualifier per declaration" + "Cannot use more than one precision qualifier per declaration", + self.errors ), TypeQualifier::StorageAccess(a) => access &= a, _ => { - return Err(ErrorKind::SemanticError( + self.errors.push(Error { + kind: ErrorKind::SemanticError("Qualifier not supported in globals".into()), meta, - "Qualifier not supported in globals".into(), - )); + }); } } } - if binding.is_some() && storage != StorageQualifier::StorageClass(StorageClass::Uniform) { - match storage { - StorageQualifier::StorageClass(StorageClass::PushConstant) - | StorageQualifier::StorageClass(StorageClass::Uniform) - | StorageQualifier::StorageClass(StorageClass::Storage { .. }) => {} - _ => { - return Err(ErrorKind::SemanticError( + match storage { + StorageQualifier::StorageClass(StorageClass::PushConstant) => { + if set.is_some() { + self.errors.push(Error { + kind: ErrorKind::SemanticError( + "set cannot be used to decorate push constant".into(), + ), meta, - "binding requires uniform or buffer storage qualifier".into(), - )) + }) + } + } + StorageQualifier::StorageClass(StorageClass::Uniform) + | StorageQualifier::StorageClass(StorageClass::Storage { .. }) => { + if binding.is_none() { + self.errors.push(Error { + kind: ErrorKind::SemanticError( + "uniform/buffer blocks require layout(binding=X)".into(), + ), + meta, + }) + } + } + _ => { + if set.is_some() || binding.is_some() { + self.errors.push(Error { + kind: ErrorKind::SemanticError( + "set/binding can only be applied to uniform/buffer blocks".into(), + ), + meta, + }) } } } if (sampling.is_some() || interpolation.is_some()) && location.is_none() { - return Err(ErrorKind::SemanticError( + return Err(Error { + kind: ErrorKind::SemanticError( + "Sampling and interpolation qualifiers can only be used in in/out variables" + .into(), + ), meta, - "Sampling and interpolation qualifiers can only be used in in/out variables".into(), - )); + }); } if let Some(location) = location { @@ -457,8 +516,9 @@ impl Parser { return Ok(GlobalOrConstant::Global(handle)); } else if let StorageQualifier::Const = storage { - let init = init.ok_or_else(|| { - ErrorKind::SemanticError(meta, "const values must have an initializer".into()) + let init = init.ok_or_else(|| Error { + kind: ErrorKind::SemanticError("const values must have an initializer".into()), + meta, })?; if let Some(name) = name { let lookup = GlobalLookup { @@ -491,7 +551,10 @@ impl Parser { let handle = self.module.global_variables.append(GlobalVariable { name: name.clone(), class, - binding, + binding: binding.map(|binding| ResourceBinding { + group: set.unwrap_or(0), + binding, + }), ty, init, }); @@ -522,11 +585,14 @@ impl Parser { init, meta, }: VarDeclaration, - ) -> Result, ErrorKind> { + ) -> Result> { #[cfg(feature = "glsl-validate")] if let Some(ref name) = name { if ctx.lookup_local_var_current_scope(name).is_some() { - return Err(ErrorKind::VariableAlreadyDeclared(meta, name.clone())); + self.errors.push(Error { + kind: ErrorKind::VariableAlreadyDeclared(name.clone()), + meta, + }) } } @@ -537,10 +603,13 @@ impl Parser { match *qualifier { TypeQualifier::StorageQualifier(StorageQualifier::Const) => { if !mutable { - return Err(ErrorKind::SemanticError( + self.errors.push(Error { + kind: ErrorKind::SemanticError( + "Cannot use more than one constant qualifier per declaration" + .into(), + ), meta, - "Cannot use more than one constant qualifier per declaration".into(), - )); + }) } mutable = false; @@ -549,14 +618,13 @@ impl Parser { p, precision, meta, - "Cannot use more than one precision qualifier per declaration" + "Cannot use more than one precision qualifier per declaration", + self.errors ), - _ => { - return Err(ErrorKind::SemanticError( - meta, - "Qualifier not supported in locals".into(), - )); - } + _ => self.errors.push(Error { + kind: ErrorKind::SemanticError("Qualifier not supported in locals".into()), + meta, + }), } } diff --git a/tests/in/glsl/800-out-of-bounds-panic.vert b/tests/in/glsl/800-out-of-bounds-panic.vert index babca1668f..e689d26767 100644 --- a/tests/in/glsl/800-out-of-bounds-panic.vert +++ b/tests/in/glsl/800-out-of-bounds-panic.vert @@ -21,6 +21,5 @@ layout(location = 0) out vec4 frag_color; void main() { frag_color = color; gl_Position = view_matrix * world_matrix * vec4(position, 0.0, 1.0); - // TODO: https://github.com/gfx-rs/naga/issues/901 - // gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0; + gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0; } diff --git a/tests/out/wgsl/800-out-of-bounds-panic-vert.wgsl b/tests/out/wgsl/800-out-of-bounds-panic-vert.wgsl index 84a5e065da..6046dc3f4e 100644 --- a/tests/out/wgsl/800-out-of-bounds-panic-vert.wgsl +++ b/tests/out/wgsl/800-out-of-bounds-panic-vert.wgsl @@ -28,6 +28,9 @@ fn main1() { let _e10: mat4x4 = global1.world_matrix; let _e12: vec2 = position1; gl_Position = ((_e9 * _e10) * vec4(_e12, 0.0, 1.0)); + let _e18: vec4 = gl_Position; + let _e20: vec4 = gl_Position; + gl_Position.z = ((_e18.z + _e20.w) / 2.0); return; }