Skip to content

Commit 1d3d361

Browse files
authored
🐛 Handle unrecognized tokens. (#7)
Also add unit tests to cover this.
1 parent 29f781e commit 1d3d361

File tree

4 files changed

+33
-1
lines changed

4 files changed

+33
-1
lines changed

kalcy/include/kalcy/error.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ struct InternalError : Error {
2121
using Error::Error;
2222
};
2323

24+
///
25+
/// \brief Unrecognized token.
26+
///
27+
struct UnrecognizedToken : Error {
28+
explicit UnrecognizedToken(Token token);
29+
};
30+
2431
///
2532
/// \brief Parse error.
2633
///

kalcy/src/error.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ auto Error::build_highlight(char const higlight) const -> std::string {
1111
return ret.str();
1212
}
1313

14+
UnrecognizedToken::UnrecognizedToken(Token const token) : Error(token, std::format("unrecognized token: '{}'", token.lexeme)) {}
15+
1416
ParseError::ParseError(Token const token) : Error(token, "parse error") {}
1517

1618
ParseError::ParseError(Token const token, Token::Type const expected)

kalcy/src/scanner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <kalcy/error.hpp>
12
#include <kalcy/scanner.hpp>
23
#include <cassert>
34
#include <cctype>
@@ -28,7 +29,7 @@ auto Scanner::next() -> Token {
2829
if (match_number(out)) { return out; }
2930
if (match_identifier(out)) { return out; }
3031

31-
return {};
32+
throw UnrecognizedToken{make_token(Token::Type::eNone, {&m_text.front(), 1})};
3233
}
3334

3435
auto Scanner::match_single(Token& out) -> bool {

tests/tests/test_parser.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,28 @@ ADD_TEST(ParseErrorOnExtraneous) {
9797
EXPECT(did_throw);
9898
}
9999

100+
ADD_TEST(ParseErrorOnInvalidToken) {
101+
bool did_throw{};
102+
try {
103+
parse("`");
104+
} catch (UnrecognizedToken const& e) {
105+
EXPECT(e.token.location == 0);
106+
EXPECT(e.token.lexeme == "`");
107+
did_throw = true;
108+
}
109+
EXPECT(did_throw);
110+
111+
did_throw = false;
112+
try {
113+
parse("pi@");
114+
} catch (UnrecognizedToken const& e) {
115+
EXPECT(e.token.location == 2);
116+
EXPECT(e.token.lexeme == "@");
117+
did_throw = true;
118+
}
119+
EXPECT(did_throw);
120+
}
121+
100122
ADD_TEST(ParsePrecedence) {
101123
auto result = parse("1 + 2 * 3");
102124
ASSERT(result != nullptr);

0 commit comments

Comments
 (0)