diff --git a/include/Nazara/Shader/ShaderBuilder.hpp b/include/Nazara/Shader/ShaderBuilder.hpp index 9c48a0431..29f206c00 100644 --- a/include/Nazara/Shader/ShaderBuilder.hpp +++ b/include/Nazara/Shader/ShaderBuilder.hpp @@ -198,7 +198,7 @@ namespace Nz::ShaderBuilder { inline ShaderAst::WhileStatementPtr operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr body) const; }; -} + } constexpr Impl::AccessIndex AccessIndex; constexpr Impl::AccessMember AccessMember; diff --git a/include/Nazara/Shader/ShaderBuilder.inl b/include/Nazara/Shader/ShaderBuilder.inl index b7116e353..b6e145265 100644 --- a/include/Nazara/Shader/ShaderBuilder.inl +++ b/include/Nazara/Shader/ShaderBuilder.inl @@ -315,6 +315,7 @@ namespace Nz::ShaderBuilder inline ShaderAst::ExpressionStatementPtr Impl::ExpressionStatement::operator()(ShaderAst::ExpressionPtr expression) const { auto expressionStatementNode = std::make_unique(); + expressionStatementNode->sourceLocation = expression->sourceLocation; expressionStatementNode->expression = std::move(expression); return expressionStatementNode; @@ -421,6 +422,7 @@ namespace Nz::ShaderBuilder inline ShaderAst::ScopedStatementPtr Impl::Scoped::operator()(ShaderAst::StatementPtr statement) const { auto scopedNode = std::make_unique(); + scopedNode->sourceLocation = statement->sourceLocation; scopedNode->statement = std::move(statement); return scopedNode; diff --git a/include/Nazara/Shader/ShaderLangErrors.hpp b/include/Nazara/Shader/ShaderLangErrors.hpp index 6a0c81340..800341e12 100644 --- a/include/Nazara/Shader/ShaderLangErrors.hpp +++ b/include/Nazara/Shader/ShaderLangErrors.hpp @@ -34,7 +34,7 @@ namespace Nz::ShaderLang public: inline Error(SourceLocation sourceLocation, ErrorCategory errorCategory, unsigned int errorType) noexcept; Error(const Error&) = delete; - Error(Error&&) = delete; + Error(Error&&) noexcept = default; ~Error() = default; inline ErrorCategory GetErrorCategory() const; @@ -45,7 +45,7 @@ namespace Nz::ShaderLang const char* what() const noexcept override; Error& operator=(const Error&) = delete; - Error& operator=(Error&&) = delete; + Error& operator=(Error&&) noexcept = default; protected: virtual std::string BuildErrorMessage() const = 0; @@ -82,7 +82,7 @@ namespace Nz::ShaderLang }; #define NAZARA_SHADERLANG_NEWERRORTYPE(Prefix, BaseClass, ErrorType, ErrorName, ErrorString, ...) \ - class Prefix ## ErrorName ## Error : public BaseClass \ + class Prefix ## ErrorName ## Error final : public BaseClass \ { \ public: \ template Prefix ## ErrorName ## Error(SourceLocation sourceLocation, Args&&... args) : \ diff --git a/include/Nazara/Shader/ShaderLangLexer.hpp b/include/Nazara/Shader/ShaderLangLexer.hpp index 4cdd5e815..35b1097ba 100644 --- a/include/Nazara/Shader/ShaderLangLexer.hpp +++ b/include/Nazara/Shader/ShaderLangLexer.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -26,10 +27,8 @@ namespace Nz::ShaderLang struct Token { - unsigned int column; - unsigned int line; + SourceLocation location; TokenType type; - std::shared_ptr file; std::variant data; }; diff --git a/include/Nazara/Shader/ShaderLangParser.hpp b/include/Nazara/Shader/ShaderLangParser.hpp index 05746709f..cb46e30a6 100644 --- a/include/Nazara/Shader/ShaderLangParser.hpp +++ b/include/Nazara/Shader/ShaderLangParser.hpp @@ -25,6 +25,13 @@ namespace Nz::ShaderLang ShaderAst::ModulePtr Parse(const std::vector& tokens); private: + struct Attribute + { + ShaderAst::AttributeType type; + ShaderAst::ExpressionPtr args; + SourceLocation sourceLocation; + }; + // Flow control const Token& Advance(); void Consume(std::size_t count = 1); @@ -33,9 +40,9 @@ namespace Nz::ShaderLang const Token& Expect(TokenType type); const Token& Peek(std::size_t advance = 0); - std::vector ParseAttributes(); - void ParseModuleStatement(std::vector attributes); - void ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue& type, ShaderAst::ExpressionPtr& initialValue); + std::vector ParseAttributes(); + void ParseModuleStatement(std::vector attributes); + void ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue& type, ShaderAst::ExpressionPtr& initialValue, SourceLocation& sourceLocation); ShaderAst::ExpressionPtr BuildIdentifierAccess(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 ParseConstStatement(); ShaderAst::StatementPtr ParseDiscardStatement(); - ShaderAst::StatementPtr ParseExternalBlock(std::vector attributes = {}); - ShaderAst::StatementPtr ParseForDeclaration(std::vector attributes = {}); - std::vector ParseFunctionBody(); - ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector attributes = {}); + ShaderAst::StatementPtr ParseExternalBlock(std::vector attributes = {}); + ShaderAst::StatementPtr ParseForDeclaration(std::vector attributes = {}); + ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector attributes = {}); ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter(); ShaderAst::StatementPtr ParseImportStatement(); ShaderAst::StatementPtr ParseOptionDeclaration(); ShaderAst::StatementPtr ParseReturnStatement(); - ShaderAst::StatementPtr ParseRootStatement(std::vector attributes = {}); + ShaderAst::StatementPtr ParseRootStatement(std::vector attributes = {}); ShaderAst::StatementPtr ParseSingleStatement(); ShaderAst::StatementPtr ParseStatement(); - std::vector ParseStatementList(); - ShaderAst::StatementPtr ParseStructDeclaration(std::vector attributes = {}); + std::vector ParseStatementList(SourceLocation* sourceLocation); + ShaderAst::StatementPtr ParseStructDeclaration(std::vector attributes = {}); ShaderAst::StatementPtr ParseVariableDeclaration(); - ShaderAst::StatementPtr ParseWhileStatement(std::vector attributes); + ShaderAst::StatementPtr ParseWhileStatement(std::vector attributes); // Expressions ShaderAst::ExpressionPtr ParseBinOpRhs(int exprPrecedence, ShaderAst::ExpressionPtr lhs); ShaderAst::ExpressionPtr ParseConstSelectExpression(); ShaderAst::ExpressionPtr ParseExpression(); - std::vector ParseExpressionList(TokenType terminationToken); + std::vector ParseExpressionList(TokenType terminationToken, SourceLocation* terminationLocation); ShaderAst::ExpressionPtr ParseFloatingPointExpression(); ShaderAst::ExpressionPtr ParseIdentifier(); ShaderAst::ExpressionPtr ParseIntegerExpression(); @@ -75,8 +81,7 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr ParseStringExpression(); ShaderAst::ExpressionPtr ParseVariableAssignation(); - ShaderAst::AttributeType ParseIdentifierAsAttributeType(); - const std::string& ParseIdentifierAsName(); + const std::string& ParseIdentifierAsName(SourceLocation* sourceLocation); std::string ParseModuleName(); ShaderAst::ExpressionPtr ParseType(); diff --git a/include/Nazara/Shader/ShaderLangSourceLocation.hpp b/include/Nazara/Shader/ShaderLangSourceLocation.hpp index 5af6768fa..895f8dbc8 100644 --- a/include/Nazara/Shader/ShaderLangSourceLocation.hpp +++ b/include/Nazara/Shader/ShaderLangSourceLocation.hpp @@ -21,8 +21,13 @@ namespace Nz::ShaderLang inline SourceLocation(unsigned int line, unsigned int startColumn, unsigned int endColumn, std::shared_ptr file); inline SourceLocation(unsigned int startLine, unsigned int endLine, unsigned int startColumn, unsigned int endColumn, std::shared_ptr file); + inline void ExtendToLeft(const SourceLocation& leftLocation); + inline void ExtendToRight(const SourceLocation& rightLocation); + inline bool IsValid() const; + static inline SourceLocation BuildFromTo(const SourceLocation& leftSource, const SourceLocation& rightSource); + std::shared_ptr file; //< Since the same file will be used for every node, prevent holding X time the same path UInt32 endColumn; UInt32 endLine; diff --git a/include/Nazara/Shader/ShaderLangSourceLocation.inl b/include/Nazara/Shader/ShaderLangSourceLocation.inl index 4e3c3cc54..7766a0d84 100644 --- a/include/Nazara/Shader/ShaderLangSourceLocation.inl +++ b/include/Nazara/Shader/ShaderLangSourceLocation.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include 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 { return startLine != 0 && endLine != 0 && endColumn != 0 && startColumn != 0; diff --git a/src/Nazara/Shader/Ast/AstSerializer.cpp b/src/Nazara/Shader/Ast/AstSerializer.cpp index cc01b2197..1d73ce8e1 100644 --- a/src/Nazara/Shader/Ast/AstSerializer.cpp +++ b/src/Nazara/Shader/Ast/AstSerializer.cpp @@ -460,7 +460,7 @@ namespace Nz::ShaderAst if (newString) { Value(const_cast(*val)); //< won't be used for writing - m_stringIndices.emplace(*val, m_stringIndices.size()); + m_stringIndices.emplace(*val, SafeCast(m_stringIndices.size())); } else Value(it->second); //< string index diff --git a/src/Nazara/Shader/ShaderLangLexer.cpp b/src/Nazara/Shader/ShaderLangLexer.cpp index cb2468974..36b87d8a8 100644 --- a/src/Nazara/Shader/ShaderLangLexer.cpp +++ b/src/Nazara/Shader/ShaderLangLexer.cpp @@ -91,9 +91,9 @@ namespace Nz::ShaderLang char c = Peek(0); Token token; - token.column = static_cast(currentPos - lastLineFeed); - token.file = currentFile; - token.line = lineNumber; + token.location.startColumn = static_cast(currentPos - lastLineFeed); + token.location.startLine = lineNumber; + token.location.file = currentFile; if (c == '\0') { @@ -223,6 +223,8 @@ namespace Nz::ShaderLang currentPos++; } + token.location.endColumn = static_cast(currentPos - lastLineFeed); + if (floatingPoint) { tokenType = TokenType::FloatingPointValue; @@ -234,10 +236,7 @@ namespace Nz::ShaderLang char* end; double value = std::strtod(ptr, &end); if (end != &ptr[valueStr.size()]) - { - unsigned int columnOffset = SafeCast(end - ptr); - throw LexerBadNumberError{ SourceLocation{ token.line, token.column + columnOffset, token.file } }; - } + throw LexerBadNumberError{ token.location }; token.data = value; } @@ -249,11 +248,10 @@ namespace Nz::ShaderLang std::from_chars_result r = std::from_chars(&str[start], &str[currentPos + 1], value); if (r.ptr != &str[currentPos + 1]) { - unsigned int columnOffset = SafeCast(r.ptr - &str[start]); 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; @@ -292,7 +290,7 @@ namespace Nz::ShaderLang tokenType = TokenType::LogicalOr; } 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; } @@ -313,7 +311,7 @@ namespace Nz::ShaderLang tokenType = TokenType::LogicalAnd; } 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; } @@ -415,7 +413,8 @@ namespace Nz::ShaderLang case '\0': case '\n': case '\r': - throw LexerUnfinishedStringError{ SourceLocation{ token.line, SafeCast(currentPos - lastLineFeed), token.file } }; + token.location.endColumn = static_cast(currentPos - lastLineFeed); + throw LexerUnfinishedStringError{ token.location }; case '\\': { @@ -429,7 +428,8 @@ namespace Nz::ShaderLang case '"': character = '"'; break; case '\\': character = '\\'; break; default: - throw LexerUnrecognizedCharError{ SourceLocation{ token.line, SafeCast(currentPos - lastLineFeed), token.file } }; + token.location.endColumn = static_cast(currentPos - lastLineFeed); + throw LexerUnrecognizedCharError{ token.location }; } break; } @@ -469,12 +469,14 @@ namespace Nz::ShaderLang break; } else - throw LexerUnrecognizedTokenError{ SourceLocation{ token.line, token.column, token.file } }; + throw LexerUnrecognizedTokenError{ token.location }; } } if (tokenType) { + token.location.endColumn = static_cast(currentPos - lastLineFeed); + token.location.endLine = lineNumber; token.type = *tokenType; tokens.push_back(std::move(token)); @@ -503,16 +505,16 @@ namespace Nz::ShaderLang if (tokens.empty()) return {}; - unsigned int lastLineNumber = tokens.front().line; + unsigned int lastLineNumber = tokens.front().location.startLine; std::stringstream ss; bool empty = true; 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) ss << '\n'; } @@ -534,6 +536,10 @@ namespace Nz::ShaderLang ss << "(" << std::get(token.data) << ")"; break; + case TokenType::StringValue: + ss << "(\"" << std::get(token.data) << "\")"; + break; + default: break; } diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index 02f13fe12..3f759fe7b 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -59,25 +59,6 @@ namespace Nz::ShaderLang { "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 void HandleUniqueAttribute(ShaderAst::ExpressionValue& targetAttribute, Parser::Attribute&& attribute) { @@ -148,7 +129,7 @@ namespace Nz::ShaderLang if (!m_context->module) { const Token& nextToken = Peek(); - throw ParserUnexpectedTokenError{ TokenLocation(nextToken) }; + throw ParserUnexpectedTokenError{ nextToken.location }; } if (!statement) @@ -177,7 +158,7 @@ namespace Nz::ShaderLang const Token& Parser::Expect(const Token& token, TokenType type) { if (token.type != type) - throw ParserExpectedTokenError{ TokenLocation(token), type, token.type }; + throw ParserExpectedTokenError{ token.location, type, token.type }; return token; } @@ -185,7 +166,7 @@ namespace Nz::ShaderLang const Token& Parser::ExpectNot(const Token& token, TokenType type) { if (token.type == type) - throw ParserUnexpectedTokenError{ TokenLocation(token), type }; + throw ParserUnexpectedTokenError{ token.location, type }; return token; } @@ -235,11 +216,11 @@ namespace Nz::ShaderLang const Token& identifierToken = Expect(Advance(), TokenType::Identifier); const std::string& identifier = std::get(identifierToken.data); - SourceLocation attributeLocation = TokenLocation(identifierToken); + SourceLocation attributeLocation = identifierToken.location; auto it = s_identifierToAttributeType.find(identifier); if (it == s_identifierToAttributeType.end()) - throw ParserUnknownAttributeError{ attributeLocation }; + throw ParserUnknownAttributeError{ identifierToken.location }; ShaderAst::AttributeType attributeType = it->second; @@ -251,7 +232,7 @@ namespace Nz::ShaderLang arg = ParseExpression(); const Token& closeToken = Expect(Advance(), TokenType::ClosingParenthesis); - ExtendLocationToToken(attributeLocation, closeToken); + attributeLocation.ExtendToRight(closeToken.location); } expectComma = true; @@ -273,7 +254,7 @@ namespace Nz::ShaderLang if (m_context->parsingImportedModule) { const Token& token = Peek(); - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; } const Token& moduleToken = Expect(Advance(), TokenType::Module); @@ -355,7 +336,7 @@ namespace Nz::ShaderLang } if (!moduleVersion.has_value()) - throw ParserMissingAttributeError{ TokenLocation(moduleToken) }; + throw ParserMissingAttributeError{ moduleToken.location }; if (!moduleId) moduleId = Uuid::Generate(); @@ -376,7 +357,7 @@ namespace Nz::ShaderLang if (!statement) { const Token& token = Peek(); - throw ParserUnexpectedEndOfFileError{ TokenLocation(token) }; + throw ParserUnexpectedEndOfFileError{ token.location }; } module->rootNode->statements.push_back(std::move(statement)); @@ -401,15 +382,15 @@ namespace Nz::ShaderLang Expect(Advance(), TokenType::Semicolon); if (m_context->module) - throw ParserDuplicateModuleError{ TokenLocation(moduleToken) }; + throw ParserDuplicateModuleError{ moduleToken.location }; m_context->module = std::move(module); } } - void Parser::ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue& type, ShaderAst::ExpressionPtr& initialValue) + void Parser::ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue& type, ShaderAst::ExpressionPtr& initialValue, SourceLocation& sourceLocation) { - name = ParseIdentifierAsName(); + name = ParseIdentifierAsName(nullptr); if (Peek().type == TokenType::Colon) { @@ -424,40 +405,61 @@ namespace Nz::ShaderLang 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) { if (rhs->GetType() == ShaderAst::NodeType::IdentifierExpression) - return ShaderBuilder::AccessMember(std::move(lhs), { std::move(SafeCast(*rhs).identifier) }); + { + SourceLocation location = SourceLocation::BuildFromTo(lhs->sourceLocation, rhs->sourceLocation); + + auto accessMemberExpr = ShaderBuilder::AccessMember(std::move(lhs), { std::move(SafeCast(*rhs).identifier) }); + accessMemberExpr->sourceLocation = std::move(location); + + return accessMemberExpr; + } else return BuildIndexAccess(std::move(lhs), std::move(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) { - 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() { - Expect(Advance(), TokenType::Alias); + const Token& aliasToken = Expect(Advance(), TokenType::Alias); - std::string name = ParseIdentifierAsName(); + std::string name = ParseIdentifierAsName(nullptr); Expect(Advance(), TokenType::Assign); 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() @@ -470,9 +472,11 @@ namespace Nz::ShaderLang if (!first) 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(); @@ -483,6 +487,7 @@ namespace Nz::ShaderLang Expect(Advance(), TokenType::ClosingParenthesis); condStatement.statement = ParseStatement(); + branch->sourceLocation.ExtendToRight(condStatement.statement->sourceLocation); if (Peek().type != TokenType::Else || Peek(1).type != TokenType::If) break; @@ -492,6 +497,7 @@ namespace Nz::ShaderLang { Consume(); branch->elseStatement = ParseStatement(); + branch->sourceLocation.ExtendToRight(branch->elseStatement->sourceLocation); } return branch; @@ -499,7 +505,9 @@ namespace Nz::ShaderLang ShaderAst::StatementPtr Parser::ParseConstStatement() { - Expect(Advance(), TokenType::Const); + const Token& constToken = Expect(Advance(), TokenType::Const); + + SourceLocation constLocation = constToken.location; const Token& token = Peek(); switch (token.type) @@ -510,30 +518,37 @@ namespace Nz::ShaderLang ShaderAst::ExpressionValue constType; 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: { auto branch = ParseBranchStatement(); SafeCast(*branch).isConst = true; + branch->sourceLocation.ExtendToLeft(constLocation); return branch; } default: - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; } } ShaderAst::StatementPtr Parser::ParseDiscardStatement() { - Expect(Advance(), TokenType::Discard); - Expect(Advance(), TokenType::Semicolon); + const Token& discardToken = Expect(Advance(), TokenType::Discard); + 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 attributes) @@ -544,9 +559,7 @@ namespace Nz::ShaderLang Expect(Advance(), TokenType::OpenCurlyBracket); std::unique_ptr externalStatement = std::make_unique(); - externalStatement->sourceLocation.startColumn = externalToken.column; - externalStatement->sourceLocation.startLine = externalToken.line; - externalStatement->sourceLocation.file = externalToken.file; + externalStatement->sourceLocation = externalToken.location; ShaderAst::ExpressionValue condition; @@ -610,9 +623,13 @@ namespace Nz::ShaderLang } } - extVar.name = ParseIdentifierAsName(); + extVar.name = ParseIdentifierAsName(&extVar.sourceLocation); Expect(Advance(), TokenType::Colon); - extVar.type = ParseType(); + + auto typeExpr = ParseType(); + extVar.sourceLocation.ExtendToRight(typeExpr->sourceLocation); + + extVar.type = std::move(typeExpr); } Expect(Advance(), TokenType::ClosingCurlyBracket); @@ -629,7 +646,7 @@ namespace Nz::ShaderLang const Token& forToken = Expect(Advance(), TokenType::For); - std::string varName = ParseIdentifierAsName(); + std::string varName = ParseIdentifierAsName(nullptr); Expect(Advance(), TokenType::In); @@ -652,6 +669,7 @@ namespace Nz::ShaderLang ShaderAst::StatementPtr statement = ParseStatement(); 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 for (auto&& attribute : attributes) @@ -675,6 +693,7 @@ namespace Nz::ShaderLang ShaderAst::StatementPtr statement = ParseStatement(); 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 for (auto&& attribute : attributes) @@ -694,18 +713,13 @@ namespace Nz::ShaderLang } } - std::vector Parser::ParseFunctionBody() - { - return ParseStatementList(); - } - ShaderAst::StatementPtr Parser::ParseFunctionDeclaration(std::vector attributes) { NAZARA_USE_ANONYMOUS_NAMESPACE const auto& funcToken = Expect(Advance(), TokenType::FunctionDeclaration); - std::string functionName = ParseIdentifierAsName(); + std::string functionName = ParseIdentifierAsName(nullptr); Expect(Advance(), TokenType::OpenParenthesis); @@ -736,9 +750,13 @@ namespace Nz::ShaderLang returnType = ParseType(); } - std::vector functionBody = ParseFunctionBody(); + SourceLocation functionLocation; + std::vector functionBody = ParseStatementList(&functionLocation); + + functionLocation.ExtendToLeft(funcToken.location); auto func = ShaderBuilder::DeclareFunction(std::move(functionName), std::move(parameters), std::move(functionBody), std::move(returnType)); + func->sourceLocation = std::move(functionLocation); ShaderAst::ExpressionValue condition; @@ -781,31 +799,37 @@ namespace Nz::ShaderLang { ShaderAst::DeclareFunctionStatement::Parameter parameter; - parameter.name = ParseIdentifierAsName(); + parameter.name = ParseIdentifierAsName(¶meter.sourceLocation); Expect(Advance(), TokenType::Colon); - parameter.type = ParseType(); + auto typeExpr = ParseType(); + parameter.sourceLocation.ExtendToRight(typeExpr->sourceLocation); + + parameter.type = std::move(typeExpr); return parameter; } ShaderAst::StatementPtr Parser::ParseImportStatement() { - Expect(Advance(), TokenType::Import); + const Token& importToken = Expect(Advance(), TokenType::Import); 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() { - Expect(Advance(), TokenType::Option); + const Token& optionToken = Expect(Advance(), TokenType::Option); - std::string optionName = ParseIdentifierAsName(); + std::string optionName = ParseIdentifierAsName(nullptr); Expect(Advance(), TokenType::Colon); @@ -819,22 +843,28 @@ namespace Nz::ShaderLang 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() { - Expect(Advance(), TokenType::Return); + const Token& returnToken = Expect(Advance(), TokenType::Return); ShaderAst::ExpressionPtr expr; if (Peek().type != TokenType::Semicolon) 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 attributes) @@ -844,19 +874,19 @@ namespace Nz::ShaderLang { case TokenType::Alias: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; + throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type }; return ParseAliasDeclaration(); case TokenType::Const: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; + throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type }; return ParseConstStatement(); case TokenType::EndOfStream: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; + throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type }; return {}; @@ -865,7 +895,7 @@ namespace Nz::ShaderLang case TokenType::Import: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; + throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type }; return ParseImportStatement(); @@ -880,7 +910,7 @@ namespace Nz::ShaderLang case TokenType::Option: { if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; + throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type }; return ParseOptionDeclaration(); } @@ -892,7 +922,7 @@ namespace Nz::ShaderLang return ParseStructDeclaration(std::move(attributes)); default: - throw ParserUnexpectedTokenError{ TokenLocation(nextToken), nextToken.type }; + throw ParserUnexpectedTokenError{ nextToken.location, nextToken.type }; } } @@ -907,14 +937,14 @@ namespace Nz::ShaderLang { case TokenType::Const: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; statement = ParseConstStatement(); break; case TokenType::Discard: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; statement = ParseDiscardStatement(); break; @@ -926,14 +956,14 @@ namespace Nz::ShaderLang case TokenType::Let: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; statement = ParseVariableDeclaration(); break; case TokenType::Identifier: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; statement = ShaderBuilder::ExpressionStatement(ParseVariableAssignation()); Expect(Advance(), TokenType::Semicolon); @@ -941,7 +971,7 @@ namespace Nz::ShaderLang case TokenType::If: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; statement = ParseBranchStatement(); break; @@ -953,7 +983,7 @@ namespace Nz::ShaderLang case TokenType::Return: if (!attributes.empty()) - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; statement = ParseReturnStatement(); break; @@ -964,7 +994,7 @@ namespace Nz::ShaderLang break; default: - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; } } while (!statement); //< small trick to repeat parsing once we got attributes @@ -975,14 +1005,19 @@ namespace Nz::ShaderLang ShaderAst::StatementPtr Parser::ParseStatement() { 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 return ParseSingleStatement(); } - std::vector Parser::ParseStatementList() + std::vector Parser::ParseStatementList(SourceLocation* sourceLocation) { - Expect(Advance(), TokenType::OpenCurlyBracket); + const Token& openToken = Expect(Advance(), TokenType::OpenCurlyBracket); std::vector statements; while (Peek().type != TokenType::ClosingCurlyBracket) @@ -990,7 +1025,10 @@ namespace Nz::ShaderLang ExpectNot(Peek(), TokenType::EndOfStream); 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; } @@ -1002,7 +1040,7 @@ namespace Nz::ShaderLang const auto& structToken = Expect(Advance(), TokenType::Struct); ShaderAst::StructDescription description; - description.name = ParseIdentifierAsName(); + description.name = ParseIdentifierAsName(nullptr); ShaderAst::ExpressionValue condition; ShaderAst::ExpressionValue exported; @@ -1078,19 +1116,27 @@ namespace Nz::ShaderLang } } - structField.name = ParseIdentifierAsName(); + structField.name = ParseIdentifierAsName(&structField.sourceLocation); Expect(Advance(), TokenType::Colon); 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()) - 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 - return ShaderBuilder::DeclareStruct(std::move(description), std::move(exported)); + return structDeclStatement; } ShaderAst::ExpressionPtr Parser::ParseVariableAssignation() @@ -1113,7 +1159,7 @@ namespace Nz::ShaderLang case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break; default: - throw ParserUnexpectedTokenError{ TokenLocation(token) }; + throw ParserUnexpectedTokenError{ token.location }; } Consume(); @@ -1121,20 +1167,28 @@ namespace Nz::ShaderLang // Value expression 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() { - Expect(Advance(), TokenType::Let); + const auto& letToken = Expect(Advance(), TokenType::Let); + + SourceLocation letLocation = letToken.location; std::string variableName; ShaderAst::ExpressionValue variableType; 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 attributes) @@ -1152,6 +1206,7 @@ namespace Nz::ShaderLang ShaderAst::StatementPtr body = ParseStatement(); auto whileStatement = ShaderBuilder::While(std::move(condition), std::move(body)); + whileStatement->sourceLocation = SourceLocation::BuildFromTo(whileToken.location, whileStatement->body->sourceLocation); for (auto&& attribute : attributes) { @@ -1176,7 +1231,7 @@ namespace Nz::ShaderLang const Token& token = Peek(); TokenType currentTokenType = token.type; if (currentTokenType == TokenType::EndOfStream) - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; int tokenPrecedence = GetTokenPrecedence(currentTokenType); if (tokenPrecedence < exprPrecedence) @@ -1187,8 +1242,10 @@ namespace Nz::ShaderLang Consume(); // 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->sourceLocation = SourceLocation::BuildFromTo(token.location, closingLocation); continue; } @@ -1197,8 +1254,11 @@ namespace Nz::ShaderLang Consume(); // Indices - auto parameters = ParseExpressionList(TokenType::ClosingSquareBracket); + SourceLocation closingLocation; + auto parameters = ParseExpressionList(TokenType::ClosingSquareBracket, &closingLocation); + lhs = ShaderBuilder::AccessIndex(std::move(lhs), std::move(parameters)); + lhs->sourceLocation = SourceLocation::BuildFromTo(token.location, closingLocation); continue; } @@ -1231,7 +1291,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{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; } }(); } @@ -1239,7 +1299,7 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr Parser::ParseConstSelectExpression() { - Expect(Advance(), TokenType::ConstSelect); + const Token& constSelectToken = Expect(Advance(), TokenType::ConstSelect); Expect(Advance(), TokenType::OpenParenthesis); ShaderAst::ExpressionPtr cond = ParseExpression(); @@ -1252,9 +1312,12 @@ namespace Nz::ShaderLang 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() @@ -1262,7 +1325,7 @@ namespace Nz::ShaderLang return ParseBinOpRhs(0, ParsePrimaryExpression()); } - std::vector Parser::ParseExpressionList(TokenType terminationToken) + std::vector Parser::ParseExpressionList(TokenType terminationToken, SourceLocation* terminationLocation) { std::vector parameters; bool first = true; @@ -1275,7 +1338,9 @@ namespace Nz::ShaderLang parameters.push_back(ParseExpression()); } - Expect(Advance(), terminationToken); + const Token& endToken = Expect(Advance(), terminationToken); + if (terminationLocation) + *terminationLocation = endToken.location; return parameters; } @@ -1283,7 +1348,10 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr Parser::ParseFloatingPointExpression() { const Token& floatingPointToken = Expect(Advance(), TokenType::FloatingPointValue); - return ShaderBuilder::Constant(float(std::get(floatingPointToken.data))); //< FIXME + auto constantExpr = ShaderBuilder::Constant(float(std::get(floatingPointToken.data))); //< FIXME + constantExpr->sourceLocation = floatingPointToken.location; + + return constantExpr; } ShaderAst::ExpressionPtr Parser::ParseIdentifier() @@ -1291,20 +1359,28 @@ namespace Nz::ShaderLang const Token& identifierToken = Expect(Advance(), TokenType::Identifier); const std::string& identifier = std::get(identifierToken.data); - return ShaderBuilder::Identifier(identifier); + auto identifierExpr = ShaderBuilder::Identifier(identifier); + identifierExpr->sourceLocation = identifierToken.location; + + return identifierExpr; } ShaderAst::ExpressionPtr Parser::ParseIntegerExpression() { const Token& integerToken = Expect(Advance(), TokenType::IntegerValue); - return ShaderBuilder::Constant(SafeCast(std::get(integerToken.data))); //< FIXME + auto constantExpr = ShaderBuilder::Constant(SafeCast(std::get(integerToken.data))); //< FIXME + constantExpr->sourceLocation = integerToken.location; + + return constantExpr; } ShaderAst::ExpressionPtr Parser::ParseParenthesisExpression() { - Expect(Advance(), TokenType::OpenParenthesis); + const Token& openToken = Expect(Advance(), TokenType::OpenParenthesis); 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; } @@ -1312,34 +1388,48 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr Parser::ParsePrimaryExpression() { const Token& token = Peek(); + + ShaderAst::ExpressionPtr primaryExpr; switch (token.type) { case TokenType::BoolFalse: Consume(); - return ShaderBuilder::Constant(false); + primaryExpr = ShaderBuilder::Constant(false); + primaryExpr->sourceLocation = token.location; + break; case TokenType::BoolTrue: Consume(); - return ShaderBuilder::Constant(true); + primaryExpr = ShaderBuilder::Constant(true); + primaryExpr->sourceLocation = token.location; + break; case TokenType::ConstSelect: - return ParseConstSelectExpression(); + primaryExpr = ParseConstSelectExpression(); + break; case TokenType::FloatingPointValue: - return ParseFloatingPointExpression(); + primaryExpr = ParseFloatingPointExpression(); + break; case TokenType::Identifier: - return ParseIdentifier(); + primaryExpr = ParseIdentifier(); + break; case TokenType::IntegerValue: - return ParseIntegerExpression(); + primaryExpr = ParseIntegerExpression(); + break; case TokenType::Minus: { Consume(); 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: @@ -1347,7 +1437,11 @@ namespace Nz::ShaderLang Consume(); 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: @@ -1355,40 +1449,56 @@ namespace Nz::ShaderLang Consume(); 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: - return ParseParenthesisExpression(); + primaryExpr = ParseParenthesisExpression(); + break; case TokenType::StringValue: - return ParseStringExpression(); + primaryExpr = ParseStringExpression(); + break; default: - throw ParserUnexpectedTokenError{ TokenLocation(token), token.type }; + throw ParserUnexpectedTokenError{ token.location, token.type }; } + + primaryExpr->sourceLocation.ExtendToLeft(token.location); + + return primaryExpr; } ShaderAst::ExpressionPtr Parser::ParseStringExpression() { const Token& litteralToken = Expect(Advance(), TokenType::StringValue); - return ShaderBuilder::Constant(std::get(litteralToken.data)); + auto constantExpr = ShaderBuilder::Constant(std::get(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); + if (sourceLocation) + *sourceLocation = identifierToken.location; + return std::get(identifierToken.data); } std::string Parser::ParseModuleName() { - std::string moduleName = ParseIdentifierAsName(); + std::string moduleName = ParseIdentifierAsName(nullptr); while (Peek().type == TokenType::Dot) { Consume(); moduleName += '.'; - moduleName += ParseIdentifierAsName(); + moduleName += ParseIdentifierAsName(nullptr); } return moduleName; @@ -1397,12 +1507,16 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr Parser::ParseType() { // Handle () as no type - if (Peek().type == TokenType::OpenParenthesis) + const Token& openToken = Peek(); + if (openToken.type == TokenType::OpenParenthesis) { 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();