Skip to content
This repository was archived by the owner on Oct 12, 2026. It is now read-only.

Commit 464ebf1

Browse files
committed
BUG: Fix REPL exiting after reporting errors.
- Remove the Logger and migrate all logging to DiagnosticEmitter. - Refactor the diagnostics module to simplify the emission API and improve consistency. - Fix the REPL exiting after recoverable errors by resetting the diagnostic state after each interpretation. - Allow DiagnosticEmitter to throw ControlledExit for REPL error recovery, removing `noexcept` from methods that may emit diagnostics. Fixes #11 Ref #1
1 parent 0190ccb commit 464ebf1

16 files changed

Lines changed: 161 additions & 190 deletions

File tree

‎include/lbd/Context.hpp‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#pragma once
22

3-
#include <lbd/Logger.hpp>
43
#include <lbd/Options.hpp>
54
#include <lbd/diagnostics/DiagnosticEmitter.hpp>
65
#include <lbd/source/BufferManager.hpp>
@@ -18,14 +17,11 @@ namespace lbd
1817

1918
[[nodiscard]] Options &getOptions();
2019

21-
[[nodiscard]] Logger &getLogger();
22-
2320
/// Emits error upon unable to load the file.
2421
[[nodiscard]] source::BufferId loadFile(const std::string &path, const source::Range &range);
2522

2623
private:
2724
Options options;
28-
Logger logger;
2925
source::BufferManager bufferManager;
3026
diagnostics::DiagnosticRenderer diagnosticRenderer;
3127
diagnostics::DiagnosticEmitter diagnosticEmitter;

‎include/lbd/Logger.hpp‎

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <optional>
34
#include <vector>
45
#include <lbd/diagnostics/ContextFrame.hpp>
56
#include <lbd/diagnostics/Severity.hpp>
@@ -10,21 +11,21 @@ namespace lbd::diagnostics
1011
class Diagnostic
1112
{
1213
public:
13-
Diagnostic(Severity severity, const source::Range &range, std::string message,
14+
Diagnostic(Severity severity, const std::optional<source::Range> &range, std::string message,
1415
const std::vector<ContextFrame> &contextStack);
1516

16-
[[nodiscard]] Severity getSeverity() const;
17+
[[nodiscard]] Severity getSeverity() const noexcept { return m_severity; }
1718

18-
[[nodiscard]] source::Range getRange() const;
19+
[[nodiscard]] const std::optional<source::Range> &getRange() const noexcept { return m_range; }
1920

20-
[[nodiscard]] std::string_view getMessage() const;
21+
[[nodiscard]] std::string_view getMessage() const noexcept { return m_message; }
2122

22-
[[nodiscard]] const std::vector<ContextFrame> &getContextStack() const;
23+
[[nodiscard]] const std::vector<ContextFrame> &getContextStack() const noexcept { return m_contextStack; }
2324

2425
private:
25-
Severity severity;
26-
source::Range range;
27-
std::string message;
28-
std::vector<ContextFrame> contextStack;
26+
Severity m_severity;
27+
std::optional<source::Range> m_range;
28+
std::string m_message;
29+
std::vector<ContextFrame> m_contextStack;
2930
};
30-
}
31+
}

