Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ClangASTNodesEmitter.cpp
35230 views
//=== ClangASTNodesEmitter.cpp - Generate Clang AST node tables -*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// These tablegen backends emit Clang AST node tables9//10//===----------------------------------------------------------------------===//1112#include "ASTTableGen.h"13#include "TableGenBackends.h"1415#include "llvm/TableGen/Error.h"16#include "llvm/TableGen/Record.h"17#include "llvm/TableGen/TableGenBackend.h"18#include <cctype>19#include <map>20#include <set>21#include <string>22using namespace llvm;23using namespace clang;24using namespace clang::tblgen;2526/// ClangASTNodesEmitter - The top-level class emits .inc files containing27/// declarations of Clang statements.28///29namespace {30class ClangASTNodesEmitter {31// A map from a node to each of its derived nodes.32typedef std::multimap<ASTNode, ASTNode> ChildMap;33typedef ChildMap::const_iterator ChildIterator;3435std::set<ASTNode> PrioritizedClasses;36RecordKeeper &Records;37ASTNode Root;38const std::string &NodeClassName;39const std::string &BaseSuffix;40std::string MacroHierarchyName;41ChildMap Tree;4243// Create a macro-ized version of a name44static std::string macroName(std::string S) {45for (unsigned i = 0; i < S.size(); ++i)46S[i] = std::toupper(S[i]);4748return S;49}5051const std::string ¯oHierarchyName() {52assert(Root && "root node not yet derived!");53if (MacroHierarchyName.empty())54MacroHierarchyName = macroName(std::string(Root.getName()));55return MacroHierarchyName;56}5758// Return the name to be printed in the base field. Normally this is59// the record's name plus the base suffix, but if it is the root node and60// the suffix is non-empty, it's just the suffix.61std::string baseName(ASTNode node) {62if (node == Root && !BaseSuffix.empty())63return BaseSuffix;6465return node.getName().str() + BaseSuffix;66}6768void deriveChildTree();6970std::pair<ASTNode, ASTNode> EmitNode(raw_ostream& OS, ASTNode Base);71public:72explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N,73const std::string &S,74std::string_view PriorizeIfSubclassOf)75: Records(R), NodeClassName(N), BaseSuffix(S) {76auto vecPrioritized =77PriorizeIfSubclassOf.empty()78? std::vector<Record *>{}79: R.getAllDerivedDefinitions(PriorizeIfSubclassOf);80PrioritizedClasses =81std::set<ASTNode>(vecPrioritized.begin(), vecPrioritized.end());82}8384// run - Output the .inc file contents85void run(raw_ostream &OS);86};87} // end anonymous namespace8889//===----------------------------------------------------------------------===//90// Statement Node Tables (.inc file) generation.91//===----------------------------------------------------------------------===//9293// Returns the first and last non-abstract subrecords94// Called recursively to ensure that nodes remain contiguous95std::pair<ASTNode, ASTNode> ClangASTNodesEmitter::EmitNode(raw_ostream &OS,96ASTNode Base) {97std::string BaseName = macroName(std::string(Base.getName()));9899ChildIterator i = Tree.lower_bound(Base), e = Tree.upper_bound(Base);100bool HasChildren = (i != e);101102ASTNode First, Last;103if (!Base.isAbstract())104First = Last = Base;105106auto comp = [this](ASTNode LHS, ASTNode RHS) {107auto LHSPrioritized = PrioritizedClasses.count(LHS) > 0;108auto RHSPrioritized = PrioritizedClasses.count(RHS) > 0;109if (LHSPrioritized && !RHSPrioritized)110return true;111if (!LHSPrioritized && RHSPrioritized)112return false;113114return LHS.getName() > RHS.getName();115};116auto SortedChildren = std::set<ASTNode, decltype(comp)>(comp);117118for (; i != e; ++i) {119SortedChildren.insert(i->second);120}121122for (const auto &Child : SortedChildren) {123bool Abstract = Child.isAbstract();124std::string NodeName = macroName(std::string(Child.getName()));125126OS << "#ifndef " << NodeName << "\n";127OS << "# define " << NodeName << "(Type, Base) "128<< BaseName << "(Type, Base)\n";129OS << "#endif\n";130131if (Abstract) OS << "ABSTRACT_" << macroHierarchyName() << "(";132OS << NodeName << "(" << Child.getName() << ", " << baseName(Base) << ")";133if (Abstract) OS << ")";134OS << "\n";135136auto Result = EmitNode(OS, Child);137assert(Result.first && Result.second && "node didn't have children?");138139// Update the range of Base.140if (!First) First = Result.first;141Last = Result.second;142143OS << "#undef " << NodeName << "\n\n";144}145146// If there aren't first/last nodes, it must be because there were no147// children and this node was abstract, which is not a sensible combination.148if (!First) {149PrintFatalError(Base.getLoc(), "abstract node has no children");150}151assert(Last && "set First without Last");152153if (HasChildren) {154// Use FOO_RANGE unless this is the last of the ranges, in which case155// use LAST_FOO_RANGE.156if (Base == Root)157OS << "LAST_" << macroHierarchyName() << "_RANGE(";158else159OS << macroHierarchyName() << "_RANGE(";160OS << Base.getName() << ", " << First.getName() << ", "161<< Last.getName() << ")\n\n";162}163164return std::make_pair(First, Last);165}166167void ClangASTNodesEmitter::deriveChildTree() {168assert(!Root && "already computed tree");169170// Emit statements171const std::vector<Record*> Stmts172= Records.getAllDerivedDefinitions(NodeClassName);173174for (auto *R : Stmts) {175if (auto B = R->getValueAsOptionalDef(BaseFieldName))176Tree.insert(std::make_pair(B, R));177else if (Root)178PrintFatalError(R->getLoc(),179Twine("multiple root nodes in \"") + NodeClassName180+ "\" hierarchy");181else182Root = R;183}184185if (!Root)186PrintFatalError(Twine("didn't find root node in \"") + NodeClassName187+ "\" hierarchy");188}189190void ClangASTNodesEmitter::run(raw_ostream &OS) {191deriveChildTree();192193emitSourceFileHeader("List of AST nodes of a particular kind", OS, Records);194195// Write the preamble196OS << "#ifndef ABSTRACT_" << macroHierarchyName() << "\n";197OS << "# define ABSTRACT_" << macroHierarchyName() << "(Type) Type\n";198OS << "#endif\n";199200OS << "#ifndef " << macroHierarchyName() << "_RANGE\n";201OS << "# define "202<< macroHierarchyName() << "_RANGE(Base, First, Last)\n";203OS << "#endif\n\n";204205OS << "#ifndef LAST_" << macroHierarchyName() << "_RANGE\n";206OS << "# define LAST_" << macroHierarchyName()207<< "_RANGE(Base, First, Last) " << macroHierarchyName()208<< "_RANGE(Base, First, Last)\n";209OS << "#endif\n\n";210211EmitNode(OS, Root);212213OS << "#undef " << macroHierarchyName() << "\n";214OS << "#undef " << macroHierarchyName() << "_RANGE\n";215OS << "#undef LAST_" << macroHierarchyName() << "_RANGE\n";216OS << "#undef ABSTRACT_" << macroHierarchyName() << "\n";217}218219void clang::EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,220const std::string &N, const std::string &S,221std::string_view PriorizeIfSubclassOf) {222ClangASTNodesEmitter(RK, N, S, PriorizeIfSubclassOf).run(OS);223}224225void printDeclContext(const std::multimap<Record *, Record *> &Tree,226Record *DeclContext, raw_ostream &OS) {227if (!DeclContext->getValueAsBit(AbstractFieldName))228OS << "DECL_CONTEXT(" << DeclContext->getName() << ")\n";229auto i = Tree.lower_bound(DeclContext);230auto end = Tree.upper_bound(DeclContext);231for (; i != end; ++i) {232printDeclContext(Tree, i->second, OS);233}234}235236// Emits and addendum to a .inc file to enumerate the clang declaration237// contexts.238void clang::EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) {239// FIXME: Find a .td file format to allow for this to be represented better.240241emitSourceFileHeader("List of AST Decl nodes", OS, Records);242243OS << "#ifndef DECL_CONTEXT\n";244OS << "# define DECL_CONTEXT(DECL)\n";245OS << "#endif\n";246247std::vector<Record *> DeclContextsVector =248Records.getAllDerivedDefinitions(DeclContextNodeClassName);249std::vector<Record *> Decls =250Records.getAllDerivedDefinitions(DeclNodeClassName);251252std::multimap<Record *, Record *> Tree;253254const std::vector<Record *> Stmts =255Records.getAllDerivedDefinitions(DeclNodeClassName);256257for (auto *R : Stmts) {258if (auto *B = R->getValueAsOptionalDef(BaseFieldName))259Tree.insert(std::make_pair(B, R));260}261262for (auto *DeclContext : DeclContextsVector) {263printDeclContext(Tree, DeclContext, OS);264}265266OS << "#undef DECL_CONTEXT\n";267}268269270