#include "Lexer.hpp" namespace jk { /*explicit*/ Lexer::Lexer(Logger& logger, Loc const& loc) : m_logger { logger } , m_loc { loc } { m_scanners.push_back(std::bind(&Lexer::scan_int, this)); } /*virtual*/ Lexer::~Lexer() { } void Lexer::scan(std::string const& source) { m_source = source; m_cursor = 0; } std::shared_ptr Lexer::next() { skip_spaces(); while (more(m_cursor) && current(m_cursor) == '#') { while (more(m_cursor) && current(m_cursor) != '\n') { m_cursor++; } skip_spaces(); } std::optional info; for (auto scanner: m_scanners) { auto my_info = scanner(); if ((!info && my_info) || (info && my_info && my_info->cursor > info->cursor)) { info = my_info; } } if (info) { m_cursor = info->cursor; return std::make_shared(info->type, info->repr, m_loc); } if (more(m_cursor)) { std::string text; while (more(m_cursor) && !std::isspace(current(m_cursor))) { text += current(m_cursor); m_cursor++; } std::stringstream ss; ss << "unknown text '" << text << "'"; m_logger.log(LOG_ERROR, m_loc, ss.str()); } return nullptr; } bool Lexer::more(size_t index) const { return index < m_source.size(); } char Lexer::current(size_t index) const { assert(more(index)); return m_source[index]; } void Lexer::skip_spaces() { while (more(m_cursor) && std::isspace(current(m_cursor))) { if (current(m_cursor) == '\n') { m_loc = Loc { m_loc.path(), m_loc.line() + 1, m_loc.column() }; } m_cursor++; } } std::optional Lexer::scan_int() const { size_t cursor = m_cursor; std::string repr; while (more(cursor) && std::isdigit(current(cursor))) { repr += current(cursor); cursor++; } if (repr.empty() == false) { return ScanInfo { cursor, NODE_INT, repr }; } return std::nullopt; } }