From 5d24ab1e797ef221e8baa898c0ddc0618e92c24b Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Fri, 5 Jan 2024 01:11:09 +0100 Subject: [PATCH] Fix bug --- src/SourceFile.cpp | 4 ++-- src/SourceFile.h | 9 +++++++- src/ast/ASTBuilder.cpp | 12 +++++----- src/ast/ASTBuilder.h | 5 ++-- src/ast/ASTNodes.cpp | 8 +++---- src/exception/AntlrThrowingErrorListener.cpp | 2 +- src/exception/AntlrThrowingErrorListener.h | 10 ++++---- src/exception/SemanticError.cpp | 7 +++--- src/exception/SemanticError.h | 2 +- src/symboltablebuilder/SymbolTableBuilder.cpp | 2 +- src/typechecker/TypeChecker.cpp | 4 +++- src/util/CodeLoc.cpp | 6 +++++ src/util/CodeLoc.h | 23 +++++++++++-------- 13 files changed, 58 insertions(+), 36 deletions(-) diff --git a/src/SourceFile.cpp b/src/SourceFile.cpp index 24d951c17..933d24aca 100644 --- a/src/SourceFile.cpp +++ b/src/SourceFile.cpp @@ -51,8 +51,8 @@ void SourceFile::runLexer() { throw CompilerError(SOURCE_FILE_NOT_FOUND, "Source file at path '" + filePath.string() + "' does not exist."); // Create error handlers for lexer and parser - antlrCtx.lexerErrorHandler = std::make_unique(ThrowingErrorListenerMode::LEXER, filePath); - antlrCtx.parserErrorHandler = std::make_unique(ThrowingErrorListenerMode::PARSER, filePath); + antlrCtx.lexerErrorHandler = std::make_unique(ThrowingErrorListenerMode::LEXER, this); + antlrCtx.parserErrorHandler = std::make_unique(ThrowingErrorListenerMode::PARSER, this); // Tokenize input antlrCtx.inputStream = std::make_unique(fileInputStream); diff --git a/src/SourceFile.h b/src/SourceFile.h index 0f98a26a9..e2f9125ef 100644 --- a/src/SourceFile.h +++ b/src/SourceFile.h @@ -47,7 +47,14 @@ enum CompileStageType : uint8_t { FINISHED }; -enum CompileStageIOType { IO_CODE, IO_TOKENS, IO_CST, IO_AST, IO_IR, IO_OBJECT_FILE }; +enum CompileStageIOType : uint8_t { + IO_CODE, + IO_TOKENS, + IO_CST, + IO_AST, + IO_IR, + IO_OBJECT_FILE, +}; struct SourceFileAntlrCtx { // Create error handlers for lexer and parser diff --git a/src/ast/ASTBuilder.cpp b/src/ast/ASTBuilder.cpp index e0496c683..8e6691307 100644 --- a/src/ast/ASTBuilder.cpp +++ b/src/ast/ASTBuilder.cpp @@ -15,7 +15,7 @@ namespace spice::compiler { ASTBuilder::ASTBuilder(GlobalResourceManager &resourceManager, SourceFile *sourceFile, antlr4::ANTLRInputStream *inputStream) - : CompilerPass(resourceManager, sourceFile), filePath(sourceFile->filePath), inputStream(inputStream) {} + : CompilerPass(resourceManager, sourceFile), inputStream(inputStream) {} std::any ASTBuilder::visitEntry(SpiceParser::EntryContext *ctx) { auto entryNode = createNode(ctx); @@ -1386,11 +1386,11 @@ int8_t ASTBuilder::parseChar(TerminalNode *terminal) { case '0': return '\0'; default: - const CodeLoc codeLoc(terminal->getSymbol(), filePath); + const CodeLoc codeLoc(terminal->getSymbol(), sourceFile); throw ParserError(codeLoc, INVALID_CHAR_LITERAL, "Invalid escape sequence " + input); } } else { - const CodeLoc codeLoc(terminal->getSymbol(), filePath); + const CodeLoc codeLoc(terminal->getSymbol(), sourceFile); throw ParserError(codeLoc, INVALID_CHAR_LITERAL, "Invalid char literal " + input); } } @@ -1437,10 +1437,10 @@ T ASTBuilder::parseNumeric(ConstantNode *constantNode, TerminalNode *terminal, s } return cb(input, 10); } catch (std::out_of_range &e) { - const CodeLoc codeLoc(terminal->getSymbol(), filePath); + const CodeLoc codeLoc(terminal->getSymbol(), sourceFile); throw ParserError(codeLoc, NUMBER_OUT_OF_RANGE, "The provided number is out of range"); } catch (std::invalid_argument &e) { - const CodeLoc codeLoc(terminal->getSymbol(), filePath); + const CodeLoc codeLoc(terminal->getSymbol(), sourceFile); throw ParserError(codeLoc, NUMBER_OUT_OF_RANGE, "You tried to parse '" + input + "' as an integer, but it was no integer"); } } @@ -1467,7 +1467,7 @@ std::string ASTBuilder::getIdentifier(TerminalNode *terminal) { isReserved |= std::find(std::begin(RESERVED_KEYWORDS), std::end(RESERVED_KEYWORDS), identifier) != std::end(RESERVED_KEYWORDS); // Print error message if (isReserved) { - const CodeLoc codeLoc(terminal->getSymbol(), filePath); + const CodeLoc codeLoc(terminal->getSymbol(), sourceFile); throw ParserError(codeLoc, RESERVED_KEYWORD, "'" + identifier + "' is a reserved keyword. Please use another name instead"); } diff --git a/src/ast/ASTBuilder.h b/src/ast/ASTBuilder.h index 479010956..7adcebe8a 100644 --- a/src/ast/ASTBuilder.h +++ b/src/ast/ASTBuilder.h @@ -120,14 +120,15 @@ class ASTBuilder : private CompilerPass, public SpiceVisitor { private: // Members - const std::filesystem::path &filePath; antlr4::ANTLRInputStream *inputStream; std::stack parentStack; // Private methods template T *createNode(const ParserRuleContext *ctx); template T *concludeNode(T *node); - ALWAYS_INLINE CodeLoc getCodeLoc(const ParserRuleContext *ctx) { return CodeLoc(ctx->start, filePath); } + ALWAYS_INLINE CodeLoc getCodeLoc(const ParserRuleContext *ctx) { + return {ctx->start, ctx->start->getStartIndex(), ctx->stop->getStopIndex(), sourceFile}; + } int32_t parseInt(ConstantNode *constantNode, TerminalNode *terminal); int16_t parseShort(ConstantNode *constantNode, TerminalNode *terminal); int64_t parseLong(ConstantNode *constantNode, TerminalNode *terminal); diff --git a/src/ast/ASTNodes.cpp b/src/ast/ASTNodes.cpp index ce02fc0b3..9df07511d 100644 --- a/src/ast/ASTNodes.cpp +++ b/src/ast/ASTNodes.cpp @@ -13,9 +13,8 @@ namespace spice::compiler { static constexpr size_t ERROR_MESSAGE_CONTEXT = 20; std::string ASTNode::getErrorMessage() const { - antlr4::CharStream *inputStream = codeLoc.token->getInputStream(); - const antlr4::misc::Interval sourceInterval(codeLoc.token->getStartIndex(), codeLoc.token->getStopIndex()); - antlr4::misc::Interval extSourceInterval(sourceInterval); + antlr4::CharStream *inputStream = codeLoc.sourceFile->antlrCtx.inputStream.get(); + antlr4::misc::Interval extSourceInterval(codeLoc.sourceInterval); // If we have a multi-line interval, only use the first line if (size_t offset = inputStream->getText(extSourceInterval).find('\n'); offset != std::string::npos) @@ -53,7 +52,8 @@ std::string ASTNode::getErrorMessage() const { // Build error message std::stringstream ss; ss << lineNumberStr << " " << inputStream->getText(extSourceInterval) << "\n"; - ss << std::string(markerIndentation, ' ') << std::string(std::min(sourceInterval.length(), extSourceInterval.length()), '^'); + ss << std::string(markerIndentation, ' '); + ss << std::string(std::min(codeLoc.sourceInterval.length(), extSourceInterval.length()), '^'); return ss.str(); } diff --git a/src/exception/AntlrThrowingErrorListener.cpp b/src/exception/AntlrThrowingErrorListener.cpp index af7e21ad6..15805b9c6 100644 --- a/src/exception/AntlrThrowingErrorListener.cpp +++ b/src/exception/AntlrThrowingErrorListener.cpp @@ -10,7 +10,7 @@ namespace spice::compiler { void AntlrThrowingErrorListener::syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *offendingSymbol, size_t line, size_t charPositionInLine, const std::string &msg, std::exception_ptr e) { - const CodeLoc codeLoc(line, charPositionInLine, filePath); + const CodeLoc codeLoc(line, charPositionInLine, sourceFile); if (mode == ThrowingErrorListenerMode::LEXER) throw LexerError(codeLoc, TOKENIZING_FAILED, msg); else diff --git a/src/exception/AntlrThrowingErrorListener.h b/src/exception/AntlrThrowingErrorListener.h index b201af29b..f19a8c7c5 100644 --- a/src/exception/AntlrThrowingErrorListener.h +++ b/src/exception/AntlrThrowingErrorListener.h @@ -9,7 +9,10 @@ namespace spice::compiler { -enum class ThrowingErrorListenerMode { +// Forward declarations +class SourceFile; + +enum class ThrowingErrorListenerMode : uint8_t { LEXER, PARSER, }; @@ -17,8 +20,7 @@ enum class ThrowingErrorListenerMode { class AntlrThrowingErrorListener : public antlr4::BaseErrorListener { public: // Constructors - AntlrThrowingErrorListener(ThrowingErrorListenerMode mode, std::filesystem::path filePath) - : mode(mode), filePath(std::move(filePath)){}; + AntlrThrowingErrorListener(ThrowingErrorListenerMode mode, SourceFile *sourceFile) : mode(mode), sourceFile(sourceFile){}; // Public methods void syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *offendingSymbol, size_t line, size_t charPositionInLine, @@ -27,7 +29,7 @@ class AntlrThrowingErrorListener : public antlr4::BaseErrorListener { private: // Private members ThrowingErrorListenerMode mode; - std::filesystem::path filePath; + SourceFile *sourceFile; }; } // namespace spice::compiler \ No newline at end of file diff --git a/src/exception/SemanticError.cpp b/src/exception/SemanticError.cpp index fbae12084..23c8e0bcc 100644 --- a/src/exception/SemanticError.cpp +++ b/src/exception/SemanticError.cpp @@ -7,13 +7,14 @@ namespace spice::compiler { -SemanticError::SemanticError(const ASTNode *node, const SemanticErrorType &type, const std::string &msg) { +SemanticError::SemanticError(const ASTNode *node, const SemanticErrorType &type, const std::string &msg, bool printErrorMessage) { assert(node != nullptr); errorMessage = "[Error|Semantic] " + node->codeLoc.toPrettyString() + ":\n"; errorMessage += getMessagePrefix(type) + ": " + msg; - const std::string nodeErrorMessage = node->getErrorMessage(); - if (!nodeErrorMessage.empty()) + if (printErrorMessage) { + const std::string nodeErrorMessage = node->getErrorMessage(); errorMessage += "\n\n" + nodeErrorMessage; + } } /** diff --git a/src/exception/SemanticError.h b/src/exception/SemanticError.h index 74b5be807..7259914d8 100644 --- a/src/exception/SemanticError.h +++ b/src/exception/SemanticError.h @@ -117,7 +117,7 @@ enum SemanticErrorType : uint8_t { class SemanticError : public std::exception { public: // Constructors - SemanticError(const ASTNode *node, const SemanticErrorType &type, const std::string &message); + SemanticError(const ASTNode *node, const SemanticErrorType &type, const std::string &message, bool printErrorMessage = true); // Public methods [[nodiscard]] const char *what() const noexcept override; diff --git a/src/symboltablebuilder/SymbolTableBuilder.cpp b/src/symboltablebuilder/SymbolTableBuilder.cpp index 0340c5d40..18ffd9c3a 100644 --- a/src/symboltablebuilder/SymbolTableBuilder.cpp +++ b/src/symboltablebuilder/SymbolTableBuilder.cpp @@ -23,7 +23,7 @@ std::any SymbolTableBuilder::visitEntry(EntryNode *node) { // Check if the main function exists if (sourceFile->mainFile && !cliOptions.noEntryFct && !hasMainFunction) - throw SemanticError(node, MISSING_MAIN_FUNCTION, "No main function found"); + throw SemanticError(node, MISSING_MAIN_FUNCTION, "No main function found", false); return nullptr; } diff --git a/src/typechecker/TypeChecker.cpp b/src/typechecker/TypeChecker.cpp index 8026664d7..7d5f8be6b 100644 --- a/src/typechecker/TypeChecker.cpp +++ b/src/typechecker/TypeChecker.cpp @@ -2349,7 +2349,9 @@ std::any TypeChecker::visitCustomDataType(CustomDataTypeNode *node) { if (entryType.is(TY_STRUCT)) { // Check if struct is defined before the current code location, if defined in the same source file - if (entry->declNode->codeLoc.sourceFilePath == node->codeLoc.sourceFilePath && entry->declNode->codeLoc > node->codeLoc) + const CodeLoc &declCodeLoc = entry->declNode->codeLoc; + const CodeLoc &codeLoc = node->codeLoc; + if (declCodeLoc.sourceFile->filePath == codeLoc.sourceFile->filePath && declCodeLoc > codeLoc) SOFT_ERROR_ST(node, REFERENCED_UNDEFINED_STRUCT, "Structs must be defined before usage") if (allTemplateTypesConcrete || !isParamOrFieldOrReturnType) { // Only do the next step, if we have concrete template types diff --git a/src/util/CodeLoc.cpp b/src/util/CodeLoc.cpp index a979300f1..6906c3cb8 100644 --- a/src/util/CodeLoc.cpp +++ b/src/util/CodeLoc.cpp @@ -2,6 +2,7 @@ #include "CodeLoc.h" +#include "SourceFile.h" #include #include @@ -21,6 +22,7 @@ std::string CodeLoc::toString() const { return "L" + std::to_string(line) + "C" * @return Pretty code location */ std::string CodeLoc::toPrettyString() const { + const std::filesystem::path &sourceFilePath = sourceFile->filePath; const std::string prefix = sourceFilePath.empty() ? "" : sourceFilePath.generic_string() + ":"; return prefix + std::to_string(line) + ":" + std::to_string(col); } @@ -39,4 +41,8 @@ std::string CodeLoc::toPrettyLine() const { return "L" + std::to_string(line); } */ std::string CodeLoc::toPrettyLineAndColumn() const { return toString(); } +bool operator==(const CodeLoc &a, const CodeLoc &b) { + return a.sourceFile->filePath == b.sourceFile->filePath && a.line == b.line && a.col == b.col; +} + } // namespace spice::compiler \ No newline at end of file diff --git a/src/util/CodeLoc.h b/src/util/CodeLoc.h index 55dd6eeb6..99d636526 100644 --- a/src/util/CodeLoc.h +++ b/src/util/CodeLoc.h @@ -13,18 +13,23 @@ namespace spice::compiler { +// Forward declarations +class SourceFile; + struct CodeLoc { public: // Constructors - CodeLoc(size_t line, size_t col, std::filesystem::path sourceFilePath = "") - : line(line), col(col), sourceFilePath(std::move(sourceFilePath)) {} - explicit CodeLoc(const antlr4::Token *token, std::filesystem::path sourceFilePath = "") - : token(token), line(token->getLine()), col(token->getCharPositionInLine() + 1), - sourceFilePath(std::move(sourceFilePath)){}; + explicit CodeLoc(const antlr4::Token *token, SourceFile *sourceFile = nullptr) + : sourceInterval(token->getStartIndex(), token->getStopIndex()), line(token->getLine()), + col(token->getCharPositionInLine() + 1), sourceFile(sourceFile){}; + CodeLoc(const antlr4::Token *token, size_t startIdx, size_t stopIdx, SourceFile *sourceFile = nullptr) + : sourceInterval(startIdx, stopIdx), line(token->getLine()), col(token->getCharPositionInLine() + 1), + sourceFile(sourceFile){}; + CodeLoc(size_t line, size_t col, SourceFile *sourceFile = nullptr) : line(line), col(col), sourceFile(sourceFile) {} // Public members - const antlr4::Token *token = nullptr; - std::filesystem::path sourceFilePath; + SourceFile *sourceFile = nullptr; + const antlr4::misc::Interval sourceInterval; size_t line; size_t col; @@ -35,9 +40,7 @@ struct CodeLoc { [[nodiscard]] std::string toPrettyLineAndColumn() const; // Operators - ALWAYS_INLINE friend bool operator==(const CodeLoc &a, const CodeLoc &b) { - return a.sourceFilePath == b.sourceFilePath && a.line == b.line && a.col == b.col; - } + friend bool operator==(const CodeLoc &a, const CodeLoc &b); ALWAYS_INLINE friend bool operator<(const CodeLoc &a, const CodeLoc &b) { return a.line == b.line ? a.col < b.col : a.line < b.line; }