Shader: Fill SourceLocation info to AST when parsing

This commit is contained in:
SirLynix 2022-03-28 18:24:51 +02:00 committed by Jérôme Leclercq
parent 8429411755
commit 78f4751967
10 changed files with 339 additions and 173 deletions

View File

@ -198,7 +198,7 @@ namespace Nz::ShaderBuilder
{ {
inline ShaderAst::WhileStatementPtr operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr body) const; inline ShaderAst::WhileStatementPtr operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr body) const;
}; };
} }
constexpr Impl::AccessIndex AccessIndex; constexpr Impl::AccessIndex AccessIndex;
constexpr Impl::AccessMember AccessMember; constexpr Impl::AccessMember AccessMember;

View File

@ -315,6 +315,7 @@ namespace Nz::ShaderBuilder
inline ShaderAst::ExpressionStatementPtr Impl::ExpressionStatement::operator()(ShaderAst::ExpressionPtr expression) const inline ShaderAst::ExpressionStatementPtr Impl::ExpressionStatement::operator()(ShaderAst::ExpressionPtr expression) const
{ {
auto expressionStatementNode = std::make_unique<ShaderAst::ExpressionStatement>(); auto expressionStatementNode = std::make_unique<ShaderAst::ExpressionStatement>();
expressionStatementNode->sourceLocation = expression->sourceLocation;
expressionStatementNode->expression = std::move(expression); expressionStatementNode->expression = std::move(expression);
return expressionStatementNode; return expressionStatementNode;
@ -421,6 +422,7 @@ namespace Nz::ShaderBuilder
inline ShaderAst::ScopedStatementPtr Impl::Scoped::operator()(ShaderAst::StatementPtr statement) const inline ShaderAst::ScopedStatementPtr Impl::Scoped::operator()(ShaderAst::StatementPtr statement) const
{ {
auto scopedNode = std::make_unique<ShaderAst::ScopedStatement>(); auto scopedNode = std::make_unique<ShaderAst::ScopedStatement>();
scopedNode->sourceLocation = statement->sourceLocation;
scopedNode->statement = std::move(statement); scopedNode->statement = std::move(statement);
return scopedNode; return scopedNode;

View File

@ -34,7 +34,7 @@ namespace Nz::ShaderLang
public: public:
inline Error(SourceLocation sourceLocation, ErrorCategory errorCategory, unsigned int errorType) noexcept; inline Error(SourceLocation sourceLocation, ErrorCategory errorCategory, unsigned int errorType) noexcept;
Error(const Error&) = delete; Error(const Error&) = delete;
Error(Error&&) = delete; Error(Error&&) noexcept = default;
~Error() = default; ~Error() = default;
inline ErrorCategory GetErrorCategory() const; inline ErrorCategory GetErrorCategory() const;
@ -45,7 +45,7 @@ namespace Nz::ShaderLang
const char* what() const noexcept override; const char* what() const noexcept override;
Error& operator=(const Error&) = delete; Error& operator=(const Error&) = delete;
Error& operator=(Error&&) = delete; Error& operator=(Error&&) noexcept = default;
protected: protected:
virtual std::string BuildErrorMessage() const = 0; virtual std::string BuildErrorMessage() const = 0;
@ -82,7 +82,7 @@ namespace Nz::ShaderLang
}; };
#define NAZARA_SHADERLANG_NEWERRORTYPE(Prefix, BaseClass, ErrorType, ErrorName, ErrorString, ...) \ #define NAZARA_SHADERLANG_NEWERRORTYPE(Prefix, BaseClass, ErrorType, ErrorName, ErrorString, ...) \
class Prefix ## ErrorName ## Error : public BaseClass \ class Prefix ## ErrorName ## Error final : public BaseClass \
{ \ { \
public: \ public: \
template<typename... Args> Prefix ## ErrorName ## Error(SourceLocation sourceLocation, Args&&... args) : \ template<typename... Args> Prefix ## ErrorName ## Error(SourceLocation sourceLocation, Args&&... args) : \

View File

@ -9,6 +9,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 <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
@ -26,10 +27,8 @@ namespace Nz::ShaderLang
struct Token struct Token
{ {
unsigned int column; SourceLocation location;
unsigned int line;
TokenType type; TokenType type;
std::shared_ptr<const std::string> file;
std::variant<double, long long, std::string> data; std::variant<double, long long, std::string> data;
}; };

View File

@ -25,6 +25,13 @@ namespace Nz::ShaderLang
ShaderAst::ModulePtr Parse(const std::vector<Token>& tokens); ShaderAst::ModulePtr Parse(const std::vector<Token>& tokens);
private: private:
struct Attribute
{
ShaderAst::AttributeType type;
ShaderAst::ExpressionPtr args;
SourceLocation sourceLocation;
};
// Flow control // Flow control
const Token& Advance(); const Token& Advance();
void Consume(std::size_t count = 1); void Consume(std::size_t count = 1);
@ -33,9 +40,9 @@ namespace Nz::ShaderLang
const Token& Expect(TokenType type); const Token& Expect(TokenType type);
const Token& Peek(std::size_t advance = 0); const Token& Peek(std::size_t advance = 0);
std::vector<ShaderAst::ExprValue> ParseAttributes(); std::vector<Attribute> ParseAttributes();
void ParseModuleStatement(std::vector<ShaderAst::ExprValue> attributes); void ParseModuleStatement(std::vector<Attribute> attributes);
void ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue<ShaderAst::ExpressionType>& type, ShaderAst::ExpressionPtr& initialValue); void ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue<ShaderAst::ExpressionType>& type, ShaderAst::ExpressionPtr& initialValue, SourceLocation& sourceLocation);
ShaderAst::ExpressionPtr BuildIdentifierAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs); ShaderAst::ExpressionPtr BuildIdentifierAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs);
ShaderAst::ExpressionPtr BuildIndexAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs); ShaderAst::ExpressionPtr BuildIndexAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs);
@ -46,27 +53,26 @@ namespace Nz::ShaderLang
ShaderAst::StatementPtr ParseBranchStatement(); ShaderAst::StatementPtr ParseBranchStatement();
ShaderAst::StatementPtr ParseConstStatement(); ShaderAst::StatementPtr ParseConstStatement();
ShaderAst::StatementPtr ParseDiscardStatement(); ShaderAst::StatementPtr ParseDiscardStatement();
ShaderAst::StatementPtr ParseExternalBlock(std::vector<ShaderAst::ExprValue> attributes = {}); ShaderAst::StatementPtr ParseExternalBlock(std::vector<Attribute> attributes = {});
ShaderAst::StatementPtr ParseForDeclaration(std::vector<ShaderAst::ExprValue> attributes = {}); ShaderAst::StatementPtr ParseForDeclaration(std::vector<Attribute> attributes = {});
std::vector<ShaderAst::StatementPtr> ParseFunctionBody(); ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector<Attribute> attributes = {});
ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector<ShaderAst::ExprValue> attributes = {});
ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter(); ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter();
ShaderAst::StatementPtr ParseImportStatement(); ShaderAst::StatementPtr ParseImportStatement();
ShaderAst::StatementPtr ParseOptionDeclaration(); ShaderAst::StatementPtr ParseOptionDeclaration();
ShaderAst::StatementPtr ParseReturnStatement(); ShaderAst::StatementPtr ParseReturnStatement();
ShaderAst::StatementPtr ParseRootStatement(std::vector<ShaderAst::ExprValue> attributes = {}); ShaderAst::StatementPtr ParseRootStatement(std::vector<Attribute> attributes = {});
ShaderAst::StatementPtr ParseSingleStatement(); ShaderAst::StatementPtr ParseSingleStatement();
ShaderAst::StatementPtr ParseStatement(); ShaderAst::StatementPtr ParseStatement();
std::vector<ShaderAst::StatementPtr> ParseStatementList(); std::vector<ShaderAst::StatementPtr> ParseStatementList(SourceLocation* sourceLocation);
ShaderAst::StatementPtr ParseStructDeclaration(std::vector<ShaderAst::ExprValue> attributes = {}); ShaderAst::StatementPtr ParseStructDeclaration(std::vector<Attribute> attributes = {});
ShaderAst::StatementPtr ParseVariableDeclaration(); ShaderAst::StatementPtr ParseVariableDeclaration();
ShaderAst::StatementPtr ParseWhileStatement(std::vector<ShaderAst::ExprValue> attributes); ShaderAst::StatementPtr ParseWhileStatement(std::vector<Attribute> attributes);
// Expressions // Expressions
ShaderAst::ExpressionPtr ParseBinOpRhs(int exprPrecedence, ShaderAst::ExpressionPtr lhs); ShaderAst::ExpressionPtr ParseBinOpRhs(int exprPrecedence, ShaderAst::ExpressionPtr lhs);
ShaderAst::ExpressionPtr ParseConstSelectExpression(); ShaderAst::ExpressionPtr ParseConstSelectExpression();
ShaderAst::ExpressionPtr ParseExpression(); ShaderAst::ExpressionPtr ParseExpression();
std::vector<ShaderAst::ExpressionPtr> ParseExpressionList(TokenType terminationToken); std::vector<ShaderAst::ExpressionPtr> ParseExpressionList(TokenType terminationToken, SourceLocation* terminationLocation);
ShaderAst::ExpressionPtr ParseFloatingPointExpression(); ShaderAst::ExpressionPtr ParseFloatingPointExpression();
ShaderAst::ExpressionPtr ParseIdentifier(); ShaderAst::ExpressionPtr ParseIdentifier();
ShaderAst::ExpressionPtr ParseIntegerExpression(); ShaderAst::ExpressionPtr ParseIntegerExpression();
@ -75,8 +81,7 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr ParseStringExpression(); ShaderAst::ExpressionPtr ParseStringExpression();
ShaderAst::ExpressionPtr ParseVariableAssignation(); ShaderAst::ExpressionPtr ParseVariableAssignation();
ShaderAst::AttributeType ParseIdentifierAsAttributeType(); const std::string& ParseIdentifierAsName(SourceLocation* sourceLocation);
const std::string& ParseIdentifierAsName();
std::string ParseModuleName(); std::string ParseModuleName();
ShaderAst::ExpressionPtr ParseType(); ShaderAst::ExpressionPtr ParseType();

