1 //===-- ClangASTNodesEmitter.cpp - Generate Clang AST node tables ---------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // These tablegen backends emit Clang AST node tables
11 //===----------------------------------------------------------------------===//
13 #include "ASTTableGen.h"
14 #include "TableGenBackends.h"
16 #include "llvm/TableGen/Error.h"
17 #include "llvm/TableGen/Record.h"
18 #include "llvm/TableGen/TableGenBackend.h"
23 using namespace clang
;
24 using namespace clang::tblgen
;
26 /// ClangASTNodesEmitter - The top-level class emits .inc files containing
27 /// declarations of Clang statements.
30 class ClangASTNodesEmitter
{
31 // A map from a node to each of its derived nodes.
32 typedef std::multimap
<ASTNode
, ASTNode
> ChildMap
;
33 typedef ChildMap::const_iterator ChildIterator
;
35 std::set
<ASTNode
> PrioritizedClasses
;
36 const RecordKeeper
&Records
;
38 const std::string
&NodeClassName
;
39 const std::string
&BaseSuffix
;
40 std::string MacroHierarchyName
;
43 // Create a macro-ized version of a name
44 static std::string
macroName(StringRef S
) { return S
.upper(); }
46 const std::string
¯oHierarchyName() {
47 assert(Root
&& "root node not yet derived!");
48 if (MacroHierarchyName
.empty())
49 MacroHierarchyName
= macroName(Root
.getName());
50 return MacroHierarchyName
;
53 // Return the name to be printed in the base field. Normally this is
54 // the record's name plus the base suffix, but if it is the root node and
55 // the suffix is non-empty, it's just the suffix.
56 std::string
baseName(ASTNode node
) {
57 if (node
== Root
&& !BaseSuffix
.empty())
60 return node
.getName().str() + BaseSuffix
;
63 void deriveChildTree();
65 std::pair
<ASTNode
, ASTNode
> EmitNode(raw_ostream
& OS
, ASTNode Base
);
67 explicit ClangASTNodesEmitter(const RecordKeeper
&R
, const std::string
&N
,
69 std::string_view PriorizeIfSubclassOf
)
70 : Records(R
), NodeClassName(N
), BaseSuffix(S
) {
71 ArrayRef
<const Record
*> vecPrioritized
=
72 R
.getAllDerivedDefinitionsIfDefined(PriorizeIfSubclassOf
);
74 std::set
<ASTNode
>(vecPrioritized
.begin(), vecPrioritized
.end());
77 // run - Output the .inc file contents
78 void run(raw_ostream
&OS
);
80 } // end anonymous namespace
82 //===----------------------------------------------------------------------===//
83 // Statement Node Tables (.inc file) generation.
84 //===----------------------------------------------------------------------===//
86 // Returns the first and last non-abstract subrecords
87 // Called recursively to ensure that nodes remain contiguous
88 std::pair
<ASTNode
, ASTNode
> ClangASTNodesEmitter::EmitNode(raw_ostream
&OS
,
90 std::string BaseName
= macroName(Base
.getName());
92 auto [II
, E
] = Tree
.equal_range(Base
);
93 bool HasChildren
= II
!= E
;
96 if (!Base
.isAbstract())
99 auto Comp
= [this](const ASTNode
&LHS
, const ASTNode
&RHS
) {
100 bool LHSPrioritized
= PrioritizedClasses
.count(LHS
) > 0;
101 bool RHSPrioritized
= PrioritizedClasses
.count(RHS
) > 0;
102 return std::tuple(LHSPrioritized
, LHS
.getName()) >
103 std::tuple(RHSPrioritized
, RHS
.getName());
105 auto SortedChildren
= std::set
<ASTNode
, decltype(Comp
)>(Comp
);
107 for (; II
!= E
; ++II
) {
108 SortedChildren
.insert(II
->second
);
111 for (const auto &Child
: SortedChildren
) {
112 bool Abstract
= Child
.isAbstract();
113 std::string NodeName
= macroName(Child
.getName());
115 OS
<< "#ifndef " << NodeName
<< "\n";
116 OS
<< "# define " << NodeName
<< "(Type, Base) "
117 << BaseName
<< "(Type, Base)\n";
120 if (Abstract
) OS
<< "ABSTRACT_" << macroHierarchyName() << "(";
121 OS
<< NodeName
<< "(" << Child
.getName() << ", " << baseName(Base
) << ")";
122 if (Abstract
) OS
<< ")";
125 auto Result
= EmitNode(OS
, Child
);
126 assert(Result
.first
&& Result
.second
&& "node didn't have children?");
128 // Update the range of Base.
129 if (!First
) First
= Result
.first
;
130 Last
= Result
.second
;
132 OS
<< "#undef " << NodeName
<< "\n\n";
135 // If there aren't first/last nodes, it must be because there were no
136 // children and this node was abstract, which is not a sensible combination.
138 PrintFatalError(Base
.getLoc(), "abstract node has no children");
139 assert(Last
&& "set First without Last");
142 // Use FOO_RANGE unless this is the last of the ranges, in which case
143 // use LAST_FOO_RANGE.
145 OS
<< "LAST_" << macroHierarchyName() << "_RANGE(";
147 OS
<< macroHierarchyName() << "_RANGE(";
148 OS
<< Base
.getName() << ", " << First
.getName() << ", "
149 << Last
.getName() << ")\n\n";
152 return std::make_pair(First
, Last
);
155 void ClangASTNodesEmitter::deriveChildTree() {
156 assert(!Root
&& "already computed tree");
159 for (const Record
*R
: Records
.getAllDerivedDefinitions(NodeClassName
)) {
160 if (auto B
= R
->getValueAsOptionalDef(BaseFieldName
))
163 PrintFatalError(R
->getLoc(),
164 Twine("multiple root nodes in \"") + NodeClassName
171 PrintFatalError(Twine("didn't find root node in \"") + NodeClassName
175 void ClangASTNodesEmitter::run(raw_ostream
&OS
) {
178 emitSourceFileHeader("List of AST nodes of a particular kind", OS
, Records
);
180 // Write the preamble
181 OS
<< "#ifndef ABSTRACT_" << macroHierarchyName() << "\n";
182 OS
<< "# define ABSTRACT_" << macroHierarchyName() << "(Type) Type\n";
185 OS
<< "#ifndef " << macroHierarchyName() << "_RANGE\n";
187 << macroHierarchyName() << "_RANGE(Base, First, Last)\n";
190 OS
<< "#ifndef LAST_" << macroHierarchyName() << "_RANGE\n";
191 OS
<< "# define LAST_" << macroHierarchyName()
192 << "_RANGE(Base, First, Last) " << macroHierarchyName()
193 << "_RANGE(Base, First, Last)\n";
198 OS
<< "#undef " << macroHierarchyName() << "\n";
199 OS
<< "#undef " << macroHierarchyName() << "_RANGE\n";
200 OS
<< "#undef LAST_" << macroHierarchyName() << "_RANGE\n";
201 OS
<< "#undef ABSTRACT_" << macroHierarchyName() << "\n";
204 void clang::EmitClangASTNodes(const RecordKeeper
&RK
, raw_ostream
&OS
,
205 const std::string
&N
, const std::string
&S
,
206 std::string_view PriorizeIfSubclassOf
) {
207 ClangASTNodesEmitter(RK
, N
, S
, PriorizeIfSubclassOf
).run(OS
);
210 void printDeclContext(const std::multimap
<const Record
*, const Record
*> &Tree
,
211 const Record
*DeclContext
, raw_ostream
&OS
) {
212 if (!DeclContext
->getValueAsBit(AbstractFieldName
))
213 OS
<< "DECL_CONTEXT(" << DeclContext
->getName() << ")\n";
214 auto [II
, E
] = Tree
.equal_range(DeclContext
);
215 for (; II
!= E
; ++II
) {
216 printDeclContext(Tree
, II
->second
, OS
);
220 // Emits and addendum to a .inc file to enumerate the clang declaration
222 void clang::EmitClangDeclContext(const RecordKeeper
&Records
, raw_ostream
&OS
) {
223 // FIXME: Find a .td file format to allow for this to be represented better.
225 emitSourceFileHeader("List of AST Decl nodes", OS
, Records
);
227 OS
<< "#ifndef DECL_CONTEXT\n";
228 OS
<< "# define DECL_CONTEXT(DECL)\n";
231 std::multimap
<const Record
*, const Record
*> Tree
;
233 for (const Record
*R
: Records
.getAllDerivedDefinitions(DeclNodeClassName
)) {
234 if (auto *B
= R
->getValueAsOptionalDef(BaseFieldName
))
238 for (const Record
*DeclContext
:
239 Records
.getAllDerivedDefinitions(DeclContextNodeClassName
)) {
240 printDeclContext(Tree
, DeclContext
, OS
);
243 OS
<< "#undef DECL_CONTEXT\n";