xref: /freebsd-src/contrib/llvm-project/clang/lib/Format/Macros.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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