From ffd66f1f866354bb79a137f55bca5aa970394d23 Mon Sep 17 00:00:00 2001 From: erick-alcachofa Date: Sun, 5 Oct 2025 22:51:16 -0600 Subject: [PATCH] feat: Added peekExpect method for token type validation in tokenizer Signed-off-by: erick-alcachofa Introduced `peekExpect(std::size_t, TokenV)` to the Tokenizer class, enabling token lookahead with explicit token type checks. This method returns an `Unexpected` error with diagnostic info if the expected token type does not match the peeked token. Includes a special case handling (workaround) for distinguishing between `>` and `>>` tokens when parsing the token stream. --- lib/include/artichoke/Tokenizer/Tokenizer.hpp | 1 + lib/src/Tokenizer/Tokenizer.cpp | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/lib/include/artichoke/Tokenizer/Tokenizer.hpp b/lib/include/artichoke/Tokenizer/Tokenizer.hpp index 7269d57..33c5485 100644 --- a/lib/include/artichoke/Tokenizer/Tokenizer.hpp +++ b/lib/include/artichoke/Tokenizer/Tokenizer.hpp @@ -25,6 +25,7 @@ namespace arti::lang { Expected consume(std::size_t n = 1) noexcept; Expected peek(std::size_t n = 0) noexcept; + Expected peekExpect(std::size_t n, TokenV tokenType) noexcept; bool finished() const noexcept; diff --git a/lib/src/Tokenizer/Tokenizer.cpp b/lib/src/Tokenizer/Tokenizer.cpp index f95b457..4cc905e 100644 --- a/lib/src/Tokenizer/Tokenizer.cpp +++ b/lib/src/Tokenizer/Tokenizer.cpp @@ -106,6 +106,62 @@ namespace arti::lang { return tokensBuffer.at(n); } + Expected + Tokenizer::peekExpect(std::size_t n, TokenV tokenType) noexcept { + if (tokensBuffer.size() > (n + 1)) { + auto tokenAt = tokensBuffer.at(n); + + if (tokenAt.value != tokenType) { + return Unexpected<> { + Exception{ + .line = tokenAt.line, + .column = tokenAt.column, + .message = std::format( + "OExpected token of type {}, got {}", + toString(tokenType), toString(tokenAt) + ) + } + }; + } + + return tokenAt; + } + + auto token = peek(n); + + if (!token) { + return token; + } + + /* TODO: Look for a nicer fix for this corner case */ + if (tokenType == TokenV::opGt && token->value == TokenV::opRShift) { + token->strValue.remove_suffix(1); + token->value = TokenV::opGt; + auto peekTok = *token; + tokensBuffer.pop_back(); + tokensBuffer.push_back(*token); + token->column += 1; + token->strValue = std::string_view{token->strValue.begin() + 1, 1}; + tokensBuffer.push_back(*token); + token = peekTok; + } + + if (token->value != tokenType) { + return Unexpected<> { + Exception{ + .line = token->line, + .column = token->column, + .message = std::format( + "OExpected token of type {}, got {}", + toString(tokenType), toString(*token) + ) + } + }; + } + + return *token; + } + bool Tokenizer::finished() const noexcept { if (tokensGenerator.finished()) { if (!tokensBuffer.empty()) {