Line data Source code
1 : #include "stax/lexer/lexer.hpp"
2 :
3 : #include <format>
4 : #include <stax/utils/result.hpp>
5 : #include <utility>
6 :
7 : namespace stax::lexer {
8 :
9 30 : Lexer::Lexer(std::string input) : input_(std::move(input)) {
10 15 : curr_ = input_.begin();
11 15 : peek_ = curr_ + 1;
12 15 : ConsumeWhitespace();
13 15 : }
14 :
15 158 : auto Lexer::NextToken() -> result_t<token::Token> {
16 316 : if (IsWhitespace(*curr_)) {
17 72 : ConsumeWhitespace();
18 : }
19 316 : if (curr_ == input_.end()) return token::Token{token::Type::kEOF, ""};
20 :
21 130 : std::optional<token::Token> t;
22 260 : switch (const auto c = *curr_) {
23 13 : case '=': t = token::Token{token::Type::kAssign, "="}; break;
24 4 : case '+': t = token::Token{token::Type::kPlus, "+"}; break;
25 2 : case '-': t = token::Token{token::Type::kMinus, "-"}; break;
26 1 : case '>': t = token::Token{token::Type::kGreater, ">"}; break;
27 1 : case '<': t = token::Token{token::Type::kLess, "<"}; break;
28 1 : case '~': t = token::Token{token::Type::kTilde, "~"}; break;
29 1 : case '!': t = token::Token{token::Type::kBang, "!"}; break;
30 6 : case '(': t = token::Token{token::Type::kLParen, "("}; break;
31 6 : case ')': t = token::Token{token::Type::kRParen, ")"}; break;
32 4 : case '{': t = token::Token{token::Type::kLBrace, "{"}; break;
33 4 : case '}': t = token::Token{token::Type::kRBrace, "}"}; break;
34 5 : case ',': t = token::Token{token::Type::kComma, ","}; break;
35 17 : case ';': t = token::Token{token::Type::kSemicolon, ";"}; break;
36 65 : default: {
37 : // Deal with numerics and letters
38 65 : if (IsLetter(c)) {
39 49 : TRY_RESULT(const auto sv, Identifier());
40 :
41 49 : if (kKeywords.contains(sv)) {
42 3 : return token::Token{kKeywords.at(sv), sv};
43 : }
44 :
45 46 : return token::Token{token::Type::kIdent, sv};
46 49 : }
47 :
48 16 : if (IsDigit(c)) {
49 16 : TRY_RESULT(const auto sv, Number());
50 16 : return token::Token(token::Type::kInt, sv);
51 16 : }
52 :
53 0 : return result::Err(Error::IllegalCharacter,
54 0 : std::format("{} not recognized", c));
55 : }
56 : }
57 :
58 65 : Advance();
59 :
60 65 : if (t.has_value()) {
61 65 : return t.value();
62 : }
63 :
64 0 : return result::Err(Error::Syntax);
65 : }
66 :
67 49 : auto Lexer::Identifier() -> result_t<std::string_view> {
68 49 : auto beg = curr_;
69 336 : while (IsLetter(*curr_)) {
70 119 : Advance();
71 : }
72 :
73 49 : return std::string_view{beg, curr_};
74 : }
75 :
76 16 : auto Lexer::Number() -> result_t<std::string_view> {
77 16 : auto beg = curr_;
78 78 : while (IsDigit(*curr_)) {
79 23 : Advance();
80 : }
81 :
82 16 : return std::string_view{beg, curr_};
83 : }
84 :
85 309 : void Lexer::Advance() {
86 309 : ++curr_;
87 309 : ++peek_;
88 309 : }
89 :
90 87 : void Lexer::ConsumeWhitespace() {
91 378 : while (IsWhitespace(*curr_)) {
92 102 : Advance();
93 : }
94 87 : }
95 :
96 : } // namespace stax::lexer
|