1*e8d8bef9SDimitry Andric //===--- MacroExpander.h - Format C++ code ----------------------*- C++ -*-===// 2*e8d8bef9SDimitry Andric // 3*e8d8bef9SDimitry Andric // The LLVM Compiler Infrastructure 4*e8d8bef9SDimitry Andric // 5*e8d8bef9SDimitry Andric // This file is distributed under the University of Illinois Open Source 6*e8d8bef9SDimitry Andric // License. See LICENSE.TXT for details. 7*e8d8bef9SDimitry Andric // 8*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 9*e8d8bef9SDimitry Andric /// 10*e8d8bef9SDimitry Andric /// \file 11*e8d8bef9SDimitry Andric /// This file contains the main building blocks of macro support in 12*e8d8bef9SDimitry Andric /// clang-format. 13*e8d8bef9SDimitry Andric /// 14*e8d8bef9SDimitry Andric /// In order to not violate the requirement that clang-format can format files 15*e8d8bef9SDimitry Andric /// in isolation, clang-format's macro support uses expansions users provide 16*e8d8bef9SDimitry Andric /// as part of clang-format's style configuration. 17*e8d8bef9SDimitry Andric /// 18*e8d8bef9SDimitry Andric /// Macro definitions are of the form "MACRO(p1, p2)=p1 + p2", but only support 19*e8d8bef9SDimitry Andric /// one level of expansion (\see MacroExpander for a full description of what 20*e8d8bef9SDimitry Andric /// is supported). 21*e8d8bef9SDimitry Andric /// 22*e8d8bef9SDimitry Andric /// As part of parsing, clang-format uses the MacroExpander to expand the 23*e8d8bef9SDimitry Andric /// spelled token streams into expanded token streams when it encounters a 24*e8d8bef9SDimitry Andric /// macro call. The UnwrappedLineParser continues to parse UnwrappedLines 25*e8d8bef9SDimitry Andric /// from the expanded token stream. 26*e8d8bef9SDimitry Andric /// After the expanded unwrapped lines are parsed, the MacroUnexpander matches 27*e8d8bef9SDimitry Andric /// the spelled token stream into unwrapped lines that best resemble the 28*e8d8bef9SDimitry Andric /// structure of the expanded unwrapped lines. 29*e8d8bef9SDimitry Andric /// 30*e8d8bef9SDimitry Andric /// When formatting, clang-format formats the expanded unwrapped lines first, 31*e8d8bef9SDimitry Andric /// determining the token types. Next, it formats the spelled unwrapped lines, 32*e8d8bef9SDimitry Andric /// keeping the token types fixed, while allowing other formatting decisions 33*e8d8bef9SDimitry Andric /// to change. 34*e8d8bef9SDimitry Andric /// 35*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 36*e8d8bef9SDimitry Andric 37*e8d8bef9SDimitry Andric #ifndef CLANG_LIB_FORMAT_MACROS_H 38*e8d8bef9SDimitry Andric #define CLANG_LIB_FORMAT_MACROS_H 39*e8d8bef9SDimitry Andric 40*e8d8bef9SDimitry Andric #include <string> 41*e8d8bef9SDimitry Andric #include <unordered_map> 42*e8d8bef9SDimitry Andric #include <vector> 43*e8d8bef9SDimitry Andric 44*e8d8bef9SDimitry Andric #include "Encoding.h" 45*e8d8bef9SDimitry Andric #include "FormatToken.h" 46*e8d8bef9SDimitry Andric #include "llvm/ADT/ArrayRef.h" 47*e8d8bef9SDimitry Andric #include "llvm/ADT/SmallVector.h" 48*e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h" 49*e8d8bef9SDimitry Andric 50*e8d8bef9SDimitry Andric namespace llvm { 51*e8d8bef9SDimitry Andric class MemoryBuffer; 52*e8d8bef9SDimitry Andric } // namespace llvm 53*e8d8bef9SDimitry Andric 54*e8d8bef9SDimitry Andric namespace clang { 55*e8d8bef9SDimitry Andric class IdentifierTable; 56*e8d8bef9SDimitry Andric class SourceManager; 57*e8d8bef9SDimitry Andric 58*e8d8bef9SDimitry Andric namespace format { 59*e8d8bef9SDimitry Andric struct FormatStyle; 60*e8d8bef9SDimitry Andric 61*e8d8bef9SDimitry Andric /// Takes a set of macro definitions as strings and allows expanding calls to 62*e8d8bef9SDimitry Andric /// those macros. 63*e8d8bef9SDimitry Andric /// 64*e8d8bef9SDimitry Andric /// For example: 65*e8d8bef9SDimitry Andric /// Definition: A(x, y)=x + y 66*e8d8bef9SDimitry Andric /// Call : A(int a = 1, 2) 67*e8d8bef9SDimitry Andric /// Expansion : int a = 1 + 2 68*e8d8bef9SDimitry Andric /// 69*e8d8bef9SDimitry Andric /// Expansion does not check arity of the definition. 70*e8d8bef9SDimitry Andric /// If fewer arguments than expected are provided, the remaining parameters 71*e8d8bef9SDimitry Andric /// are considered empty: 72*e8d8bef9SDimitry Andric /// Call : A(a) 73*e8d8bef9SDimitry Andric /// Expansion: a + 74*e8d8bef9SDimitry Andric /// If more arguments than expected are provided, they will be discarded. 75*e8d8bef9SDimitry Andric /// 76*e8d8bef9SDimitry Andric /// The expander does not support: 77*e8d8bef9SDimitry Andric /// - recursive expansion 78*e8d8bef9SDimitry Andric /// - stringification 79*e8d8bef9SDimitry Andric /// - concatenation 80*e8d8bef9SDimitry Andric /// - variadic macros 81*e8d8bef9SDimitry Andric /// 82*e8d8bef9SDimitry Andric /// Furthermore, only a single expansion of each macro argument is supported, 83*e8d8bef9SDimitry Andric /// so that we cannot get conflicting formatting decisions from different 84*e8d8bef9SDimitry Andric /// expansions. 85*e8d8bef9SDimitry Andric /// Definition: A(x)=x+x 86*e8d8bef9SDimitry Andric /// Call : A(id) 87*e8d8bef9SDimitry Andric /// Expansion : id+x 88*e8d8bef9SDimitry Andric /// 89*e8d8bef9SDimitry Andric class MacroExpander { 90*e8d8bef9SDimitry Andric public: 91*e8d8bef9SDimitry Andric using ArgsList = llvm::ArrayRef<llvm::SmallVector<FormatToken *, 8>>; 92*e8d8bef9SDimitry Andric 93*e8d8bef9SDimitry Andric /// Construct a macro expander from a set of macro definitions. 94*e8d8bef9SDimitry Andric /// Macro definitions must be encoded as UTF-8. 95*e8d8bef9SDimitry Andric /// 96*e8d8bef9SDimitry Andric /// Each entry in \p Macros must conform to the following simple 97*e8d8bef9SDimitry Andric /// macro-definition language: 98*e8d8bef9SDimitry Andric /// <definition> ::= <id> <expansion> | <id> "(" <params> ")" <expansion> 99*e8d8bef9SDimitry Andric /// <params> ::= <id-list> | "" 100*e8d8bef9SDimitry Andric /// <id-list> ::= <id> | <id> "," <params> 101*e8d8bef9SDimitry Andric /// <expansion> ::= "=" <tail> | <eof> 102*e8d8bef9SDimitry Andric /// <tail> ::= <tok> <tail> | <eof> 103*e8d8bef9SDimitry Andric /// 104*e8d8bef9SDimitry Andric /// Macros that cannot be parsed will be silently discarded. 105*e8d8bef9SDimitry Andric /// 106*e8d8bef9SDimitry Andric MacroExpander(const std::vector<std::string> &Macros, 107*e8d8bef9SDimitry Andric clang::SourceManager &SourceMgr, const FormatStyle &Style, 108*e8d8bef9SDimitry Andric llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator, 109*e8d8bef9SDimitry Andric IdentifierTable &IdentTable); 110*e8d8bef9SDimitry Andric ~MacroExpander(); 111*e8d8bef9SDimitry Andric 112*e8d8bef9SDimitry Andric /// Returns whether a macro \p Name is defined. 113*e8d8bef9SDimitry Andric bool defined(llvm::StringRef Name) const; 114*e8d8bef9SDimitry Andric 115*e8d8bef9SDimitry Andric /// Returns whether the macro has no arguments and should not consume 116*e8d8bef9SDimitry Andric /// subsequent parentheses. 117*e8d8bef9SDimitry Andric bool objectLike(llvm::StringRef Name) const; 118*e8d8bef9SDimitry Andric 119*e8d8bef9SDimitry Andric /// Returns the expanded stream of format tokens for \p ID, where 120*e8d8bef9SDimitry Andric /// each element in \p Args is a positional argument to the macro call. 121*e8d8bef9SDimitry Andric llvm::SmallVector<FormatToken *, 8> expand(FormatToken *ID, 122*e8d8bef9SDimitry Andric ArgsList Args) const; 123*e8d8bef9SDimitry Andric 124*e8d8bef9SDimitry Andric private: 125*e8d8bef9SDimitry Andric struct Definition; 126*e8d8bef9SDimitry Andric class DefinitionParser; 127*e8d8bef9SDimitry Andric 128*e8d8bef9SDimitry Andric void parseDefinition(const std::string &Macro); 129*e8d8bef9SDimitry Andric 130*e8d8bef9SDimitry Andric clang::SourceManager &SourceMgr; 131*e8d8bef9SDimitry Andric const FormatStyle &Style; 132*e8d8bef9SDimitry Andric llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator; 133*e8d8bef9SDimitry Andric IdentifierTable &IdentTable; 134*e8d8bef9SDimitry Andric std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers; 135*e8d8bef9SDimitry Andric llvm::StringMap<Definition> Definitions; 136*e8d8bef9SDimitry Andric }; 137*e8d8bef9SDimitry Andric 138*e8d8bef9SDimitry Andric } // namespace format 139*e8d8bef9SDimitry Andric } // namespace clang 140*e8d8bef9SDimitry Andric 141*e8d8bef9SDimitry Andric #endif 142