From cd3fa8b6e4225f5c3cf51ddd3d545a76b5528d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Sat, 5 Jul 2025 09:36:12 +0900 Subject: [PATCH 1/7] Handle null types --- src/Compiler/ModuleBuilder.cpp | 3 +++ src/Logger.cpp | 5 +++++ src/Parser/Expression/ExpressionBinary.cpp | 14 ++++++++------ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Compiler/ModuleBuilder.cpp b/src/Compiler/ModuleBuilder.cpp index eaebd4b..ecc9281 100644 --- a/src/Compiler/ModuleBuilder.cpp +++ b/src/Compiler/ModuleBuilder.cpp @@ -228,6 +228,9 @@ llvm::Value *ModuleBuilder::valueForExpression(shared_ptr expression } llvm::Value *ModuleBuilder::valueForLiteral(shared_ptr expression) { + if (expression->getValueType() == nullptr) + return llvm::UndefValue::get(typeVoid); + switch (expression->getValueType()->getKind()) { case ValueTypeKind::NONE: return llvm::UndefValue::get(typeVoid); diff --git a/src/Logger.cpp b/src/Logger.cpp index f2d7727..f4617f1 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -367,6 +367,9 @@ string Logger::toString(shared_ptr expression) { } string Logger::toString(shared_ptr expression) { + if (expression->getValueType() == nullptr) + return "?"; + switch (expression->getValueType()->getKind()) { case ValueTypeKind::NONE: return "NONE"; @@ -392,6 +395,8 @@ string Logger::toString(shared_ptr expression) { string Logger::toString(shared_ptr expression) { string text; text += toString(expression->getStatementBlock()); + if (!text.empty()) + text += '\n'; if (expression->getResultStatementExpression() != nullptr) text += toString(expression->getResultStatementExpression()); return text; diff --git a/src/Parser/Expression/ExpressionBinary.cpp b/src/Parser/Expression/ExpressionBinary.cpp index aa162fe..4530801 100644 --- a/src/Parser/Expression/ExpressionBinary.cpp +++ b/src/Parser/Expression/ExpressionBinary.cpp @@ -54,13 +54,15 @@ Expression(ExpressionKind::BINARY, nullptr), operation(ExpressionBinaryOperation break; } - // Types must match - if (left->getValueType() != right->getValueType()) - valueType = ValueType::NONE; + if (left->getValueType() != nullptr && right->getValueType() != nullptr) { + // Types must match + if (left->getValueType() != right->getValueType()) + valueType = ValueType::NONE; - // Booleans can only do = or != - if (valueType->getKind() == ValueTypeKind::BOOL && (token->getKind() != TokenKind::EQUAL || token->getKind() != TokenKind::NOT_EQUAL)) - valueType = ValueType::NONE; + // Booleans can only do = or != + if (valueType->getKind() == ValueTypeKind::BOOL && (token->getKind() != TokenKind::EQUAL || token->getKind() != TokenKind::NOT_EQUAL)) + valueType = ValueType::NONE; + } } ExpressionBinaryOperation ExpressionBinary::getOperation() { From 2e0015c9bef63f038c58543f27502b2fd1d7b399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Sat, 5 Jul 2025 10:38:25 +0900 Subject: [PATCH 2/7] Added test app --- .gitignore | 1 - apps/fib.brc | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 apps/fib.brc diff --git a/.gitignore b/.gitignore index 57b7346..0f82e52 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ brb .vscode/settings.json *.dSYM -*.brc build/ \ No newline at end of file diff --git a/apps/fib.brc b/apps/fib.brc new file mode 100644 index 0000000..6993ecf --- /dev/null +++ b/apps/fib.brc @@ -0,0 +1,34 @@ +@extern putchar fun: character sint32 -> sint32 + +fib fun: number sint32 -> sint32 + ret if number < 2: + number + else + fib(number - 1) + fib(number - 2) + ; +; + +printNum fun: number sint32 + biggest sint32 <- 10 + rep biggest <= number: biggest <- biggest * 10 + biggest <- biggest / 10 + + rep biggest > 0: + digit sint32 <- number / biggest + putchar(digit + '0') + number <- number % biggest + biggest <- biggest / 10 + ; +; + +// Print 20 first fibonacci numbers +main fun -> sint32 + rep i sint32 <- 0, i < 20: + res sint32 <- fib(i) + printNum(res) + putchar('\n') + i <- i + 1 + ; + + ret 0 +; \ No newline at end of file From da1b5852ff8f3a656fd4a688884578518364ae85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Sat, 5 Jul 2025 18:42:58 +0900 Subject: [PATCH 3/7] Added scopes --- {apps => samples}/fib.brc | 2 +- src/Compiler/ModuleBuilder.cpp | 83 +++++++++++++++++++++++++++++----- src/Compiler/ModuleBuilder.h | 15 +++++- 3 files changed, 85 insertions(+), 15 deletions(-) rename {apps => samples}/fib.brc (94%) diff --git a/apps/fib.brc b/samples/fib.brc similarity index 94% rename from apps/fib.brc rename to samples/fib.brc index 6993ecf..11fd516 100644 --- a/apps/fib.brc +++ b/samples/fib.brc @@ -21,7 +21,7 @@ printNum fun: number sint32 ; ; -// Print 20 first fibonacci numbers +// Print first 20 fibonaci numbers main fun -> sint32 rep i sint32 <- 0, i < 20: res sint32 <- fib(i) diff --git a/src/Compiler/ModuleBuilder.cpp b/src/Compiler/ModuleBuilder.cpp index ecc9281..4e94401 100644 --- a/src/Compiler/ModuleBuilder.cpp +++ b/src/Compiler/ModuleBuilder.cpp @@ -33,9 +33,9 @@ moduleName(moduleName), sourceFileName(sourceFileName), statements(statements) { } shared_ptr ModuleBuilder::getModule() { - for (shared_ptr &statement : statements) { + scopes.push(Scope()); + for (shared_ptr &statement : statements) buildStatement(statement); - } return module; } @@ -80,12 +80,15 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state // build function declaration llvm::FunctionType *funType = llvm::FunctionType::get(typeForValueType(statement->getReturnValueType()), types, false); llvm::Function *fun = llvm::Function::Create(funType, llvm::GlobalValue::ExternalLinkage, statement->getName(), module.get()); - funMap[statement->getName()] = fun; + if (!setFun(statement->getName(), fun)) + return; // define function body llvm::BasicBlock *block = llvm::BasicBlock::Create(*context, statement->getName(), fun); builder->SetInsertPoint(block); + scopes.push(Scope()); + // build arguments int i=0; for (auto &arg : fun->args()) { @@ -94,7 +97,8 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state arg.setName(name); llvm::AllocaInst *alloca = builder->CreateAlloca(type, nullptr, name); - allocaMap[name] = alloca; + if (!setAlloca(name, alloca)) + return; builder->CreateStore(&arg, alloca); i++; @@ -103,6 +107,8 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state // build function body buildStatement(statement->getStatementBlock()); + scopes.pop(); + // verify string errorMessage; llvm::raw_string_ostream llvmErrorMessage(errorMessage); @@ -113,14 +119,16 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state void ModuleBuilder::buildVarDeclaration(shared_ptr statement) { llvm::Value *value = valueForExpression(statement->getExpression()); llvm::AllocaInst *alloca = builder->CreateAlloca(typeForValueType(statement->getValueType()), nullptr, statement->getName()); - allocaMap[statement->getName()] = alloca; + + if (!setAlloca(statement->getName(), alloca)) + return; builder->CreateStore(value, alloca); } void ModuleBuilder::buildAssignment(shared_ptr statement) { - llvm::AllocaInst *alloca = allocaMap[statement->getName()]; + llvm::AllocaInst *alloca = getAlloca(statement->getName()); if (alloca == nullptr) - failWithMessage("Variable " + statement->getName() + " not defined"); + return; llvm::Value *value = valueForExpression(statement->getExpression()); builder->CreateStore(value, alloca); @@ -151,6 +159,8 @@ void ModuleBuilder::buildLoop(shared_ptr statement) { llvm::BasicBlock *bodyBlock = llvm::BasicBlock::Create(*context, "loopBody"); llvm::BasicBlock *afterBlock = llvm::BasicBlock::Create(*context, "loopPost"); + scopes.push(Scope()); + // loop init if (initStatement != nullptr) buildStatement(statement->getInitStatement()); @@ -181,6 +191,8 @@ void ModuleBuilder::buildLoop(shared_ptr statement) { // loop post fun->insert(fun->end(), afterBlock); builder->SetInsertPoint(afterBlock); + + scopes.pop(); } void ModuleBuilder::buildMetaExternFunction(shared_ptr statement) { @@ -193,7 +205,8 @@ void ModuleBuilder::buildMetaExternFunction(shared_ptrgetReturnValueType()), types, false); llvm::Function *fun = llvm::Function::Create(funType, llvm::GlobalValue::ExternalLinkage, statement->getName(), module.get()); - funMap[statement->getName()] = fun; + if (!setFun(statement->getName(), fun)) + return; // build arguments int i=0; @@ -343,13 +356,16 @@ llvm::Value *ModuleBuilder::valueForIfElse(shared_ptr expressi builder->CreateCondBr(conditionValue, thenBlock, elseBlock); // Then + scopes.push(Scope()); builder->SetInsertPoint(thenBlock); buildStatement(expression->getThenBlock()->getStatementBlock()); llvm::Value *thenValue = valueForExpression(expression->getThenBlock()->getResultStatementExpression()->getExpression()); builder->CreateBr(mergeBlock); thenBlock = builder->GetInsertBlock(); + scopes.pop(); // Else + scopes.push(Scope()); fun->insert(fun->end(), elseBlock); builder->SetInsertPoint(elseBlock); llvm::Value *elseValue = nullptr; @@ -360,6 +376,7 @@ llvm::Value *ModuleBuilder::valueForIfElse(shared_ptr expressi } builder->CreateBr(mergeBlock); elseBlock = builder->GetInsertBlock(); + scopes.pop(); // Merge fun->insert(fun->end(), mergeBlock); @@ -378,17 +395,17 @@ llvm::Value *ModuleBuilder::valueForIfElse(shared_ptr expressi } llvm::Value *ModuleBuilder::valueForVar(shared_ptr expression) { - llvm::AllocaInst *alloca = allocaMap[expression->getName()]; + llvm::AllocaInst *alloca = getAlloca(expression->getName()); if (alloca == nullptr) - failWithMessage("Variable " + expression->getName() + " not defined"); + return nullptr; return builder->CreateLoad(alloca->getAllocatedType(), alloca, expression->getName()); } llvm::Value *ModuleBuilder::valueForCall(shared_ptr expression) { - llvm::Function *fun = funMap[expression->getName()]; + llvm::Function *fun = getFun(expression->getName()); if (fun == nullptr) - failWithMessage("Function " + expression->getName() + " not defined"); + return nullptr; llvm::FunctionType *funType = fun->getFunctionType(); vector argValues; for (shared_ptr &argumentExpression : expression->getArgumentExpressions()) { @@ -398,6 +415,48 @@ llvm::Value *ModuleBuilder::valueForCall(shared_ptr expression) return builder->CreateCall(funType, fun, llvm::ArrayRef(argValues)); } +bool ModuleBuilder::setAlloca(string name, llvm::AllocaInst *alloca) { + if (scopes.top().allocaMap[name] != nullptr) + return false; + + scopes.top().allocaMap[name] = alloca; + return true; +} + +llvm::AllocaInst* ModuleBuilder::getAlloca(string name) { + stack scopes = this->scopes; + + while (!scopes.empty()) { + llvm::AllocaInst *alloca = scopes.top().allocaMap[name]; + if (alloca != nullptr) + return alloca; + scopes.pop(); + } + + return nullptr; +} + +bool ModuleBuilder::setFun(string name, llvm::Function *fun) { + if (scopes.top().funMap[name] != nullptr) + return false; + + scopes.top().funMap[name] = fun; + return true; +} + +llvm::Function* ModuleBuilder::getFun(string name) { + stack scopes = this->scopes; + + while (!scopes.empty()) { + llvm::Function *fun = scopes.top().funMap[name]; + if (fun != nullptr) + return fun; + scopes.pop(); + } + + return nullptr; +} + llvm::Type *ModuleBuilder::typeForValueType(shared_ptr valueType) { switch (valueType->getKind()) { case ValueTypeKind::NONE: diff --git a/src/Compiler/ModuleBuilder.h b/src/Compiler/ModuleBuilder.h index 1850951..fc75511 100644 --- a/src/Compiler/ModuleBuilder.h +++ b/src/Compiler/ModuleBuilder.h @@ -2,6 +2,7 @@ #define MODULE_BUILDER_H #include +#include #include #include @@ -33,6 +34,11 @@ class StatementBlock; using namespace std; +typedef struct { + map allocaMap; + map funMap; +} Scope; + class ModuleBuilder { private: string moduleName; @@ -48,8 +54,7 @@ private: llvm::Type *typeReal32; vector> statements; - map allocaMap; - map funMap; + stack scopes; void buildStatement(shared_ptr statement); void buildFunctionDeclaration(shared_ptr statement); @@ -72,6 +77,12 @@ private: llvm::Value *valueForVar(shared_ptr expression); llvm::Value *valueForCall(shared_ptr expression); + bool setAlloca(string name, llvm::AllocaInst *alloca); + llvm::AllocaInst *getAlloca(string name); + + bool setFun(string name, llvm::Function *fun); + llvm::Function *getFun(string name); + llvm::Type *typeForValueType(shared_ptr valueType); void failWithMessage(string message); From 1e7ecaf801961caabec813fc8b624f0b7a61c679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Sat, 5 Jul 2025 20:29:29 +0900 Subject: [PATCH 4/7] Handle empty call --- src/Parser/Parser.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 402f882..521ff88 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -501,19 +501,21 @@ shared_ptr Parser::matchExpressionCall() { currentIndex++; // left parenthesis vector> argumentExpressions; - do { - tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line - - shared_ptr argumentExpression = nextExpression(); - if (argumentExpression == nullptr) - return nullptr; - argumentExpressions.push_back(argumentExpression); - } while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)); - - tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line if (!tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) { - markError(TokenKind::RIGHT_PAREN, {}); - return nullptr; + do { + tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line + + shared_ptr argumentExpression = nextExpression(); + if (argumentExpression == nullptr) + return nullptr; + argumentExpressions.push_back(argumentExpression); + } while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true)); + + tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // optional new line + if (!tryMatchingTokenKinds({TokenKind::RIGHT_PAREN}, true, true)) { + markError(TokenKind::RIGHT_PAREN, {}); + return nullptr; + } } return make_shared(identifierToken->getLexme(), argumentExpressions); From 48f27169d0f4cf6f3fc8873c4075a11b8a3c792f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Sat, 5 Jul 2025 21:58:11 +0900 Subject: [PATCH 5/7] Added builder error --- src/Compiler/ModuleBuilder.cpp | 5 +++++ src/Compiler/ModuleBuilder.h | 4 ++++ src/Error.cpp | 10 +++++++++- src/Error.h | 10 +++++++--- src/Logger.cpp | 17 ++++++++++++----- src/Parser/Parser.h | 2 +- 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/Compiler/ModuleBuilder.cpp b/src/Compiler/ModuleBuilder.cpp index 4e94401..d8f0710 100644 --- a/src/Compiler/ModuleBuilder.cpp +++ b/src/Compiler/ModuleBuilder.cpp @@ -1,5 +1,6 @@ #include "ModuleBuilder.h" +#include "Error.h" #include "Parser/ValueType.h" #include "Parser/Expression/ExpressionGrouping.h" @@ -474,3 +475,7 @@ void ModuleBuilder::failWithMessage(string message) { cerr << "Error! Building module \"" << moduleName << "\" from \"" + sourceFileName + "\" failed:" << endl << message << endl; exit(1); } + +void ModuleBuilder::markError(int line, int column, string message) { + errors.push_back(Error::builderError(line, column, message)); +} diff --git a/src/Compiler/ModuleBuilder.h b/src/Compiler/ModuleBuilder.h index fc75511..2148c2e 100644 --- a/src/Compiler/ModuleBuilder.h +++ b/src/Compiler/ModuleBuilder.h @@ -11,6 +11,7 @@ #include #include +class Error; class ValueType; class Expression; @@ -41,6 +42,7 @@ typedef struct { class ModuleBuilder { private: + vector> errors; string moduleName; string sourceFileName; @@ -86,6 +88,8 @@ private: llvm::Type *typeForValueType(shared_ptr valueType); void failWithMessage(string message); + void markError(int line, int column, string message); + public: ModuleBuilder(string moduleName, string sourceFileName, vector> statements); shared_ptr getModule(); diff --git a/src/Error.cpp b/src/Error.cpp index a4f5b06..3a2f5a5 100644 --- a/src/Error.cpp +++ b/src/Error.cpp @@ -1,11 +1,19 @@ #include "Error.h" +shared_ptr Error::builderError(int line, int column, string message) { + Error e = Error(ErrorKind::BUILDER_ERROR, line, column, {}, nullptr, {}, message); + return nullptr; +} + Error::Error(int line, int column, string lexme) : kind(ErrorKind::LEXER_ERROR), line(line), column(column), lexme(lexme) { } Error::Error(shared_ptr actualToken, optional expectedTokenKind, optional message) : kind(ErrorKind::PARSER_ERROR), actualToken(actualToken), expectedTokenKind(expectedTokenKind), message(message) { } +Error::Error(ErrorKind kind, int line, int column, optional lexme, shared_ptr actualToken, optional expectedTokenKind, optional message): +kind(kind), line(line), column(column), lexme(lexme), actualToken(actualToken), expectedTokenKind(expectedTokenKind), message(message) { } + ErrorKind Error::getKind() { return kind; } @@ -18,7 +26,7 @@ int Error::getColumn() { return column; } -string Error::getLexme() { +optional Error::getLexme() { return lexme; } diff --git a/src/Error.h b/src/Error.h index 97dc968..204562f 100644 --- a/src/Error.h +++ b/src/Error.h @@ -10,7 +10,8 @@ using namespace std; enum class ErrorKind { LEXER_ERROR, - PARSER_ERROR + PARSER_ERROR, + BUILDER_ERROR }; class Error { @@ -19,21 +20,24 @@ private: int line; int column; - string lexme; + optional lexme; shared_ptr actualToken; optional expectedTokenKind; optional message; public: + static shared_ptr builderError(int line, int column, string message); + Error(int line, int column, string lexme); Error(shared_ptr actualToken, optional expectedTokenKind, optional message); + Error(ErrorKind kind, int line, int column, optional lexme, shared_ptr actualToken, optional expectedTokenKind, optional message); ErrorKind getKind(); int getLine(); int getColumn(); - string getLexme(); + optional getLexme(); shared_ptr getActualToken(); optional getExpectedTokenKind(); diff --git a/src/Logger.cpp b/src/Logger.cpp index f4617f1..4863089 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -2,6 +2,8 @@ #include +#include "Error.h" + #include "Lexer/Token.h" #include "Parser/ValueType.h" @@ -24,8 +26,6 @@ #include "Parser/Expression/ExpressionCall.h" #include "Parser/Expression/ExpressionBlock.h" -#include "Error.h" - string Logger::toString(shared_ptr token) { switch (token->getKind()) { case TokenKind::PLUS: @@ -421,10 +421,12 @@ void Logger::print(vector> statements) { void Logger::print(shared_ptr error) { string message; switch (error->getKind()) { - case ErrorKind::LEXER_ERROR: - message = format("Unexpected token \"{}\" at line: {}, column: {}", error->getLexme(), error->getLine() + 1, error->getColumn() + 1); + case ErrorKind::LEXER_ERROR: { + string lexme = error->getLexme() ? *(error->getLexme()) : ""; + message = format("Unexpected token \"{}\" at line: {}, column: {}", lexme, error->getLine() + 1, error->getColumn() + 1); break; - case ErrorKind::PARSER_ERROR: + } + case ErrorKind::PARSER_ERROR: { shared_ptr token = error->getActualToken(); optional expectedTokenKind = error->getExpectedTokenKind(); optional errorMessage = error->getMessage(); @@ -443,6 +445,11 @@ void Logger::print(shared_ptr error) { if (errorMessage) message += format(". {}", *errorMessage); break; + } + case ErrorKind::BUILDER_ERROR: { + message = ""; + break; + } } cout << message << endl; } \ No newline at end of file diff --git a/src/Parser/Parser.h b/src/Parser/Parser.h index 1d6533c..79dddee 100644 --- a/src/Parser/Parser.h +++ b/src/Parser/Parser.h @@ -14,9 +14,9 @@ using namespace std; class Parser { private: + vector> errors; vector> tokens; int currentIndex = 0; - vector> errors; shared_ptr nextStatement(); shared_ptr nextInBlockStatement(); From d927540b5f1633c61347dd0c06e087c82fcefd87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Sat, 5 Jul 2025 22:50:16 +0900 Subject: [PATCH 6/7] Fixed up errors --- src/Error.cpp | 39 ++++++++++++++++++++++++++++++++------- src/Error.h | 4 ++-- src/Lexer/Lexer.cpp | 5 +++-- src/Parser/Parser.cpp | 2 +- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Error.cpp b/src/Error.cpp index 3a2f5a5..3078e95 100644 --- a/src/Error.cpp +++ b/src/Error.cpp @@ -1,15 +1,40 @@ #include "Error.h" -shared_ptr Error::builderError(int line, int column, string message) { - Error e = Error(ErrorKind::BUILDER_ERROR, line, column, {}, nullptr, {}, message); - return nullptr; +shared_ptr Error::lexerError(int line, int column, string lexme) { + return make_shared( + ErrorKind::LEXER_ERROR, + line, + column, + lexme, + nullptr, + optional(), + optional() + ); } -Error::Error(int line, int column, string lexme) : -kind(ErrorKind::LEXER_ERROR), line(line), column(column), lexme(lexme) { } +shared_ptr Error::parserError(shared_ptr actualToken, optional expectedTokenKind, optional message) { + return make_shared( + ErrorKind::PARSER_ERROR, + 0, + 0, + optional(), + actualToken, + expectedTokenKind, + message + ); +} -Error::Error(shared_ptr actualToken, optional expectedTokenKind, optional message) : -kind(ErrorKind::PARSER_ERROR), actualToken(actualToken), expectedTokenKind(expectedTokenKind), message(message) { } +shared_ptr Error::builderError(int line, int column, string message) { + return make_shared( + ErrorKind::BUILDER_ERROR, + line, + column, + optional(), + nullptr, + optional(), + message + ); +} Error::Error(ErrorKind kind, int line, int column, optional lexme, shared_ptr actualToken, optional expectedTokenKind, optional message): kind(kind), line(line), column(column), lexme(lexme), actualToken(actualToken), expectedTokenKind(expectedTokenKind), message(message) { } diff --git a/src/Error.h b/src/Error.h index 204562f..4e83c68 100644 --- a/src/Error.h +++ b/src/Error.h @@ -27,10 +27,10 @@ private: optional message; public: + static shared_ptr lexerError(int line, int column, string lexme); + static shared_ptr parserError(shared_ptr actualToken, optional expectedTokenKind, optional message); static shared_ptr builderError(int line, int column, string message); - Error(int line, int column, string lexme); - Error(shared_ptr actualToken, optional expectedTokenKind, optional message); Error(ErrorKind kind, int line, int column, optional lexme, shared_ptr actualToken, optional expectedTokenKind, optional message); ErrorKind getKind(); diff --git a/src/Lexer/Lexer.cpp b/src/Lexer/Lexer.cpp index e90acb5..8d4ec3a 100644 --- a/src/Lexer/Lexer.cpp +++ b/src/Lexer/Lexer.cpp @@ -1,9 +1,10 @@ #include "Lexer.h" -#include "Token.h" #include "Error.h" #include "Logger.h" +#include "Token.h" + Lexer::Lexer(string source): source(source) { } @@ -506,5 +507,5 @@ void Lexer::markError() { } else { lexme = "EOF"; } - errors.push_back(make_shared(currentLine, startColumn, lexme)); + errors.push_back(Error::lexerError(currentLine, startColumn, lexme)); } diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 521ff88..979b15c 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -655,5 +655,5 @@ void Parser::markError(optional expectedTokenKind, optional m while (!tryMatchingTokenKinds(safeKinds, false, true)) currentIndex++; - errors.push_back(make_shared(actualToken, expectedTokenKind, message)); + errors.push_back(Error::parserError(actualToken, expectedTokenKind, message)); } From d81f82c81858171702f031d672421acfbd149171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Grodzi=C5=84ski?= Date: Sat, 5 Jul 2025 23:10:52 +0900 Subject: [PATCH 7/7] Handle errors through logger and error class in module builder --- src/Compiler/ModuleBuilder.cpp | 36 ++++++++++++++++++++++------------ src/Compiler/ModuleBuilder.h | 1 - src/Logger.cpp | 3 ++- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/Compiler/ModuleBuilder.cpp b/src/Compiler/ModuleBuilder.cpp index d8f0710..5777fe5 100644 --- a/src/Compiler/ModuleBuilder.cpp +++ b/src/Compiler/ModuleBuilder.cpp @@ -1,6 +1,7 @@ #include "ModuleBuilder.h" #include "Error.h" +#include "Logger.h" #include "Parser/ValueType.h" #include "Parser/Expression/ExpressionGrouping.h" @@ -37,6 +38,13 @@ shared_ptr ModuleBuilder::getModule() { scopes.push(Scope()); for (shared_ptr &statement : statements) buildStatement(statement); + + if (!errors.empty()) { + for (shared_ptr &error : errors) + Logger::print(error); + exit(1); + } + return module; } @@ -67,7 +75,7 @@ void ModuleBuilder::buildStatement(shared_ptr statement) { buildExpression(dynamic_pointer_cast(statement)); return; default: - failWithMessage("Unexpected statement"); + markError(0, 0, "Unexpected statement"); } } @@ -114,7 +122,7 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr state string errorMessage; llvm::raw_string_ostream llvmErrorMessage(errorMessage); if (llvm::verifyFunction(*fun, &llvmErrorMessage)) - failWithMessage(errorMessage); + markError(0, 0, errorMessage); } void ModuleBuilder::buildVarDeclaration(shared_ptr statement) { @@ -237,7 +245,8 @@ llvm::Value *ModuleBuilder::valueForExpression(shared_ptr expression case ExpressionKind::CALL: return valueForCall(dynamic_pointer_cast(expression)); default: - failWithMessage("Unexpected expression"); + markError(0, 0, "Unexpected expression"); + return nullptr; } } @@ -275,7 +284,8 @@ llvm::Value *ModuleBuilder::valueForBinary(shared_ptr expressi return valueForBinaryReal(expression->getOperation(), leftValue, rightValue); } - failWithMessage("Unexpected operation"); + markError(0, 0, "Unexpected operation"); + return nullptr; } llvm::Value *ModuleBuilder::valueForBinaryBool(ExpressionBinaryOperation operation, llvm::Value *leftValue, llvm::Value *rightValue) { @@ -285,7 +295,8 @@ llvm::Value *ModuleBuilder::valueForBinaryBool(ExpressionBinaryOperation operati case ExpressionBinaryOperation::NOT_EQUAL: return builder->CreateICmpNE(leftValue, rightValue); default: - failWithMessage("Undefined operation for boolean operands"); + markError(0, 0, "Unexpecgted operation for boolean operands"); + return nullptr; } } @@ -417,8 +428,10 @@ llvm::Value *ModuleBuilder::valueForCall(shared_ptr expression) } bool ModuleBuilder::setAlloca(string name, llvm::AllocaInst *alloca) { - if (scopes.top().allocaMap[name] != nullptr) + if (scopes.top().allocaMap[name] != nullptr) { + markError(0, 0, format("Variable \"{}\" already defined", name)); return false; + } scopes.top().allocaMap[name] = alloca; return true; @@ -434,12 +447,15 @@ llvm::AllocaInst* ModuleBuilder::getAlloca(string name) { scopes.pop(); } + markError(0, 0, format("Variable \"{}\" not defined in scope", name)); return nullptr; } bool ModuleBuilder::setFun(string name, llvm::Function *fun) { - if (scopes.top().funMap[name] != nullptr) + if (scopes.top().funMap[name] != nullptr) { + markError(0, 0, format("Function \"{}\" already defined", name)); return false; + } scopes.top().funMap[name] = fun; return true; @@ -455,6 +471,7 @@ llvm::Function* ModuleBuilder::getFun(string name) { scopes.pop(); } + markError(0, 0, format("Function \"{}\" not defined in scope", name)); return nullptr; } @@ -471,11 +488,6 @@ llvm::Type *ModuleBuilder::typeForValueType(shared_ptr valueType) { } } -void ModuleBuilder::failWithMessage(string message) { - cerr << "Error! Building module \"" << moduleName << "\" from \"" + sourceFileName + "\" failed:" << endl << message << endl; - exit(1); -} - void ModuleBuilder::markError(int line, int column, string message) { errors.push_back(Error::builderError(line, column, message)); } diff --git a/src/Compiler/ModuleBuilder.h b/src/Compiler/ModuleBuilder.h index 2148c2e..ddc70df 100644 --- a/src/Compiler/ModuleBuilder.h +++ b/src/Compiler/ModuleBuilder.h @@ -86,7 +86,6 @@ private: llvm::Function *getFun(string name); llvm::Type *typeForValueType(shared_ptr valueType); - void failWithMessage(string message); void markError(int line, int column, string message); diff --git a/src/Logger.cpp b/src/Logger.cpp index 4863089..b776a35 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -447,7 +447,8 @@ void Logger::print(shared_ptr error) { break; } case ErrorKind::BUILDER_ERROR: { - message = ""; + string errorMessage = error->getMessage() ? *(error->getMessage()) : ""; + message = format("Error at line {}, column {}: {}", error->getLine(), error->getColumn(), errorMessage); break; } }