xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
1*480093f4SDimitry Andric //=== ASTTableGen.cpp - Helper functions for working with AST records -----===//
2*480093f4SDimitry Andric //
3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*480093f4SDimitry Andric //
7*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8*480093f4SDimitry Andric //
9*480093f4SDimitry Andric // This file defines some helper functions for working with tblegen reocrds
10*480093f4SDimitry Andric // for the Clang AST: that is, the contents of files such as DeclNodes.td,
11*480093f4SDimitry Andric // StmtNodes.td, and TypeNodes.td.
12*480093f4SDimitry Andric //
13*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
14*480093f4SDimitry Andric 
15*480093f4SDimitry Andric #include "ASTTableGen.h"
16*480093f4SDimitry Andric #include "llvm/TableGen/Record.h"
17*480093f4SDimitry Andric #include "llvm/TableGen/Error.h"
18*480093f4SDimitry Andric 
19*480093f4SDimitry Andric using namespace llvm;
20*480093f4SDimitry Andric using namespace clang;
21*480093f4SDimitry Andric using namespace clang::tblgen;
22*480093f4SDimitry Andric 
23*480093f4SDimitry Andric llvm::StringRef clang::tblgen::HasProperties::getName() const {
24*480093f4SDimitry Andric   if (auto node = getAs<ASTNode>()) {
25*480093f4SDimitry Andric     return node.getName();
26*480093f4SDimitry Andric   } else if (auto typeCase = getAs<TypeCase>()) {
27*480093f4SDimitry Andric     return typeCase.getCaseName();
28*480093f4SDimitry Andric   } else {
29*480093f4SDimitry Andric     PrintFatalError(getLoc(), "unexpected node declaring properties");
30*480093f4SDimitry Andric   }
31*480093f4SDimitry Andric }
32*480093f4SDimitry Andric 
33*480093f4SDimitry Andric static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
34*480093f4SDimitry Andric   StringRef nodeName = node->getName();
35*480093f4SDimitry Andric   if (!nodeName.endswith(suffix)) {
36*480093f4SDimitry Andric     PrintFatalError(node->getLoc(),
37*480093f4SDimitry Andric                     Twine("name of node doesn't end in ") + suffix);
38*480093f4SDimitry Andric   }
39*480093f4SDimitry Andric   return nodeName.drop_back(suffix.size());
40*480093f4SDimitry Andric }
41*480093f4SDimitry Andric 
42*480093f4SDimitry Andric // Decl node names don't end in Decl for historical reasons, and it would
43*480093f4SDimitry Andric // be somewhat annoying to fix now.  Conveniently, this means the ID matches
44*480093f4SDimitry Andric // is exactly the node name, and the class name is simply that plus Decl.
45*480093f4SDimitry Andric std::string clang::tblgen::DeclNode::getClassName() const {
46*480093f4SDimitry Andric   return (Twine(getName()) + "Decl").str();
47*480093f4SDimitry Andric }
48*480093f4SDimitry Andric StringRef clang::tblgen::DeclNode::getId() const {
49*480093f4SDimitry Andric   return getName();
50*480093f4SDimitry Andric }
51*480093f4SDimitry Andric 
52*480093f4SDimitry Andric // Type nodes are all named ending in Type, just like the corresponding
53*480093f4SDimitry Andric // C++ class, and the ID just strips this suffix.
54*480093f4SDimitry Andric StringRef clang::tblgen::TypeNode::getClassName() const {
55*480093f4SDimitry Andric   return getName();
56*480093f4SDimitry Andric }
57*480093f4SDimitry Andric StringRef clang::tblgen::TypeNode::getId() const {
58*480093f4SDimitry Andric   return removeExpectedNodeNameSuffix(getRecord(), "Type");
59*480093f4SDimitry Andric }
60*480093f4SDimitry Andric 
61*480093f4SDimitry Andric // Stmt nodes are named the same as the C++ class, which has no regular
62*480093f4SDimitry Andric // naming convention (all the non-expression statements end in Stmt,
63*480093f4SDimitry Andric // and *many* expressions end in Expr, but there are also several
64*480093f4SDimitry Andric // core expression classes like IntegerLiteral and BinaryOperator with
65*480093f4SDimitry Andric // no standard suffix).  The ID adds "Class" for historical reasons.
66*480093f4SDimitry Andric StringRef clang::tblgen::StmtNode::getClassName() const {
67*480093f4SDimitry Andric   return getName();
68*480093f4SDimitry Andric }
69*480093f4SDimitry Andric std::string clang::tblgen::StmtNode::getId() const {
70*480093f4SDimitry Andric   return (Twine(getName()) + "Class").str();
71*480093f4SDimitry Andric }
72*480093f4SDimitry Andric 
73*480093f4SDimitry Andric /// Emit a string spelling out the C++ value type.
74*480093f4SDimitry Andric void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
75*480093f4SDimitry Andric   if (!isGenericSpecialization()) {
76*480093f4SDimitry Andric     if (!forRead && isConstWhenWriting())
77*480093f4SDimitry Andric       out << "const ";
78*480093f4SDimitry Andric     out << getCXXTypeName();
79*480093f4SDimitry Andric   } else if (auto elementType = getArrayElementType()) {
80*480093f4SDimitry Andric     out << "llvm::ArrayRef<";
81*480093f4SDimitry Andric     elementType.emitCXXValueTypeName(forRead, out);
82*480093f4SDimitry Andric     out << ">";
83*480093f4SDimitry Andric   } else if (auto valueType = getOptionalElementType()) {
84*480093f4SDimitry Andric     out << "llvm::Optional<";
85*480093f4SDimitry Andric     valueType.emitCXXValueTypeName(forRead, out);
86*480093f4SDimitry Andric     out << ">";
87*480093f4SDimitry Andric   } else {
88*480093f4SDimitry Andric     //PrintFatalError(getLoc(), "unexpected generic property type");
89*480093f4SDimitry Andric     abort();
90*480093f4SDimitry Andric   }
91*480093f4SDimitry Andric }
92*480093f4SDimitry Andric 
93*480093f4SDimitry Andric // A map from a node to each of its child nodes.
94*480093f4SDimitry Andric using ChildMap = std::multimap<ASTNode, ASTNode>;
95*480093f4SDimitry Andric 
96*480093f4SDimitry Andric static void visitASTNodeRecursive(ASTNode node, ASTNode base,
97*480093f4SDimitry Andric                                   const ChildMap &map,
98*480093f4SDimitry Andric                                   ASTNodeHierarchyVisitor<ASTNode> visit) {
99*480093f4SDimitry Andric   visit(node, base);
100*480093f4SDimitry Andric 
101*480093f4SDimitry Andric   auto i = map.lower_bound(node), e = map.upper_bound(node);
102*480093f4SDimitry Andric   for (; i != e; ++i) {
103*480093f4SDimitry Andric     visitASTNodeRecursive(i->second, node, map, visit);
104*480093f4SDimitry Andric   }
105*480093f4SDimitry Andric }
106*480093f4SDimitry Andric 
107*480093f4SDimitry Andric static void visitHierarchy(RecordKeeper &records,
108*480093f4SDimitry Andric                            StringRef nodeClassName,
109*480093f4SDimitry Andric                            ASTNodeHierarchyVisitor<ASTNode> visit) {
110*480093f4SDimitry Andric   // Check for the node class, just as a sanity check.
111*480093f4SDimitry Andric   if (!records.getClass(nodeClassName)) {
112*480093f4SDimitry Andric     PrintFatalError(Twine("cannot find definition for node class ")
113*480093f4SDimitry Andric                       + nodeClassName);
114*480093f4SDimitry Andric   }
115*480093f4SDimitry Andric 
116*480093f4SDimitry Andric   // Find all the nodes in the hierarchy.
117*480093f4SDimitry Andric   auto nodes = records.getAllDerivedDefinitions(nodeClassName);
118*480093f4SDimitry Andric 
119*480093f4SDimitry Andric   // Derive the child map.
120*480093f4SDimitry Andric   ChildMap hierarchy;
121*480093f4SDimitry Andric   ASTNode root;
122*480093f4SDimitry Andric   for (ASTNode node : nodes) {
123*480093f4SDimitry Andric     if (auto base = node.getBase())
124*480093f4SDimitry Andric       hierarchy.insert(std::make_pair(base, node));
125*480093f4SDimitry Andric     else if (root)
126*480093f4SDimitry Andric       PrintFatalError(node.getLoc(),
127*480093f4SDimitry Andric                       "multiple root nodes in " + nodeClassName + " hierarchy");
128*480093f4SDimitry Andric     else
129*480093f4SDimitry Andric       root = node;
130*480093f4SDimitry Andric   }
131*480093f4SDimitry Andric   if (!root)
132*480093f4SDimitry Andric     PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
133*480093f4SDimitry Andric 
134*480093f4SDimitry Andric   // Now visit the map recursively, starting at the root node.
135*480093f4SDimitry Andric   visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
136*480093f4SDimitry Andric }
137*480093f4SDimitry Andric 
138*480093f4SDimitry Andric void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
139*480093f4SDimitry Andric                                               StringRef nodeClassName,
140*480093f4SDimitry Andric                                       ASTNodeHierarchyVisitor<ASTNode> visit) {
141*480093f4SDimitry Andric   visitHierarchy(records, nodeClassName, visit);
142*480093f4SDimitry Andric }
143