xref: /freebsd-src/contrib/llvm-project/clang/lib/Lex/PPCaching.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--- PPCaching.cpp - Handle caching lexed tokens ----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements pieces of the Preprocessor interface that manage the
100b57cec5SDimitry Andric // caching of lexed tokens.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
150b57cec5SDimitry Andric using namespace clang;
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric // EnableBacktrackAtThisPos - From the point that this method is called, and
180b57cec5SDimitry Andric // until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor
190b57cec5SDimitry Andric // keeps track of the lexed tokens so that a subsequent Backtrack() call will
200b57cec5SDimitry Andric // make the Preprocessor re-lex the same tokens.
210b57cec5SDimitry Andric //
220b57cec5SDimitry Andric // Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can
230b57cec5SDimitry Andric // be called multiple times and CommitBacktrackedTokens/Backtrack calls will
240b57cec5SDimitry Andric // be combined with the EnableBacktrackAtThisPos calls in reverse order.
EnableBacktrackAtThisPos()250b57cec5SDimitry Andric void Preprocessor::EnableBacktrackAtThisPos() {
260b57cec5SDimitry Andric   assert(LexLevel == 0 && "cannot use lookahead while lexing");
270b57cec5SDimitry Andric   BacktrackPositions.push_back(CachedLexPos);
280b57cec5SDimitry Andric   EnterCachingLexMode();
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric // Disable the last EnableBacktrackAtThisPos call.
CommitBacktrackedTokens()320b57cec5SDimitry Andric void Preprocessor::CommitBacktrackedTokens() {
330b57cec5SDimitry Andric   assert(!BacktrackPositions.empty()
340b57cec5SDimitry Andric          && "EnableBacktrackAtThisPos was not called!");
350b57cec5SDimitry Andric   BacktrackPositions.pop_back();
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric // Make Preprocessor re-lex the tokens that were lexed since
390b57cec5SDimitry Andric // EnableBacktrackAtThisPos() was previously called.
Backtrack()400b57cec5SDimitry Andric void Preprocessor::Backtrack() {
410b57cec5SDimitry Andric   assert(!BacktrackPositions.empty()
420b57cec5SDimitry Andric          && "EnableBacktrackAtThisPos was not called!");
430b57cec5SDimitry Andric   CachedLexPos = BacktrackPositions.back();
440b57cec5SDimitry Andric   BacktrackPositions.pop_back();
450b57cec5SDimitry Andric   recomputeCurLexerKind();
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric 
CachingLex(Token & Result)480b57cec5SDimitry Andric void Preprocessor::CachingLex(Token &Result) {
490b57cec5SDimitry Andric   if (!InCachingLexMode())
500b57cec5SDimitry Andric     return;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   // The assert in EnterCachingLexMode should prevent this from happening.
530b57cec5SDimitry Andric   assert(LexLevel == 1 &&
540b57cec5SDimitry Andric          "should not use token caching within the preprocessor");
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   if (CachedLexPos < CachedTokens.size()) {
570b57cec5SDimitry Andric     Result = CachedTokens[CachedLexPos++];
580b57cec5SDimitry Andric     Result.setFlag(Token::IsReinjected);
590b57cec5SDimitry Andric     return;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   ExitCachingLexMode();
630b57cec5SDimitry Andric   Lex(Result);
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   if (isBacktrackEnabled()) {
660b57cec5SDimitry Andric     // Cache the lexed token.
670b57cec5SDimitry Andric     EnterCachingLexModeUnchecked();
680b57cec5SDimitry Andric     CachedTokens.push_back(Result);
690b57cec5SDimitry Andric     ++CachedLexPos;
700b57cec5SDimitry Andric     return;
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   if (CachedLexPos < CachedTokens.size()) {
740b57cec5SDimitry Andric     EnterCachingLexModeUnchecked();
750b57cec5SDimitry Andric   } else {
760b57cec5SDimitry Andric     // All cached tokens were consumed.
770b57cec5SDimitry Andric     CachedTokens.clear();
780b57cec5SDimitry Andric     CachedLexPos = 0;
790b57cec5SDimitry Andric   }
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
EnterCachingLexMode()820b57cec5SDimitry Andric void Preprocessor::EnterCachingLexMode() {
830b57cec5SDimitry Andric   // The caching layer sits on top of all the other lexers, so it's incorrect
840b57cec5SDimitry Andric   // to cache tokens while inside a nested lex action. The cached tokens would
850b57cec5SDimitry Andric   // be retained after returning to the enclosing lex action and, at best,
860b57cec5SDimitry Andric   // would appear at the wrong position in the token stream.
870b57cec5SDimitry Andric   assert(LexLevel == 0 &&
880b57cec5SDimitry Andric          "entered caching lex mode while lexing something else");
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   if (InCachingLexMode()) {
91*5f757f3fSDimitry Andric     assert(CurLexerCallback == CLK_CachingLexer && "Unexpected lexer kind");
920b57cec5SDimitry Andric     return;
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   EnterCachingLexModeUnchecked();
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
EnterCachingLexModeUnchecked()980b57cec5SDimitry Andric void Preprocessor::EnterCachingLexModeUnchecked() {
99*5f757f3fSDimitry Andric   assert(CurLexerCallback != CLK_CachingLexer && "already in caching lex mode");
1000b57cec5SDimitry Andric   PushIncludeMacroStack();
101*5f757f3fSDimitry Andric   CurLexerCallback = CLK_CachingLexer;
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric 
PeekAhead(unsigned N)1050b57cec5SDimitry Andric const Token &Preprocessor::PeekAhead(unsigned N) {
1060b57cec5SDimitry Andric   assert(CachedLexPos + N > CachedTokens.size() && "Confused caching.");
1070b57cec5SDimitry Andric   ExitCachingLexMode();
1080b57cec5SDimitry Andric   for (size_t C = CachedLexPos + N - CachedTokens.size(); C > 0; --C) {
1090b57cec5SDimitry Andric     CachedTokens.push_back(Token());
1100b57cec5SDimitry Andric     Lex(CachedTokens.back());
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric   EnterCachingLexMode();
1130b57cec5SDimitry Andric   return CachedTokens.back();
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
AnnotatePreviousCachedTokens(const Token & Tok)1160b57cec5SDimitry Andric void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {
1170b57cec5SDimitry Andric   assert(Tok.isAnnotation() && "Expected annotation token");
1180b57cec5SDimitry Andric   assert(CachedLexPos != 0 && "Expected to have some cached tokens");
1190b57cec5SDimitry Andric   assert(CachedTokens[CachedLexPos-1].getLastLoc() == Tok.getAnnotationEndLoc()
1200b57cec5SDimitry Andric          && "The annotation should be until the most recent cached token");
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // Start from the end of the cached tokens list and look for the token
1230b57cec5SDimitry Andric   // that is the beginning of the annotation token.
1240b57cec5SDimitry Andric   for (CachedTokensTy::size_type i = CachedLexPos; i != 0; --i) {
1250b57cec5SDimitry Andric     CachedTokensTy::iterator AnnotBegin = CachedTokens.begin() + i-1;
1260b57cec5SDimitry Andric     if (AnnotBegin->getLocation() == Tok.getLocation()) {
1270b57cec5SDimitry Andric       assert((BacktrackPositions.empty() || BacktrackPositions.back() <= i) &&
1280b57cec5SDimitry Andric              "The backtrack pos points inside the annotated tokens!");
1290b57cec5SDimitry Andric       // Replace the cached tokens with the single annotation token.
1300b57cec5SDimitry Andric       if (i < CachedLexPos)
1310b57cec5SDimitry Andric         CachedTokens.erase(AnnotBegin + 1, CachedTokens.begin() + CachedLexPos);
1320b57cec5SDimitry Andric       *AnnotBegin = Tok;
1330b57cec5SDimitry Andric       CachedLexPos = i;
1340b57cec5SDimitry Andric       return;
1350b57cec5SDimitry Andric     }
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
IsPreviousCachedToken(const Token & Tok) const1390b57cec5SDimitry Andric bool Preprocessor::IsPreviousCachedToken(const Token &Tok) const {
1400b57cec5SDimitry Andric   // There's currently no cached token...
1410b57cec5SDimitry Andric   if (!CachedLexPos)
1420b57cec5SDimitry Andric     return false;
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   const Token LastCachedTok = CachedTokens[CachedLexPos - 1];
1450b57cec5SDimitry Andric   if (LastCachedTok.getKind() != Tok.getKind())
1460b57cec5SDimitry Andric     return false;
1470b57cec5SDimitry Andric 
148fe6060f1SDimitry Andric   SourceLocation::IntTy RelOffset = 0;
1490b57cec5SDimitry Andric   if ((!getSourceManager().isInSameSLocAddrSpace(
1500b57cec5SDimitry Andric           Tok.getLocation(), getLastCachedTokenLocation(), &RelOffset)) ||
1510b57cec5SDimitry Andric       RelOffset)
1520b57cec5SDimitry Andric     return false;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   return true;
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
ReplacePreviousCachedToken(ArrayRef<Token> NewToks)1570b57cec5SDimitry Andric void Preprocessor::ReplacePreviousCachedToken(ArrayRef<Token> NewToks) {
1580b57cec5SDimitry Andric   assert(CachedLexPos != 0 && "Expected to have some cached tokens");
1590b57cec5SDimitry Andric   CachedTokens.insert(CachedTokens.begin() + CachedLexPos - 1, NewToks.begin(),
1600b57cec5SDimitry Andric                       NewToks.end());
1610b57cec5SDimitry Andric   CachedTokens.erase(CachedTokens.begin() + CachedLexPos - 1 + NewToks.size());
1620b57cec5SDimitry Andric   CachedLexPos += NewToks.size() - 1;
1630b57cec5SDimitry Andric }
164