Shader: Improve attribute source location

This commit is contained in:
SirLynix 2022-03-28 08:52:57 +02:00 committed by Jérôme Leclercq
parent 98237acb6f
commit 8429411755
7 changed files with 158 additions and 152 deletions

View File

@ -11,7 +11,7 @@
#include <Nazara/Shader/Config.hpp> #include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/Ast/AstExpressionVisitor.hpp> #include <Nazara/Shader/Ast/AstExpressionVisitor.hpp>
#include <Nazara/Shader/Ast/AstStatementVisitor.hpp> #include <Nazara/Shader/Ast/AstStatementVisitor.hpp>
#include <Nazara/Shader/Ast/Attribute.hpp> #include <Nazara/Shader/Ast/ExpressionValue.hpp>
#include <vector> #include <vector>
namespace Nz::ShaderAst namespace Nz::ShaderAst

View File

@ -10,7 +10,7 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp> #include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderLangSourceLocation.hpp> #include <Nazara/Shader/ShaderLangSourceLocation.hpp>
#include <Nazara/Shader/Ast/Attribute.hpp> #include <Nazara/Shader/Ast/ExpressionValue.hpp>
#include <Nazara/Shader/Ast/Module.hpp> #include <Nazara/Shader/Ast/Module.hpp>
#include <vector> #include <vector>

View File

@ -9,8 +9,8 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/ShaderLangSourceLocation.hpp> #include <Nazara/Shader/ShaderLangSourceLocation.hpp>
#include <Nazara/Shader/Ast/Attribute.hpp>
#include <Nazara/Shader/Ast/Enums.hpp> #include <Nazara/Shader/Ast/Enums.hpp>
#include <Nazara/Shader/Ast/ExpressionValue.hpp>
#include <Nazara/Utility/Enums.hpp> #include <Nazara/Utility/Enums.hpp>
#include <optional> #include <optional>
#include <string> #include <string>

View File

@ -4,13 +4,11 @@
#pragma once #pragma once
#ifndef NAZARA_SHADER_AST_ATTRIBUTE_HPP #ifndef NAZARA_SHADER_AST_EXPRESSIONVALUE_HPP
#define NAZARA_SHADER_AST_ATTRIBUTE_HPP #define NAZARA_SHADER_AST_EXPRESSIONVALUE_HPP
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Ast/Enums.hpp> #include <Nazara/Shader/Ast/Enums.hpp>
#include <memory>
#include <optional>
#include <variant> #include <variant>
namespace Nz::ShaderAst namespace Nz::ShaderAst
@ -47,16 +45,8 @@ namespace Nz::ShaderAst
private: private:
std::variant<std::monostate, T, ExpressionPtr> m_value; std::variant<std::monostate, T, ExpressionPtr> m_value;
}; };
struct ExprValue
{
using Param = std::optional<ExpressionPtr>;
AttributeType type;
Param args;
};
} }
#include <Nazara/Shader/Ast/Attribute.inl> #include <Nazara/Shader/Ast/ExpressionValue.inl>
#endif // NAZARA_SHADER_AST_ATTRIBUTE_HPP #endif // NAZARA_SHADER_AST_EXPRESSIONVALUE_HPP

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Engine - Shader module" // This file is part of the "Nazara Engine - Shader module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Shader/Ast/Attribute.hpp> #include <Nazara/Shader/Ast/ExpressionValue.hpp>
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>
#include <Nazara/Shader/Debug.hpp> #include <Nazara/Shader/Debug.hpp>

View File

@ -13,10 +13,10 @@
#include <Nazara/Math/Vector4.hpp> #include <Nazara/Math/Vector4.hpp>
#include <Nazara/Shader/Config.hpp> #include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderLangSourceLocation.hpp> #include <Nazara/Shader/ShaderLangSourceLocation.hpp>
#include <Nazara/Shader/Ast/Attribute.hpp>
#include <Nazara/Shader/Ast/ConstantValue.hpp> #include <Nazara/Shader/Ast/ConstantValue.hpp>
#include <Nazara/Shader/Ast/Enums.hpp> #include <Nazara/Shader/Ast/Enums.hpp>
#include <Nazara/Shader/Ast/ExpressionType.hpp> #include <Nazara/Shader/Ast/ExpressionType.hpp>
#include <Nazara/Shader/Ast/ExpressionValue.hpp>
#include <array> #include <array>
#include <memory> #include <memory>
#include <optional> #include <optional>

