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 12 : Lexer::Lexer(std::string input) : input_(std::move(input)) {
10 6 : curr_ = input_.begin();
11 6 : peek_ = curr_ + 1;
12 6 : ConsumeWhitespace();
13 6 : }
14 :
15 126 : auto Lexer::NextToken() -> result_t<token::Token> {
16 252 : if (IsWhitespace(*curr_)) {
17 79 : ConsumeWhitespace();
18 : }
19 252 : if (curr_ == input_.end()) return token::Token{token::Type::kEOF, ""};
20 :
21 116 : std::optional<token::Token> t;
22 232 : switch (const auto c = *curr_) {
23 13 : case '=': t = token::Token{token::Type::kAssign, "="}; break;
24 3 : 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 5 : case '(': t = token::Token{token::Type::kLParen, "("}; break;
31 5 : 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 3 : case ',': t = token::Token{token::Type::kComma, ","}; break;
35 16 : case ';': t = token::Token{token::Type::kSemicolon, ";"}; break;
36 57 : default: {
37 : // Deal with numerics and letters
38 57 : if (IsLetter(c)) {
39 40 : TRY_RESULT(const auto sv, Identifier());
40 :
41 40 : if (kKeywords.contains(sv)) {
42 3 : return token::Token{kKeywords.at(sv), sv};
43 : }
44 :
45 37 : return token::Token{token::Type::kIdent, sv};
46 40 : }
47 :
48 17 : if (IsDigit(c)) {
49 17 : TRY_RESULT(const auto sv, Number());
50 17 : return token::Token(token::Type::kInt, sv);
51 17 : }
52 :
53 0 : return result::Err(Error::IllegalCharacter,
54 0 : std::format("{} not recognized", c));
55 : }
56 : }
57 :
58 59 : Advance();
59 :
60 59 : if (t.has_value()) {
61 59 : return t.value();
62 : }
63 :
64 0 : return result::Err(Error::Syntax);
65 : }
66 :
67 40 : auto Lexer::Identifier() -> result_t<std::string_view> {
68 40 : auto beg = curr_;
69 290 : while (IsLetter(*curr_)) {
70 105 : Advance();
71 : }
72 :
73 80 : return {beg, curr_};
74 : }
75 :
76 17 : auto Lexer::Number() -> result_t<std::string_view> {
77 17 : auto beg = curr_;
78 82 : while (IsDigit(*curr_)) {
79 24 : Advance();
80 : }
81 :
82 34 : return {beg, curr_};
83 : }
84 :
85 361 : void Lexer::Advance() {
86 361 : ++curr_;
87 361 : ++peek_;
88 361 : }
89 :
90 85 : void Lexer::ConsumeWhitespace() {
91 516 : while (IsWhitespace(*curr_)) {
92 173 : Advance();
93 : }
94 85 : }
95 :
96 : } // namespace stax::lexer
|