Skip to content

Commit c945217

Browse files
committed
Extend API of Lexer with a new method PeekNextToken
1 parent 1a2c161 commit c945217

File tree

2 files changed

+72
-13
lines changed

2 files changed

+72
-13
lines changed

source/tcppLibrary.hpp

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ namespace tcpp
195195

196196
TToken GetNextToken() TCPP_NOEXCEPT;
197197

198+
/*!
199+
\brief The method allows to peek token without changing current pointer
200+
201+
\param[in] offset Distance of overlooking, passing 0 is equivalent to invoking GetNextToken()
202+
*/
203+
204+
TToken PeekNextToken(size_t offset = 1);
205+
198206
bool HasNextToken() const TCPP_NOEXCEPT;
199207

200208
void AppendFront(const std::vector<TToken>& tokens) TCPP_NOEXCEPT;
@@ -205,6 +213,8 @@ namespace tcpp
205213
size_t GetCurrLineIndex() const TCPP_NOEXCEPT;
206214
size_t GetCurrPos() const TCPP_NOEXCEPT;
207215
private:
216+
TToken _getNextTokenInternal(bool ignoreQueue) TCPP_NOEXCEPT;
217+
208218
TToken _scanTokens(std::string& inputLine) TCPP_NOEXCEPT;
209219

210220
std::string _requestSourceLine() TCPP_NOEXCEPT;
@@ -450,24 +460,27 @@ namespace tcpp
450460

451461
TToken Lexer::GetNextToken() TCPP_NOEXCEPT
452462
{
453-
if (!mTokensQueue.empty())
463+
return _getNextTokenInternal(false);
464+
}
465+
466+
TToken Lexer::PeekNextToken(size_t offset)
467+
{
468+
if (!mTokensQueue.empty() && offset < mTokensQueue.size())
454469
{
455-
auto currToken = mTokensQueue.front();
456-
mTokensQueue.pop_front();
470+
return *std::next(mTokensQueue.begin(), offset);
471+
}
457472

458-
return currToken;
473+
for (size_t i = 0; i < (offset - mTokensQueue.size()); i++)
474+
{
475+
mTokensQueue.push_back(_getNextTokenInternal(true));
459476
}
460477

461-
if (mCurrLine.empty())
478+
if (mTokensQueue.empty())
462479
{
463-
// \note if it's still empty then we've reached the end of the source
464-
if ((mCurrLine = _requestSourceLine()).empty())
465-
{
466-
return mEOFToken;
467-
}
480+
return GetNextToken();
468481
}
469482

470-
return _scanTokens(mCurrLine);
483+
return mTokensQueue.back();
471484
}
472485

473486
bool Lexer::HasNextToken() const TCPP_NOEXCEPT
@@ -585,6 +598,28 @@ namespace tcpp
585598
}
586599

587600

601+
TToken Lexer::_getNextTokenInternal(bool ignoreQueue) TCPP_NOEXCEPT
602+
{
603+
if (!ignoreQueue && !mTokensQueue.empty())
604+
{
605+
auto currToken = mTokensQueue.front();
606+
mTokensQueue.pop_front();
607+
608+
return currToken;
609+
}
610+
611+
if (mCurrLine.empty())
612+
{
613+
// \note if it's still empty then we've reached the end of the source
614+
if ((mCurrLine = _requestSourceLine()).empty())
615+
{
616+
return mEOFToken;
617+
}
618+
}
619+
620+
return _scanTokens(mCurrLine);
621+
}
622+
588623
TToken Lexer::_scanTokens(std::string& inputLine) TCPP_NOEXCEPT
589624
{
590625
char ch = '\0';
@@ -983,10 +1018,19 @@ namespace tcpp
9831018
}
9841019

9851020

1021+
static const std::vector<std::string> BuiltInDefines
1022+
{
1023+
"__LINE__",
1024+
};
1025+
1026+
9861027
Preprocessor::Preprocessor(Lexer& lexer, const TOnErrorCallback& onErrorCallback, const TOnIncludeCallback& onIncludeCallback) TCPP_NOEXCEPT:
9871028
mpLexer(&lexer), mOnErrorCallback(onErrorCallback), mOnIncludeCallback(onIncludeCallback)
9881029
{
989-
mSymTable.push_back({ "__LINE__" });
1030+
for (auto&& currSystemDefine : BuiltInDefines)
1031+
{
1032+
mSymTable.push_back({ currSystemDefine });
1033+
}
9901034
}
9911035

9921036
bool Preprocessor::AddCustomDirectiveHandler(const std::string& directive, const TDirectiveHandler& handler) TCPP_NOEXCEPT
@@ -1253,7 +1297,7 @@ namespace tcpp
12531297
{
12541298
static const std::unordered_map<std::string, std::function<TToken()>> systemMacrosTable
12551299
{
1256-
{ "__LINE__", [&idToken]() { return TToken { E_TOKEN_TYPE::BLOB, std::to_string(idToken.mLineId) }; } }
1300+
{ BuiltInDefines[0], [&idToken]() { return TToken {E_TOKEN_TYPE::BLOB, std::to_string(idToken.mLineId)}; }} // __LINE__
12571301
};
12581302

12591303
auto iter = systemMacrosTable.find(macroDesc.mName);

tests/lexerTests.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,4 +329,19 @@ TEST_CASE("Lexer Tests")
329329
REQUIRE(lexer.GetNextToken().mType == E_TOKEN_TYPE::COMMENTARY);
330330
REQUIRE(lexer.GetNextToken().mType == E_TOKEN_TYPE::END);
331331
}
332+
333+
SECTION("TestPeekNextToken_IterateOverSequenceUsingOffset_CorrectlyProcessStreamAndReturnsTokens")
334+
{
335+
Lexer lexer(std::make_unique<MockInputStream>(std::vector<std::string> { "(2, 3)" }));
336+
337+
REQUIRE(lexer.PeekNextToken(0).mType == E_TOKEN_TYPE::OPEN_BRACKET); // PeekNextToken(0) equals to GetNextToken()
338+
REQUIRE(lexer.PeekNextToken(1).mType == E_TOKEN_TYPE::NUMBER);
339+
REQUIRE(lexer.PeekNextToken(2).mType == E_TOKEN_TYPE::COMMA);
340+
REQUIRE(lexer.PeekNextToken(3).mType == E_TOKEN_TYPE::SPACE);
341+
REQUIRE(lexer.PeekNextToken(4).mType == E_TOKEN_TYPE::NUMBER);
342+
REQUIRE(lexer.PeekNextToken(5).mType == E_TOKEN_TYPE::CLOSE_BRACKET);
343+
REQUIRE(lexer.PeekNextToken(6).mType == E_TOKEN_TYPE::END);
344+
345+
REQUIRE(lexer.GetNextToken().mType == E_TOKEN_TYPE::NUMBER);
346+
}
332347
}

0 commit comments

Comments
 (0)