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(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(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(Base.getName()); 91 92 auto [II, E] = Tree.equal_range(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(LHS) > 0; 101 bool RHSPrioritized = PrioritizedClasses.count(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(II->second); 109 } 110 111 for (const auto &Child : SortedChildren) { 112 bool Abstract = Child.isAbstract(); 113 std::string NodeName = macroName(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(Base) << ")"; 122 if (Abstract) OS << ")"; 123 OS << "\n"; 124 125 auto Result = EmitNode(OS, 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(Base.getLoc(), "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(First, Last); 153 } 154 155 void ClangASTNodesEmitter::deriveChildTree() { 156 assert(!Root && "already computed tree"); 157 158 // Emit statements 159 for (const Record *R : Records.getAllDerivedDefinitions(NodeClassName)) { 160 if (auto B = R->getValueAsOptionalDef(BaseFieldName)) 161 Tree.insert({B, R}); 162 else if (Root) 163 PrintFatalError(R->getLoc(), 164 Twine("multiple root nodes in \"") + NodeClassName 165 + "\" hierarchy"); 166 else 167 Root = R; 168 } 169 170 if (!Root) 171 PrintFatalError(Twine("didn't find root node in \"") + NodeClassName 172 + "\" hierarchy"); 173 } 174 175 void ClangASTNodesEmitter::run(raw_ostream &OS) { 176 deriveChildTree(); 177 178 emitSourceFileHeader("List of AST nodes of a particular kind", OS, 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, 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(DeclContext); 216 for (; II != E; ++II) { 217 printDeclContext(Tree, 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("List of AST Decl nodes", OS, 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({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