diff --git a/include/Nazara/Shader/Ast/Enums.hpp b/include/Nazara/Shader/Ast/Enums.hpp index cdd34b9f1..daa0b68e7 100644 --- a/include/Nazara/Shader/Ast/Enums.hpp +++ b/include/Nazara/Shader/Ast/Enums.hpp @@ -33,6 +33,7 @@ namespace Nz DepthWrite, //< Depth write mode (function only) - has argument type EarlyFragmentTests, //< Entry point (function only) - has argument on/off Entry, //< Entry point (function only) - has argument type + Export, //< Exported (external block, function and struct only) Layout, //< Struct layout (struct only) - has argument style Location, //< Location (struct member only) - has argument index LangVersion, //< NZSL version - has argument version string diff --git a/include/Nazara/Shader/Ast/Nodes.hpp b/include/Nazara/Shader/Ast/Nodes.hpp index 8a207cbb8..6ffd24a6b 100644 --- a/include/Nazara/Shader/Ast/Nodes.hpp +++ b/include/Nazara/Shader/Ast/Nodes.hpp @@ -249,9 +249,9 @@ namespace Nz::ShaderAst NodeType GetType() const override; void Visit(AstStatementVisitor& visitor) override; - ExpressionValue type; std::optional constIndex; std::string name; + ExpressionValue type; ExpressionPtr expression; }; @@ -262,11 +262,11 @@ namespace Nz::ShaderAst struct ExternalVar { + std::optional varIndex; + std::string name; ExpressionValue bindingIndex; ExpressionValue bindingSet; ExpressionValue type; - std::optional varIndex; - std::string name; }; ExpressionValue bindingSet; @@ -284,15 +284,15 @@ namespace Nz::ShaderAst ExpressionValue type; }; - ExpressionValue depthWrite; - ExpressionValue earlyFragmentTests; - ExpressionValue entryStage; - ExpressionValue returnType; std::optional funcIndex; std::optional varIndex; std::string name; std::vector parameters; std::vector statements; + ExpressionValue depthWrite; + ExpressionValue earlyFragmentTests; + ExpressionValue entryStage; + ExpressionValue returnType; }; struct NAZARA_SHADER_API DeclareOptionStatement : Statement @@ -312,6 +312,7 @@ namespace Nz::ShaderAst void Visit(AstStatementVisitor& visitor) override; std::optional structIndex; + ExpressionValue isExported; StructDescription description; }; diff --git a/src/Nazara/Shader/Ast/AstCloner.cpp b/src/Nazara/Shader/Ast/AstCloner.cpp index 15353aea5..43ddda43e 100644 --- a/src/Nazara/Shader/Ast/AstCloner.cpp +++ b/src/Nazara/Shader/Ast/AstCloner.cpp @@ -148,6 +148,7 @@ namespace Nz::ShaderAst { auto clone = std::make_unique(); clone->structIndex = node.structIndex; + clone->isExported = Clone(node.isExported); clone->description.layout = Clone(node.description.layout); clone->description.name = node.description.name; diff --git a/src/Nazara/Shader/Ast/AstSerializer.cpp b/src/Nazara/Shader/Ast/AstSerializer.cpp index 70464714f..1d587e2a1 100644 --- a/src/Nazara/Shader/Ast/AstSerializer.cpp +++ b/src/Nazara/Shader/Ast/AstSerializer.cpp @@ -3,9 +3,9 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include -#include #include namespace Nz::ShaderAst @@ -249,6 +249,7 @@ namespace Nz::ShaderAst void AstSerializerBase::Serialize(DeclareStructStatement& node) { OptVal(node.structIndex); + ExprValue(node.isExported); Value(node.description.name); ExprValue(node.description.layout); diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index b2582ee69..f85a15dad 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -939,6 +939,9 @@ namespace Nz::ShaderAst auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); + if (clone->isExported.HasValue()) + clone->isExported = ComputeExprValue(clone->isExported); + std::unordered_set declaredMembers; for (auto& member : clone->description.members) { diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index 8def0b884..114b53d79 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -28,6 +28,7 @@ namespace Nz::ShaderLang { "depth_write", ShaderAst::AttributeType::DepthWrite }, { "early_fragment_tests", ShaderAst::AttributeType::EarlyFragmentTests }, { "entry", ShaderAst::AttributeType::Entry }, + { "export", ShaderAst::AttributeType::Export }, { "layout", ShaderAst::AttributeType::Layout }, { "location", ShaderAst::AttributeType::Location }, { "nzsl_version", ShaderAst::AttributeType::LangVersion }, @@ -66,15 +67,27 @@ namespace Nz::ShaderLang } template - void HandleUniqueAttribute(const std::string_view& attributeName, ShaderAst::ExpressionValue& targetAttribute, ShaderAst::ExprValue::Param&& param, bool requireValue = true) + void HandleUniqueAttribute(const std::string_view& attributeName, ShaderAst::ExpressionValue& targetAttribute, ShaderAst::ExprValue::Param&& param) { if (targetAttribute.HasValue()) throw AttributeError{ "attribute " + std::string(attributeName) + " must be present once" }; - if (!param && requireValue) + if (param) + targetAttribute = std::move(*param); + else throw AttributeError{ "attribute " + std::string(attributeName) + " requires a parameter" }; + } - targetAttribute = std::move(*param); + template + void HandleUniqueAttribute(const std::string_view& attributeName, ShaderAst::ExpressionValue& targetAttribute, ShaderAst::ExprValue::Param&& param, T defaultValue) + { + if (targetAttribute.HasValue()) + throw AttributeError{ "attribute " + std::string(attributeName) + " must be present once" }; + + if (param) + targetAttribute = std::move(*param); + else + targetAttribute = std::move(defaultValue); } template @@ -122,7 +135,7 @@ namespace Nz::ShaderLang { ShaderAst::StatementPtr statement = ParseRootStatement(); if (!m_context->module) - throw UnexpectedToken{ "unexpected token before module declaration" }; + throw UnexpectedToken{}; //< "unexpected token before module declaration" if (!statement) break; @@ -611,7 +624,7 @@ namespace Nz::ShaderLang break; case ShaderAst::AttributeType::EarlyFragmentTests: - HandleUniqueAttribute("early_fragment_tests", func->earlyFragmentTests, std::move(arg), false); + HandleUniqueAttribute("early_fragment_tests", func->earlyFragmentTests, std::move(arg), true); break; default: @@ -836,6 +849,7 @@ namespace Nz::ShaderLang description.name = ParseIdentifierAsName(); ShaderAst::ExpressionValue condition; + ShaderAst::ExpressionValue exported; for (auto&& [attributeType, attributeParam] : attributes) { @@ -845,6 +859,10 @@ namespace Nz::ShaderLang HandleUniqueAttribute("cond", condition, std::move(attributeParam)); break; + case ShaderAst::AttributeType::Export: + HandleUniqueAttribute("export", exported, std::move(attributeParam), true); + break; + case ShaderAst::AttributeType::Layout: HandleUniqueStringAttribute("layout", s_layoutMapping, description.layout, std::move(attributeParam)); break; @@ -917,9 +935,9 @@ namespace Nz::ShaderLang Expect(Advance(), TokenType::ClosingCurlyBracket); if (condition.HasValue()) - return ShaderBuilder::ConditionalStatement(std::move(condition).GetExpression(), ShaderBuilder::DeclareStruct(std::move(description))); + return ShaderBuilder::ConditionalStatement(std::move(condition).GetExpression(), ShaderBuilder::DeclareStruct(std::move(description), std::move(exported))); else - return ShaderBuilder::DeclareStruct(std::move(description)); + return ShaderBuilder::DeclareStruct(std::move(description), std::move(exported)); } ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()