diff --git a/include/Nazara/Shader/Ast/AstTypes.hpp b/include/Nazara/Shader/Ast/AstTypes.hpp index 0b12cc7ff..c940a8d63 100644 --- a/include/Nazara/Shader/Ast/AstTypes.hpp +++ b/include/Nazara/Shader/Ast/AstTypes.hpp @@ -7,6 +7,7 @@ #ifndef NAZARA_SHADER_AST_ASTTYPES_HPP #define NAZARA_SHADER_AST_ASTTYPES_HPP +#include #include #include #include @@ -28,7 +29,7 @@ namespace Nz::ShaderAst struct PartialType { std::vector parameters; - std::function buildFunc; + std::function buildFunc; }; } diff --git a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp index 77e2d8a6e..d608251e9 100644 --- a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp +++ b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp @@ -60,7 +60,6 @@ namespace Nz::ShaderAst private: enum class IdentifierCategory; enum class ValidationResult; - struct AstError; struct CurrentFunctionData; struct Environment; struct FunctionData; @@ -122,8 +121,8 @@ namespace Nz::ShaderAst ExpressionPtr CacheResult(ExpressionPtr expression); std::optional ComputeConstantValue(Expression& expr) const; - template ValidationResult ComputeExprValue(ExpressionValue& attribute) const; - template ValidationResult ComputeExprValue(const ExpressionValue& attribute, ExpressionValue& targetAttribute); + template ValidationResult ComputeExprValue(ExpressionValue& attribute, const ShaderLang::SourceLocation& sourceLocation) const; + template ValidationResult ComputeExprValue(const ExpressionValue& attribute, ExpressionValue& targetAttribute, const ShaderLang::SourceLocation& sourceLocation); template std::unique_ptr PropagateConstants(T& node) const; void PreregisterIndices(const Module& module); @@ -144,11 +143,11 @@ namespace Nz::ShaderAst const IdentifierData* ResolveAliasIdentifier(const IdentifierData* identifier, const ShaderLang::SourceLocation& sourceLocation) const; void ResolveFunctions(); - std::size_t ResolveStruct(const AliasType& aliasType); - std::size_t ResolveStruct(const ExpressionType& exprType); - std::size_t ResolveStruct(const IdentifierType& identifierType); - std::size_t ResolveStruct(const StructType& structType); - std::size_t ResolveStruct(const UniformType& uniformType); + std::size_t ResolveStruct(const AliasType& aliasType, const ShaderLang::SourceLocation& sourceLocation); + std::size_t ResolveStruct(const ExpressionType& exprType, const ShaderLang::SourceLocation& sourceLocation); + std::size_t ResolveStruct(const IdentifierType& identifierType, const ShaderLang::SourceLocation& sourceLocation); + std::size_t ResolveStruct(const StructType& structType, const ShaderLang::SourceLocation& sourceLocation); + std::size_t ResolveStruct(const UniformType& uniformType, const ShaderLang::SourceLocation& sourceLocation); ExpressionType ResolveType(const ExpressionType& exprType, bool resolveAlias, const ShaderLang::SourceLocation& sourceLocation); std::optional ResolveTypeExpr(const ExpressionValue& exprTypeValue, bool resolveAlias, const ShaderLang::SourceLocation& sourceLocation); diff --git a/include/Nazara/Shader/ShaderLangErrorList.hpp b/include/Nazara/Shader/ShaderLangErrorList.hpp index d8a91edd8..0a939ebec 100644 --- a/include/Nazara/Shader/ShaderLangErrorList.hpp +++ b/include/Nazara/Shader/ShaderLangErrorList.hpp @@ -51,11 +51,18 @@ NAZARA_SHADERLANG_PARSER_ERROR(16, UnexpectedEndOfFile, "unexpected end of file" NAZARA_SHADERLANG_PARSER_ERROR(17, UnexpectedToken, "unexpected token {}", ShaderLang::TokenType) // Compiler errors +NAZARA_SHADERLANG_COMPILER_ERROR(2, AliasUnexpectedType, "for now, only aliases, functions and structs can be aliased") +NAZARA_SHADERLANG_COMPILER_ERROR(2, ArrayLength, "array length must a strictly positive integer") +NAZARA_SHADERLANG_COMPILER_ERROR(2, AssignTemporary, "temporary values cannot be assigned") +NAZARA_SHADERLANG_COMPILER_ERROR(2, AttributeUnexpectedExpression, "unexpected expression for this type") +NAZARA_SHADERLANG_COMPILER_ERROR(2, AttributeUnexpectedType, "unexpected attribute type") NAZARA_SHADERLANG_COMPILER_ERROR(2, BinaryIncompatibleTypes, "incompatibles types ( and )") NAZARA_SHADERLANG_COMPILER_ERROR(2, BinaryUnsupported, "{} type () does not support this binary operation", std::string) NAZARA_SHADERLANG_COMPILER_ERROR(2, BranchOutsideOfFunction, "non-const branching statements can only exist inside a function") -NAZARA_SHADERLANG_COMPILER_ERROR(2, CastIncompatibleTypes, "incompatibles types ( and )") NAZARA_SHADERLANG_COMPILER_ERROR(2, CastComponentMismatch, "component count doesn't match required component count") +NAZARA_SHADERLANG_COMPILER_ERROR(2, CastIncompatibleTypes, "incompatibles types ( and )") +NAZARA_SHADERLANG_COMPILER_ERROR(2, CastMatrixExpectedVector, "expected vector type, got ") +NAZARA_SHADERLANG_COMPILER_ERROR(2, CastMatrixVectorComponentMismatch, "vector component count ({}) doesn't match target matrix row count ({})", UInt32, UInt32) NAZARA_SHADERLANG_COMPILER_ERROR(2, CircularImport, "circular import detected on {}", std::string) NAZARA_SHADERLANG_COMPILER_ERROR(2, ConditionExpectedBool, "expected a boolean value") NAZARA_SHADERLANG_COMPILER_ERROR(2, ConstMissingExpression, "const variables must have an expression") @@ -63,41 +70,69 @@ NAZARA_SHADERLANG_COMPILER_ERROR(2, ConstantExpectedValue, "expected a value") NAZARA_SHADERLANG_COMPILER_ERROR(2, ConstantExpressionRequired, "a constant expression is required in this context") NAZARA_SHADERLANG_COMPILER_ERROR(2, DepthWriteAttribute, "only fragment entry-points can have the depth_write attribute") NAZARA_SHADERLANG_COMPILER_ERROR(2, DiscardEarlyFragmentTests, "discard is not compatible with early fragment tests") +NAZARA_SHADERLANG_COMPILER_ERROR(2, DiscardOutsideOfFragmentStage, "discard can only be used in the fragment stage (function gets called in the {} stage)", ShaderStageType) +NAZARA_SHADERLANG_COMPILER_ERROR(2, DiscardOutsideOfFunction, "discard can only be used inside a function") NAZARA_SHADERLANG_COMPILER_ERROR(2, EarlyFragmentTestsAttribute, "only functions with entry(frag) attribute can have the early_fragments_tests attribute") NAZARA_SHADERLANG_COMPILER_ERROR(2, EntryFunctionParameter, "entry functions can either take one struct parameter or no parameter") NAZARA_SHADERLANG_COMPILER_ERROR(2, EntryPointAlreadyDefined, "the same entry type has been defined multiple times") NAZARA_SHADERLANG_COMPILER_ERROR(2, ExpectedFunction, "expected function expression") NAZARA_SHADERLANG_COMPILER_ERROR(2, ExpectedIntrinsicFunction, "expected intrinsic function expression") +NAZARA_SHADERLANG_COMPILER_ERROR(2, ExpectedPartialType, "only partial types can be specialized, got ") NAZARA_SHADERLANG_COMPILER_ERROR(2, ExtAlreadyDeclared, "external variable {} is already declared", std::string) -NAZARA_SHADERLANG_COMPILER_ERROR(2, ExtTypeNotAllowed, "external variable {} is of wrong type: only uniform and sampler are allowed in external blocks", std::string) NAZARA_SHADERLANG_COMPILER_ERROR(2, ExtBindingAlreadyUsed, "binding (set={}, binding={}) is already in use", UInt32, UInt32) NAZARA_SHADERLANG_COMPILER_ERROR(2, ExtMissingBindingIndex, "external variable requires a binding index") +NAZARA_SHADERLANG_COMPILER_ERROR(2, ExtTypeNotAllowed, "external variable {} is of wrong type: only uniform and sampler are allowed in external blocks", std::string) NAZARA_SHADERLANG_COMPILER_ERROR(2, ForEachUnsupportedType, "for-each statements can only be called on array types, got ") +NAZARA_SHADERLANG_COMPILER_ERROR(2, ForFromTypeExpectIntegerType, "numerical for from expression must be an integer or unsigned integer, got ") +NAZARA_SHADERLANG_COMPILER_ERROR(2, ForStepUnmatchingType, "numerical for step expression type () must match from expression type ()") +NAZARA_SHADERLANG_COMPILER_ERROR(2, ForToUnmatchingType, "numerical for to expression type () must match from expression type ()") +NAZARA_SHADERLANG_COMPILER_ERROR(2, FullTypeExpected, "expected a full type, got ") +NAZARA_SHADERLANG_COMPILER_ERROR(2, FunctionCallExpectedFunction, "expected function expression") NAZARA_SHADERLANG_COMPILER_ERROR(2, FunctionCallOutsideOfFunction, "function calls must happen inside a function") +NAZARA_SHADERLANG_COMPILER_ERROR(2, FunctionCallUnexpectedEntryFunction, "{} is an entry function which cannot be called by the program", std::string) +NAZARA_SHADERLANG_COMPILER_ERROR(2, FunctionCallUnmatchingParameterCount, "function {} expects {} parameter(s), but got {}", std::string, UInt32, UInt32) +NAZARA_SHADERLANG_COMPILER_ERROR(2, FunctionCallUnmatchingParameterType, "function {} parameter #{} type mismatch (expected , got )", std::string, UInt32) NAZARA_SHADERLANG_COMPILER_ERROR(2, FunctionDeclarationInsideFunction, "a function cannot be defined inside another function") NAZARA_SHADERLANG_COMPILER_ERROR(2, IdentifierAlreadyUsed, "identifier {} is already used", std::string) -NAZARA_SHADERLANG_COMPILER_ERROR(2, IntrinsicExpectedParameterCount, "expected {} parameter(s)", unsigned int) +NAZARA_SHADERLANG_COMPILER_ERROR(2, IndexRequiresIntegerIndices, "index access requires integer indices (got )") +NAZARA_SHADERLANG_COMPILER_ERROR(2, IndexStructRequiresInt32Indices, "struct indexing requires constant i32 indices (got )") +NAZARA_SHADERLANG_COMPILER_ERROR(2, IndexUnexpectedType, "unexpected type: only arrays, structs, vectors and matrices can be indexed (got )") NAZARA_SHADERLANG_COMPILER_ERROR(2, IntrinsicExpectedFloat, "expected scalar or vector floating-points") -NAZARA_SHADERLANG_COMPILER_ERROR(2, IntrinsicExpectedType, "expected type for parameter #{}, got ", unsigned int) +NAZARA_SHADERLANG_COMPILER_ERROR(2, IntrinsicExpectedParameterCount, "expected {} parameter(s)", UInt32) +NAZARA_SHADERLANG_COMPILER_ERROR(2, IntrinsicExpectedType, "expected type for parameter #{}, got ", UInt32) NAZARA_SHADERLANG_COMPILER_ERROR(2, IntrinsicUnexpectedBoolean, "boolean parameters are not allowed") NAZARA_SHADERLANG_COMPILER_ERROR(2, IntrinsicUnmatchingParameterType, "all types must match") NAZARA_SHADERLANG_COMPILER_ERROR(2, InvalidScalarSwizzle, "invalid swizzle for scalar") NAZARA_SHADERLANG_COMPILER_ERROR(2, InvalidSwizzle, "invalid swizzle {}", std::string) NAZARA_SHADERLANG_COMPILER_ERROR(2, MissingOptionValue, "option {} requires a value (no default value set)", std::string) -NAZARA_SHADERLANG_COMPILER_ERROR(2, PartialTypeExpect, "expected a {} type at #{}", std::string, unsigned int) +NAZARA_SHADERLANG_COMPILER_ERROR(2, ModuleCompilationFailed, "module {} compilation failed: {}", std::string, std::string) +NAZARA_SHADERLANG_COMPILER_ERROR(2, ModuleNotFound, "module {} not found", std::string) +NAZARA_SHADERLANG_COMPILER_ERROR(2, NoModuleResolver, "import statement found but no module resolver has been set (and partial sanitization is not enabled)") +NAZARA_SHADERLANG_COMPILER_ERROR(2, OptionDeclarationInsideFunction, "options must be declared outside of functions") +NAZARA_SHADERLANG_COMPILER_ERROR(2, PartialTypeExpect, "expected a {} type at #{}", std::string, UInt32) +NAZARA_SHADERLANG_COMPILER_ERROR(2, PartialTypeParameterCountMismatch, "parameter count mismatch (expected {}, got {})", UInt32, UInt32) +NAZARA_SHADERLANG_COMPILER_ERROR(2, SamplerUnexpectedType, "for now only f32 samplers are supported (got )") NAZARA_SHADERLANG_COMPILER_ERROR(2, StructDeclarationInsideFunction, "structs must be declared outside of functions") -NAZARA_SHADERLANG_COMPILER_ERROR(2, VarDeclarationMissingTypeAndValue, "variable must either have a type or an initial value") -NAZARA_SHADERLANG_COMPILER_ERROR(2, VarDeclarationTypeUnmatching, "initial expression type () doesn't match specified type ()") -NAZARA_SHADERLANG_COMPILER_ERROR(2, UnexpectedAccessedType, "unexpected type (only struct and vectors can be indexed with identifiers)") +NAZARA_SHADERLANG_COMPILER_ERROR(2, StructExpected, "struct type expected, got ") +NAZARA_SHADERLANG_COMPILER_ERROR(2, StructFieldBuiltinLocation, "a struct field cannot have both builtin and location attributes") +NAZARA_SHADERLANG_COMPILER_ERROR(2, StructFieldMultiple, "multiple {} active struct field found, only one can be active at a time", std::string) +NAZARA_SHADERLANG_COMPILER_ERROR(2, StructLayoutInnerMismatch, "inner struct layout mismatch, struct is declared with {} but field has layout {}", std::string, std::string) +NAZARA_SHADERLANG_COMPILER_ERROR(2, StructLayoutTypeNotAllowed, "{} type is not allowed in {} layout", std::string, std::string) +NAZARA_SHADERLANG_COMPILER_ERROR(2, SwizzleUnexpectedType, "expression type () does not support swizzling") NAZARA_SHADERLANG_COMPILER_ERROR(2, UnaryUnsupported, "type () does not support this unary operation", std::string) -NAZARA_SHADERLANG_COMPILER_ERROR(2, UnmatchingTypes, "left expression type () doesn't match right expression type ()") +NAZARA_SHADERLANG_COMPILER_ERROR(2, UnexpectedAccessedType, "unexpected type (only struct and vectors can be indexed with identifiers)") NAZARA_SHADERLANG_COMPILER_ERROR(2, UnknownField, "unknown field {}", std::string) -NAZARA_SHADERLANG_COMPILER_ERROR(2, UnknownMethod, "unknown method {}", std::string) NAZARA_SHADERLANG_COMPILER_ERROR(2, UnknownIdentifier, "unknown identifier {}", std::string) -NAZARA_SHADERLANG_COMPILER_ERROR(2, WhileUnrollNotSupported, "unroll(always) is not yet supported on while") +NAZARA_SHADERLANG_COMPILER_ERROR(2, UnknownMethod, "unknown method {}", std::string) +NAZARA_SHADERLANG_COMPILER_ERROR(2, UnmatchingTypes, "left expression type () doesn't match right expression type ()") +NAZARA_SHADERLANG_COMPILER_ERROR(2, VarDeclarationMissingTypeAndValue, "variable must either have a type or an initial value") +NAZARA_SHADERLANG_COMPILER_ERROR(2, VarDeclarationOutsideOfFunction, "global variables outside of external blocks are forbidden") +NAZARA_SHADERLANG_COMPILER_ERROR(2, VarDeclarationTypeUnmatching, "initial expression type () doesn't match specified type ()") +NAZARA_SHADERLANG_COMPILER_ERROR(2, WhileUnrollNotSupported, "unroll(always) is not yet supported on while, use a for loop") // AST errors NAZARA_SHADERLANG_AST_ERROR(1, AlreadyUsedIndex, "index {} is already used", std::size_t) +NAZARA_SHADERLANG_AST_ERROR(1, AttributeRequiresValue, "index {} is already used", std::size_t) NAZARA_SHADERLANG_AST_ERROR(2, AlreadyUsedIndexPreregister, "cannot preregister used index {} as its already used", std::size_t) NAZARA_SHADERLANG_AST_ERROR(2, EmptyIdentifier, "identifier cannot be empty") NAZARA_SHADERLANG_AST_ERROR(2, Internal, "internal error: {}", std::string) diff --git a/include/Nazara/Shader/ShaderLangSourceLocation.hpp b/include/Nazara/Shader/ShaderLangSourceLocation.hpp index 895f8dbc8..159f5bb6a 100644 --- a/include/Nazara/Shader/ShaderLangSourceLocation.hpp +++ b/include/Nazara/Shader/ShaderLangSourceLocation.hpp @@ -28,7 +28,7 @@ namespace Nz::ShaderLang static inline SourceLocation BuildFromTo(const SourceLocation& leftSource, const SourceLocation& rightSource); - std::shared_ptr file; //< Since the same file will be used for every node, prevent holding X time the same path + std::shared_ptr file; //< Since the same file will be used for every node, prevent storing X time the same path UInt32 endColumn; UInt32 endLine; UInt32 startColumn; diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index e0fa438e8..255a098a7 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -26,11 +26,6 @@ namespace Nz::ShaderAst { - struct SanitizeVisitor::AstError - { - std::string errMsg; - }; - struct SanitizeVisitor::CurrentFunctionData { std::optional stageType; @@ -317,7 +312,7 @@ namespace Nz::ShaderAst } else if (IsStructType(resolvedType)) { - std::size_t structIndex = ResolveStruct(resolvedType); + std::size_t structIndex = ResolveStruct(resolvedType, indexedExpr->sourceLocation); const StructDescription* s = m_context->structs.Retrieve(structIndex, indexedExpr->sourceLocation); // Retrieve member index (not counting disabled fields) @@ -1025,7 +1020,7 @@ namespace Nz::ShaderAst std::optional defaultBlockSet = 0; if (clone->bindingSet.HasValue()) { - if (ComputeExprValue(clone->bindingSet) == ValidationResult::Validated) + if (ComputeExprValue(clone->bindingSet, node.sourceLocation) == ValidationResult::Validated) defaultBlockSet = clone->bindingSet.GetResultingValue(); else defaultBlockSet.reset(); //< Unresolved value @@ -1037,11 +1032,11 @@ namespace Nz::ShaderAst throw ShaderLang::CompilerExtMissingBindingIndexError{ extVar.sourceLocation }; if (extVar.bindingSet.HasValue()) - ComputeExprValue(extVar.bindingSet); + ComputeExprValue(extVar.bindingSet, node.sourceLocation); else if (defaultBlockSet) extVar.bindingSet = *defaultBlockSet; - ComputeExprValue(extVar.bindingIndex); + ComputeExprValue(extVar.bindingIndex, node.sourceLocation); if (extVar.bindingSet.IsResultingValue() && extVar.bindingIndex.IsResultingValue()) { @@ -1110,16 +1105,16 @@ namespace Nz::ShaderAst clone->returnType = ExpressionType{ NoType{} }; if (node.depthWrite.HasValue()) - ComputeExprValue(node.depthWrite, clone->depthWrite); + ComputeExprValue(node.depthWrite, clone->depthWrite, node.sourceLocation); if (node.earlyFragmentTests.HasValue()) - ComputeExprValue(node.earlyFragmentTests, clone->earlyFragmentTests); + ComputeExprValue(node.earlyFragmentTests, clone->earlyFragmentTests, node.sourceLocation); if (node.entryStage.HasValue()) - ComputeExprValue(node.entryStage, clone->entryStage); + ComputeExprValue(node.entryStage, clone->entryStage, node.sourceLocation); if (node.isExported.HasValue()) - ComputeExprValue(node.isExported, clone->isExported); + ComputeExprValue(node.isExported, clone->isExported, node.sourceLocation); if (clone->entryStage.IsResultingValue()) { @@ -1181,7 +1176,7 @@ namespace Nz::ShaderAst StatementPtr SanitizeVisitor::Clone(DeclareOptionStatement& node) { if (m_context->currentFunction) - throw AstError{ "options must be declared outside of functions" }; + throw ShaderLang::CompilerOptionDeclarationInsideFunctionError{ node.sourceLocation }; auto clone = StaticUniquePointerCast(AstCloner::Clone(node)); if (clone->optName.empty()) @@ -1246,34 +1241,34 @@ namespace Nz::ShaderAst auto clone = StaticUniquePointerCast(AstCloner::Clone(node)); if (clone->isExported.HasValue()) - ComputeExprValue(clone->isExported); + ComputeExprValue(clone->isExported, node.sourceLocation); if (clone->description.layout.HasValue()) - ComputeExprValue(clone->description.layout); + ComputeExprValue(clone->description.layout, node.sourceLocation); std::unordered_set declaredMembers; for (auto& member : clone->description.members) { if (member.cond.HasValue()) { - ComputeExprValue(member.cond); + ComputeExprValue(member.cond, node.sourceLocation); if (member.cond.IsResultingValue() && !member.cond.GetResultingValue()) continue; } if (member.builtin.HasValue()) - ComputeExprValue(member.builtin); + ComputeExprValue(member.builtin, node.sourceLocation); if (member.locationIndex.HasValue()) - ComputeExprValue(member.locationIndex); + ComputeExprValue(member.locationIndex, node.sourceLocation); if (member.builtin.HasValue() && member.locationIndex.HasValue()) - throw AstError{ "A struct field cannot have both builtin and location attributes" }; + throw ShaderLang::CompilerStructFieldBuiltinLocationError{ member.sourceLocation }; if (declaredMembers.find(member.name) != declaredMembers.end()) { if ((!member.cond.HasValue() || !member.cond.IsResultingValue()) && !m_context->options.allowPartialSanitization) - throw AstError{ "struct member " + member.name + " found multiple time" }; + throw ShaderLang::CompilerStructFieldMultipleError{ member.sourceLocation, member.name }; } declaredMembers.insert(member.name); @@ -1290,13 +1285,13 @@ namespace Nz::ShaderAst const ExpressionType& targetType = ResolveAlias(member.type.GetResultingValue()); if (IsPrimitiveType(targetType) && std::get(targetType) == PrimitiveType::Boolean) - throw AstError{ "boolean type is not allowed in std140 layout" }; + throw ShaderLang::CompilerStructLayoutTypeNotAllowedError{ member.sourceLocation, "bool", "std140" }; else if (IsStructType(targetType)) { std::size_t structIndex = std::get(targetType).structIndex; const StructDescription* desc = m_context->structs.Retrieve(structIndex, member.sourceLocation); if (!desc->layout.HasValue() || desc->layout.GetResultingValue() != clone->description.layout.GetResultingValue()) - throw AstError{ "inner struct layout mismatch" }; + throw ShaderLang::CompilerStructLayoutInnerMismatchError{ member.sourceLocation, "std140", "" }; } } } @@ -1311,7 +1306,7 @@ namespace Nz::ShaderAst StatementPtr SanitizeVisitor::Clone(DeclareVariableStatement& node) { if (!m_context->currentFunction) - throw AstError{ "global variables outside of external blocks are forbidden" }; + throw ShaderLang::CompilerVarDeclarationOutsideOfFunctionError{ node.sourceLocation }; auto clone = StaticUniquePointerCast(AstCloner::Clone(node)); Validate(*clone); @@ -1322,7 +1317,7 @@ namespace Nz::ShaderAst StatementPtr SanitizeVisitor::Clone(DiscardStatement& node) { if (!m_context->currentFunction) - throw AstError{ "discard can only be used inside a function" }; + throw ShaderLang::CompilerDiscardOutsideOfFunctionError{ node.sourceLocation }; m_context->currentFunction->flags |= FunctionFlag::DoesDiscard; @@ -1339,7 +1334,7 @@ namespace Nz::ShaderAst StatementPtr SanitizeVisitor::Clone(ForStatement& node) { if (node.varName.empty()) - throw AstError{ "numerical for variable name cannot be empty" }; + throw ShaderLang::AstEmptyIdentifierError{ node.sourceLocation }; auto fromExpr = CloneExpression(MandatoryExpr(node.fromExpr, node.sourceLocation)); auto stepExpr = CloneExpression(node.stepExpr); @@ -1378,7 +1373,7 @@ namespace Nz::ShaderAst return clone; }; - if (node.unroll.HasValue() && ComputeExprValue(node.unroll, unrollValue) == ValidationResult::Unresolved) + if (node.unroll.HasValue() && ComputeExprValue(node.unroll, unrollValue, node.sourceLocation) == ValidationResult::Unresolved) return CloneFor(); //< unresolved unroll if (!fromExprType || !toExprType) @@ -1386,15 +1381,15 @@ namespace Nz::ShaderAst const ExpressionType& resolvedFromExprType = ResolveAlias(*fromExprType); if (!IsPrimitiveType(resolvedFromExprType)) - throw AstError{ "numerical for from expression must be an integer or unsigned integer" }; + throw ShaderLang::CompilerForFromTypeExpectIntegerTypeError{ fromExpr->sourceLocation }; PrimitiveType counterType = std::get(resolvedFromExprType); if (counterType != PrimitiveType::Int32 && counterType != PrimitiveType::UInt32) - throw AstError{ "numerical for from expression must be an integer or unsigned integer" }; + throw ShaderLang::CompilerForFromTypeExpectIntegerTypeError{ fromExpr->sourceLocation }; const ExpressionType& resolvedToExprType = ResolveAlias(*toExprType); if (resolvedToExprType != resolvedFromExprType) - throw AstError{ "numerical for to expression type must match from expression type" }; + throw ShaderLang::CompilerForToUnmatchingTypeError{ toExpr->sourceLocation }; if (stepExpr) { @@ -1404,7 +1399,7 @@ namespace Nz::ShaderAst const ExpressionType& resolvedStepExprType = ResolveAlias(*stepExprType); if (resolvedStepExprType != resolvedFromExprType) - throw AstError{ "numerical for step expression type must match from expression type" }; + throw ShaderLang::CompilerForStepUnmatchingTypeError{ stepExpr->sourceLocation }; } if (unrollValue.HasValue()) @@ -1463,7 +1458,7 @@ namespace Nz::ShaderAst break; default: - throw AstError{ "internal error" }; + throw ShaderLang::AstInternalError{ node.sourceLocation, "unexpected counter type " }; } PopScope(); @@ -1580,7 +1575,7 @@ namespace Nz::ShaderAst ExpressionValue unrollValue; if (node.unroll.HasValue()) { - if (ComputeExprValue(node.unroll, unrollValue) == ValidationResult::Unresolved) + if (ComputeExprValue(node.unroll, unrollValue, node.sourceLocation) == ValidationResult::Unresolved) return AstCloner::Clone(node); //< unresolved unroll type if (unrollValue.GetResultingValue() == LoopUnroll::Always) @@ -1696,7 +1691,7 @@ namespace Nz::ShaderAst if (!m_context->options.moduleResolver) { if (!m_context->options.allowPartialSanitization) - throw AstError{ "module " + node.moduleName + " not found" }; + throw ShaderLang::CompilerNoModuleResolverError{ node.sourceLocation }; // when partially sanitizing, importing a whole module could register any identifier, so at this point we can't see unknown identifiers as errors m_context->allowUnknownIdentifiers = true; @@ -1706,7 +1701,7 @@ namespace Nz::ShaderAst ModulePtr targetModule = m_context->options.moduleResolver->Resolve(node.moduleName); if (!targetModule) - throw AstError{ "module " + node.moduleName + " not found" }; + throw ShaderLang::CompilerModuleNotFoundError{ node.sourceLocation, node.moduleName }; std::size_t moduleIndex; @@ -1738,7 +1733,7 @@ namespace Nz::ShaderAst std::string error; sanitizedModule->rootNode = SanitizeInternal(*targetModule->rootNode, &error); if (!sanitizedModule->rootNode) - throw AstError{ "module " + node.moduleName + " compilation failed: " + error }; + throw ShaderLang::CompilerModuleCompilationFailedError{ node.sourceLocation, node.moduleName, error }; moduleIndex = m_context->modules.size(); @@ -1872,7 +1867,7 @@ namespace Nz::ShaderAst if (clone->unroll.HasValue()) { - if (ComputeExprValue(clone->unroll) == ValidationResult::Validated && clone->unroll.GetResultingValue() == LoopUnroll::Always) + if (ComputeExprValue(clone->unroll, node.sourceLocation) == ValidationResult::Validated && clone->unroll.GetResultingValue() == LoopUnroll::Always) throw ShaderLang::CompilerWhileUnrollNotSupportedError{ node.sourceLocation }; } @@ -2088,10 +2083,10 @@ namespace Nz::ShaderAst } template - auto SanitizeVisitor::ComputeExprValue(ExpressionValue& attribute) const -> ValidationResult + auto SanitizeVisitor::ComputeExprValue(ExpressionValue& attribute, const ShaderLang::SourceLocation& sourceLocation) const -> ValidationResult { if (!attribute.HasValue()) - throw AstError{ "attribute expected a value" }; + throw ShaderLang::AstAttributeRequiresValueError{ sourceLocation }; if (attribute.IsExpression()) { @@ -2107,23 +2102,23 @@ namespace Nz::ShaderAst if (std::holds_alternative(*value) && std::is_same_v) attribute = static_cast(std::get(*value)); else - throw AstError{ "unexpected attribute type" }; + throw ShaderLang::CompilerAttributeUnexpectedTypeError{ sourceLocation }; } else attribute = std::get(*value); } else - throw AstError{ "unexpected expression for this type" }; + throw ShaderLang::CompilerAttributeUnexpectedExpressionError{ sourceLocation }; } return ValidationResult::Validated; } template - auto SanitizeVisitor::ComputeExprValue(const ExpressionValue& attribute, ExpressionValue& targetAttribute) -> ValidationResult + auto SanitizeVisitor::ComputeExprValue(const ExpressionValue& attribute, ExpressionValue& targetAttribute, const ShaderLang::SourceLocation& sourceLocation) -> ValidationResult { if (!attribute.HasValue()) - throw AstError{ "attribute expected a value" }; + throw ShaderLang::AstAttributeRequiresValueError{ sourceLocation }; if (attribute.IsExpression()) { @@ -2142,13 +2137,13 @@ namespace Nz::ShaderAst if (std::holds_alternative(*value) && std::is_same_v) targetAttribute = static_cast(std::get(*value)); else - throw AstError{ "unexpected attribute type" }; + throw ShaderLang::CompilerAttributeUnexpectedTypeError{ sourceLocation }; } else targetAttribute = std::get(*value); } else - throw AstError{ "unexpected expression for this type" }; + throw ShaderLang::CompilerAttributeUnexpectedExpressionError{ sourceLocation }; } else { @@ -2167,7 +2162,7 @@ namespace Nz::ShaderAst { const ConstantValue* value = m_context->constantValues.TryRetrieve(constantId, node.sourceLocation); if (!value && !m_context->options.allowPartialSanitization) - throw AstError{ "invalid constant index #" + std::to_string(constantId) }; + throw ShaderLang::AstInvalidConstantIndexError{ node.sourceLocation, constantId }; return value; }; @@ -2219,7 +2214,7 @@ namespace Nz::ShaderAst // Array RegisterType("array", PartialType { { TypeParameterCategory::FullType, TypeParameterCategory::ConstantValue }, - [=](const TypeParameter* parameters, std::size_t parameterCount) -> ExpressionType + [=](const TypeParameter* parameters, std::size_t parameterCount, const ShaderLang::SourceLocation& sourceLocation) -> ExpressionType { assert(parameterCount == 2); assert(std::holds_alternative(parameters[0])); @@ -2233,7 +2228,7 @@ namespace Nz::ShaderAst { Int32 value = std::get(length); if (value <= 0) - throw AstError{ "array length must a positive integer" }; + throw ShaderLang::CompilerArrayLengthError{ sourceLocation }; lengthValue = SafeCast(value); } @@ -2241,10 +2236,10 @@ namespace Nz::ShaderAst { lengthValue = std::get(length); if (lengthValue == 0) - throw AstError{ "array length must a positive integer" }; + throw ShaderLang::CompilerArrayLengthError{ sourceLocation }; } else - throw AstError{ "array length must a positive integer" }; + throw ShaderLang::CompilerArrayLengthError{ sourceLocation }; ArrayType arrayType; arrayType.containedType = std::make_unique(); @@ -2260,7 +2255,7 @@ namespace Nz::ShaderAst { RegisterType("mat" + std::to_string(componentCount), PartialType { { TypeParameterCategory::PrimitiveType }, - [=](const TypeParameter* parameters, std::size_t parameterCount) -> ExpressionType + [=](const TypeParameter* parameters, std::size_t parameterCount, const ShaderLang::SourceLocation& /*sourceLocation*/) -> ExpressionType { assert(parameterCount == 1); assert(std::holds_alternative(*parameters)); @@ -2280,7 +2275,7 @@ namespace Nz::ShaderAst { RegisterType("vec" + std::to_string(componentCount), PartialType { { TypeParameterCategory::PrimitiveType }, - [=](const TypeParameter* parameters, std::size_t parameterCount) -> ExpressionType + [=](const TypeParameter* parameters, std::size_t parameterCount, const ShaderLang::SourceLocation& /*sourceLocation*/) -> ExpressionType { assert(parameterCount == 1); assert(std::holds_alternative(*parameters)); @@ -2319,7 +2314,7 @@ namespace Nz::ShaderAst { RegisterType(std::move(sampler.typeName), PartialType { { TypeParameterCategory::PrimitiveType }, - [=](const TypeParameter* parameters, std::size_t parameterCount) -> ExpressionType + [=](const TypeParameter* parameters, std::size_t parameterCount, const ShaderLang::SourceLocation& sourceLocation) -> ExpressionType { assert(parameterCount == 1); assert(std::holds_alternative(*parameters)); @@ -2331,7 +2326,7 @@ namespace Nz::ShaderAst // TODO: Add support for integer samplers if (primitiveType != PrimitiveType::Float32) - throw AstError{ "for now only f32 samplers are supported" }; + throw ShaderLang::CompilerSamplerUnexpectedTypeError{ sourceLocation }; return SamplerType { sampler.imageType, primitiveType @@ -2343,7 +2338,7 @@ namespace Nz::ShaderAst // uniform RegisterType("uniform", PartialType { { TypeParameterCategory::StructType }, - [=](const TypeParameter* parameters, std::size_t parameterCount) -> ExpressionType + [=](const TypeParameter* parameters, std::size_t parameterCount, const ShaderLang::SourceLocation& /*sourceLocation*/) -> ExpressionType { assert(parameterCount == 1); assert(std::holds_alternative(*parameters)); @@ -2672,23 +2667,23 @@ namespace Nz::ShaderAst for (const auto& [funcIndex, funcData] : m_context->functions.values) { if (funcData.flags.Test(FunctionFlag::DoesDiscard) && funcData.node->entryStage.HasValue() && funcData.node->entryStage.GetResultingValue() != ShaderStageType::Fragment) - throw AstError{ "discard can only be used in the fragment stage" }; + throw ShaderLang::CompilerDiscardOutsideOfFragmentStageError{ funcData.node->sourceLocation, funcData.node->entryStage.GetResultingValue() }; } } - std::size_t SanitizeVisitor::ResolveStruct(const AliasType& aliasType) + std::size_t SanitizeVisitor::ResolveStruct(const AliasType& aliasType, const ShaderLang::SourceLocation& sourceLocation) { - return ResolveStruct(aliasType.targetType->type); + return ResolveStruct(aliasType.targetType->type, sourceLocation); } - std::size_t SanitizeVisitor::ResolveStruct(const ExpressionType& exprType) + std::size_t SanitizeVisitor::ResolveStruct(const ExpressionType& exprType, const ShaderLang::SourceLocation& sourceLocation) { return std::visit([&](auto&& arg) -> std::size_t { using T = std::decay_t; if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) - return ResolveStruct(arg); + return ResolveStruct(arg, sourceLocation); else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || @@ -2700,31 +2695,31 @@ namespace Nz::ShaderAst std::is_same_v || std::is_same_v) { - throw AstError{ "expression is not a structure" }; + throw ShaderLang::CompilerStructExpectedError{ sourceLocation }; } else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, exprType); } - std::size_t SanitizeVisitor::ResolveStruct(const IdentifierType& identifierType) + std::size_t SanitizeVisitor::ResolveStruct(const IdentifierType& identifierType, const ShaderLang::SourceLocation& sourceLocation) { const IdentifierData* identifierData = FindIdentifier(identifierType.name); if (!identifierData) - throw AstError{ "unknown identifier " + identifierType.name }; + throw ShaderLang::CompilerUnknownIdentifierError{ sourceLocation, identifierType.name }; if (identifierData->category != IdentifierCategory::Struct) - throw AstError{ identifierType.name + " is not a struct" }; + throw ShaderLang::CompilerStructExpectedError{ sourceLocation }; return identifierData->index; } - std::size_t SanitizeVisitor::ResolveStruct(const StructType& structType) + std::size_t SanitizeVisitor::ResolveStruct(const StructType& structType, const ShaderLang::SourceLocation& /*sourceLocation*/) { return structType.structIndex; } - std::size_t SanitizeVisitor::ResolveStruct(const UniformType& uniformType) + std::size_t SanitizeVisitor::ResolveStruct(const UniformType& uniformType, const ShaderLang::SourceLocation& /*sourceLocation*/) { return uniformType.containedType.structIndex; } @@ -2743,7 +2738,7 @@ namespace Nz::ShaderAst const auto& type = m_context->types.Retrieve(typeIndex, sourceLocation); if (std::holds_alternative(type)) - throw AstError{ "full type expected" }; + throw ShaderLang::CompilerFullTypeExpectedError{ sourceLocation }; return std::get(type); } @@ -2790,13 +2785,6 @@ namespace Nz::ShaderAst { output = StaticUniquePointerCast(AstCloner::Clone(rootNode)); } - catch (const AstError& err) - { - if (!error) - throw std::runtime_error(err.errMsg); - - *error = err.errMsg; - } catch (const std::runtime_error& err) { if (!error) @@ -2825,7 +2813,7 @@ namespace Nz::ShaderAst auto SanitizeVisitor::Validate(DeclareAliasStatement& node) -> ValidationResult { if (node.name.empty()) - throw std::runtime_error("invalid alias name"); + throw ShaderLang::AstEmptyIdentifierError{ node.sourceLocation }; const ExpressionType* exprType = GetExpressionType(*node.expression); if (!exprType) @@ -2836,7 +2824,7 @@ namespace Nz::ShaderAst IdentifierData targetIdentifier; if (IsStructType(resolvedType)) { - std::size_t structIndex = ResolveStruct(resolvedType); + std::size_t structIndex = ResolveStruct(resolvedType, node.expression->sourceLocation); targetIdentifier = { structIndex, IdentifierCategory::Struct }; } else if (IsFunctionType(resolvedType)) @@ -2850,7 +2838,7 @@ namespace Nz::ShaderAst targetIdentifier = { alias.aliasIndex, IdentifierCategory::Alias }; } else - throw AstError{ "for now, only aliases, functions and structs can be aliased" }; + throw ShaderLang::CompilerAliasUnexpectedTypeError{ node.sourceLocation }; node.aliasIndex = RegisterAlias(node.name, targetIdentifier, node.aliasIndex, node.sourceLocation); return ValidationResult::Validated; @@ -2884,11 +2872,11 @@ namespace Nz::ShaderAst const auto& type = m_context->types.Retrieve(typeIndex, node.sourceLocation); if (!std::holds_alternative(type)) - throw std::runtime_error("only partial types can be specialized"); + throw ShaderLang::CompilerExpectedPartialTypeError{ node.sourceLocation }; const PartialType& partialType = std::get(type); if (partialType.parameters.size() != node.indices.size()) - throw std::runtime_error("parameter count mismatch"); + throw ShaderLang::CompilerPartialTypeParameterCountMismatchError{ node.sourceLocation, SafeCast(partialType.parameters.size()), SafeCast(node.indices.size()) }; StackVector parameters = NazaraStackVector(TypeParameter, partialType.parameters.size()); for (std::size_t i = 0; i < partialType.parameters.size(); ++i) @@ -2921,7 +2909,7 @@ namespace Nz::ShaderAst case TypeParameterCategory::PrimitiveType: { if (!IsPrimitiveType(resolvedType)) - throw ShaderLang::CompilerPartialTypeExpectError{ indexExpr->sourceLocation, "primitive", SafeCast(i) }; + throw ShaderLang::CompilerPartialTypeExpectError{ indexExpr->sourceLocation, "primitive", SafeCast(i) }; break; } @@ -2929,7 +2917,7 @@ namespace Nz::ShaderAst case TypeParameterCategory::StructType: { if (!IsStructType(resolvedType)) - throw ShaderLang::CompilerPartialTypeExpectError{ indexExpr->sourceLocation, "struct", SafeCast(i) }; + throw ShaderLang::CompilerPartialTypeExpectError{ indexExpr->sourceLocation, "struct", SafeCast(i) }; break; } @@ -2945,7 +2933,7 @@ namespace Nz::ShaderAst } assert(parameters.size() == partialType.parameters.size()); - node.cachedExpressionType = partialType.buildFunc(parameters.data(), parameters.size()); + node.cachedExpressionType = partialType.buildFunc(parameters.data(), parameters.size(), node.sourceLocation); } else { @@ -2959,11 +2947,11 @@ namespace Nz::ShaderAst return ValidationResult::Unresolved; if (!IsPrimitiveType(*indexType)) - throw AstError{ "AccessIndex expects integer indices" }; + throw ShaderLang::CompilerIndexRequiresIntegerIndicesError{ node.sourceLocation }; PrimitiveType primitiveIndexType = std::get(*indexType); if (primitiveIndexType != PrimitiveType::Int32 && primitiveIndexType != PrimitiveType::UInt32) - throw AstError{ "AccessIndex expects integer indices" }; + throw ShaderLang::CompilerIndexRequiresIntegerIndicesError{ node.sourceLocation }; if (IsArrayType(resolvedExprType)) { @@ -2974,13 +2962,13 @@ namespace Nz::ShaderAst else if (IsStructType(resolvedExprType)) { if (primitiveIndexType != PrimitiveType::Int32) - throw AstError{ "struct can only be accessed with constant i32 indices" }; + throw ShaderLang::CompilerIndexStructRequiresInt32IndicesError{ node.sourceLocation }; ConstantValueExpression& constantExpr = static_cast(*indexExpr); Int32 index = std::get(constantExpr.value); - std::size_t structIndex = ResolveStruct(resolvedExprType); + std::size_t structIndex = ResolveStruct(resolvedExprType, indexExpr->sourceLocation); const StructDescription* s = m_context->structs.Retrieve(structIndex, indexExpr->sourceLocation); std::optional resolvedExprTypeOpt = ResolveTypeExpr(s->members[index].type, true, indexExpr->sourceLocation); @@ -3005,7 +2993,7 @@ namespace Nz::ShaderAst resolvedExprType = swizzledVec.type; } else - throw AstError{ "unexpected type (only struct, vectors and matrices can be indexed)" }; + throw ShaderLang::CompilerIndexUnexpectedTypeError{ node.sourceLocation }; } node.cachedExpressionType = std::move(resolvedExprType); @@ -3025,7 +3013,7 @@ namespace Nz::ShaderAst return ValidationResult::Unresolved; if (GetExpressionCategory(*node.left) != ExpressionCategory::LValue) - throw AstError{ "Assignation is only possible with a l-value" }; + throw ShaderLang::CompilerAssignTemporaryError{ node.sourceLocation }; std::optional binaryType; switch (node.op) @@ -3086,19 +3074,19 @@ namespace Nz::ShaderAst const IdentifierData* targetIdentifier = ResolveAliasIdentifier(&m_context->aliases.Retrieve(alias.aliasId, node.sourceLocation), node.sourceLocation); if (targetIdentifier->category != IdentifierCategory::Function) - throw AstError{ "expected function expression" }; + throw ShaderLang::CompilerFunctionCallExpectedFunctionError{ node.sourceLocation }; targetFuncIndex = targetIdentifier->index; } else - throw AstError{ "expected function expression" }; + throw ShaderLang::CompilerFunctionCallExpectedFunctionError{ node.sourceLocation }; auto& funcData = m_context->functions.Retrieve(targetFuncIndex, node.sourceLocation); const DeclareFunctionStatement* referenceDeclaration = funcData.node; if (referenceDeclaration->entryStage.HasValue()) - throw AstError{ referenceDeclaration->name + " is an entry function which cannot be called by the program" }; + throw ShaderLang::CompilerFunctionCallUnexpectedEntryFunctionError{ node.sourceLocation, referenceDeclaration->name }; for (std::size_t i = 0; i < node.parameters.size(); ++i) { @@ -3107,11 +3095,11 @@ namespace Nz::ShaderAst return ValidationResult::Unresolved; if (ResolveAlias(*parameterType) != ResolveAlias(referenceDeclaration->parameters[i].type.GetResultingValue())) - throw AstError{ "function " + referenceDeclaration->name + " parameter " + std::to_string(i) + " type mismatch" }; + throw ShaderLang::CompilerFunctionCallUnmatchingParameterTypeError{ node.sourceLocation, referenceDeclaration->name, SafeCast(i) }; } if (node.parameters.size() != referenceDeclaration->parameters.size()) - throw AstError{ "function " + referenceDeclaration->name + " expected " + std::to_string(referenceDeclaration->parameters.size()) + " parameters, got " + std::to_string(node.parameters.size()) }; + throw ShaderLang::CompilerFunctionCallUnmatchingParameterCountError{ node.sourceLocation, referenceDeclaration->name, SafeCast(referenceDeclaration->parameters.size()), SafeCast(node.parameters.size()) }; node.cachedExpressionType = referenceDeclaration->returnType.GetResultingValue(); return ValidationResult::Validated; @@ -3138,7 +3126,7 @@ namespace Nz::ShaderAst if (IsMatrixType(ResolveAlias(*firstExprType))) { if (node.expressions[1]) - throw AstError{ "too many expressions" }; + throw ShaderLang::CompilerCastComponentMismatchError{ node.expressions[1]->sourceLocation }; // Matrix to matrix cast: always valid } @@ -3149,7 +3137,7 @@ namespace Nz::ShaderAst { const auto& exprPtr = node.expressions[i]; if (!exprPtr) - throw AstError{ "component count doesn't match required component count" }; + throw ShaderLang::CompilerCastComponentMismatchError{ node.sourceLocation }; const ExpressionType* exprType = GetExpressionType(*exprPtr); if (!exprType) @@ -3157,11 +3145,11 @@ namespace Nz::ShaderAst const ExpressionType& resolvedExprType = ResolveAlias(*exprType); if (!IsVectorType(resolvedExprType)) - throw AstError{ "expected vector type" }; + throw ShaderLang::CompilerCastMatrixExpectedVectorError{ node.sourceLocation }; const VectorType& vecType = std::get(resolvedExprType); if (vecType.componentCount != targetMatrixType.rowCount) - throw AstError{ "vector component count must match target matrix row count" }; + throw ShaderLang::CompilerCastMatrixVectorComponentMismatchError{ node.expressions[i]->sourceLocation, SafeCast(vecType.componentCount), SafeCast(targetMatrixType.rowCount) }; } } } @@ -3435,7 +3423,7 @@ namespace Nz::ShaderAst const ExpressionType& resolvedExprType = ResolveAlias(*exprType); if (!IsPrimitiveType(resolvedExprType) && !IsVectorType(resolvedExprType)) - throw AstError{ "Cannot swizzle this type" }; + throw ShaderLang::CompilerSwizzleUnexpectedTypeError{ node.sourceLocation }; PrimitiveType baseType; std::size_t componentCount; @@ -3706,7 +3694,7 @@ namespace Nz::ShaderAst auto SanitizeVisitor::ValidateIntrinsicParamCount(IntrinsicExpression& node) -> ValidationResult { if (node.parameters.size() != N) - throw ShaderLang::CompilerIntrinsicExpectedParameterCountError{ node.sourceLocation, SafeCast(N) }; + throw ShaderLang::CompilerIntrinsicExpectedParameterCountError{ node.sourceLocation, SafeCast(N) }; for (auto& param : node.parameters) MandatoryExpr(param, node.sourceLocation); @@ -3760,7 +3748,7 @@ namespace Nz::ShaderAst const ExpressionType& resolvedType = ResolveAlias(*type); if (!func(resolvedType)) - throw ShaderLang::CompilerIntrinsicExpectedTypeError{ parameter.sourceLocation, SafeCast(N) }; + throw ShaderLang::CompilerIntrinsicExpectedTypeError{ parameter.sourceLocation, SafeCast(N) }; return ValidationResult::Validated; } diff --git a/src/Nazara/Shader/ShaderLangErrors.cpp b/src/Nazara/Shader/ShaderLangErrors.cpp index 9ff685095..4158efc2a 100644 --- a/src/Nazara/Shader/ShaderLangErrors.cpp +++ b/src/Nazara/Shader/ShaderLangErrors.cpp @@ -58,6 +58,24 @@ struct fmt::formatter : formatter } }; +template <> +struct fmt::formatter : formatter +{ + template + auto format(const Nz::ShaderStageType& p, FormatContext& ctx) -> decltype(ctx.out()) + { + // TODO: Add ToString + std::string_view name = ""; + switch (p) + { + case Nz::ShaderStageType::Fragment: name = "fragment"; break; + case Nz::ShaderStageType::Vertex: name = "vertex"; break; + } + + return formatter::format(name, ctx); + } +}; + template <> struct fmt::formatter : formatter {