Shader/Parser: Fix handling of . in rvalues + add support for swizzling

For example: var.field was okay but texture.Sample(uv).x wasn't
This commit is contained in:
Jérôme Leclercq
2021-05-05 12:05:46 +02:00
parent eb67990b7b
commit 7d4a084a62
2 changed files with 95 additions and 43 deletions

View File

@@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Shader/ShaderLangParser.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <cassert>
#include <Nazara/Shader/Debug.hpp>
@@ -696,7 +697,7 @@ namespace Nz::ShaderLang
}
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
{
{
ShaderAst::ExpressionPtr left = ParseExpression();
Expect(Advance(), TokenType::Assign);
@@ -740,6 +741,36 @@ namespace Nz::ShaderLang
int tokenPrecedence = GetTokenPrecedence(currentOp.type);
if (tokenPrecedence < exprPrecedence)
return lhs;
if (currentOp.type == TokenType::Dot)
{
std::unique_ptr<ShaderAst::AccessMemberIdentifierExpression> accessMemberNode = std::make_unique<ShaderAst::AccessMemberIdentifierExpression>();
accessMemberNode->structExpr = std::move(lhs);
do
{
Consume();
accessMemberNode->memberIdentifiers.push_back(ParseIdentifierAsName());
}
while (Peek().type == TokenType::Dot);
// FIXME
if (!accessMemberNode->memberIdentifiers.empty() && accessMemberNode->memberIdentifiers.front() == "Sample")
{
if (Peek().type == TokenType::OpenParenthesis)
{
auto parameters = ParseParameters();
parameters.insert(parameters.begin(), std::move(accessMemberNode->structExpr));
lhs = ShaderBuilder::Intrinsic(ShaderAst::IntrinsicType::SampleTexture, std::move(parameters));
continue;
}
}
lhs = std::move(accessMemberNode);
continue;
}
Consume();
ShaderAst::ExpressionPtr rhs = ParsePrimaryExpression();
@@ -780,25 +811,8 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr Parser::ParseIdentifier()
{
const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
const std::string& identifier = std::get<std::string>(identifierToken.data);
ShaderAst::ExpressionPtr identifierExpr = ShaderBuilder::Identifier(identifier);
if (Peek().type == TokenType::Dot)
{
std::unique_ptr<ShaderAst::AccessMemberIdentifierExpression> accessMemberNode = std::make_unique<ShaderAst::AccessMemberIdentifierExpression>();
accessMemberNode->structExpr = std::move(identifierExpr);
do
{
Consume();
accessMemberNode->memberIdentifiers.push_back(ParseIdentifierAsName());
} while (Peek().type == TokenType::Dot);
identifierExpr = std::move(accessMemberNode);
}
const std::string& identifier = std::get<std::string>(identifierToken.data);
return ShaderBuilder::Identifier(identifier);
}
@@ -866,25 +880,7 @@ namespace Nz::ShaderLang
}
}
if (IsVariableInScope(identifier))
{
auto node = ParseIdentifier();
if (node->GetType() == ShaderAst::NodeType::AccessMemberIdentifierExpression)
{
ShaderAst::AccessMemberIdentifierExpression* memberExpr = static_cast<ShaderAst::AccessMemberIdentifierExpression*>(node.get());
if (!memberExpr->memberIdentifiers.empty() && memberExpr->memberIdentifiers.front() == "Sample")
{
if (Peek().type == TokenType::OpenParenthesis)
{
auto parameters = ParseParameters();
parameters.insert(parameters.begin(), std::move(memberExpr->structExpr));
return ShaderBuilder::Intrinsic(ShaderAst::IntrinsicType::SampleTexture, std::move(parameters));
}
}
}
return node;
if (IsVariableInScope(identifier))
return ParseIdentifier();
Consume();
@@ -1001,10 +997,11 @@ namespace Nz::ShaderLang
int Parser::GetTokenPrecedence(TokenType token)
{
switch (token)
{
case TokenType::Plus: return 20;
{
case TokenType::Plus: return 20;
case TokenType::Divide: return 40;
case TokenType::Multiply: return 40;
case TokenType::Multiply: return 40;
case TokenType::Minus: return 20;
case TokenType::Dot: return 50;
default: return -1;
}