1 | //===-- ClangASTNodesEmitter.cpp - Generate Clang AST node tables ---------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // These tablegen backends emit Clang AST node tables |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "ASTTableGen.h" |
14 | #include "TableGenBackends.h" |
15 | |
16 | #include "llvm/TableGen/Error.h" |
17 | #include "llvm/TableGen/Record.h" |
18 | #include "llvm/TableGen/TableGenBackend.h" |
19 | #include <map> |
20 | #include <set> |
21 | #include <string> |
22 | using namespace llvm; |
23 | using namespace clang; |
24 | using namespace clang::tblgen; |
25 | |
26 | /// ClangASTNodesEmitter - The top-level class emits .inc files containing |
27 | /// declarations of Clang statements. |
28 | /// |
29 | namespace { |
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; |
34 | |
35 | std::set<ASTNode> PrioritizedClasses; |
36 | const RecordKeeper &Records; |
37 | ASTNode Root; |
38 | const std::string &NodeClassName; |
39 | const std::string &BaseSuffix; |
40 | std::string MacroHierarchyName; |
41 | ChildMap Tree; |
42 | |
43 | // Create a macro-ized version of a name |
44 | static std::string macroName(StringRef S) { return S.upper(); } |
45 | |
46 | const std::string ¯oHierarchyName() { |
47 | assert(Root && "root node not yet derived!" ); |
48 | if (MacroHierarchyName.empty()) |
49 | MacroHierarchyName = macroName(S: Root.getName()); |
50 | return MacroHierarchyName; |
51 | } |
52 | |
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()) |
58 | return BaseSuffix; |
59 | |
60 | return node.getName().str() + BaseSuffix; |
61 | } |
62 | |
63 | void deriveChildTree(); |
64 | |
65 | std::pair<ASTNode, ASTNode> EmitNode(raw_ostream& OS, ASTNode Base); |
66 | public: |
67 | explicit ClangASTNodesEmitter(const RecordKeeper &R, const std::string &N, |
68 | const std::string &S, |
69 | std::string_view PriorizeIfSubclassOf) |
70 | : Records(R), NodeClassName(N), BaseSuffix(S) { |
71 | ArrayRef<const Record *> vecPrioritized = |
72 | R.getAllDerivedDefinitionsIfDefined(ClassName: PriorizeIfSubclassOf); |
73 | PrioritizedClasses = |
74 | std::set<ASTNode>(vecPrioritized.begin(), vecPrioritized.end()); |
75 | } |
76 | |
77 | // run - Output the .inc file contents |
78 | void run(raw_ostream &OS); |
79 | }; |
80 | } // end anonymous namespace |
81 | |
82 | //===----------------------------------------------------------------------===// |
83 | // Statement Node Tables (.inc file) generation. |
84 | //===----------------------------------------------------------------------===// |
85 | |
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, |
89 | ASTNode Base) { |
90 | std::string BaseName = macroName(S: Base.getName()); |
91 | |
92 | auto [II, E] = Tree.equal_range(x: Base); |
93 | bool HasChildren = II != E; |
94 | |
95 | ASTNode First, Last; |
96 | if (!Base.isAbstract()) |
97 | First = Last = Base; |
98 | |
99 | auto Comp = [this](const ASTNode &LHS, const ASTNode &RHS) { |
100 | bool LHSPrioritized = PrioritizedClasses.count(x: LHS) > 0; |
101 | bool RHSPrioritized = PrioritizedClasses.count(x: RHS) > 0; |
102 | return std::tuple(LHSPrioritized, LHS.getName()) > |
103 | std::tuple(RHSPrioritized, RHS.getName()); |
104 | }; |
105 | auto SortedChildren = std::set<ASTNode, decltype(Comp)>(Comp); |
106 | |
107 | for (; II != E; ++II) { |
108 | SortedChildren.insert(x: II->second); |
109 | } |
110 | |
111 | for (const auto &Child : SortedChildren) { |
112 | bool Abstract = Child.isAbstract(); |
113 | std::string NodeName = macroName(S: Child.getName()); |
114 | |
115 | OS << "#ifndef " << NodeName << "\n" ; |
116 | OS << "# define " << NodeName << "(Type, Base) " |
117 | << BaseName << "(Type, Base)\n" ; |
118 | OS << "#endif\n" ; |
119 | |
120 | if (Abstract) OS << "ABSTRACT_" << macroHierarchyName() << "(" ; |
121 | OS << NodeName << "(" << Child.getName() << ", " << baseName(node: Base) << ")" ; |
122 | if (Abstract) OS << ")" ; |
123 | OS << "\n" ; |
124 | |
125 | auto Result = EmitNode(OS, Base: Child); |
126 | assert(Result.first && Result.second && "node didn't have children?" ); |
127 | |
128 | // Update the range of Base. |
129 | if (!First) First = Result.first; |
130 | Last = Result.second; |
131 | |
132 | OS << "#undef " << NodeName << "\n\n" ; |
133 | } |
134 | |
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. |
137 | if (!First) |
138 | PrintFatalError(ErrorLoc: Base.getLoc(), Msg: "abstract node has no children" ); |
139 | assert(Last && "set First without Last" ); |
140 | |
141 | if (HasChildren) { |
142 | // Use FOO_RANGE unless this is the last of the ranges, in which case |
143 | // use LAST_FOO_RANGE. |
144 | if (Base == Root) |
145 | OS << "LAST_" << macroHierarchyName() << "_RANGE(" ; |
146 | else |
147 | OS << macroHierarchyName() << "_RANGE(" ; |
148 | OS << Base.getName() << ", " << First.getName() << ", " |
149 | << Last.getName() << ")\n\n" ; |
150 | } |
151 | |
152 | return std::make_pair(x&: First, y&: Last); |
153 | } |
154 | |
155 | void ClangASTNodesEmitter::deriveChildTree() { |
156 | assert(!Root && "already computed tree" ); |
157 | |
158 | // Emit statements |
159 | for (const Record *R : Records.getAllDerivedDefinitions(ClassName: NodeClassName)) { |
160 | if (auto B = R->getValueAsOptionalDef(BaseFieldName)) |
161 | Tree.insert(x: {B, R}); |
162 | else if (Root) |
163 | PrintFatalError(ErrorLoc: R->getLoc(), |
164 | Msg: Twine("multiple root nodes in \"" ) + NodeClassName |
165 | + "\" hierarchy" ); |
166 | else |
167 | Root = R; |
168 | } |
169 | |
170 | if (!Root) |
171 | PrintFatalError(Msg: Twine("didn't find root node in \"" ) + NodeClassName |
172 | + "\" hierarchy" ); |
173 | } |
174 | |
175 | void ClangASTNodesEmitter::run(raw_ostream &OS) { |
176 | deriveChildTree(); |
177 | |
178 | emitSourceFileHeader(Desc: "List of AST nodes of a particular kind" , OS, Record: Records); |
179 | |
180 | // Write the preamble |
181 | OS << "#ifndef ABSTRACT_" << macroHierarchyName() << "\n" ; |
182 | OS << "# define ABSTRACT_" << macroHierarchyName() << "(Type) Type\n" ; |
183 | OS << "#endif\n" ; |
184 | |
185 | OS << "#ifndef " << macroHierarchyName() << "_RANGE\n" ; |
186 | OS << "# define " |
187 | << macroHierarchyName() << "_RANGE(Base, First, Last)\n" ; |
188 | OS << "#endif\n\n" ; |
189 | |
190 | OS << "#ifndef LAST_" << macroHierarchyName() << "_RANGE\n" ; |
191 | OS << "# define LAST_" << macroHierarchyName() |
192 | << "_RANGE(Base, First, Last) " << macroHierarchyName() |
193 | << "_RANGE(Base, First, Last)\n" ; |
194 | OS << "#endif\n\n" ; |
195 | |
196 | EmitNode(OS, Base: Root); |
197 | |
198 | OS << "#undef " << macroHierarchyName() << "\n" ; |
199 | OS << "#undef " << macroHierarchyName() << "_RANGE\n" ; |
200 | OS << "#undef LAST_" << macroHierarchyName() << "_RANGE\n" ; |
201 | OS << "#undef ABSTRACT_" << macroHierarchyName() << "\n" ; |
202 | } |
203 | |
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); |
208 | } |
209 | |
210 | static void |
211 | printDeclContext(const std::multimap<const Record *, const Record *> &Tree, |
212 | const Record *DeclContext, raw_ostream &OS) { |
213 | if (!DeclContext->getValueAsBit(AbstractFieldName)) |
214 | OS << "DECL_CONTEXT(" << DeclContext->getName() << ")\n" ; |
215 | auto [II, E] = Tree.equal_range(x: DeclContext); |
216 | for (; II != E; ++II) { |
217 | printDeclContext(Tree, DeclContext: II->second, OS); |
218 | } |
219 | } |
220 | |
221 | // Emits and addendum to a .inc file to enumerate the clang declaration |
222 | // contexts. |
223 | void clang::EmitClangDeclContext(const RecordKeeper &Records, raw_ostream &OS) { |
224 | // FIXME: Find a .td file format to allow for this to be represented better. |
225 | |
226 | emitSourceFileHeader(Desc: "List of AST Decl nodes" , OS, Record: Records); |
227 | |
228 | OS << "#ifndef DECL_CONTEXT\n" ; |
229 | OS << "# define DECL_CONTEXT(DECL)\n" ; |
230 | OS << "#endif\n" ; |
231 | |
232 | std::multimap<const Record *, const Record *> Tree; |
233 | |
234 | for (const Record *R : Records.getAllDerivedDefinitions(DeclNodeClassName)) { |
235 | if (auto *B = R->getValueAsOptionalDef(BaseFieldName)) |
236 | Tree.insert(x: {B, R}); |
237 | } |
238 | |
239 | for (const Record *DeclContext : |
240 | Records.getAllDerivedDefinitions(DeclContextNodeClassName)) { |
241 | printDeclContext(Tree, DeclContext, OS); |
242 | } |
243 | |
244 | OS << "#undef DECL_CONTEXT\n" ; |
245 | } |
246 | |