diff --git a/include/Nazara/Shader/ShaderEnums.hpp b/include/Nazara/Shader/ShaderEnums.hpp index f5182c243..5c2d3136d 100644 --- a/include/Nazara/Shader/ShaderEnums.hpp +++ b/include/Nazara/Shader/ShaderEnums.hpp @@ -16,6 +16,12 @@ namespace Nz::ShaderAst Simple //< = }; + enum class AttributeType + { + Entry, //< Entry point (function only) - has argument type + Layout //< Struct layout (struct only) - has argument style + }; + enum class BasicType { Boolean, //< bool diff --git a/include/Nazara/Shader/ShaderLangParser.hpp b/include/Nazara/Shader/ShaderLangParser.hpp index 4c0e12d86..785136702 100644 --- a/include/Nazara/Shader/ShaderLangParser.hpp +++ b/include/Nazara/Shader/ShaderLangParser.hpp @@ -25,6 +25,12 @@ namespace Nz::ShaderLang public: using exception::exception; }; + + class UnknownAttribute : public std::exception + { + public: + using exception::exception; + }; class UnknownType : public std::exception { @@ -49,10 +55,13 @@ namespace Nz::ShaderLang private: // Flow control const Token& Advance(); + void Consume(std::size_t count = 1); const Token& Expect(const Token& token, TokenType type); const Token& Expect(TokenType type); const Token& Peek(std::size_t advance = 0); + std::vector ParseAttributes(); + // Statements std::vector ParseFunctionBody(); ShaderAst::StatementPtr ParseFunctionDeclaration(); @@ -70,6 +79,7 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr ParseParenthesisExpression(); ShaderAst::ExpressionPtr ParsePrimaryExpression(); + ShaderAst::AttributeType ParseIdentifierAsAttributeType(); const std::string& ParseIdentifierAsName(); ShaderAst::ShaderExpressionType ParseIdentifierAsType(); @@ -77,6 +87,7 @@ namespace Nz::ShaderLang struct Context { + std::vector pendingAttributes; std::unique_ptr root; std::size_t tokenCount; std::size_t tokenIndex = 0; diff --git a/include/Nazara/Shader/ShaderNodes.hpp b/include/Nazara/Shader/ShaderNodes.hpp index 7aeef561c..4e532ad14 100644 --- a/include/Nazara/Shader/ShaderNodes.hpp +++ b/include/Nazara/Shader/ShaderNodes.hpp @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -25,6 +25,12 @@ namespace Nz::ShaderAst class AstExpressionVisitor; class AstStatementVisitor; + struct Attribute + { + AttributeType type; + std::string args; + }; + struct NAZARA_SHADER_API Node { Node() = default; diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index d4ecbf0d5..4cd73eedc 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -33,6 +33,11 @@ namespace Nz::ShaderLang { "vec3u32", ShaderAst::BasicType::UInt3 }, { "vec4u32", ShaderAst::BasicType::UInt4 }, }; + + std::unordered_map identifierToAttributeType = { + { "entry", ShaderAst::AttributeType::Entry }, + { "layout", ShaderAst::AttributeType::Layout }, + }; } ShaderAst::StatementPtr Parser::Parse(const std::vector& tokens) @@ -51,6 +56,10 @@ namespace Nz::ShaderLang const Token& nextToken = Peek(); switch (nextToken.type) { + case TokenType::OpenAttribute: + context.pendingAttributes = ParseAttributes(); + break; + case TokenType::FunctionDeclaration: context.root->statements.push_back(ParseFunctionDeclaration()); break; @@ -75,6 +84,12 @@ namespace Nz::ShaderLang return token; } + void Parser::Consume(std::size_t count) + { + assert(m_context->tokenIndex + count < m_context->tokenCount); + m_context->tokenIndex += count; + } + const Token& Parser::Expect(const Token& token, TokenType type) { if (token.type != type) @@ -97,6 +112,58 @@ namespace Nz::ShaderLang return m_context->tokens[m_context->tokenIndex + advance]; } + std::vector Parser::ParseAttributes() + { + std::vector attributes; + + Expect(Advance(), TokenType::OpenAttribute); + + bool expectComma = false; + for (;;) + { + const Token& t = Peek(); + if (t.type == TokenType::ClosingAttribute) + { + // Parse [[attribute1]] [[attribute2]] the same as [[attribute1, attribute2]] + if (Peek(1).type == TokenType::OpenAttribute) + { + Consume(2); + expectComma = false; + continue; + } + + break; + } + + if (expectComma) + Expect(Advance(), TokenType::Comma); + + ShaderAst::AttributeType attributeType = ParseIdentifierAsAttributeType(); + + std::string arg; + if (Peek().type == TokenType::OpenParenthesis) + { + Consume(); + + if (Peek().type == TokenType::Identifier) + arg = std::get(Advance().data); + + Expect(Advance(), TokenType::ClosingParenthesis); + } + + expectComma = true; + + attributes.push_back({ + attributeType, + std::move(arg) + }); + } + + Expect(Advance(), TokenType::ClosingAttribute); + + return attributes; + } + std::vector Parser::ParseFunctionBody() { return ParseStatementList(); @@ -120,10 +187,7 @@ namespace Nz::ShaderLang break; if (!firstParameter) - { - Expect(t, TokenType::Comma); - Advance(); - } + Expect(Advance(), TokenType::Comma); parameters.push_back(ParseFunctionParameter()); firstParameter = false; @@ -134,8 +198,7 @@ namespace Nz::ShaderLang ShaderAst::ShaderExpressionType returnType = ShaderAst::BasicType::Void; if (Peek().type == TokenType::FunctionReturn) { - Advance(); //< Consume -> - + Consume(); returnType = ParseIdentifierAsType(); } @@ -218,7 +281,7 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr expression; if (Peek().type == TokenType::Assign) { - Advance(); + Consume(); expression = ParseExpression(); } @@ -235,7 +298,7 @@ namespace Nz::ShaderLang if (tokenPrecedence < exprPrecedence) return lhs; - Advance(); + Consume(); ShaderAst::ExpressionPtr rhs = ParsePrimaryExpression(); const Token& nextOp = Peek(); @@ -255,7 +318,6 @@ namespace Nz::ShaderLang default: throw UnexpectedToken{}; } } - lhs = ShaderBuilder::Binary(binaryType, std::move(lhs), std::move(rhs)); } @@ -295,15 +357,15 @@ namespace Nz::ShaderLang switch (token.type) { case TokenType::BoolFalse: - Advance(); + Consume(); return ShaderBuilder::Constant(false); case TokenType::BoolTrue: - Advance(); + Consume(); return ShaderBuilder::Constant(true); case TokenType::FloatingPointValue: - Advance(); + Consume(); return ShaderBuilder::Constant(float(std::get(token.data))); //< FIXME case TokenType::Identifier: @@ -320,6 +382,18 @@ namespace Nz::ShaderLang } } + ShaderAst::AttributeType Parser::ParseIdentifierAsAttributeType() + { + const Token& identifierToken = Expect(Advance(), TokenType::Identifier); + const std::string& identifier = std::get(identifierToken.data); + + auto it = identifierToAttributeType.find(identifier); + if (it == identifierToAttributeType.end()) + throw UnknownAttribute{}; + + return it->second; + } + const std::string& Parser::ParseIdentifierAsName() { const Token& identifierToken = Expect(Advance(), TokenType::Identifier);