View File

@ -59,55 +59,73 @@ namespace Nz::ShaderLang
{ "never", ShaderAst::LoopUnroll::Never } { "never", ShaderAst::LoopUnroll::Never }
}; };
template<typename T> SourceLocation TokenLocation(const Token& token)
void HandleUniqueAttribute(const Token& token, ShaderAst::AttributeType attributeType, ShaderAst::ExpressionValue<T>& targetAttribute, ShaderAst::ExprValue::Param&& param)
{ {
if (targetAttribute.HasValue()) SourceLocation sourceLoc;
throw ParserAttributeMultipleUniqueError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes sourceLoc.file = token.file;
sourceLoc.startColumn = sourceLoc.endColumn = token.column;
sourceLoc.startLine = sourceLoc.endLine = token.line;
if (param) return sourceLoc;
targetAttribute = std::move(*param); }
else
throw ParserAttributeMissingParameterError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes void ExtendLocationToToken(SourceLocation& location, const Token& token)
{
assert(location.file == token.file);
assert(token.line >= location.startLine);
location.endLine = token.line;
assert(token.column >= location.startColumn);
location.endColumn = location.endColumn;
} }
template<typename T> template<typename T>
void HandleUniqueAttribute(const Token& token, ShaderAst::AttributeType attributeType, ShaderAst::ExpressionValue<T>& targetAttribute, ShaderAst::ExprValue::Param&& param, T defaultValue) void HandleUniqueAttribute(ShaderAst::ExpressionValue<T>& targetAttribute, Parser::Attribute&& attribute)
{ {
if (targetAttribute.HasValue()) if (targetAttribute.HasValue())
throw ParserAttributeMultipleUniqueError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes throw ParserAttributeMultipleUniqueError{ attribute.sourceLocation, attribute.type };
if (param) if (!attribute.args)
targetAttribute = std::move(*param); throw ParserAttributeMissingParameterError{ attribute.sourceLocation, attribute.type };
targetAttribute = std::move(attribute.args);
}
template<typename T>
void HandleUniqueAttribute(ShaderAst::ExpressionValue<T>& targetAttribute, Parser::Attribute&& attribute, T defaultValue)
{
if (targetAttribute.HasValue())
throw ParserAttributeMultipleUniqueError{ attribute.sourceLocation, attribute.type };
if (attribute.args)
targetAttribute = std::move(attribute.args);
else else
targetAttribute = std::move(defaultValue); targetAttribute = std::move(defaultValue);
} }
template<typename T> template<typename T>
void HandleUniqueStringAttribute(const Token& token, ShaderAst::AttributeType attributeType, const std::unordered_map<std::string, T>& map, ShaderAst::ExpressionValue<T>& targetAttribute, ShaderAst::ExprValue::Param&& param, std::optional<T> defaultValue = {}) void HandleUniqueStringAttribute(ShaderAst::ExpressionValue<T>& targetAttribute, Parser::Attribute&& attribute, const std::unordered_map<std::string, T>& map, std::optional<T> defaultValue = {})
{ {
if (targetAttribute.HasValue()) if (targetAttribute.HasValue())
throw ParserAttributeMultipleUniqueError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes throw ParserAttributeMultipleUniqueError{ attribute.sourceLocation, attribute.type };
//FIXME: This should be handled with global values at sanitization stage //FIXME: This should be handled with global values at sanitization stage
if (param) if (attribute.args)
{ {
const ShaderAst::ExpressionPtr& expr = *param; if (attribute.args->GetType() != ShaderAst::NodeType::IdentifierExpression)
if (expr->GetType() != ShaderAst::NodeType::IdentifierExpression) throw ParserAttributeParameterIdentifierError{ attribute.args->sourceLocation, attribute.type };
throw ParserAttributeParameterIdentifierError{ SourceLocation{ token.line, token.column, token.file }, attributeType };
const std::string& exprStr = static_cast<ShaderAst::IdentifierExpression&>(*expr).identifier; const std::string& exprStr = static_cast<ShaderAst::IdentifierExpression&>(*attribute.args).identifier;
auto it = map.find(exprStr); auto it = map.find(exprStr);
if (it == map.end()) if (it == map.end())
throw ParserAttributeInvalidParameterError{ SourceLocation{ token.line, token.column, token.file }, exprStr, attributeType }; throw ParserAttributeInvalidParameterError{ attribute.args->sourceLocation, exprStr, attribute.type };
targetAttribute = it->second; targetAttribute = it->second;
} }
else else
{ {
if (!defaultValue) if (!defaultValue)
throw ParserAttributeMissingParameterError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes throw ParserAttributeMissingParameterError{ attribute.sourceLocation, attribute.type };
targetAttribute = defaultValue.value(); targetAttribute = defaultValue.value();
} }
@ -122,7 +140,7 @@ namespace Nz::ShaderLang
m_context = &context; m_context = &context;
std::vector<ShaderAst::ExprValue> attributes; std::vector<Attribute> attributes;
for (;;) for (;;)
{ {
@ -130,7 +148,7 @@ namespace Nz::ShaderLang
if (!m_context->module) if (!m_context->module)
{ {
const Token& nextToken = Peek(); const Token& nextToken = Peek();
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file } }; throw ParserUnexpectedTokenError{ TokenLocation(nextToken) };
} }
if (!statement) if (!statement)
@ -159,7 +177,7 @@ namespace Nz::ShaderLang
const Token& Parser::Expect(const Token& token, TokenType type) const Token& Parser::Expect(const Token& token, TokenType type)
{ {
if (token.type != type) if (token.type != type)
throw ParserExpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, type, token.type }; throw ParserExpectedTokenError{ TokenLocation(token), type, token.type };
return token; return token;
} }
@ -167,7 +185,7 @@ namespace Nz::ShaderLang
const Token& Parser::ExpectNot(const Token& token, TokenType type) const Token& Parser::ExpectNot(const Token& token, TokenType type)
{ {
if (token.type == type) if (token.type == type)
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, type }; throw ParserUnexpectedTokenError{ TokenLocation(token), type };
return token; return token;
} }
@ -186,9 +204,9 @@ namespace Nz::ShaderLang
return m_context->tokens[m_context->tokenIndex + advance]; return m_context->tokens[m_context->tokenIndex + advance];
} }
std::vector<ShaderAst::ExprValue> Parser::ParseAttributes() std::vector<Parser::Attribute> Parser::ParseAttributes()
{ {
std::vector<ShaderAst::ExprValue> attributes; std::vector<Parser::Attribute> attributes;
Expect(Advance(), TokenType::OpenSquareBracket); Expect(Advance(), TokenType::OpenSquareBracket);
@ -214,23 +232,34 @@ namespace Nz::ShaderLang
if (expectComma) if (expectComma)
Expect(Advance(), TokenType::Comma); Expect(Advance(), TokenType::Comma);
ShaderAst::AttributeType attributeType = ParseIdentifierAsAttributeType(); const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
const std::string& identifier = std::get<std::string>(identifierToken.data);
ShaderAst::ExprValue::Param arg; SourceLocation attributeLocation = TokenLocation(identifierToken);
auto it = s_identifierToAttributeType.find(identifier);
if (it == s_identifierToAttributeType.end())
throw ParserUnknownAttributeError{ attributeLocation };
ShaderAst::AttributeType attributeType = it->second;
ShaderAst::ExpressionPtr arg;
if (Peek().type == TokenType::OpenParenthesis) if (Peek().type == TokenType::OpenParenthesis)
{ {
Consume(); Consume();
arg = ParseExpression(); arg = ParseExpression();
Expect(Advance(), TokenType::ClosingParenthesis); const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis);
ExtendLocationToToken(attributeLocation, closeToken);
} }
expectComma = true; expectComma = true;
attributes.push_back({ attributes.push_back({
attributeType, attributeType,
std::move(arg) std::move(arg),
attributeLocation
}); });
} }
@ -239,12 +268,12 @@ namespace Nz::ShaderLang
return attributes; return attributes;
} }
void Parser::ParseModuleStatement(std::vector<ShaderAst::ExprValue> attributes) void Parser::ParseModuleStatement(std::vector<Attribute> attributes)
{ {
if (m_context->parsingImportedModule) if (m_context->parsingImportedModule)
{ {
const Token& token = Peek(); const Token& token = Peek();
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
} }
const Token& moduleToken = Expect(Advance(), TokenType::Module); const Token& moduleToken = Expect(Advance(), TokenType::Module);
@ -252,7 +281,7 @@ namespace Nz::ShaderLang
std::optional<UInt32> moduleVersion; std::optional<UInt32> moduleVersion;
std::optional<Uuid> moduleId; std::optional<Uuid> moduleId;
for (auto&& [attributeType, arg] : attributes) for (auto&& [attributeType, expr, location] : attributes)
{ {
switch (attributeType) switch (attributeType)
{ {
@ -260,18 +289,17 @@ namespace Nz::ShaderLang
{ {
// Version parsing // Version parsing
if (moduleVersion.has_value()) if (moduleVersion.has_value())
throw ParserAttributeMultipleUniqueError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; //< TODO: Improve source location for attributes throw ParserAttributeMultipleUniqueError{ location, attributeType };
if (!arg) if (!expr)
throw ParserAttributeMissingParameterError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; //< TODO: Improve source location for attributes throw ParserAttributeMissingParameterError{ location, attributeType };
const ShaderAst::ExpressionPtr& expr = *arg;
if (expr->GetType() != ShaderAst::NodeType::ConstantValueExpression) if (expr->GetType() != ShaderAst::NodeType::ConstantValueExpression)
throw ParserAttributeExpectStringError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; throw ParserAttributeExpectStringError{ location, attributeType };
auto& constantValue = SafeCast<ShaderAst::ConstantValueExpression&>(*expr); auto& constantValue = SafeCast<ShaderAst::ConstantValueExpression&>(*expr);
if (ShaderAst::GetConstantType(constantValue.value) != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::String }) if (ShaderAst::GetConstantType(constantValue.value) != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::String })
throw ParserAttributeExpectStringError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; throw ParserAttributeExpectStringError{ location, attributeType };
const std::string& versionStr = std::get<std::string>(constantValue.value); const std::string& versionStr = std::get<std::string>(constantValue.value);
@ -279,7 +307,7 @@ namespace Nz::ShaderLang
std::smatch versionMatch; std::smatch versionMatch;
if (!std::regex_match(versionStr, versionMatch, versionRegex)) if (!std::regex_match(versionStr, versionMatch, versionRegex))
throw ParserInvalidVersionError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, versionStr }; throw ParserInvalidVersionError{ location, versionStr };
assert(versionMatch.size() == 6); assert(versionMatch.size() == 6);
@ -299,36 +327,35 @@ namespace Nz::ShaderLang
case ShaderAst::AttributeType::Uuid: case ShaderAst::AttributeType::Uuid:
{ {
if (moduleId.has_value()) if (moduleId.has_value())
throw ParserAttributeMultipleUniqueError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; //< TODO: Improve source location for attributes throw ParserAttributeMultipleUniqueError{ location, attributeType };
if (!arg) if (!expr)
throw ParserAttributeMissingParameterError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; //< TODO: Improve source location for attributes throw ParserAttributeMissingParameterError{ location, attributeType };
const ShaderAst::ExpressionPtr& expr = *arg;
if (expr->GetType() != ShaderAst::NodeType::ConstantValueExpression) if (expr->GetType() != ShaderAst::NodeType::ConstantValueExpression)
throw ParserAttributeExpectStringError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; throw ParserAttributeExpectStringError{ location, attributeType };
auto& constantValue = SafeCast<ShaderAst::ConstantValueExpression&>(*expr); auto& constantValue = SafeCast<ShaderAst::ConstantValueExpression&>(*expr);
if (ShaderAst::GetConstantType(constantValue.value) != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::String }) if (ShaderAst::GetConstantType(constantValue.value) != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::String })
throw ParserAttributeExpectStringError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; throw ParserAttributeExpectStringError{ location, attributeType };
const std::string& uuidStr = std::get<std::string>(constantValue.value); const std::string& uuidStr = std::get<std::string>(constantValue.value);
Uuid uuid = Uuid::FromString(uuidStr); Uuid uuid = Uuid::FromString(uuidStr);
if (uuid.IsNull()) if (uuid.IsNull())
throw ParserInvalidUuidError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, uuidStr }; throw ParserInvalidUuidError{ location, uuidStr };
moduleId = uuid; moduleId = uuid;
break; break;
} }
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; throw ParserUnexpectedAttributeError{ location, attributeType };
} }
} }
if (!moduleVersion.has_value()) if (!moduleVersion.has_value())
throw ParserMissingAttributeError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file } }; throw ParserMissingAttributeError{ TokenLocation(moduleToken) };
if (!moduleId) if (!moduleId)
moduleId = Uuid::Generate(); moduleId = Uuid::Generate();
@ -349,7 +376,7 @@ namespace Nz::ShaderLang
if (!statement) if (!statement)
{ {
const Token& token = Peek(); const Token& token = Peek();
throw ParserUnexpectedEndOfFileError{ SourceLocation{ token.line, token.column, token.file } }; throw ParserUnexpectedEndOfFileError{ TokenLocation(token) };
} }
module->rootNode->statements.push_back(std::move(statement)); module->rootNode->statements.push_back(std::move(statement));
@ -374,7 +401,7 @@ namespace Nz::ShaderLang
Expect(Advance(), TokenType::Semicolon); Expect(Advance(), TokenType::Semicolon);
if (m_context->module) if (m_context->module)
throw ParserDuplicateModuleError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file } }; throw ParserDuplicateModuleError{ TokenLocation(moduleToken) };
m_context->module = std::move(module); m_context->module = std::move(module);
} }
@ -497,7 +524,7 @@ namespace Nz::ShaderLang
} }
default: default:
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
} }
} }
@ -509,7 +536,7 @@ namespace Nz::ShaderLang
return ShaderBuilder::Discard(); return ShaderBuilder::Discard();
} }
ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<ShaderAst::ExprValue> attributes) ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<Attribute> attributes)
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
@ -517,23 +544,26 @@ namespace Nz::ShaderLang
Expect(Advance(), TokenType::OpenCurlyBracket); Expect(Advance(), TokenType::OpenCurlyBracket);
std::unique_ptr<ShaderAst::DeclareExternalStatement> externalStatement = std::make_unique<ShaderAst::DeclareExternalStatement>(); std::unique_ptr<ShaderAst::DeclareExternalStatement> externalStatement = std::make_unique<ShaderAst::DeclareExternalStatement>();
externalStatement->sourceLocation.startColumn = externalToken.column;
externalStatement->sourceLocation.startLine = externalToken.line;
externalStatement->sourceLocation.file = externalToken.file;
ShaderAst::ExpressionValue<bool> condition; ShaderAst::ExpressionValue<bool> condition;
for (auto&& [attributeType, arg] : attributes) for (auto&& attribute : attributes)
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Cond: case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(externalToken, attributeType, condition, std::move(arg)); HandleUniqueAttribute(condition, std::move(attribute));
break; break;
case ShaderAst::AttributeType::Set: case ShaderAst::AttributeType::Set:
HandleUniqueAttribute(externalToken, attributeType, externalStatement->bindingSet, std::move(arg)); HandleUniqueAttribute(externalStatement->bindingSet, std::move(attribute));
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ externalToken.line, externalToken.column, externalToken.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
@ -562,20 +592,20 @@ namespace Nz::ShaderLang
if (token.type == TokenType::OpenSquareBracket) if (token.type == TokenType::OpenSquareBracket)
{ {
for (auto&& [attributeType, arg] : ParseAttributes()) for (auto&& attribute : ParseAttributes())
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Binding: case ShaderAst::AttributeType::Binding:
HandleUniqueAttribute(externalToken, attributeType, extVar.bindingIndex, std::move(arg)); HandleUniqueAttribute(extVar.bindingIndex, std::move(attribute));
break; break;
case ShaderAst::AttributeType::Set: case ShaderAst::AttributeType::Set:
HandleUniqueAttribute(externalToken, attributeType, extVar.bindingSet, std::move(arg)); HandleUniqueAttribute(extVar.bindingSet, std::move(attribute));
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
} }
@ -593,7 +623,7 @@ namespace Nz::ShaderLang
return externalStatement; return externalStatement;
} }
ShaderAst::StatementPtr Parser::ParseForDeclaration(std::vector<ShaderAst::ExprValue> attributes) ShaderAst::StatementPtr Parser::ParseForDeclaration(std::vector<Attribute> attributes)
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
@ -624,16 +654,16 @@ namespace Nz::ShaderLang
auto forNode = ShaderBuilder::For(std::move(varName), std::move(expr), std::move(toExpr), std::move(stepExpr), std::move(statement)); auto forNode = ShaderBuilder::For(std::move(varName), std::move(expr), std::move(toExpr), std::move(stepExpr), std::move(statement));
// TODO: Deduplicate code // TODO: Deduplicate code
for (auto&& [attributeType, arg] : attributes) for (auto&& attribute : attributes)
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Unroll: case ShaderAst::AttributeType::Unroll:
HandleUniqueStringAttribute(forToken, attributeType, s_unrollModes, forNode->unroll, std::move(arg), std::make_optional(ShaderAst::LoopUnroll::Always)); HandleUniqueStringAttribute(forNode->unroll, std::move(attribute), s_unrollModes, std::make_optional(ShaderAst::LoopUnroll::Always));
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ forToken.line, forToken.column, forToken.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
@ -647,16 +677,16 @@ namespace Nz::ShaderLang
auto forEachNode = ShaderBuilder::ForEach(std::move(varName), std::move(expr), std::move(statement)); auto forEachNode = ShaderBuilder::ForEach(std::move(varName), std::move(expr), std::move(statement));
// TODO: Deduplicate code // TODO: Deduplicate code
for (auto&& [attributeType, arg] : attributes) for (auto&& attribute : attributes)
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Unroll: case ShaderAst::AttributeType::Unroll:
HandleUniqueStringAttribute(forToken, attributeType, s_unrollModes, forEachNode->unroll, std::move(arg), std::make_optional(ShaderAst::LoopUnroll::Always)); HandleUniqueStringAttribute(forEachNode->unroll, std::move(attribute), s_unrollModes, std::make_optional(ShaderAst::LoopUnroll::Always));
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ forToken.line, forToken.column, forToken.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
@ -669,7 +699,7 @@ namespace Nz::ShaderLang
return ParseStatementList(); return ParseStatementList();
} }
ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector<ShaderAst::ExprValue> attributes) ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector<Attribute> attributes)
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
@ -712,32 +742,32 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionValue<bool> condition; ShaderAst::ExpressionValue<bool> condition;
for (auto&& [attributeType, attributeParam] : attributes) for (auto&& attribute : attributes)
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Cond: case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(funcToken, attributeType, condition, std::move(attributeParam)); HandleUniqueAttribute(condition, std::move(attribute));
break; break;
case ShaderAst::AttributeType::Entry: case ShaderAst::AttributeType::Entry:
HandleUniqueStringAttribute(funcToken, attributeType, s_entryPoints, func->entryStage, std::move(attributeParam)); HandleUniqueStringAttribute(func->entryStage, std::move(attribute), s_entryPoints);
break; break;
case ShaderAst::AttributeType::Export: case ShaderAst::AttributeType::Export:
HandleUniqueAttribute(funcToken, attributeType, func->isExported, std::move(attributeParam), true); HandleUniqueAttribute(func->isExported, std::move(attribute), true);
break; break;
case ShaderAst::AttributeType::DepthWrite: case ShaderAst::AttributeType::DepthWrite:
HandleUniqueStringAttribute(funcToken, attributeType, s_depthWriteModes, func->depthWrite, std::move(attributeParam)); HandleUniqueStringAttribute(func->depthWrite, std::move(attribute), s_depthWriteModes);
break; break;
case ShaderAst::AttributeType::EarlyFragmentTests: case ShaderAst::AttributeType::EarlyFragmentTests:
HandleUniqueAttribute(funcToken, attributeType, func->earlyFragmentTests, std::move(attributeParam), true); HandleUniqueAttribute(func->earlyFragmentTests, std::move(attribute));
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ funcToken.line, funcToken.column, funcToken.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
@ -807,26 +837,26 @@ namespace Nz::ShaderLang
return ShaderBuilder::Return(std::move(expr)); return ShaderBuilder::Return(std::move(expr));
} }
ShaderAst::StatementPtr Parser::ParseRootStatement(std::vector<ShaderAst::ExprValue> attributes) ShaderAst::StatementPtr Parser::ParseRootStatement(std::vector<Attribute> attributes)
{ {
const Token& nextToken = Peek(); const Token& nextToken = Peek();
switch (nextToken.type) switch (nextToken.type)
{ {
case TokenType::Alias: case TokenType::Alias:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type }; throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseAliasDeclaration(); return ParseAliasDeclaration();
case TokenType::Const: case TokenType::Const:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type }; throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseConstStatement(); return ParseConstStatement();
case TokenType::EndOfStream: case TokenType::EndOfStream:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type }; throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return {}; return {};
@ -835,7 +865,7 @@ namespace Nz::ShaderLang
case TokenType::Import: case TokenType::Import:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type }; throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseImportStatement(); return ParseImportStatement();
@ -850,7 +880,7 @@ namespace Nz::ShaderLang
case TokenType::Option: case TokenType::Option:
{ {
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type }; throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseOptionDeclaration(); return ParseOptionDeclaration();
} }
@ -862,13 +892,13 @@ namespace Nz::ShaderLang
return ParseStructDeclaration(std::move(attributes)); return ParseStructDeclaration(std::move(attributes));
default: default:
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type }; throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
} }
} }
ShaderAst::StatementPtr Parser::ParseSingleStatement() ShaderAst::StatementPtr Parser::ParseSingleStatement()
{ {
std::vector<ShaderAst::ExprValue> attributes; std::vector<Attribute> attributes;
ShaderAst::StatementPtr statement; ShaderAst::StatementPtr statement;
do do
{ {
@ -877,14 +907,14 @@ namespace Nz::ShaderLang
{ {
case TokenType::Const: case TokenType::Const:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseConstStatement(); statement = ParseConstStatement();
break; break;
case TokenType::Discard: case TokenType::Discard:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseDiscardStatement(); statement = ParseDiscardStatement();
break; break;
@ -896,14 +926,14 @@ namespace Nz::ShaderLang
case TokenType::Let: case TokenType::Let:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseVariableDeclaration(); statement = ParseVariableDeclaration();
break; break;
case TokenType::Identifier: case TokenType::Identifier:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ShaderBuilder::ExpressionStatement(ParseVariableAssignation()); statement = ShaderBuilder::ExpressionStatement(ParseVariableAssignation());
Expect(Advance(), TokenType::Semicolon); Expect(Advance(), TokenType::Semicolon);
@ -911,7 +941,7 @@ namespace Nz::ShaderLang
case TokenType::If: case TokenType::If:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseBranchStatement(); statement = ParseBranchStatement();
break; break;
@ -923,7 +953,7 @@ namespace Nz::ShaderLang
case TokenType::Return: case TokenType::Return:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseReturnStatement(); statement = ParseReturnStatement();
break; break;
@ -934,7 +964,7 @@ namespace Nz::ShaderLang
break; break;
default: default:
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
} }
} }
while (!statement); //< small trick to repeat parsing once we got attributes while (!statement); //< small trick to repeat parsing once we got attributes
@ -965,7 +995,7 @@ namespace Nz::ShaderLang
return statements; return statements;
} }
ShaderAst::StatementPtr Parser::ParseStructDeclaration(std::vector<ShaderAst::ExprValue> attributes) ShaderAst::StatementPtr Parser::ParseStructDeclaration(std::vector<Attribute> attributes)
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
@ -977,24 +1007,24 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionValue<bool> condition; ShaderAst::ExpressionValue<bool> condition;
ShaderAst::ExpressionValue<bool> exported; ShaderAst::ExpressionValue<bool> exported;
for (auto&& [attributeType, attributeParam] : attributes) for (auto&& attribute : attributes)
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Cond: case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(structToken, attributeType, condition, std::move(attributeParam)); HandleUniqueAttribute(condition, std::move(attribute));
break; break;
case ShaderAst::AttributeType::Export: case ShaderAst::AttributeType::Export:
HandleUniqueAttribute(structToken, attributeType, exported, std::move(attributeParam), true); HandleUniqueAttribute(exported, std::move(attribute), true);
break; break;
case ShaderAst::AttributeType::Layout: case ShaderAst::AttributeType::Layout:
HandleUniqueStringAttribute(structToken, attributeType, s_layoutMapping, description.layout, std::move(attributeParam)); HandleUniqueStringAttribute(description.layout, std::move(attribute), s_layoutMapping);
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ structToken.line, structToken.column, structToken.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
@ -1026,24 +1056,24 @@ namespace Nz::ShaderLang
if (token.type == TokenType::OpenSquareBracket) if (token.type == TokenType::OpenSquareBracket)
{ {
for (auto&& [attributeType, arg] : ParseAttributes()) for (auto&& attribute : ParseAttributes())
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Builtin: case ShaderAst::AttributeType::Builtin:
HandleUniqueStringAttribute(token, attributeType, s_builtinMapping, structField.builtin, std::move(arg)); HandleUniqueStringAttribute(structField.builtin, std::move(attribute), s_builtinMapping);
break; break;
case ShaderAst::AttributeType::Cond: case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(token, attributeType, structField.cond, std::move(arg)); HandleUniqueAttribute(structField.cond, std::move(attribute));
break; break;
case ShaderAst::AttributeType::Location: case ShaderAst::AttributeType::Location:
HandleUniqueAttribute(token, attributeType, structField.locationIndex, std::move(arg)); HandleUniqueAttribute(structField.locationIndex, std::move(attribute));
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
} }
@ -1083,7 +1113,7 @@ namespace Nz::ShaderLang
case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break; case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break;
default: default:
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file } }; throw ParserUnexpectedTokenError{ TokenLocation(token) };
} }
Consume(); Consume();
@ -1107,7 +1137,7 @@ namespace Nz::ShaderLang
return ShaderBuilder::DeclareVariable(std::move(variableName), std::move(variableType), std::move(expression)); return ShaderBuilder::DeclareVariable(std::move(variableName), std::move(variableType), std::move(expression));
} }
ShaderAst::StatementPtr Parser::ParseWhileStatement(std::vector<ShaderAst::ExprValue> attributes) ShaderAst::StatementPtr Parser::ParseWhileStatement(std::vector<Attribute> attributes)
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
@ -1123,16 +1153,16 @@ namespace Nz::ShaderLang
auto whileStatement = ShaderBuilder::While(std::move(condition), std::move(body)); auto whileStatement = ShaderBuilder::While(std::move(condition), std::move(body));
for (auto&& [attributeType, arg] : attributes) for (auto&& attribute : attributes)
{ {
switch (attributeType) switch (attribute.type)
{ {
case ShaderAst::AttributeType::Unroll: case ShaderAst::AttributeType::Unroll:
HandleUniqueStringAttribute(whileToken, attributeType, s_unrollModes, whileStatement->unroll, std::move(arg), std::make_optional(ShaderAst::LoopUnroll::Always)); HandleUniqueStringAttribute(whileStatement->unroll, std::move(attribute), s_unrollModes, std::make_optional(ShaderAst::LoopUnroll::Always));
break; break;
default: default:
throw ParserUnexpectedAttributeError{ SourceLocation{ whileToken.line, whileToken.column, whileToken.file }, attributeType }; throw ParserUnexpectedAttributeError{ attribute.sourceLocation, attribute.type };
} }
} }
@ -1146,7 +1176,7 @@ namespace Nz::ShaderLang
const Token& token = Peek(); const Token& token = Peek();
TokenType currentTokenType = token.type; TokenType currentTokenType = token.type;
if (currentTokenType == TokenType::EndOfStream) if (currentTokenType == TokenType::EndOfStream)
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
int tokenPrecedence = GetTokenPrecedence(currentTokenType); int tokenPrecedence = GetTokenPrecedence(currentTokenType);
if (tokenPrecedence < exprPrecedence) if (tokenPrecedence < exprPrecedence)
@ -1201,7 +1231,7 @@ namespace Nz::ShaderLang
case TokenType::NotEqual: return BuildBinary(ShaderAst::BinaryType::CompNe, std::move(lhs), std::move(rhs)); case TokenType::NotEqual: return BuildBinary(ShaderAst::BinaryType::CompNe, std::move(lhs), std::move(rhs));
case TokenType::Plus: return BuildBinary(ShaderAst::BinaryType::Add, std::move(lhs), std::move(rhs)); case TokenType::Plus: return BuildBinary(ShaderAst::BinaryType::Add, std::move(lhs), std::move(rhs));
default: default:
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
} }
}(); }();
} }
@ -1335,7 +1365,7 @@ namespace Nz::ShaderLang
return ParseStringExpression(); return ParseStringExpression();
default: default:
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type }; throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
} }
} }
@ -1345,20 +1375,6 @@ namespace Nz::ShaderLang
return ShaderBuilder::Constant(std::get<std::string>(litteralToken.data)); return ShaderBuilder::Constant(std::get<std::string>(litteralToken.data));
} }
ShaderAst::AttributeType Parser::ParseIdentifierAsAttributeType()
{
NAZARA_USE_ANONYMOUS_NAMESPACE
const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
const std::string& identifier = std::get<std::string>(identifierToken.data);
auto it = s_identifierToAttributeType.find(identifier);
if (it == s_identifierToAttributeType.end())
throw ParserUnknownAttributeError{ SourceLocation{ identifierToken.line, identifierToken.column, identifierToken.file } };
return it->second;
}
const std::string& Parser::ParseIdentifierAsName() const std::string& Parser::ParseIdentifierAsName()
{ {
const Token& identifierToken = Expect(Advance(), TokenType::Identifier); const Token& identifierToken = Expect(Advance(), TokenType::Identifier);