View File

@ -21,8 +21,13 @@ namespace Nz::ShaderLang
inline SourceLocation(unsigned int line, unsigned int startColumn, unsigned int endColumn, std::shared_ptr<const std::string> file); inline SourceLocation(unsigned int line, unsigned int startColumn, unsigned int endColumn, std::shared_ptr<const std::string> file);
inline SourceLocation(unsigned int startLine, unsigned int endLine, unsigned int startColumn, unsigned int endColumn, std::shared_ptr<const std::string> file); inline SourceLocation(unsigned int startLine, unsigned int endLine, unsigned int startColumn, unsigned int endColumn, std::shared_ptr<const std::string> file);
inline void ExtendToLeft(const SourceLocation& leftLocation);
inline void ExtendToRight(const SourceLocation& rightLocation);
inline bool IsValid() const; inline bool IsValid() const;
static inline SourceLocation BuildFromTo(const SourceLocation& leftSource, const SourceLocation& rightSource);
std::shared_ptr<const std::string> file; //< Since the same file will be used for every node, prevent holding X time the same path std::shared_ptr<const std::string> file; //< Since the same file will be used for every node, prevent holding X time the same path
UInt32 endColumn; UInt32 endColumn;
UInt32 endLine; UInt32 endLine;

View File

@ -3,6 +3,7 @@
// 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/ShaderLangSourceLocation.hpp> #include <Nazara/Shader/ShaderLangSourceLocation.hpp>
#include <cassert>
#include <Nazara/Shader/Debug.hpp> #include <Nazara/Shader/Debug.hpp>
namespace Nz::ShaderLang namespace Nz::ShaderLang
@ -42,6 +43,40 @@ namespace Nz::ShaderLang
{ {
} }
inline void SourceLocation::ExtendToLeft(const SourceLocation& leftLocation)
{
assert(file == leftLocation.file);
assert(leftLocation.startLine <= endLine);
startLine = leftLocation.startLine;
assert(leftLocation.startLine < endLine || leftLocation.startColumn <= endColumn);
startColumn = leftLocation.startColumn;
}
inline void SourceLocation::ExtendToRight(const SourceLocation& rightLocation)
{
assert(file == rightLocation.file);
assert(rightLocation.endLine >= startLine);
endLine = rightLocation.endLine;
assert(rightLocation.endLine > startLine || rightLocation.endColumn >= startColumn);
endColumn = endColumn;
}
inline SourceLocation SourceLocation::BuildFromTo(const SourceLocation& leftSource, const SourceLocation& rightSource)
{
assert(leftSource.file == rightSource.file);
assert(leftSource.startLine <= rightSource.endLine);
assert(leftSource.startLine < rightSource.endLine || leftSource.startColumn <= rightSource.endColumn);
SourceLocation sourceLoc;
sourceLoc.file = leftSource.file;
sourceLoc.startLine = leftSource.startLine;
sourceLoc.startColumn = leftSource.startColumn;
sourceLoc.endLine = rightSource.endLine;
sourceLoc.endColumn = rightSource.endColumn;
return sourceLoc;
}
inline bool SourceLocation::IsValid() const inline bool SourceLocation::IsValid() const
{ {
return startLine != 0 && endLine != 0 && endColumn != 0 && startColumn != 0; return startLine != 0 && endLine != 0 && endColumn != 0 && startColumn != 0;

View File

@ -460,7 +460,7 @@ namespace Nz::ShaderAst
if (newString) if (newString)
{ {
Value(const_cast<std::string&>(*val)); //< won't be used for writing Value(const_cast<std::string&>(*val)); //< won't be used for writing
m_stringIndices.emplace(*val, m_stringIndices.size()); m_stringIndices.emplace(*val, SafeCast<UInt32>(m_stringIndices.size()));
} }
else else
Value(it->second); //< string index Value(it->second); //< string index

View File

@ -91,9 +91,9 @@ namespace Nz::ShaderLang
char c = Peek(0); char c = Peek(0);
Token token; Token token;
token.column = static_cast<unsigned int>(currentPos - lastLineFeed); token.location.startColumn = static_cast<unsigned int>(currentPos - lastLineFeed);
token.file = currentFile; token.location.startLine = lineNumber;
token.line = lineNumber; token.location.file = currentFile;
if (c == '\0') if (c == '\0')
{ {
@ -223,6 +223,8 @@ namespace Nz::ShaderLang
currentPos++; currentPos++;
} }
token.location.endColumn = static_cast<unsigned int>(currentPos - lastLineFeed);
if (floatingPoint) if (floatingPoint)
{ {
tokenType = TokenType::FloatingPointValue; tokenType = TokenType::FloatingPointValue;
@ -234,10 +236,7 @@ namespace Nz::ShaderLang
char* end; char* end;
double value = std::strtod(ptr, &end); double value = std::strtod(ptr, &end);
if (end != &ptr[valueStr.size()]) if (end != &ptr[valueStr.size()])
{ throw LexerBadNumberError{ token.location };
unsigned int columnOffset = SafeCast<unsigned int>(end - ptr);
throw LexerBadNumberError{ SourceLocation{ token.line, token.column + columnOffset, token.file } };
}
token.data = value; token.data = value;
} }
@ -249,11 +248,10 @@ namespace Nz::ShaderLang
std::from_chars_result r = std::from_chars(&str[start], &str[currentPos + 1], value); std::from_chars_result r = std::from_chars(&str[start], &str[currentPos + 1], value);
if (r.ptr != &str[currentPos + 1]) if (r.ptr != &str[currentPos + 1])
{ {
unsigned int columnOffset = SafeCast<unsigned int>(r.ptr - &str[start]);
if (r.ec == std::errc::result_out_of_range) if (r.ec == std::errc::result_out_of_range)
throw LexerNumberOutOfRangeError{ SourceLocation{ token.line, token.column, token.column + columnOffset, token.file } }; throw LexerNumberOutOfRangeError{ token.location };
throw LexerBadNumberError{ SourceLocation{ token.line, token.column, token.column + columnOffset, token.file } }; throw LexerBadNumberError{ token.location };
} }
token.data = value; token.data = value;
@ -292,7 +290,7 @@ namespace Nz::ShaderLang
tokenType = TokenType::LogicalOr; tokenType = TokenType::LogicalOr;
} }
else else
throw LexerUnrecognizedTokenError{ SourceLocation{ token.line, token.column, token.file } }; //< TODO: Add BOR (a | b) throw LexerUnrecognizedTokenError{ token.location }; //< TODO: Add BOR (a | b)
break; break;
} }
@ -313,7 +311,7 @@ namespace Nz::ShaderLang
tokenType = TokenType::LogicalAnd; tokenType = TokenType::LogicalAnd;
} }
else else
throw LexerUnrecognizedTokenError{ SourceLocation{ token.line, token.column, token.file } }; //< TODO: Add BAND (a & b) throw LexerUnrecognizedTokenError{ token.location }; //< TODO: Add BAND (a & b)
break; break;
} }
@ -415,7 +413,8 @@ namespace Nz::ShaderLang
case '\0': case '\0':
case '\n': case '\n':
case '\r': case '\r':
throw LexerUnfinishedStringError{ SourceLocation{ token.line, SafeCast<unsigned int>(currentPos - lastLineFeed), token.file } }; token.location.endColumn = static_cast<unsigned int>(currentPos - lastLineFeed);
throw LexerUnfinishedStringError{ token.location };
case '\\': case '\\':
{ {
@ -429,7 +428,8 @@ namespace Nz::ShaderLang
case '"': character = '"'; break; case '"': character = '"'; break;
case '\\': character = '\\'; break; case '\\': character = '\\'; break;
default: default:
throw LexerUnrecognizedCharError{ SourceLocation{ token.line, SafeCast<unsigned int>(currentPos - lastLineFeed), token.file } }; token.location.endColumn = static_cast<unsigned int>(currentPos - lastLineFeed);
throw LexerUnrecognizedCharError{ token.location };
} }
break; break;
} }
@ -469,12 +469,14 @@ namespace Nz::ShaderLang
break; break;
} }
else else
throw LexerUnrecognizedTokenError{ SourceLocation{ token.line, token.column, token.file } }; throw LexerUnrecognizedTokenError{ token.location };
} }
} }
if (tokenType) if (tokenType)
{ {
token.location.endColumn = static_cast<unsigned int>(currentPos - lastLineFeed);
token.location.endLine = lineNumber;
token.type = *tokenType; token.type = *tokenType;
tokens.push_back(std::move(token)); tokens.push_back(std::move(token));
@ -503,16 +505,16 @@ namespace Nz::ShaderLang
if (tokens.empty()) if (tokens.empty())
return {}; return {};
unsigned int lastLineNumber = tokens.front().line; unsigned int lastLineNumber = tokens.front().location.startLine;
std::stringstream ss; std::stringstream ss;
bool empty = true; bool empty = true;
for (const Token& token : tokens) for (const Token& token : tokens)
{ {
if (token.line != lastLineNumber && pretty) if (token.location.startLine != lastLineNumber && pretty)
{ {
lastLineNumber = token.line; lastLineNumber = token.location.startLine;
if (!empty) if (!empty)
ss << '\n'; ss << '\n';
} }
@ -534,6 +536,10 @@ namespace Nz::ShaderLang
ss << "(" << std::get<long long>(token.data) << ")"; ss << "(" << std::get<long long>(token.data) << ")";
break; break;
case TokenType::StringValue:
ss << "(\"" << std::get<std::string>(token.data) << "\")";
break;
default: default:
break; break;
} }

View File

@ -59,25 +59,6 @@ namespace Nz::ShaderLang
{ "never", ShaderAst::LoopUnroll::Never } { "never", ShaderAst::LoopUnroll::Never }
}; };
SourceLocation TokenLocation(const Token& token)
{
SourceLocation sourceLoc;
sourceLoc.file = token.file;
sourceLoc.startColumn = sourceLoc.endColumn = token.column;
sourceLoc.startLine = sourceLoc.endLine = token.line;
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> template<typename T>
void HandleUniqueAttribute(ShaderAst::ExpressionValue<T>& targetAttribute, Parser::Attribute&& attribute) void HandleUniqueAttribute(ShaderAst::ExpressionValue<T>& targetAttribute, Parser::Attribute&& attribute)
{ {
@ -148,7 +129,7 @@ namespace Nz::ShaderLang
if (!m_context->module) if (!m_context->module)
{ {
const Token& nextToken = Peek(); const Token& nextToken = Peek();
throw ParserUnexpectedTokenError{ TokenLocation(nextToken) }; throw ParserUnexpectedTokenError{ nextToken.location };
} }
if (!statement) if (!statement)
@ -177,7 +158,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{ TokenLocation(token), type, token.type }; throw ParserExpectedTokenError{ token.location, type, token.type };
return token; return token;
} }
@ -185,7 +166,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{ TokenLocation(token), type }; throw ParserUnexpectedTokenError{ token.location, type };
return token; return token;
} }
@ -235,11 +216,11 @@ namespace Nz::ShaderLang
const Token& identifierToken = Expect(Advance(), TokenType::Identifier); const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
const std::string& identifier = std::get<std::string>(identifierToken.data); const std::string& identifier = std::get<std::string>(identifierToken.data);
SourceLocation attributeLocation = TokenLocation(identifierToken); SourceLocation attributeLocation = identifierToken.location;
auto it = s_identifierToAttributeType.find(identifier); auto it = s_identifierToAttributeType.find(identifier);
if (it == s_identifierToAttributeType.end()) if (it == s_identifierToAttributeType.end())
throw ParserUnknownAttributeError{ attributeLocation }; throw ParserUnknownAttributeError{ identifierToken.location };
ShaderAst::AttributeType attributeType = it->second; ShaderAst::AttributeType attributeType = it->second;
@ -251,7 +232,7 @@ namespace Nz::ShaderLang
arg = ParseExpression(); arg = ParseExpression();
const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis); const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis);
ExtendLocationToToken(attributeLocation, closeToken); attributeLocation.ExtendToRight(closeToken.location);
} }
expectComma = true; expectComma = true;
@ -273,7 +254,7 @@ namespace Nz::ShaderLang
if (m_context->parsingImportedModule) if (m_context->parsingImportedModule)
{ {
const Token& token = Peek(); const Token& token = Peek();
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
} }
const Token& moduleToken = Expect(Advance(), TokenType::Module); const Token& moduleToken = Expect(Advance(), TokenType::Module);
@ -355,7 +336,7 @@ namespace Nz::ShaderLang
} }
if (!moduleVersion.has_value()) if (!moduleVersion.has_value())
throw ParserMissingAttributeError{ TokenLocation(moduleToken) }; throw ParserMissingAttributeError{ moduleToken.location };
if (!moduleId) if (!moduleId)
moduleId = Uuid::Generate(); moduleId = Uuid::Generate();
@ -376,7 +357,7 @@ namespace Nz::ShaderLang
if (!statement) if (!statement)
{ {
const Token& token = Peek(); const Token& token = Peek();
throw ParserUnexpectedEndOfFileError{ TokenLocation(token) }; throw ParserUnexpectedEndOfFileError{ token.location };
} }
module->rootNode->statements.push_back(std::move(statement)); module->rootNode->statements.push_back(std::move(statement));
@ -401,15 +382,15 @@ namespace Nz::ShaderLang
Expect(Advance(), TokenType::Semicolon); Expect(Advance(), TokenType::Semicolon);
if (m_context->module) if (m_context->module)
throw ParserDuplicateModuleError{ TokenLocation(moduleToken) }; throw ParserDuplicateModuleError{ moduleToken.location };
m_context->module = std::move(module); m_context->module = std::move(module);
} }
} }
void Parser::ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue<ShaderAst::ExpressionType>& type, ShaderAst::ExpressionPtr& initialValue) void Parser::ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue<ShaderAst::ExpressionType>& type, ShaderAst::ExpressionPtr& initialValue, SourceLocation& sourceLocation)
{ {
name = ParseIdentifierAsName(); name = ParseIdentifierAsName(nullptr);
if (Peek().type == TokenType::Colon) if (Peek().type == TokenType::Colon)
{ {
@ -424,40 +405,61 @@ namespace Nz::ShaderLang
initialValue = ParseExpression(); initialValue = ParseExpression();
} }
Expect(Advance(), TokenType::Semicolon); const Token& endToken = Expect(Advance(), TokenType::Semicolon);
sourceLocation.ExtendToRight(endToken.location);
} }
ShaderAst::ExpressionPtr Parser::BuildIdentifierAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs) ShaderAst::ExpressionPtr Parser::BuildIdentifierAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs)
{ {
if (rhs->GetType() == ShaderAst::NodeType::IdentifierExpression) if (rhs->GetType() == ShaderAst::NodeType::IdentifierExpression)
return ShaderBuilder::AccessMember(std::move(lhs), { std::move(SafeCast<ShaderAst::IdentifierExpression&>(*rhs).identifier) }); {
SourceLocation location = SourceLocation::BuildFromTo(lhs->sourceLocation, rhs->sourceLocation);
auto accessMemberExpr = ShaderBuilder::AccessMember(std::move(lhs), { std::move(SafeCast<ShaderAst::IdentifierExpression&>(*rhs).identifier) });
accessMemberExpr->sourceLocation = std::move(location);
return accessMemberExpr;
}
else else
return BuildIndexAccess(std::move(lhs), std::move(rhs)); return BuildIndexAccess(std::move(lhs), std::move(rhs));
} }
ShaderAst::ExpressionPtr Parser::BuildIndexAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs) ShaderAst::ExpressionPtr Parser::BuildIndexAccess(ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs)
{ {
return ShaderBuilder::AccessIndex(std::move(lhs), std::move(rhs)); SourceLocation location = SourceLocation::BuildFromTo(lhs->sourceLocation, rhs->sourceLocation);
auto accessIndexExpr = ShaderBuilder::AccessIndex(std::move(lhs), std::move(rhs));
accessIndexExpr->sourceLocation = std::move(location);
return accessIndexExpr;
} }
ShaderAst::ExpressionPtr Parser::BuildBinary(ShaderAst::BinaryType binaryType, ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs) ShaderAst::ExpressionPtr Parser::BuildBinary(ShaderAst::BinaryType binaryType, ShaderAst::ExpressionPtr lhs, ShaderAst::ExpressionPtr rhs)
{ {
return ShaderBuilder::Binary(binaryType, std::move(lhs), std::move(rhs)); SourceLocation location = SourceLocation::BuildFromTo(lhs->sourceLocation, rhs->sourceLocation);
auto accessIndexExpr = ShaderBuilder::Binary(binaryType, std::move(lhs), std::move(rhs));
accessIndexExpr->sourceLocation = std::move(location);
return accessIndexExpr;
} }
ShaderAst::StatementPtr Parser::ParseAliasDeclaration() ShaderAst::StatementPtr Parser::ParseAliasDeclaration()
{ {
Expect(Advance(), TokenType::Alias); const Token& aliasToken = Expect(Advance(), TokenType::Alias);
std::string name = ParseIdentifierAsName(); std::string name = ParseIdentifierAsName(nullptr);
Expect(Advance(), TokenType::Assign); Expect(Advance(), TokenType::Assign);
ShaderAst::ExpressionPtr expr = ParseExpression(); ShaderAst::ExpressionPtr expr = ParseExpression();
Expect(Advance(), TokenType::Semicolon); const Token& endToken = Expect(Advance(), TokenType::Semicolon);
return ShaderBuilder::DeclareAlias(std::move(name), std::move(expr)); auto aliasStatement = ShaderBuilder::DeclareAlias(std::move(name), std::move(expr));
aliasStatement->sourceLocation = SourceLocation::BuildFromTo(aliasToken.location, endToken.location);
return aliasStatement;
} }
ShaderAst::StatementPtr Parser::ParseBranchStatement() ShaderAst::StatementPtr Parser::ParseBranchStatement()
@ -470,9 +472,11 @@ namespace Nz::ShaderLang
if (!first) if (!first)
Expect(Advance(), TokenType::Else); Expect(Advance(), TokenType::Else);
first = false; const Token& ifToken = Expect(Advance(), TokenType::If);
if (first)
branch->sourceLocation = ifToken.location;
Expect(Advance(), TokenType::If); first = false;
auto& condStatement = branch->condStatements.emplace_back(); auto& condStatement = branch->condStatements.emplace_back();
@ -483,6 +487,7 @@ namespace Nz::ShaderLang
Expect(Advance(), TokenType::ClosingParenthesis); Expect(Advance(), TokenType::ClosingParenthesis);
condStatement.statement = ParseStatement(); condStatement.statement = ParseStatement();
branch->sourceLocation.ExtendToRight(condStatement.statement->sourceLocation);
if (Peek().type != TokenType::Else || Peek(1).type != TokenType::If) if (Peek().type != TokenType::Else || Peek(1).type != TokenType::If)
break; break;
@ -492,6 +497,7 @@ namespace Nz::ShaderLang
{ {
Consume(); Consume();
branch->elseStatement = ParseStatement(); branch->elseStatement = ParseStatement();
branch->sourceLocation.ExtendToRight(branch->elseStatement->sourceLocation);
} }
return branch; return branch;
@ -499,7 +505,9 @@ namespace Nz::ShaderLang
ShaderAst::StatementPtr Parser::ParseConstStatement() ShaderAst::StatementPtr Parser::ParseConstStatement()
{ {
Expect(Advance(), TokenType::Const); const Token& constToken = Expect(Advance(), TokenType::Const);
SourceLocation constLocation = constToken.location;
const Token& token = Peek(); const Token& token = Peek();
switch (token.type) switch (token.type)
@ -510,30 +518,37 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionValue<ShaderAst::ExpressionType> constType; ShaderAst::ExpressionValue<ShaderAst::ExpressionType> constType;
ShaderAst::ExpressionPtr initialValue; ShaderAst::ExpressionPtr initialValue;
ParseVariableDeclaration(constName, constType, initialValue); ParseVariableDeclaration(constName, constType, initialValue, constLocation);
return ShaderBuilder::DeclareConst(std::move(constName), std::move(constType), std::move(initialValue)); auto constDeclaration = ShaderBuilder::DeclareConst(std::move(constName), std::move(constType), std::move(initialValue));
constDeclaration->sourceLocation = std::move(constLocation);
return constDeclaration;
} }
case TokenType::If: case TokenType::If:
{ {
auto branch = ParseBranchStatement(); auto branch = ParseBranchStatement();
SafeCast<ShaderAst::BranchStatement&>(*branch).isConst = true; SafeCast<ShaderAst::BranchStatement&>(*branch).isConst = true;
branch->sourceLocation.ExtendToLeft(constLocation);
return branch; return branch;
} }
default: default:
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
} }
} }
ShaderAst::StatementPtr Parser::ParseDiscardStatement() ShaderAst::StatementPtr Parser::ParseDiscardStatement()
{ {
Expect(Advance(), TokenType::Discard); const Token& discardToken = Expect(Advance(), TokenType::Discard);
Expect(Advance(), TokenType::Semicolon); const Token& endToken = Expect(Advance(), TokenType::Semicolon);
return ShaderBuilder::Discard(); auto discardStatement = ShaderBuilder::Discard();
discardStatement->sourceLocation = SourceLocation::BuildFromTo(discardToken.location, endToken.location);
return discardStatement;
} }
ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<Attribute> attributes) ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<Attribute> attributes)
@ -544,9 +559,7 @@ 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 = externalToken.location;
externalStatement->sourceLocation.startLine = externalToken.line;
externalStatement->sourceLocation.file = externalToken.file;
ShaderAst::ExpressionValue<bool> condition; ShaderAst::ExpressionValue<bool> condition;
@ -610,9 +623,13 @@ namespace Nz::ShaderLang
} }
} }
extVar.name = ParseIdentifierAsName(); extVar.name = ParseIdentifierAsName(&extVar.sourceLocation);
Expect(Advance(), TokenType::Colon); Expect(Advance(), TokenType::Colon);
extVar.type = ParseType();
auto typeExpr = ParseType();
extVar.sourceLocation.ExtendToRight(typeExpr->sourceLocation);
extVar.type = std::move(typeExpr);
} }
Expect(Advance(), TokenType::ClosingCurlyBracket); Expect(Advance(), TokenType::ClosingCurlyBracket);
@ -629,7 +646,7 @@ namespace Nz::ShaderLang
const Token& forToken = Expect(Advance(), TokenType::For); const Token& forToken = Expect(Advance(), TokenType::For);
std::string varName = ParseIdentifierAsName(); std::string varName = ParseIdentifierAsName(nullptr);
Expect(Advance(), TokenType::In); Expect(Advance(), TokenType::In);
@ -652,6 +669,7 @@ namespace Nz::ShaderLang
ShaderAst::StatementPtr statement = ParseStatement(); ShaderAst::StatementPtr statement = ParseStatement();
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));
forNode->sourceLocation = SourceLocation::BuildFromTo(forToken.location, forNode->statement->sourceLocation);
// TODO: Deduplicate code // TODO: Deduplicate code
for (auto&& attribute : attributes) for (auto&& attribute : attributes)
@ -675,6 +693,7 @@ namespace Nz::ShaderLang
ShaderAst::StatementPtr statement = ParseStatement(); ShaderAst::StatementPtr statement = ParseStatement();
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));
forEachNode->sourceLocation = SourceLocation::BuildFromTo(forToken.location, forEachNode->statement->sourceLocation);
// TODO: Deduplicate code // TODO: Deduplicate code
for (auto&& attribute : attributes) for (auto&& attribute : attributes)
@ -694,18 +713,13 @@ namespace Nz::ShaderLang
} }
} }
std::vector<ShaderAst::StatementPtr> Parser::ParseFunctionBody()
{
return ParseStatementList();
}
ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector<Attribute> attributes) ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector<Attribute> attributes)
{ {
NAZARA_USE_ANONYMOUS_NAMESPACE NAZARA_USE_ANONYMOUS_NAMESPACE
const auto& funcToken = Expect(Advance(), TokenType::FunctionDeclaration); const auto& funcToken = Expect(Advance(), TokenType::FunctionDeclaration);
std::string functionName = ParseIdentifierAsName(); std::string functionName = ParseIdentifierAsName(nullptr);
Expect(Advance(), TokenType::OpenParenthesis); Expect(Advance(), TokenType::OpenParenthesis);
@ -736,9 +750,13 @@ namespace Nz::ShaderLang
returnType = ParseType(); returnType = ParseType();
} }
std::vector<ShaderAst::StatementPtr> functionBody = ParseFunctionBody(); SourceLocation functionLocation;
std::vector<ShaderAst::StatementPtr> functionBody = ParseStatementList(&functionLocation);
functionLocation.ExtendToLeft(funcToken.location);
auto func = ShaderBuilder::DeclareFunction(std::move(functionName), std::move(parameters), std::move(functionBody), std::move(returnType)); auto func = ShaderBuilder::DeclareFunction(std::move(functionName), std::move(parameters), std::move(functionBody), std::move(returnType));
func->sourceLocation = std::move(functionLocation);
ShaderAst::ExpressionValue<bool> condition; ShaderAst::ExpressionValue<bool> condition;
@ -781,31 +799,37 @@ namespace Nz::ShaderLang
{ {
ShaderAst::DeclareFunctionStatement::Parameter parameter; ShaderAst::DeclareFunctionStatement::Parameter parameter;
parameter.name = ParseIdentifierAsName(); parameter.name = ParseIdentifierAsName(&parameter.sourceLocation);
Expect(Advance(), TokenType::Colon); Expect(Advance(), TokenType::Colon);
parameter.type = ParseType(); auto typeExpr = ParseType();
parameter.sourceLocation.ExtendToRight(typeExpr->sourceLocation);
parameter.type = std::move(typeExpr);
return parameter; return parameter;
} }
ShaderAst::StatementPtr Parser::ParseImportStatement() ShaderAst::StatementPtr Parser::ParseImportStatement()
{ {
Expect(Advance(), TokenType::Import); const Token& importToken = Expect(Advance(), TokenType::Import);
std::string moduleName = ParseModuleName(); std::string moduleName = ParseModuleName();
Expect(Advance(), TokenType::Semicolon); const Token& endtoken = Expect(Advance(), TokenType::Semicolon);
return ShaderBuilder::Import(std::move(moduleName)); auto importStatement = ShaderBuilder::Import(std::move(moduleName));
importStatement->sourceLocation = SourceLocation::BuildFromTo(importToken.location, endtoken.location);
return importStatement;
} }
ShaderAst::StatementPtr Parser::ParseOptionDeclaration() ShaderAst::StatementPtr Parser::ParseOptionDeclaration()
{ {
Expect(Advance(), TokenType::Option); const Token& optionToken = Expect(Advance(), TokenType::Option);
std::string optionName = ParseIdentifierAsName(); std::string optionName = ParseIdentifierAsName(nullptr);
Expect(Advance(), TokenType::Colon); Expect(Advance(), TokenType::Colon);
@ -819,22 +843,28 @@ namespace Nz::ShaderLang
initialValue = ParseExpression(); initialValue = ParseExpression();
} }
Expect(Advance(), TokenType::Semicolon); const Token& endToken = Expect(Advance(), TokenType::Semicolon);
return ShaderBuilder::DeclareOption(std::move(optionName), std::move(optionType), std::move(initialValue)); auto optionDeclarationStatement = ShaderBuilder::DeclareOption(std::move(optionName), std::move(optionType), std::move(initialValue));
optionDeclarationStatement->sourceLocation = SourceLocation::BuildFromTo(optionToken.location, endToken.location);
return optionDeclarationStatement;
} }
ShaderAst::StatementPtr Parser::ParseReturnStatement() ShaderAst::StatementPtr Parser::ParseReturnStatement()
{ {
Expect(Advance(), TokenType::Return); const Token& returnToken = Expect(Advance(), TokenType::Return);
ShaderAst::ExpressionPtr expr; ShaderAst::ExpressionPtr expr;
if (Peek().type != TokenType::Semicolon) if (Peek().type != TokenType::Semicolon)
expr = ParseExpression(); expr = ParseExpression();
Expect(Advance(), TokenType::Semicolon); const Token& endToken = Expect(Advance(), TokenType::Semicolon);
return ShaderBuilder::Return(std::move(expr)); auto returnStatement = ShaderBuilder::Return(std::move(expr));
returnStatement->sourceLocation = SourceLocation::BuildFromTo(returnToken.location, endToken.location);
return returnStatement;
} }
ShaderAst::StatementPtr Parser::ParseRootStatement(std::vector<Attribute> attributes) ShaderAst::StatementPtr Parser::ParseRootStatement(std::vector<Attribute> attributes)
@ -844,19 +874,19 @@ namespace Nz::ShaderLang
{ {
case TokenType::Alias: case TokenType::Alias:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type };
return ParseAliasDeclaration(); return ParseAliasDeclaration();
case TokenType::Const: case TokenType::Const:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type };
return ParseConstStatement(); return ParseConstStatement();
case TokenType::EndOfStream: case TokenType::EndOfStream:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type };
return {}; return {};
@ -865,7 +895,7 @@ namespace Nz::ShaderLang
case TokenType::Import: case TokenType::Import:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type };
return ParseImportStatement(); return ParseImportStatement();
@ -880,7 +910,7 @@ namespace Nz::ShaderLang
case TokenType::Option: case TokenType::Option:
{ {
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type };
return ParseOptionDeclaration(); return ParseOptionDeclaration();
} }
@ -892,7 +922,7 @@ namespace Nz::ShaderLang
return ParseStructDeclaration(std::move(attributes)); return ParseStructDeclaration(std::move(attributes));
default: default:
throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type };
} }
} }
@ -907,14 +937,14 @@ namespace Nz::ShaderLang
{ {
case TokenType::Const: case TokenType::Const:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
statement = ParseConstStatement(); statement = ParseConstStatement();
break; break;
case TokenType::Discard: case TokenType::Discard:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
statement = ParseDiscardStatement(); statement = ParseDiscardStatement();
break; break;
@ -926,14 +956,14 @@ namespace Nz::ShaderLang
case TokenType::Let: case TokenType::Let:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
statement = ParseVariableDeclaration(); statement = ParseVariableDeclaration();
break; break;
case TokenType::Identifier: case TokenType::Identifier:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
statement = ShaderBuilder::ExpressionStatement(ParseVariableAssignation()); statement = ShaderBuilder::ExpressionStatement(ParseVariableAssignation());
Expect(Advance(), TokenType::Semicolon); Expect(Advance(), TokenType::Semicolon);
@ -941,7 +971,7 @@ namespace Nz::ShaderLang
case TokenType::If: case TokenType::If:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
statement = ParseBranchStatement(); statement = ParseBranchStatement();
break; break;
@ -953,7 +983,7 @@ namespace Nz::ShaderLang
case TokenType::Return: case TokenType::Return:
if (!attributes.empty()) if (!attributes.empty())
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
statement = ParseReturnStatement(); statement = ParseReturnStatement();
break; break;
@ -964,7 +994,7 @@ namespace Nz::ShaderLang
break; break;
default: default:
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
} }
} }
while (!statement); //< small trick to repeat parsing once we got attributes while (!statement); //< small trick to repeat parsing once we got attributes
@ -975,14 +1005,19 @@ namespace Nz::ShaderLang
ShaderAst::StatementPtr Parser::ParseStatement() ShaderAst::StatementPtr Parser::ParseStatement()
{ {
if (Peek().type == TokenType::OpenCurlyBracket) if (Peek().type == TokenType::OpenCurlyBracket)
return ShaderBuilder::Scoped(ShaderBuilder::MultiStatement(ParseStatementList())); {
auto multiStatement = ShaderBuilder::MultiStatement();
multiStatement->statements = ParseStatementList(&multiStatement->sourceLocation);
return ShaderBuilder::Scoped(std::move(multiStatement));
}
else else
return ParseSingleStatement(); return ParseSingleStatement();
} }
std::vector<ShaderAst::StatementPtr> Parser::ParseStatementList() std::vector<ShaderAst::StatementPtr> Parser::ParseStatementList(SourceLocation* sourceLocation)
{ {
Expect(Advance(), TokenType::OpenCurlyBracket); const Token& openToken = Expect(Advance(), TokenType::OpenCurlyBracket);
std::vector<ShaderAst::StatementPtr> statements; std::vector<ShaderAst::StatementPtr> statements;
while (Peek().type != TokenType::ClosingCurlyBracket) while (Peek().type != TokenType::ClosingCurlyBracket)
@ -990,7 +1025,10 @@ namespace Nz::ShaderLang
ExpectNot(Peek(), TokenType::EndOfStream); ExpectNot(Peek(), TokenType::EndOfStream);
statements.push_back(ParseStatement()); statements.push_back(ParseStatement());
} }
Consume(); //< Consume closing curly bracket const Token& closeToken = Expect(Advance(), TokenType::ClosingCurlyBracket);
if (sourceLocation)
*sourceLocation = SourceLocation::BuildFromTo(openToken.location, closeToken.location);
return statements; return statements;
} }
@ -1002,7 +1040,7 @@ namespace Nz::ShaderLang
const auto& structToken = Expect(Advance(), TokenType::Struct); const auto& structToken = Expect(Advance(), TokenType::Struct);
ShaderAst::StructDescription description; ShaderAst::StructDescription description;
description.name = ParseIdentifierAsName(); description.name = ParseIdentifierAsName(nullptr);
ShaderAst::ExpressionValue<bool> condition; ShaderAst::ExpressionValue<bool> condition;
ShaderAst::ExpressionValue<bool> exported; ShaderAst::ExpressionValue<bool> exported;
@ -1078,19 +1116,27 @@ namespace Nz::ShaderLang
} }
} }
structField.name = ParseIdentifierAsName(); structField.name = ParseIdentifierAsName(&structField.sourceLocation);
Expect(Advance(), TokenType::Colon); Expect(Advance(), TokenType::Colon);
structField.type = ParseType(); structField.type = ParseType();
} }
Expect(Advance(), TokenType::ClosingCurlyBracket); const Token& endToken = Expect(Advance(), TokenType::ClosingCurlyBracket);
auto structDeclStatement = ShaderBuilder::DeclareStruct(std::move(description), std::move(exported));
structDeclStatement->sourceLocation = SourceLocation::BuildFromTo(structToken.location, endToken.location);
if (condition.HasValue()) if (condition.HasValue())
return ShaderBuilder::ConditionalStatement(std::move(condition).GetExpression(), ShaderBuilder::DeclareStruct(std::move(description), std::move(exported))); {
auto condStatement = ShaderBuilder::ConditionalStatement(std::move(condition).GetExpression(), std::move(structDeclStatement));
condStatement->sourceLocation = condStatement->statement->sourceLocation;
return condStatement;
}
else else
return ShaderBuilder::DeclareStruct(std::move(description), std::move(exported)); return structDeclStatement;
} }
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation() ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
@ -1113,7 +1159,7 @@ namespace Nz::ShaderLang
case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break; case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break;
default: default:
throw ParserUnexpectedTokenError{ TokenLocation(token) }; throw ParserUnexpectedTokenError{ token.location };
} }
Consume(); Consume();
@ -1121,20 +1167,28 @@ namespace Nz::ShaderLang
// Value expression // Value expression
ShaderAst::ExpressionPtr right = ParseExpression(); ShaderAst::ExpressionPtr right = ParseExpression();
return ShaderBuilder::Assign(assignType, std::move(left), std::move(right)); auto assignExpr = ShaderBuilder::Assign(assignType, std::move(left), std::move(right));
assignExpr->sourceLocation = SourceLocation::BuildFromTo(assignExpr->left->sourceLocation, assignExpr->right->sourceLocation);
return assignExpr;
} }
ShaderAst::StatementPtr Parser::ParseVariableDeclaration() ShaderAst::StatementPtr Parser::ParseVariableDeclaration()
{ {
Expect(Advance(), TokenType::Let); const auto& letToken = Expect(Advance(), TokenType::Let);
SourceLocation letLocation = letToken.location;
std::string variableName; std::string variableName;
ShaderAst::ExpressionValue<ShaderAst::ExpressionType> variableType; ShaderAst::ExpressionValue<ShaderAst::ExpressionType> variableType;
ShaderAst::ExpressionPtr expression; ShaderAst::ExpressionPtr expression;
ParseVariableDeclaration(variableName, variableType, expression); ParseVariableDeclaration(variableName, variableType, expression, letLocation);
return ShaderBuilder::DeclareVariable(std::move(variableName), std::move(variableType), std::move(expression)); auto variableDeclStatement = ShaderBuilder::DeclareVariable(std::move(variableName), std::move(variableType), std::move(expression));
variableDeclStatement->sourceLocation = std::move(letLocation);
return variableDeclStatement;
} }
ShaderAst::StatementPtr Parser::ParseWhileStatement(std::vector<Attribute> attributes) ShaderAst::StatementPtr Parser::ParseWhileStatement(std::vector<Attribute> attributes)
@ -1152,6 +1206,7 @@ namespace Nz::ShaderLang
ShaderAst::StatementPtr body = ParseStatement(); ShaderAst::StatementPtr body = ParseStatement();
auto whileStatement = ShaderBuilder::While(std::move(condition), std::move(body)); auto whileStatement = ShaderBuilder::While(std::move(condition), std::move(body));
whileStatement->sourceLocation = SourceLocation::BuildFromTo(whileToken.location, whileStatement->body->sourceLocation);
for (auto&& attribute : attributes) for (auto&& attribute : attributes)
{ {
@ -1176,7 +1231,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{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
int tokenPrecedence = GetTokenPrecedence(currentTokenType); int tokenPrecedence = GetTokenPrecedence(currentTokenType);
if (tokenPrecedence < exprPrecedence) if (tokenPrecedence < exprPrecedence)
@ -1187,8 +1242,10 @@ namespace Nz::ShaderLang
Consume(); Consume();
// Function call // Function call
auto parameters = ParseExpressionList(TokenType::ClosingParenthesis); SourceLocation closingLocation;
auto parameters = ParseExpressionList(TokenType::ClosingParenthesis, &closingLocation);
lhs = ShaderBuilder::CallFunction(std::move(lhs), std::move(parameters)); lhs = ShaderBuilder::CallFunction(std::move(lhs), std::move(parameters));
lhs->sourceLocation = SourceLocation::BuildFromTo(token.location, closingLocation);
continue; continue;
} }
@ -1197,8 +1254,11 @@ namespace Nz::ShaderLang
Consume(); Consume();
// Indices // Indices
auto parameters = ParseExpressionList(TokenType::ClosingSquareBracket); SourceLocation closingLocation;
auto parameters = ParseExpressionList(TokenType::ClosingSquareBracket, &closingLocation);
lhs = ShaderBuilder::AccessIndex(std::move(lhs), std::move(parameters)); lhs = ShaderBuilder::AccessIndex(std::move(lhs), std::move(parameters));
lhs->sourceLocation = SourceLocation::BuildFromTo(token.location, closingLocation);
continue; continue;
} }
@ -1231,7 +1291,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{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
} }
}(); }();
} }
@ -1239,7 +1299,7 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr Parser::ParseConstSelectExpression() ShaderAst::ExpressionPtr Parser::ParseConstSelectExpression()
{ {
Expect(Advance(), TokenType::ConstSelect); const Token& constSelectToken = Expect(Advance(), TokenType::ConstSelect);
Expect(Advance(), TokenType::OpenParenthesis); Expect(Advance(), TokenType::OpenParenthesis);
ShaderAst::ExpressionPtr cond = ParseExpression(); ShaderAst::ExpressionPtr cond = ParseExpression();
@ -1252,9 +1312,12 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr falseExpr = ParseExpression(); ShaderAst::ExpressionPtr falseExpr = ParseExpression();
Expect(Advance(), TokenType::ClosingParenthesis); const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis);
return ShaderBuilder::ConditionalExpression(std::move(cond), std::move(trueExpr), std::move(falseExpr)); auto condExpr = ShaderBuilder::ConditionalExpression(std::move(cond), std::move(trueExpr), std::move(falseExpr));
condExpr->sourceLocation = SourceLocation::BuildFromTo(constSelectToken.location, closeToken.location);
return condExpr;
} }
ShaderAst::ExpressionPtr Parser::ParseExpression() ShaderAst::ExpressionPtr Parser::ParseExpression()
@ -1262,7 +1325,7 @@ namespace Nz::ShaderLang
return ParseBinOpRhs(0, ParsePrimaryExpression()); return ParseBinOpRhs(0, ParsePrimaryExpression());
} }
std::vector<ShaderAst::ExpressionPtr> Parser::ParseExpressionList(TokenType terminationToken) std::vector<ShaderAst::ExpressionPtr> Parser::ParseExpressionList(TokenType terminationToken, SourceLocation* terminationLocation)
{ {
std::vector<ShaderAst::ExpressionPtr> parameters; std::vector<ShaderAst::ExpressionPtr> parameters;
bool first = true; bool first = true;
@ -1275,7 +1338,9 @@ namespace Nz::ShaderLang
parameters.push_back(ParseExpression()); parameters.push_back(ParseExpression());
} }
Expect(Advance(), terminationToken); const Token& endToken = Expect(Advance(), terminationToken);
if (terminationLocation)
*terminationLocation = endToken.location;
return parameters; return parameters;
} }
@ -1283,7 +1348,10 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr Parser::ParseFloatingPointExpression() ShaderAst::ExpressionPtr Parser::ParseFloatingPointExpression()
{ {
const Token& floatingPointToken = Expect(Advance(), TokenType::FloatingPointValue); const Token& floatingPointToken = Expect(Advance(), TokenType::FloatingPointValue);
return ShaderBuilder::Constant(float(std::get<double>(floatingPointToken.data))); //< FIXME auto constantExpr = ShaderBuilder::Constant(float(std::get<double>(floatingPointToken.data))); //< FIXME
constantExpr->sourceLocation = floatingPointToken.location;
return constantExpr;
} }
ShaderAst::ExpressionPtr Parser::ParseIdentifier() ShaderAst::ExpressionPtr Parser::ParseIdentifier()
@ -1291,20 +1359,28 @@ namespace Nz::ShaderLang
const Token& identifierToken = Expect(Advance(), TokenType::Identifier); const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
const std::string& identifier = std::get<std::string>(identifierToken.data); const std::string& identifier = std::get<std::string>(identifierToken.data);
return ShaderBuilder::Identifier(identifier); auto identifierExpr = ShaderBuilder::Identifier(identifier);
identifierExpr->sourceLocation = identifierToken.location;
return identifierExpr;
} }
ShaderAst::ExpressionPtr Parser::ParseIntegerExpression() ShaderAst::ExpressionPtr Parser::ParseIntegerExpression()
{ {
const Token& integerToken = Expect(Advance(), TokenType::IntegerValue); const Token& integerToken = Expect(Advance(), TokenType::IntegerValue);
return ShaderBuilder::Constant(SafeCast<Int32>(std::get<long long>(integerToken.data))); //< FIXME auto constantExpr = ShaderBuilder::Constant(SafeCast<Int32>(std::get<long long>(integerToken.data))); //< FIXME
constantExpr->sourceLocation = integerToken.location;
return constantExpr;
} }
ShaderAst::ExpressionPtr Parser::ParseParenthesisExpression() ShaderAst::ExpressionPtr Parser::ParseParenthesisExpression()
{ {
Expect(Advance(), TokenType::OpenParenthesis); const Token& openToken = Expect(Advance(), TokenType::OpenParenthesis);
ShaderAst::ExpressionPtr expression = ParseExpression(); ShaderAst::ExpressionPtr expression = ParseExpression();
Expect(Advance(), TokenType::ClosingParenthesis); const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis);
expression->sourceLocation = SourceLocation::BuildFromTo(openToken.location, closeToken.location);
return expression; return expression;
} }
@ -1312,34 +1388,48 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr Parser::ParsePrimaryExpression() ShaderAst::ExpressionPtr Parser::ParsePrimaryExpression()
{ {
const Token& token = Peek(); const Token& token = Peek();
ShaderAst::ExpressionPtr primaryExpr;
switch (token.type) switch (token.type)
{ {
case TokenType::BoolFalse: case TokenType::BoolFalse:
Consume(); Consume();
return ShaderBuilder::Constant(false); primaryExpr = ShaderBuilder::Constant(false);
primaryExpr->sourceLocation = token.location;
break;
case TokenType::BoolTrue: case TokenType::BoolTrue:
Consume(); Consume();
return ShaderBuilder::Constant(true); primaryExpr = ShaderBuilder::Constant(true);
primaryExpr->sourceLocation = token.location;
break;
case TokenType::ConstSelect: case TokenType::ConstSelect:
return ParseConstSelectExpression(); primaryExpr = ParseConstSelectExpression();
break;
case TokenType::FloatingPointValue: case TokenType::FloatingPointValue:
return ParseFloatingPointExpression(); primaryExpr = ParseFloatingPointExpression();
break;
case TokenType::Identifier: case TokenType::Identifier:
return ParseIdentifier(); primaryExpr = ParseIdentifier();
break;
case TokenType::IntegerValue: case TokenType::IntegerValue:
return ParseIntegerExpression(); primaryExpr = ParseIntegerExpression();
break;
case TokenType::Minus: case TokenType::Minus:
{ {
Consume(); Consume();
ShaderAst::ExpressionPtr expr = ParseExpression(); ShaderAst::ExpressionPtr expr = ParseExpression();
return ShaderBuilder::Unary(ShaderAst::UnaryType::Minus, std::move(expr)); auto minusExpr = ShaderBuilder::Unary(ShaderAst::UnaryType::Minus, std::move(expr));
minusExpr->sourceLocation = SourceLocation::BuildFromTo(token.location, minusExpr->expression->sourceLocation);
primaryExpr = std::move(minusExpr);
break;
} }
case TokenType::Plus: case TokenType::Plus:
@ -1347,7 +1437,11 @@ namespace Nz::ShaderLang
Consume(); Consume();
ShaderAst::ExpressionPtr expr = ParseExpression(); ShaderAst::ExpressionPtr expr = ParseExpression();
return ShaderBuilder::Unary(ShaderAst::UnaryType::Plus, std::move(expr)); auto plusExpr = ShaderBuilder::Unary(ShaderAst::UnaryType::Plus, std::move(expr));
plusExpr->sourceLocation = SourceLocation::BuildFromTo(token.location, plusExpr->expression->sourceLocation);
primaryExpr = std::move(plusExpr);
break;
} }
case TokenType::Not: case TokenType::Not:
@ -1355,40 +1449,56 @@ namespace Nz::ShaderLang
Consume(); Consume();
ShaderAst::ExpressionPtr expr = ParseExpression(); ShaderAst::ExpressionPtr expr = ParseExpression();
return ShaderBuilder::Unary(ShaderAst::UnaryType::LogicalNot, std::move(expr)); auto notExpr = ShaderBuilder::Unary(ShaderAst::UnaryType::LogicalNot, std::move(expr));
notExpr->sourceLocation = SourceLocation::BuildFromTo(token.location, notExpr->expression->sourceLocation);
primaryExpr = std::move(notExpr);
break;
} }
case TokenType::OpenParenthesis: case TokenType::OpenParenthesis:
return ParseParenthesisExpression(); primaryExpr = ParseParenthesisExpression();
break;
case TokenType::StringValue: case TokenType::StringValue:
return ParseStringExpression(); primaryExpr = ParseStringExpression();
break;
default: default:
throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; throw ParserUnexpectedTokenError{ token.location, token.type };
} }
primaryExpr->sourceLocation.ExtendToLeft(token.location);
return primaryExpr;
} }
ShaderAst::ExpressionPtr Parser::ParseStringExpression() ShaderAst::ExpressionPtr Parser::ParseStringExpression()
{ {
const Token& litteralToken = Expect(Advance(), TokenType::StringValue); const Token& litteralToken = Expect(Advance(), TokenType::StringValue);
return ShaderBuilder::Constant(std::get<std::string>(litteralToken.data)); auto constantExpr = ShaderBuilder::Constant(std::get<std::string>(litteralToken.data));
constantExpr->sourceLocation = litteralToken.location;
return constantExpr;
} }
const std::string& Parser::ParseIdentifierAsName() const std::string& Parser::ParseIdentifierAsName(SourceLocation* sourceLocation)
{ {
const Token& identifierToken = Expect(Advance(), TokenType::Identifier); const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
if (sourceLocation)
*sourceLocation = identifierToken.location;
return std::get<std::string>(identifierToken.data); return std::get<std::string>(identifierToken.data);
} }
std::string Parser::ParseModuleName() std::string Parser::ParseModuleName()
{ {
std::string moduleName = ParseIdentifierAsName(); std::string moduleName = ParseIdentifierAsName(nullptr);
while (Peek().type == TokenType::Dot) while (Peek().type == TokenType::Dot)
{ {
Consume(); Consume();
moduleName += '.'; moduleName += '.';
moduleName += ParseIdentifierAsName(); moduleName += ParseIdentifierAsName(nullptr);
} }
return moduleName; return moduleName;
@ -1397,12 +1507,16 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr Parser::ParseType() ShaderAst::ExpressionPtr Parser::ParseType()
{ {
// Handle () as no type // Handle () as no type
if (Peek().type == TokenType::OpenParenthesis) const Token& openToken = Peek();
if (openToken.type == TokenType::OpenParenthesis)
{ {
Consume(); Consume();
Expect(Advance(), TokenType::ClosingParenthesis); const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis);
return ShaderBuilder::Constant(ShaderAst::NoValue{}); auto constantExpr = ShaderBuilder::Constant(ShaderAst::NoValue{});
constantExpr->sourceLocation = closeToken.location;
return constantExpr;
} }
return ParseExpression(); return ParseExpression();