#pragma once #include #include #include #include #include namespace stela { struct Pos { size_t index; int64_t line; int64_t col; }; struct Error { Pos pos; std::string message; }; enum class TokenType { Error, Eof, If, Else, Return, Public, Private, Class, Derivable, Derives, Enumeration, Associate, Attribute, Operation, StateMachine, Transition, Initial, Final, Entry, Exit, LParen, RParen, LBrace, RBrace, LBracket, RBracket, Dot, Comma, Semicolon, Colon, ColonColon, Minus, MinusLt, Equal, Id, Int, }; struct Token { TokenType type; Pos pos; uint64_t id; }; class Lexer { public: Lexer(std::ifstream& file, std::vector& errors) : file(&file) , current_char(file.get()) , errors(&errors) { } auto next() -> Token; private: inline auto step() { if (this->current_char == EOF) { this->eof_reached = true; return; } if (this->current_char == '\n') { this->line += 1; this->col = 1; } else { this->col += 1; } this->current_char = this->file->get(); this->index += 1; } inline auto single_token(TokenType type, Pos pos) -> Token { step(); return token(type, pos); } inline auto error_token(Pos pos, std::string message) const -> Token { this->errors->push_back(Error { pos, message }); return token(TokenType::Error, pos); } inline auto token(TokenType type, Pos pos) const -> Token { return Token { type, pos, 0 }; } inline auto pos() const -> Pos { return Pos { .index = this->index, .line = this->line, .col = this->col, }; } inline auto done() const -> bool { return this->eof_reached; } inline auto current() const -> char { return static_cast(this->current_char); } auto populate_keyword_map(); bool eof_reached = false; size_t index = 0; int64_t line = 1; int64_t col = 1; std::ifstream* file; int current_char; std::unordered_map keyword_map {}; std::vector symbol_values {}; std::vector int_values {}; std::vector* errors; }; }