‎include/lbd/diagnostics/DiagnosticEmitter.hpp‎

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,67 @@ namespace lbd::diagnostics
1515
class DiagnosticEmitter
1616
{
1717
public:
18-
explicit DiagnosticEmitter(DiagnosticRenderer &diagnosticRenderer);
18+
DiagnosticEmitter(DiagnosticRenderer &diagnosticRenderer, bool exitOnError);
1919

2020
void pushContext(source::Range range, std::string message);
2121

2222
void popContext();
2323

24-
/// NOTE: Use this only to report errors caused by external systems (e.g. filesystem or I/O), not by language diagnostics.
25-
[[noreturn]] void error(const source::Range &range, const std::string &message) const noexcept;
24+
[[nodiscard]] bool shouldExitOnError() const noexcept { return m_exitOnError; }
2625

27-
template<typename... Args>
28-
[[noreturn]] void error(const source::Range &range, const DiagnosticId id, Args &&... args)
26+
void setExitOnError(const bool exitOnError) noexcept { m_exitOnError = exitOnError; }
27+
28+
// Message only.
29+
void info(const std::string_view message) const { emit(Severity::INFO, std::nullopt, message); }
30+
31+
void warning(const std::string_view message) const { emit(Severity::WARNING, std::nullopt, message); }
32+
33+
[[noreturn]] void error(const std::string_view message) const { emit(Severity::ERR, std::nullopt, message); }
34+
35+
// Range + message.
36+
void info(const std::optional<source::Range> &range, std::string_view message) const;
37+
38+
void warning(const std::optional<source::Range> &range, std::string_view message) const;
39+
40+
[[noreturn]] void error(const std::optional<source::Range> &range, std::string_view message) const;
41+
42+
// Range + DiagnosticId + format args.
43+
template<typename... Arguments>
44+
void info(const std::optional<source::Range> &range, DiagnosticId id, Arguments &&... args) const
2945
{
30-
fmt::dynamic_format_arg_store<fmt::format_context> store;
31-
(store.push_back(std::forward<Args>(args)), ...);
32-
emit(Severity::ERR, id, range, store);
33-
unreachable_impl();
46+
emitImpl(Severity::INFO, range, id, std::forward<Arguments>(args)...);
3447
}
3548

36-
template<typename... Args>
37-
[[noreturn]] void warning(const source::Range &range, const DiagnosticId id, Args &&... args)
49+
template<typename... Arguments>
50+
void warning(const std::optional<source::Range> &range, DiagnosticId id, Arguments &&... args) const
51+
{
52+
emitImpl(Severity::WARNING, range, id, std::forward<Arguments>(args)...);
53+
}
54+
55+
template<typename... Arguments>
56+
[[noreturn]] void error(const std::optional<source::Range> &range, DiagnosticId id, Arguments &&... args) const
57+
{
58+
emitImpl(Severity::ERR, range, id, std::forward<Arguments>(args)...);
59+
}
60+
61+
private:
62+
template<typename... Arguments>
63+
void emitImpl(const Severity severity, const std::optional<source::Range> &range, const DiagnosticId id,
64+
Arguments &&... arguments) const
3865
{
3966
fmt::dynamic_format_arg_store<fmt::format_context> store;
40-
(store.push_back(std::forward<Args>(args)), ...);
41-
emit(Severity::WARNING, id, range, store);
67+
(store.push_back(std::forward<Arguments>(arguments)), ...);
68+
69+
emit(severity, id, range, store);
4270
}
4371

44-
void emit(Severity severity, DiagnosticId id, const source::Range &range,
72+
void emit(Severity severity, DiagnosticId id, const std::optional<source::Range> &range,
4573
const fmt::dynamic_format_arg_store<fmt::format_context> &arguments) const;
4674

47-
void emit(Severity severity, const source::Range &range, const std::string &message) const noexcept;
75+
void emit(Severity severity, const std::optional<source::Range> &range, std::string_view message) const;
4876

49-
private:
5077
DiagnosticRenderer &diagnosticRenderer;
5178
std::vector<ContextFrame> contextStack;
79+
bool m_exitOnError;
5280
};
5381
}

‎include/lbd/diagnostics/Severity.hpp‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace lbd::diagnostics
99
{
1010
enum class Severity
1111
{
12+
INFO,
1213
ERR,
1314
WARNING,
1415
NOTE,
@@ -18,6 +19,7 @@ namespace lbd::diagnostics
1819
{
1920
switch (severity)
2021
{
22+
case Severity::INFO: return "INFO";
2123
case Severity::ERR: return "ERROR";
2224
case Severity::WARNING: return "WARNING";
2325
case Severity::NOTE: return "NOTE";
@@ -29,6 +31,7 @@ namespace lbd::diagnostics
2931
{
3032
switch (severity)
3133
{
34+
case Severity::INFO: return colors.blue;
3235
case Severity::ERR: return colors.red;
3336
case Severity::WARNING: return colors.yellow;
3437
case Severity::NOTE: return colors.blue;
@@ -37,4 +40,4 @@ namespace lbd::diagnostics
3740
}
3841

3942
std::ostream &operator<<(std::ostream &outputStream, const Severity &severity);
40-
}
43+
}

‎include/lbd/frontend/lexer/Lexer.hpp‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ namespace lbd::frontend::lexer
1212
public:
1313
[[nodiscard]] explicit Lexer(Context &context, const source::Buffer &buffer) noexcept;
1414

15-
[[nodiscard]] token::Token peek() noexcept;
15+
[[nodiscard]] token::Token peek();
1616

17-
[[nodiscard]] token::Token next() noexcept;
17+
[[nodiscard]] token::Token next();
1818

1919
void advance() noexcept;
2020

@@ -23,7 +23,7 @@ namespace lbd::frontend::lexer
2323
[[nodiscard]] const source::Buffer &getBuffer() const noexcept;
2424

2525
private:
26-
[[nodiscard]] token::Token lex() noexcept;
26+
[[nodiscard]] token::Token lex();
2727

2828
[[nodiscard]] char getCurrentCharacter() const noexcept;
2929

@@ -33,7 +33,7 @@ namespace lbd::frontend::lexer
3333

3434
void advanceCursor() noexcept;
3535

36-
[[nodiscard]] token::TokenKind symbolToTokenKind(char symbol) const noexcept;
36+
[[nodiscard]] token::TokenKind symbolToTokenKind(char symbol) const;
3737

3838
Context &context;
3939
const source::Buffer &buffer;
@@ -42,4 +42,4 @@ namespace lbd::frontend::lexer
4242
source::ColumnNumber column = 1;
4343
std::optional<token::Token> currentToken; // Peeked token.
4444
};
45-
}
45+
}

