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