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