‎include/lbd/frontend/parser/Parser.hpp‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,42 +14,42 @@ namespace lbd::frontend::parser
1414
class Parser
1515
{
1616
public:
17-
[[nodiscard]] explicit Parser(Context &context, lexer::Lexer &lexer) noexcept;
17+
[[nodiscard]] explicit Parser(Context &context, lexer::Lexer &lexer);
1818

19-
[[nodiscard]] std::vector<ast::AstNodePtr> parse() const noexcept;
19+
[[nodiscard]] std::vector<ast::AstNodePtr> parse() const;
2020

2121
private:
22-
void expect(token::TokenKind kind) const noexcept;
22+
void expect(token::TokenKind kind) const;
2323

24-
void consume(token::TokenKind kind) const noexcept;
24+
void consume(token::TokenKind kind) const;
2525

2626
[[nodiscard]] std::vector<ast::AstNodePtr> parseFile(const std::string &path,
27-
const source::Range &range) const noexcept;
27+
const source::Range &range) const;
2828

29-
[[nodiscard]] ast::statement::StatementPtr parseSymbolDefinitionStatement() const noexcept;
29+
[[nodiscard]] ast::statement::StatementPtr parseSymbolDefinitionStatement() const;
3030

31-
[[nodiscard]] ast::expression::ExpressionPtr parseExpression() const noexcept;
31+
[[nodiscard]] ast::expression::ExpressionPtr parseExpression() const;
3232

33-
[[nodiscard]] ast::expression::ExpressionPtr parseLambdaExpression() const noexcept;
33+
[[nodiscard]] ast::expression::ExpressionPtr parseLambdaExpression() const;
3434

35-
[[nodiscard]] ast::expression::ExpressionPtr parseFunctionApplicationExpression() const noexcept;
35+
[[nodiscard]] ast::expression::ExpressionPtr parseFunctionApplicationExpression() const;
3636

37-
[[nodiscard]] ast::expression::IdentifierExpressionPtr parseIdentifierExpression() const noexcept;
37+
[[nodiscard]] ast::expression::IdentifierExpressionPtr parseIdentifierExpression() const;
3838

39-
[[nodiscard]] ast::expression::ExpressionPtr parseStringExpression() const noexcept;
39+
[[nodiscard]] ast::expression::ExpressionPtr parseStringExpression() const;
4040

41-
[[nodiscard]] ast::expression::ExpressionPtr parseNumberExpression() const noexcept;
41+
[[nodiscard]] ast::expression::ExpressionPtr parseNumberExpression() const;
4242

43-
[[nodiscard]] type::TypePtr parseType() const noexcept;
43+
[[nodiscard]] type::TypePtr parseType() const;
4444

4545
/// Tries to parse a qualified type, if failed fallbacks to parsing function type.
46-
[[nodiscard]] type::TypePtr parseQualifiedType() const noexcept;
46+
[[nodiscard]] type::TypePtr parseQualifiedType() const;
4747

48-
[[nodiscard]] type::TypePtr parseFunctionType() const noexcept;
48+
[[nodiscard]] type::TypePtr parseFunctionType() const;
4949

50-
[[nodiscard]] type::TypePtr parseAppliedType() const noexcept;
50+
[[nodiscard]] type::TypePtr parseAppliedType() const;
5151

52-
[[nodiscard]] type::TypePtr parsePrimaryType() const noexcept;
52+
[[nodiscard]] type::TypePtr parsePrimaryType() const;
5353

5454
Context &context;
5555
lexer::Lexer &lexer;

‎include/lbd/runtime/Interpreter.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ namespace lbd::runtime
155155
};
156156

157157
Result interpret(frontend::Program &program, Context &context,
158-
std::optional<std::shared_ptr<Environment>> globalEnvironment = std::nullopt) noexcept;
158+
std::optional<std::shared_ptr<Environment>> globalEnvironment = std::nullopt);
159159

160160
/// Add builtins Native Functions into Environment.
161161
void installBuiltins(Context &context, const std::shared_ptr<Environment> &environment);

‎src/Context.cpp‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@ namespace lbd
66
{
77
Context::Context(std::ostream &outputStream, const Options options)
88
: options(options), diagnosticRenderer(outputStream, bufferManager),
9-
diagnosticEmitter(diagnosticRenderer) {}
9+
diagnosticEmitter(diagnosticRenderer, true) {}
1010

1111
source::BufferManager &Context::getBufferManager() { return bufferManager; }
1212

1313
diagnostics::DiagnosticEmitter &Context::getDiagnosticEmitter() { return diagnosticEmitter; }
1414

1515
Options &Context::getOptions() { return options; }
1616

17-
Logger &Context::getLogger() { return logger; }
18-
1917
source::BufferId Context::loadFile(const std::string &path, const source::Range &range)
2018
{
2119
if (!std::filesystem::exists(path))

0 commit comments

Comments
 (0)