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/Ast/AstExpressionVisitor.hpp>
#include <Nazara/Shader/Ast/AstStatementVisitor.hpp>
#include <Nazara/Shader/Ast/Attribute.hpp>
#include <Nazara/Shader/Ast/ExpressionValue.hpp>
#include <vector>
namespace Nz::ShaderAst

View File

@ -10,7 +10,7 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.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 <vector>

View File

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

View File

@ -4,13 +4,11 @@
#pragma once
#ifndef NAZARA_SHADER_AST_ATTRIBUTE_HPP
#define NAZARA_SHADER_AST_ATTRIBUTE_HPP
#ifndef NAZARA_SHADER_AST_EXPRESSIONVALUE_HPP
#define NAZARA_SHADER_AST_EXPRESSIONVALUE_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Ast/Enums.hpp>
#include <memory>
#include <optional>
#include <variant>
namespace Nz::ShaderAst
@ -47,16 +45,8 @@ namespace Nz::ShaderAst
private:
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"
// 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 <stdexcept>
#include <Nazara/Shader/Debug.hpp>

View File

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

View File

@ -59,55 +59,73 @@ namespace Nz::ShaderLang
{ "never", ShaderAst::LoopUnroll::Never }
};
template<typename T>
void HandleUniqueAttribute(const Token& token, ShaderAst::AttributeType attributeType, ShaderAst::ExpressionValue<T>& targetAttribute, ShaderAst::ExprValue::Param&& param)
SourceLocation TokenLocation(const Token& token)
{
if (targetAttribute.HasValue())
throw ParserAttributeMultipleUniqueError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes
SourceLocation sourceLoc;
sourceLoc.file = token.file;
sourceLoc.startColumn = sourceLoc.endColumn = token.column;
sourceLoc.startLine = sourceLoc.endLine = token.line;
if (param)
targetAttribute = std::move(*param);
else
throw ParserAttributeMissingParameterError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes
return sourceLoc;
}
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>
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())
throw ParserAttributeMultipleUniqueError{ SourceLocation{ token.line, token.column, token.file }, attributeType }; //< TODO: Improve source location for attributes
throw ParserAttributeMultipleUniqueError{ attribute.sourceLocation, attribute.type };
if (param)
targetAttribute = std::move(*param);
if (!attribute.args)
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
targetAttribute = std::move(defaultValue);
}
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())
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
if (param)
if (attribute.args)
{
const ShaderAst::ExpressionPtr& expr = *param;
if (expr->GetType() != ShaderAst::NodeType::IdentifierExpression)
throw ParserAttributeParameterIdentifierError{ SourceLocation{ token.line, token.column, token.file }, attributeType };
if (attribute.args->GetType() != ShaderAst::NodeType::IdentifierExpression)
throw ParserAttributeParameterIdentifierError{ attribute.args->sourceLocation, attribute.type };
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);
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;
}
else
{
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();
}
@ -122,7 +140,7 @@ namespace Nz::ShaderLang
m_context = &context;
std::vector<ShaderAst::ExprValue> attributes;
std::vector<Attribute> attributes;
for (;;)
{
@ -130,7 +148,7 @@ namespace Nz::ShaderLang
if (!m_context->module)
{
const Token& nextToken = Peek();
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file } };
throw ParserUnexpectedTokenError{ TokenLocation(nextToken) };
}
if (!statement)
@ -159,7 +177,7 @@ namespace Nz::ShaderLang
const Token& Parser::Expect(const Token& token, TokenType 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;
}
@ -167,7 +185,7 @@ namespace Nz::ShaderLang
const Token& Parser::ExpectNot(const Token& token, TokenType type)
{
if (token.type == type)
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, type };
throw ParserUnexpectedTokenError{ TokenLocation(token), type };
return token;
}
@ -186,9 +204,9 @@ namespace Nz::ShaderLang
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);
@ -214,23 +232,34 @@ namespace Nz::ShaderLang
if (expectComma)
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)
{
Consume();
arg = ParseExpression();
Expect(Advance(), TokenType::ClosingParenthesis);
const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis);
ExtendLocationToToken(attributeLocation, closeToken);
}
expectComma = true;
attributes.push_back({
attributeType,
std::move(arg)
std::move(arg),
attributeLocation
});
}
@ -239,12 +268,12 @@ namespace Nz::ShaderLang
return attributes;
}
void Parser::ParseModuleStatement(std::vector<ShaderAst::ExprValue> attributes)
void Parser::ParseModuleStatement(std::vector<Attribute> attributes)
{
if (m_context->parsingImportedModule)
{
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);
@ -252,7 +281,7 @@ namespace Nz::ShaderLang
std::optional<UInt32> moduleVersion;
std::optional<Uuid> moduleId;
for (auto&& [attributeType, arg] : attributes)
for (auto&& [attributeType, expr, location] : attributes)
{
switch (attributeType)
{
@ -260,18 +289,17 @@ namespace Nz::ShaderLang
{
// Version parsing
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)
throw ParserAttributeMissingParameterError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; //< TODO: Improve source location for attributes
if (!expr)
throw ParserAttributeMissingParameterError{ location, attributeType };
const ShaderAst::ExpressionPtr& expr = *arg;
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);
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);
@ -279,7 +307,7 @@ namespace Nz::ShaderLang
std::smatch versionMatch;
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);
@ -299,36 +327,35 @@ namespace Nz::ShaderLang
case ShaderAst::AttributeType::Uuid:
{
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)
throw ParserAttributeMissingParameterError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType }; //< TODO: Improve source location for attributes
if (!expr)
throw ParserAttributeMissingParameterError{ location, attributeType };
const ShaderAst::ExpressionPtr& expr = *arg;
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);
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);
Uuid uuid = Uuid::FromString(uuidStr);
if (uuid.IsNull())
throw ParserInvalidUuidError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, uuidStr };
throw ParserInvalidUuidError{ location, uuidStr };
moduleId = uuid;
break;
}
default:
throw ParserUnexpectedAttributeError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file }, attributeType };
throw ParserUnexpectedAttributeError{ location, attributeType };
}
}
if (!moduleVersion.has_value())
throw ParserMissingAttributeError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file } };
throw ParserMissingAttributeError{ TokenLocation(moduleToken) };
if (!moduleId)
moduleId = Uuid::Generate();
@ -349,7 +376,7 @@ namespace Nz::ShaderLang
if (!statement)
{
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));
@ -374,7 +401,7 @@ namespace Nz::ShaderLang
Expect(Advance(), TokenType::Semicolon);
if (m_context->module)
throw ParserDuplicateModuleError{ SourceLocation{ moduleToken.line, moduleToken.column, moduleToken.file } };
throw ParserDuplicateModuleError{ TokenLocation(moduleToken) };
m_context->module = std::move(module);
}
@ -497,7 +524,7 @@ namespace Nz::ShaderLang
}
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();
}
ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<ShaderAst::ExprValue> attributes)
ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<Attribute> attributes)
{
NAZARA_USE_ANONYMOUS_NAMESPACE
@ -517,23 +544,26 @@ namespace Nz::ShaderLang
Expect(Advance(), TokenType::OpenCurlyBracket);
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;
for (auto&& [attributeType, arg] : attributes)
for (auto&& attribute : attributes)
{
switch (attributeType)
switch (attribute.type)
{
case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(externalToken, attributeType, condition, std::move(arg));
HandleUniqueAttribute(condition, std::move(attribute));
break;
case ShaderAst::AttributeType::Set:
HandleUniqueAttribute(externalToken, attributeType, externalStatement->bindingSet, std::move(arg));
HandleUniqueAttribute(externalStatement->bindingSet, std::move(attribute));
break;
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)
{
for (auto&& [attributeType, arg] : ParseAttributes())
for (auto&& attribute : ParseAttributes())
{
switch (attributeType)
switch (attribute.type)
{
case ShaderAst::AttributeType::Binding:
HandleUniqueAttribute(externalToken, attributeType, extVar.bindingIndex, std::move(arg));
HandleUniqueAttribute(extVar.bindingIndex, std::move(attribute));
break;
case ShaderAst::AttributeType::Set:
HandleUniqueAttribute(externalToken, attributeType, extVar.bindingSet, std::move(arg));
HandleUniqueAttribute(extVar.bindingSet, std::move(attribute));
break;
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;
}
ShaderAst::StatementPtr Parser::ParseForDeclaration(std::vector<ShaderAst::ExprValue> attributes)
ShaderAst::StatementPtr Parser::ParseForDeclaration(std::vector<Attribute> attributes)
{
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));
// TODO: Deduplicate code
for (auto&& [attributeType, arg] : attributes)
for (auto&& attribute : attributes)
{
switch (attributeType)
switch (attribute.type)
{
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;
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));
// TODO: Deduplicate code
for (auto&& [attributeType, arg] : attributes)
for (auto&& attribute : attributes)
{
switch (attributeType)
switch (attribute.type)
{
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;
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();
}
ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector<ShaderAst::ExprValue> attributes)
ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector<Attribute> attributes)
{
NAZARA_USE_ANONYMOUS_NAMESPACE
@ -712,32 +742,32 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionValue<bool> condition;
for (auto&& [attributeType, attributeParam] : attributes)
for (auto&& attribute : attributes)
{
switch (attributeType)
switch (attribute.type)
{
case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(funcToken, attributeType, condition, std::move(attributeParam));
HandleUniqueAttribute(condition, std::move(attribute));
break;
case ShaderAst::AttributeType::Entry:
HandleUniqueStringAttribute(funcToken, attributeType, s_entryPoints, func->entryStage, std::move(attributeParam));
HandleUniqueStringAttribute(func->entryStage, std::move(attribute), s_entryPoints);
break;
case ShaderAst::AttributeType::Export:
HandleUniqueAttribute(funcToken, attributeType, func->isExported, std::move(attributeParam), true);
HandleUniqueAttribute(func->isExported, std::move(attribute), true);
break;
case ShaderAst::AttributeType::DepthWrite:
HandleUniqueStringAttribute(funcToken, attributeType, s_depthWriteModes, func->depthWrite, std::move(attributeParam));
HandleUniqueStringAttribute(func->depthWrite, std::move(attribute), s_depthWriteModes);
break;
case ShaderAst::AttributeType::EarlyFragmentTests:
HandleUniqueAttribute(funcToken, attributeType, func->earlyFragmentTests, std::move(attributeParam), true);
HandleUniqueAttribute(func->earlyFragmentTests, std::move(attribute));
break;
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));
}
ShaderAst::StatementPtr Parser::ParseRootStatement(std::vector<ShaderAst::ExprValue> attributes)
ShaderAst::StatementPtr Parser::ParseRootStatement(std::vector<Attribute> attributes)
{
const Token& nextToken = Peek();
switch (nextToken.type)
{
case TokenType::Alias:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type };
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseAliasDeclaration();
case TokenType::Const:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type };
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseConstStatement();
case TokenType::EndOfStream:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type };
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return {};
@ -835,7 +865,7 @@ namespace Nz::ShaderLang
case TokenType::Import:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type };
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseImportStatement();
@ -850,7 +880,7 @@ namespace Nz::ShaderLang
case TokenType::Option:
{
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type };
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
return ParseOptionDeclaration();
}
@ -862,13 +892,13 @@ namespace Nz::ShaderLang
return ParseStructDeclaration(std::move(attributes));
default:
throw ParserUnexpectedTokenError{ SourceLocation{ nextToken.line, nextToken.column, nextToken.file }, nextToken.type };
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type };
}
}
ShaderAst::StatementPtr Parser::ParseSingleStatement()
{
std::vector<ShaderAst::ExprValue> attributes;
std::vector<Attribute> attributes;
ShaderAst::StatementPtr statement;
do
{
@ -877,14 +907,14 @@ namespace Nz::ShaderLang
{
case TokenType::Const:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type };
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseConstStatement();
break;
case TokenType::Discard:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type };
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseDiscardStatement();
break;
@ -896,14 +926,14 @@ namespace Nz::ShaderLang
case TokenType::Let:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type };
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseVariableDeclaration();
break;
case TokenType::Identifier:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type };
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ShaderBuilder::ExpressionStatement(ParseVariableAssignation());
Expect(Advance(), TokenType::Semicolon);
@ -911,7 +941,7 @@ namespace Nz::ShaderLang
case TokenType::If:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type };
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseBranchStatement();
break;
@ -923,7 +953,7 @@ namespace Nz::ShaderLang
case TokenType::Return:
if (!attributes.empty())
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file }, token.type };
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type };
statement = ParseReturnStatement();
break;
@ -934,7 +964,7 @@ namespace Nz::ShaderLang
break;
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
@ -965,7 +995,7 @@ namespace Nz::ShaderLang
return statements;
}
ShaderAst::StatementPtr Parser::ParseStructDeclaration(std::vector<ShaderAst::ExprValue> attributes)
ShaderAst::StatementPtr Parser::ParseStructDeclaration(std::vector<Attribute> attributes)
{
NAZARA_USE_ANONYMOUS_NAMESPACE
@ -977,24 +1007,24 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionValue<bool> condition;
ShaderAst::ExpressionValue<bool> exported;
for (auto&& [attributeType, attributeParam] : attributes)
for (auto&& attribute : attributes)
{
switch (attributeType)
switch (attribute.type)
{
case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(structToken, attributeType, condition, std::move(attributeParam));
HandleUniqueAttribute(condition, std::move(attribute));
break;
case ShaderAst::AttributeType::Export:
HandleUniqueAttribute(structToken, attributeType, exported, std::move(attributeParam), true);
HandleUniqueAttribute(exported, std::move(attribute), true);
break;
case ShaderAst::AttributeType::Layout:
HandleUniqueStringAttribute(structToken, attributeType, s_layoutMapping, description.layout, std::move(attributeParam));
HandleUniqueStringAttribute(description.layout, std::move(attribute), s_layoutMapping);
break;
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)
{
for (auto&& [attributeType, arg] : ParseAttributes())
for (auto&& attribute : ParseAttributes())
{
switch (attributeType)
switch (attribute.type)
{
case ShaderAst::AttributeType::Builtin:
HandleUniqueStringAttribute(token, attributeType, s_builtinMapping, structField.builtin, std::move(arg));
HandleUniqueStringAttribute(structField.builtin, std::move(attribute), s_builtinMapping);
break;
case ShaderAst::AttributeType::Cond:
HandleUniqueAttribute(token, attributeType, structField.cond, std::move(arg));
HandleUniqueAttribute(structField.cond, std::move(attribute));
break;
case ShaderAst::AttributeType::Location:
HandleUniqueAttribute(token, attributeType, structField.locationIndex, std::move(arg));
HandleUniqueAttribute(structField.locationIndex, std::move(attribute));
break;
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;
default:
throw ParserUnexpectedTokenError{ SourceLocation{ token.line, token.column, token.file } };
throw ParserUnexpectedTokenError{ TokenLocation(token) };
}
Consume();
@ -1107,7 +1137,7 @@ namespace Nz::ShaderLang
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
@ -1123,16 +1153,16 @@ namespace Nz::ShaderLang
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:
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;
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();
TokenType currentTokenType = token.type;
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);
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::Plus: return BuildBinary(ShaderAst::BinaryType::Add, std::move(lhs), std::move(rhs));
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();
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));
}
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 Token& identifierToken = Expect(Advance(), TokenType::Identifier);