mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 16:16:39 +00:00
274 lines
8.1 KiB
C++
274 lines
8.1 KiB
C++
//===--- FormatTokenSource.h - Format C++ code ------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// This file defines the \c FormatTokenSource interface, which provides a token
|
|
/// stream as well as the ability to manipulate the token stream.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H
|
|
#define LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H
|
|
|
|
#include "UnwrappedLineParser.h"
|
|
|
|
#define DEBUG_TYPE "format-token-source"
|
|
|
|
namespace clang {
|
|
namespace format {
|
|
|
|
// Navigate a token stream.
|
|
//
|
|
// Enables traversal of a token stream, resetting the position in a token
|
|
// stream, as well as inserting new tokens.
|
|
class FormatTokenSource {
|
|
public:
|
|
virtual ~FormatTokenSource() {}
|
|
|
|
// Returns the next token in the token stream.
|
|
virtual FormatToken *getNextToken() = 0;
|
|
|
|
// Returns the token preceding the token returned by the last call to
|
|
// getNextToken() in the token stream, or nullptr if no such token exists.
|
|
//
|
|
// Must not be called directly at the position directly after insertTokens()
|
|
// is called.
|
|
virtual FormatToken *getPreviousToken() = 0;
|
|
|
|
// Returns the token that would be returned by the next call to
|
|
// getNextToken().
|
|
virtual FormatToken *peekNextToken(bool SkipComment = false) = 0;
|
|
|
|
// Returns whether we are at the end of the file.
|
|
// This can be different from whether getNextToken() returned an eof token
|
|
// when the FormatTokenSource is a view on a part of the token stream.
|
|
virtual bool isEOF() = 0;
|
|
|
|
// Gets the current position in the token stream, to be used by setPosition().
|
|
//
|
|
// Note that the value of the position is not meaningful, and specifically
|
|
// should not be used to get relative token positions.
|
|
virtual unsigned getPosition() = 0;
|
|
|
|
// Resets the token stream to the state it was in when getPosition() returned
|
|
// Position, and return the token at that position in the stream.
|
|
virtual FormatToken *setPosition(unsigned Position) = 0;
|
|
|
|
// Insert the given tokens before the current position.
|
|
// Returns the first token in \c Tokens.
|
|
// The next returned token will be the second token in \c Tokens.
|
|
// Requires the last token in Tokens to be EOF; once the EOF token is reached,
|
|
// the next token will be the last token returned by getNextToken();
|
|
//
|
|
// For example, given the token sequence 'a1 a2':
|
|
// getNextToken() -> a1
|
|
// insertTokens('b1 b2') -> b1
|
|
// getNextToken() -> b2
|
|
// getNextToken() -> a1
|
|
// getNextToken() -> a2
|
|
virtual FormatToken *insertTokens(ArrayRef<FormatToken *> Tokens) = 0;
|
|
|
|
[[nodiscard]] FormatToken *getNextNonComment() {
|
|
FormatToken *Tok;
|
|
do {
|
|
Tok = getNextToken();
|
|
assert(Tok);
|
|
} while (Tok->is(tok::comment));
|
|
return Tok;
|
|
}
|
|
};
|
|
|
|
class IndexedTokenSource : public FormatTokenSource {
|
|
public:
|
|
IndexedTokenSource(ArrayRef<FormatToken *> Tokens)
|
|
: Tokens(Tokens), Position(-1) {}
|
|
|
|
FormatToken *getNextToken() override {
|
|
if (Position >= 0 && isEOF()) {
|
|
LLVM_DEBUG({
|
|
llvm::dbgs() << "Next ";
|
|
dbgToken(Position);
|
|
});
|
|
return Tokens[Position];
|
|
}
|
|
Position = successor(Position);
|
|
LLVM_DEBUG({
|
|
llvm::dbgs() << "Next ";
|
|
dbgToken(Position);
|
|
});
|
|
return Tokens[Position];
|
|
}
|
|
|
|
FormatToken *getPreviousToken() override {
|
|
assert(Position <= 0 || Tokens[Position - 1]->isNot(tok::eof));
|
|
return Position > 0 ? Tokens[Position - 1] : nullptr;
|
|
}
|
|
|
|
FormatToken *peekNextToken(bool SkipComment = false) override {
|
|
if (isEOF())
|
|
return Tokens[Position];
|
|
int Next = successor(Position);
|
|
if (SkipComment)
|
|
while (Tokens[Next]->is(tok::comment))
|
|
Next = successor(Next);
|
|
LLVM_DEBUG({
|
|
llvm::dbgs() << "Peeking ";
|
|
dbgToken(Next);
|
|
});
|
|
return Tokens[Next];
|
|
}
|
|
|
|
bool isEOF() override {
|
|
return Position == -1 ? false : Tokens[Position]->is(tok::eof);
|
|
}
|
|
|
|
unsigned getPosition() override {
|
|
LLVM_DEBUG(llvm::dbgs() << "Getting Position: " << Position << "\n");
|
|
assert(Position >= 0);
|
|
return Position;
|
|
}
|
|
|
|
FormatToken *setPosition(unsigned P) override {
|
|
LLVM_DEBUG(llvm::dbgs() << "Setting Position: " << P << "\n");
|
|
Position = P;
|
|
return Tokens[Position];
|
|
}
|
|
|
|
FormatToken *insertTokens(ArrayRef<FormatToken *> New) override {
|
|
assert(Position != -1);
|
|
assert((*New.rbegin())->Tok.is(tok::eof));
|
|
int Next = Tokens.size();
|
|
Tokens.append(New.begin(), New.end());
|
|
LLVM_DEBUG({
|
|
llvm::dbgs() << "Inserting:\n";
|
|
for (int I = Next, E = Tokens.size(); I != E; ++I)
|
|
dbgToken(I, " ");
|
|
llvm::dbgs() << " Jump from: " << (Tokens.size() - 1) << " -> "
|
|
<< Position << "\n";
|
|
});
|
|
Jumps[Tokens.size() - 1] = Position;
|
|
Position = Next;
|
|
LLVM_DEBUG({
|
|
llvm::dbgs() << "At inserted token ";
|
|
dbgToken(Position);
|
|
});
|
|
return Tokens[Position];
|
|
}
|
|
|
|
void reset() { Position = -1; }
|
|
|
|
private:
|
|
int successor(int Current) const {
|
|
int Next = Current + 1;
|
|
auto it = Jumps.find(Next);
|
|
if (it != Jumps.end()) {
|
|
Next = it->second;
|
|
assert(!Jumps.contains(Next));
|
|
}
|
|
return Next;
|
|
}
|
|
|
|
void dbgToken(int Position, StringRef Indent = "") {
|
|
FormatToken *Tok = Tokens[Position];
|
|
llvm::dbgs() << Indent << "[" << Position
|
|
<< "] Token: " << Tok->Tok.getName() << " / " << Tok->TokenText
|
|
<< ", Macro: " << !!Tok->MacroCtx << "\n";
|
|
}
|
|
|
|
SmallVector<FormatToken *> Tokens;
|
|
int Position;
|
|
|
|
// Maps from position a to position b, so that when we reach a, the token
|
|
// stream continues at position b instead.
|
|
llvm::DenseMap<int, int> Jumps;
|
|
};
|
|
|
|
class ScopedMacroState : public FormatTokenSource {
|
|
public:
|
|
ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
|
|
FormatToken *&ResetToken)
|
|
: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
|
|
PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
|
|
Token(nullptr), PreviousToken(nullptr) {
|
|
FakeEOF.Tok.startToken();
|
|
FakeEOF.Tok.setKind(tok::eof);
|
|
TokenSource = this;
|
|
Line.Level = 0;
|
|
Line.InPPDirective = true;
|
|
// InMacroBody gets set after the `#define x` part.
|
|
}
|
|
|
|
~ScopedMacroState() override {
|
|
TokenSource = PreviousTokenSource;
|
|
ResetToken = Token;
|
|
Line.InPPDirective = false;
|
|
Line.InMacroBody = false;
|
|
Line.Level = PreviousLineLevel;
|
|
}
|
|
|
|
FormatToken *getNextToken() override {
|
|
// The \c UnwrappedLineParser guards against this by never calling
|
|
// \c getNextToken() after it has encountered the first eof token.
|
|
assert(!eof());
|
|
PreviousToken = Token;
|
|
Token = PreviousTokenSource->getNextToken();
|
|
if (eof())
|
|
return &FakeEOF;
|
|
return Token;
|
|
}
|
|
|
|
FormatToken *getPreviousToken() override {
|
|
return PreviousTokenSource->getPreviousToken();
|
|
}
|
|
|
|
FormatToken *peekNextToken(bool SkipComment) override {
|
|
if (eof())
|
|
return &FakeEOF;
|
|
return PreviousTokenSource->peekNextToken(SkipComment);
|
|
}
|
|
|
|
bool isEOF() override { return PreviousTokenSource->isEOF(); }
|
|
|
|
unsigned getPosition() override { return PreviousTokenSource->getPosition(); }
|
|
|
|
FormatToken *setPosition(unsigned Position) override {
|
|
PreviousToken = nullptr;
|
|
Token = PreviousTokenSource->setPosition(Position);
|
|
return Token;
|
|
}
|
|
|
|
FormatToken *insertTokens(ArrayRef<FormatToken *> Tokens) override {
|
|
llvm_unreachable("Cannot insert tokens while parsing a macro.");
|
|
return nullptr;
|
|
}
|
|
|
|
private:
|
|
bool eof() {
|
|
return Token && Token->HasUnescapedNewline &&
|
|
!continuesLineComment(*Token, PreviousToken,
|
|
/*MinColumnToken=*/PreviousToken);
|
|
}
|
|
|
|
FormatToken FakeEOF;
|
|
UnwrappedLine &Line;
|
|
FormatTokenSource *&TokenSource;
|
|
FormatToken *&ResetToken;
|
|
unsigned PreviousLineLevel;
|
|
FormatTokenSource *PreviousTokenSource;
|
|
|
|
FormatToken *Token;
|
|
FormatToken *PreviousToken;
|
|
};
|
|
|
|
} // namespace format
|
|
} // namespace clang
|
|
|
|
#undef DEBUG_TYPE
|
|
|
|
#endif
|