xref: /openbsd-src/gnu/llvm/clang/utils/TableGen/ClangASTNodesEmitter.cpp (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
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 &macroHierarchyName() {
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