Path: blob/main/contrib/llvm-project/clang/lib/Format/FormatTokenSource.h
35233 views
//===--- FormatTokenSource.h - Format C++ code ------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file defines the \c FormatTokenSource interface, which provides a token10/// stream as well as the ability to manipulate the token stream.11///12//===----------------------------------------------------------------------===//1314#ifndef LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H15#define LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H1617#include "UnwrappedLineParser.h"1819#define DEBUG_TYPE "format-token-source"2021namespace clang {22namespace format {2324// Navigate a token stream.25//26// Enables traversal of a token stream, resetting the position in a token27// stream, as well as inserting new tokens.28class FormatTokenSource {29public:30virtual ~FormatTokenSource() {}3132// Returns the next token in the token stream.33virtual FormatToken *getNextToken() = 0;3435// Returns the token preceding the token returned by the last call to36// getNextToken() in the token stream, or nullptr if no such token exists.37//38// Must not be called directly at the position directly after insertTokens()39// is called.40virtual FormatToken *getPreviousToken() = 0;4142// Returns the token that would be returned by the next call to43// getNextToken().44virtual FormatToken *peekNextToken(bool SkipComment = false) = 0;4546// Returns whether we are at the end of the file.47// This can be different from whether getNextToken() returned an eof token48// when the FormatTokenSource is a view on a part of the token stream.49virtual bool isEOF() = 0;5051// Gets the current position in the token stream, to be used by setPosition().52//53// Note that the value of the position is not meaningful, and specifically54// should not be used to get relative token positions.55virtual unsigned getPosition() = 0;5657// Resets the token stream to the state it was in when getPosition() returned58// Position, and return the token at that position in the stream.59virtual FormatToken *setPosition(unsigned Position) = 0;6061// Insert the given tokens before the current position.62// Returns the first token in \c Tokens.63// The next returned token will be the second token in \c Tokens.64// Requires the last token in Tokens to be EOF; once the EOF token is reached,65// the next token will be the last token returned by getNextToken();66//67// For example, given the token sequence 'a1 a2':68// getNextToken() -> a169// insertTokens('b1 b2') -> b170// getNextToken() -> b271// getNextToken() -> a172// getNextToken() -> a273virtual FormatToken *insertTokens(ArrayRef<FormatToken *> Tokens) = 0;7475[[nodiscard]] FormatToken *getNextNonComment() {76FormatToken *Tok;77do {78Tok = getNextToken();79assert(Tok);80} while (Tok->is(tok::comment));81return Tok;82}83};8485class IndexedTokenSource : public FormatTokenSource {86public:87IndexedTokenSource(ArrayRef<FormatToken *> Tokens)88: Tokens(Tokens), Position(-1) {}8990FormatToken *getNextToken() override {91if (Position >= 0 && isEOF()) {92LLVM_DEBUG({93llvm::dbgs() << "Next ";94dbgToken(Position);95});96return Tokens[Position];97}98Position = successor(Position);99LLVM_DEBUG({100llvm::dbgs() << "Next ";101dbgToken(Position);102});103return Tokens[Position];104}105106FormatToken *getPreviousToken() override {107assert(Position <= 0 || Tokens[Position - 1]->isNot(tok::eof));108return Position > 0 ? Tokens[Position - 1] : nullptr;109}110111FormatToken *peekNextToken(bool SkipComment = false) override {112if (isEOF())113return Tokens[Position];114int Next = successor(Position);115if (SkipComment)116while (Tokens[Next]->is(tok::comment))117Next = successor(Next);118LLVM_DEBUG({119llvm::dbgs() << "Peeking ";120dbgToken(Next);121});122return Tokens[Next];123}124125bool isEOF() override {126return Position == -1 ? false : Tokens[Position]->is(tok::eof);127}128129unsigned getPosition() override {130LLVM_DEBUG(llvm::dbgs() << "Getting Position: " << Position << "\n");131assert(Position >= 0);132return Position;133}134135FormatToken *setPosition(unsigned P) override {136LLVM_DEBUG(llvm::dbgs() << "Setting Position: " << P << "\n");137Position = P;138return Tokens[Position];139}140141FormatToken *insertTokens(ArrayRef<FormatToken *> New) override {142assert(Position != -1);143assert((*New.rbegin())->Tok.is(tok::eof));144int Next = Tokens.size();145Tokens.append(New.begin(), New.end());146LLVM_DEBUG({147llvm::dbgs() << "Inserting:\n";148for (int I = Next, E = Tokens.size(); I != E; ++I)149dbgToken(I, " ");150llvm::dbgs() << " Jump from: " << (Tokens.size() - 1) << " -> "151<< Position << "\n";152});153Jumps[Tokens.size() - 1] = Position;154Position = Next;155LLVM_DEBUG({156llvm::dbgs() << "At inserted token ";157dbgToken(Position);158});159return Tokens[Position];160}161162void reset() { Position = -1; }163164private:165int successor(int Current) const {166int Next = Current + 1;167auto it = Jumps.find(Next);168if (it != Jumps.end()) {169Next = it->second;170assert(!Jumps.contains(Next));171}172return Next;173}174175void dbgToken(int Position, StringRef Indent = "") {176FormatToken *Tok = Tokens[Position];177llvm::dbgs() << Indent << "[" << Position178<< "] Token: " << Tok->Tok.getName() << " / " << Tok->TokenText179<< ", Macro: " << !!Tok->MacroCtx << "\n";180}181182SmallVector<FormatToken *> Tokens;183int Position;184185// Maps from position a to position b, so that when we reach a, the token186// stream continues at position b instead.187llvm::DenseMap<int, int> Jumps;188};189190class ScopedMacroState : public FormatTokenSource {191public:192ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,193FormatToken *&ResetToken)194: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),195PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),196Token(nullptr), PreviousToken(nullptr) {197FakeEOF.Tok.startToken();198FakeEOF.Tok.setKind(tok::eof);199TokenSource = this;200Line.Level = 0;201Line.InPPDirective = true;202// InMacroBody gets set after the `#define x` part.203}204205~ScopedMacroState() override {206TokenSource = PreviousTokenSource;207ResetToken = Token;208Line.InPPDirective = false;209Line.InMacroBody = false;210Line.Level = PreviousLineLevel;211}212213FormatToken *getNextToken() override {214// The \c UnwrappedLineParser guards against this by never calling215// \c getNextToken() after it has encountered the first eof token.216assert(!eof());217PreviousToken = Token;218Token = PreviousTokenSource->getNextToken();219if (eof())220return &FakeEOF;221return Token;222}223224FormatToken *getPreviousToken() override {225return PreviousTokenSource->getPreviousToken();226}227228FormatToken *peekNextToken(bool SkipComment) override {229if (eof())230return &FakeEOF;231return PreviousTokenSource->peekNextToken(SkipComment);232}233234bool isEOF() override { return PreviousTokenSource->isEOF(); }235236unsigned getPosition() override { return PreviousTokenSource->getPosition(); }237238FormatToken *setPosition(unsigned Position) override {239PreviousToken = nullptr;240Token = PreviousTokenSource->setPosition(Position);241return Token;242}243244FormatToken *insertTokens(ArrayRef<FormatToken *> Tokens) override {245llvm_unreachable("Cannot insert tokens while parsing a macro.");246return nullptr;247}248249private:250bool eof() {251return Token && Token->HasUnescapedNewline &&252!continuesLineComment(*Token, PreviousToken,253/*MinColumnToken=*/PreviousToken);254}255256FormatToken FakeEOF;257UnwrappedLine &Line;258FormatTokenSource *&TokenSource;259FormatToken *&ResetToken;260unsigned PreviousLineLevel;261FormatTokenSource *PreviousTokenSource;262263FormatToken *Token;264FormatToken *PreviousToken;265};266267} // namespace format268} // namespace clang269270#undef DEBUG_TYPE271272#endif273274275