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