/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/ClangASTNodesEmitter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //=== ClangASTNodesEmitter.cpp - Generate Clang AST node tables -*- C++ -*-===// |
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 <cctype> |
20 | | #include <map> |
21 | | #include <set> |
22 | | #include <string> |
23 | | using namespace llvm; |
24 | | using namespace clang; |
25 | | using namespace clang::tblgen; |
26 | | |
27 | | /// ClangASTNodesEmitter - The top-level class emits .inc files containing |
28 | | /// declarations of Clang statements. |
29 | | /// |
30 | | namespace { |
31 | | class ClangASTNodesEmitter { |
32 | | // A map from a node to each of its derived nodes. |
33 | | typedef std::multimap<ASTNode, ASTNode> ChildMap; |
34 | | typedef ChildMap::const_iterator ChildIterator; |
35 | | |
36 | | 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 | 0 | static std::string macroName(std::string S) { |
45 | 0 | for (unsigned i = 0; i < S.size(); ++i) |
46 | 0 | S[i] = std::toupper(S[i]); |
47 | |
|
48 | 0 | return S; |
49 | 0 | } |
50 | | |
51 | 0 | const std::string ¯oHierarchyName() { |
52 | 0 | assert(Root && "root node not yet derived!"); |
53 | 0 | if (MacroHierarchyName.empty()) |
54 | 0 | MacroHierarchyName = macroName(std::string(Root.getName())); |
55 | 0 | return MacroHierarchyName; |
56 | 0 | } |
57 | | |
58 | | // Return the name to be printed in the base field. Normally this is |
59 | | // the record's name plus the base suffix, but if it is the root node and |
60 | | // the suffix is non-empty, it's just the suffix. |
61 | 0 | std::string baseName(ASTNode node) { |
62 | 0 | if (node == Root && !BaseSuffix.empty()) |
63 | 0 | return BaseSuffix; |
64 | | |
65 | 0 | return node.getName().str() + BaseSuffix; |
66 | 0 | } |
67 | | |
68 | | void deriveChildTree(); |
69 | | |
70 | | std::pair<ASTNode, ASTNode> EmitNode(raw_ostream& OS, ASTNode Base); |
71 | | public: |
72 | | explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N, |
73 | | const std::string &S) |
74 | 0 | : Records(R), NodeClassName(N), BaseSuffix(S) {} |
75 | | |
76 | | // run - Output the .inc file contents |
77 | | void run(raw_ostream &OS); |
78 | | }; |
79 | | } // end anonymous namespace |
80 | | |
81 | | //===----------------------------------------------------------------------===// |
82 | | // Statement Node Tables (.inc file) generation. |
83 | | //===----------------------------------------------------------------------===// |
84 | | |
85 | | // Returns the first and last non-abstract subrecords |
86 | | // Called recursively to ensure that nodes remain contiguous |
87 | | std::pair<ASTNode, ASTNode> ClangASTNodesEmitter::EmitNode(raw_ostream &OS, |
88 | 0 | ASTNode Base) { |
89 | 0 | std::string BaseName = macroName(std::string(Base.getName())); |
90 | |
|
91 | 0 | ChildIterator i = Tree.lower_bound(Base), e = Tree.upper_bound(Base); |
92 | 0 | bool HasChildren = (i != e); |
93 | |
|
94 | 0 | ASTNode First, Last; |
95 | 0 | if (!Base.isAbstract()) |
96 | 0 | First = Last = Base; |
97 | |
|
98 | 0 | for (; i != e; ++i) { |
99 | 0 | ASTNode Child = i->second; |
100 | 0 | bool Abstract = Child.isAbstract(); |
101 | 0 | std::string NodeName = macroName(std::string(Child.getName())); |
102 | |
|
103 | 0 | OS << "#ifndef " << NodeName << "\n"; |
104 | 0 | OS << "# define " << NodeName << "(Type, Base) " |
105 | 0 | << BaseName << "(Type, Base)\n"; |
106 | 0 | OS << "#endif\n"; |
107 | |
|
108 | 0 | if (Abstract) OS << "ABSTRACT_" << macroHierarchyName() << "("; |
109 | 0 | OS << NodeName << "(" << Child.getName() << ", " << baseName(Base) << ")"; |
110 | 0 | if (Abstract) OS << ")"; |
111 | 0 | OS << "\n"; |
112 | |
|
113 | 0 | auto Result = EmitNode(OS, Child); |
114 | 0 | assert(Result.first && Result.second && "node didn't have children?"); |
115 | | |
116 | | // Update the range of Base. |
117 | 0 | if (!First) First = Result.first; |
118 | 0 | Last = Result.second; |
119 | |
|
120 | 0 | OS << "#undef " << NodeName << "\n\n"; |
121 | 0 | } |
122 | | |
123 | | // If there aren't first/last nodes, it must be because there were no |
124 | | // children and this node was abstract, which is not a sensible combination. |
125 | 0 | if (!First) { |
126 | 0 | PrintFatalError(Base.getLoc(), "abstract node has no children"); |
127 | 0 | } |
128 | 0 | assert(Last && "set First without Last"); |
129 | | |
130 | 0 | if (HasChildren) { |
131 | | // Use FOO_RANGE unless this is the last of the ranges, in which case |
132 | | // use LAST_FOO_RANGE. |
133 | 0 | if (Base == Root) |
134 | 0 | OS << "LAST_" << macroHierarchyName() << "_RANGE("; |
135 | 0 | else |
136 | 0 | OS << macroHierarchyName() << "_RANGE("; |
137 | 0 | OS << Base.getName() << ", " << First.getName() << ", " |
138 | 0 | << Last.getName() << ")\n\n"; |
139 | 0 | } |
140 | |
|
141 | 0 | return std::make_pair(First, Last); |
142 | 0 | } |
143 | | |
144 | 0 | void ClangASTNodesEmitter::deriveChildTree() { |
145 | 0 | assert(!Root && "already computed tree"); |
146 | | |
147 | | // Emit statements |
148 | 0 | const std::vector<Record*> Stmts |
149 | 0 | = Records.getAllDerivedDefinitions(NodeClassName); |
150 | |
|
151 | 0 | for (unsigned i = 0, e = Stmts.size(); i != e; ++i) { |
152 | 0 | Record *R = Stmts[i]; |
153 | |
|
154 | 0 | if (auto B = R->getValueAsOptionalDef(BaseFieldName)) |
155 | 0 | Tree.insert(std::make_pair(B, R)); |
156 | 0 | else if (Root) |
157 | 0 | PrintFatalError(R->getLoc(), |
158 | 0 | Twine("multiple root nodes in \"") + NodeClassName |
159 | 0 | + "\" hierarchy"); |
160 | 0 | else |
161 | 0 | Root = R; |
162 | 0 | } |
163 | |
|
164 | 0 | if (!Root) |
165 | 0 | PrintFatalError(Twine("didn't find root node in \"") + NodeClassName |
166 | 0 | + "\" hierarchy"); |
167 | 0 | } |
168 | | |
169 | 0 | void ClangASTNodesEmitter::run(raw_ostream &OS) { |
170 | 0 | deriveChildTree(); |
171 | |
|
172 | 0 | emitSourceFileHeader("List of AST nodes of a particular kind", OS); |
173 | | |
174 | | // Write the preamble |
175 | 0 | OS << "#ifndef ABSTRACT_" << macroHierarchyName() << "\n"; |
176 | 0 | OS << "# define ABSTRACT_" << macroHierarchyName() << "(Type) Type\n"; |
177 | 0 | OS << "#endif\n"; |
178 | |
|
179 | 0 | OS << "#ifndef " << macroHierarchyName() << "_RANGE\n"; |
180 | 0 | OS << "# define " |
181 | 0 | << macroHierarchyName() << "_RANGE(Base, First, Last)\n"; |
182 | 0 | OS << "#endif\n\n"; |
183 | |
|
184 | 0 | OS << "#ifndef LAST_" << macroHierarchyName() << "_RANGE\n"; |
185 | 0 | OS << "# define LAST_" |
186 | 0 | << macroHierarchyName() << "_RANGE(Base, First, Last) " |
187 | 0 | << macroHierarchyName() << "_RANGE(Base, First, Last)\n"; |
188 | 0 | OS << "#endif\n\n"; |
189 | |
|
190 | 0 | EmitNode(OS, Root); |
191 | |
|
192 | 0 | OS << "#undef " << macroHierarchyName() << "\n"; |
193 | 0 | OS << "#undef " << macroHierarchyName() << "_RANGE\n"; |
194 | 0 | OS << "#undef LAST_" << macroHierarchyName() << "_RANGE\n"; |
195 | 0 | OS << "#undef ABSTRACT_" << macroHierarchyName() << "\n"; |
196 | 0 | } |
197 | | |
198 | | void clang::EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, |
199 | 0 | const std::string &N, const std::string &S) { |
200 | 0 | ClangASTNodesEmitter(RK, N, S).run(OS); |
201 | 0 | } |
202 | | |
203 | | // Emits and addendum to a .inc file to enumerate the clang declaration |
204 | | // contexts. |
205 | 0 | void clang::EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) { |
206 | | // FIXME: Find a .td file format to allow for this to be represented better. |
207 | |
|
208 | 0 | emitSourceFileHeader("List of AST Decl nodes", OS); |
209 | |
|
210 | 0 | OS << "#ifndef DECL_CONTEXT\n"; |
211 | 0 | OS << "# define DECL_CONTEXT(DECL)\n"; |
212 | 0 | OS << "#endif\n"; |
213 | | |
214 | 0 | OS << "#ifndef DECL_CONTEXT_BASE\n"; |
215 | 0 | OS << "# define DECL_CONTEXT_BASE(DECL) DECL_CONTEXT(DECL)\n"; |
216 | 0 | OS << "#endif\n"; |
217 | | |
218 | 0 | typedef std::set<Record*> RecordSet; |
219 | 0 | typedef std::vector<Record*> RecordVector; |
220 | | |
221 | 0 | RecordVector DeclContextsVector |
222 | 0 | = Records.getAllDerivedDefinitions(DeclContextNodeClassName); |
223 | 0 | RecordVector Decls = Records.getAllDerivedDefinitions(DeclNodeClassName); |
224 | 0 | RecordSet DeclContexts (DeclContextsVector.begin(), DeclContextsVector.end()); |
225 | | |
226 | 0 | for (RecordVector::iterator i = Decls.begin(), e = Decls.end(); i != e; ++i) { |
227 | 0 | Record *R = *i; |
228 | |
|
229 | 0 | if (Record *B = R->getValueAsOptionalDef(BaseFieldName)) { |
230 | 0 | if (DeclContexts.find(B) != DeclContexts.end()) { |
231 | 0 | OS << "DECL_CONTEXT_BASE(" << B->getName() << ")\n"; |
232 | 0 | DeclContexts.erase(B); |
233 | 0 | } |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | // To keep identical order, RecordVector may be used |
238 | | // instead of RecordSet. |
239 | 0 | for (RecordVector::iterator |
240 | 0 | i = DeclContextsVector.begin(), e = DeclContextsVector.end(); |
241 | 0 | i != e; ++i) |
242 | 0 | if (DeclContexts.find(*i) != DeclContexts.end()) |
243 | 0 | OS << "DECL_CONTEXT(" << (*i)->getName() << ")\n"; |
244 | |
|
245 | 0 | OS << "#undef DECL_CONTEXT\n"; |
246 | 0 | OS << "#undef DECL_CONTEXT_BASE\n"; |
247 | 0 | } |