xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/ASTTableGen.cpp (revision 4824e7fd18a1223177218d4aec1b3c6c5c4a444e)
1480093f4SDimitry Andric //=== ASTTableGen.cpp - Helper functions for working with AST records -----===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // This file defines some helper functions for working with tblegen reocrds
10480093f4SDimitry Andric // for the Clang AST: that is, the contents of files such as DeclNodes.td,
11480093f4SDimitry Andric // StmtNodes.td, and TypeNodes.td.
12480093f4SDimitry Andric //
13480093f4SDimitry Andric //===----------------------------------------------------------------------===//
14480093f4SDimitry Andric 
15480093f4SDimitry Andric #include "ASTTableGen.h"
16480093f4SDimitry Andric #include "llvm/TableGen/Record.h"
17480093f4SDimitry Andric #include "llvm/TableGen/Error.h"
18480093f4SDimitry Andric 
19480093f4SDimitry Andric using namespace llvm;
20480093f4SDimitry Andric using namespace clang;
21480093f4SDimitry Andric using namespace clang::tblgen;
22480093f4SDimitry Andric 
23480093f4SDimitry Andric llvm::StringRef clang::tblgen::HasProperties::getName() const {
24480093f4SDimitry Andric   if (auto node = getAs<ASTNode>()) {
25480093f4SDimitry Andric     return node.getName();
26480093f4SDimitry Andric   } else if (auto typeCase = getAs<TypeCase>()) {
27480093f4SDimitry Andric     return typeCase.getCaseName();
28480093f4SDimitry Andric   } else {
29480093f4SDimitry Andric     PrintFatalError(getLoc(), "unexpected node declaring properties");
30480093f4SDimitry Andric   }
31480093f4SDimitry Andric }
32480093f4SDimitry Andric 
33480093f4SDimitry Andric static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
34480093f4SDimitry Andric   StringRef nodeName = node->getName();
35480093f4SDimitry Andric   if (!nodeName.endswith(suffix)) {
36480093f4SDimitry Andric     PrintFatalError(node->getLoc(),
37480093f4SDimitry Andric                     Twine("name of node doesn't end in ") + suffix);
38480093f4SDimitry Andric   }
39480093f4SDimitry Andric   return nodeName.drop_back(suffix.size());
40480093f4SDimitry Andric }
41480093f4SDimitry Andric 
42480093f4SDimitry Andric // Decl node names don't end in Decl for historical reasons, and it would
43480093f4SDimitry Andric // be somewhat annoying to fix now.  Conveniently, this means the ID matches
44480093f4SDimitry Andric // is exactly the node name, and the class name is simply that plus Decl.
45480093f4SDimitry Andric std::string clang::tblgen::DeclNode::getClassName() const {
46480093f4SDimitry Andric   return (Twine(getName()) + "Decl").str();
47480093f4SDimitry Andric }
48480093f4SDimitry Andric StringRef clang::tblgen::DeclNode::getId() const {
49480093f4SDimitry Andric   return getName();
50480093f4SDimitry Andric }
51480093f4SDimitry Andric 
52480093f4SDimitry Andric // Type nodes are all named ending in Type, just like the corresponding
53480093f4SDimitry Andric // C++ class, and the ID just strips this suffix.
54480093f4SDimitry Andric StringRef clang::tblgen::TypeNode::getClassName() const {
55480093f4SDimitry Andric   return getName();
56480093f4SDimitry Andric }
57480093f4SDimitry Andric StringRef clang::tblgen::TypeNode::getId() const {
58480093f4SDimitry Andric   return removeExpectedNodeNameSuffix(getRecord(), "Type");
59480093f4SDimitry Andric }
60480093f4SDimitry Andric 
61480093f4SDimitry Andric // Stmt nodes are named the same as the C++ class, which has no regular
62480093f4SDimitry Andric // naming convention (all the non-expression statements end in Stmt,
63480093f4SDimitry Andric // and *many* expressions end in Expr, but there are also several
64480093f4SDimitry Andric // core expression classes like IntegerLiteral and BinaryOperator with
65480093f4SDimitry Andric // no standard suffix).  The ID adds "Class" for historical reasons.
66480093f4SDimitry Andric StringRef clang::tblgen::StmtNode::getClassName() const {
67480093f4SDimitry Andric   return getName();
68480093f4SDimitry Andric }
69480093f4SDimitry Andric std::string clang::tblgen::StmtNode::getId() const {
70480093f4SDimitry Andric   return (Twine(getName()) + "Class").str();
71480093f4SDimitry Andric }
72480093f4SDimitry Andric 
73480093f4SDimitry Andric /// Emit a string spelling out the C++ value type.
74480093f4SDimitry Andric void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
75480093f4SDimitry Andric   if (!isGenericSpecialization()) {
76480093f4SDimitry Andric     if (!forRead && isConstWhenWriting())
77480093f4SDimitry Andric       out << "const ";
78480093f4SDimitry Andric     out << getCXXTypeName();
79480093f4SDimitry Andric   } else if (auto elementType = getArrayElementType()) {
80480093f4SDimitry Andric     out << "llvm::ArrayRef<";
81480093f4SDimitry Andric     elementType.emitCXXValueTypeName(forRead, out);
82480093f4SDimitry Andric     out << ">";
83480093f4SDimitry Andric   } else if (auto valueType = getOptionalElementType()) {
84480093f4SDimitry Andric     out << "llvm::Optional<";
85480093f4SDimitry Andric     valueType.emitCXXValueTypeName(forRead, out);
86480093f4SDimitry Andric     out << ">";
87480093f4SDimitry Andric   } else {
88480093f4SDimitry Andric     //PrintFatalError(getLoc(), "unexpected generic property type");
89480093f4SDimitry Andric     abort();
90480093f4SDimitry Andric   }
91480093f4SDimitry Andric }
92480093f4SDimitry Andric 
93480093f4SDimitry Andric // A map from a node to each of its child nodes.
94480093f4SDimitry Andric using ChildMap = std::multimap<ASTNode, ASTNode>;
95480093f4SDimitry Andric 
96480093f4SDimitry Andric static void visitASTNodeRecursive(ASTNode node, ASTNode base,
97480093f4SDimitry Andric                                   const ChildMap &map,
98480093f4SDimitry Andric                                   ASTNodeHierarchyVisitor<ASTNode> visit) {
99480093f4SDimitry Andric   visit(node, base);
100480093f4SDimitry Andric 
101480093f4SDimitry Andric   auto i = map.lower_bound(node), e = map.upper_bound(node);
102480093f4SDimitry Andric   for (; i != e; ++i) {
103480093f4SDimitry Andric     visitASTNodeRecursive(i->second, node, map, visit);
104480093f4SDimitry Andric   }
105480093f4SDimitry Andric }
106480093f4SDimitry Andric 
107480093f4SDimitry Andric static void visitHierarchy(RecordKeeper &records,
108480093f4SDimitry Andric                            StringRef nodeClassName,
109480093f4SDimitry Andric                            ASTNodeHierarchyVisitor<ASTNode> visit) {
110*4824e7fdSDimitry Andric   // Check for the node class, just as a basic correctness check.
111480093f4SDimitry Andric   if (!records.getClass(nodeClassName)) {
112480093f4SDimitry Andric     PrintFatalError(Twine("cannot find definition for node class ")
113480093f4SDimitry Andric                       + nodeClassName);
114480093f4SDimitry Andric   }
115480093f4SDimitry Andric 
116480093f4SDimitry Andric   // Find all the nodes in the hierarchy.
117480093f4SDimitry Andric   auto nodes = records.getAllDerivedDefinitions(nodeClassName);
118480093f4SDimitry Andric 
119480093f4SDimitry Andric   // Derive the child map.
120480093f4SDimitry Andric   ChildMap hierarchy;
121480093f4SDimitry Andric   ASTNode root;
122480093f4SDimitry Andric   for (ASTNode node : nodes) {
123480093f4SDimitry Andric     if (auto base = node.getBase())
124480093f4SDimitry Andric       hierarchy.insert(std::make_pair(base, node));
125480093f4SDimitry Andric     else if (root)
126480093f4SDimitry Andric       PrintFatalError(node.getLoc(),
127480093f4SDimitry Andric                       "multiple root nodes in " + nodeClassName + " hierarchy");
128480093f4SDimitry Andric     else
129480093f4SDimitry Andric       root = node;
130480093f4SDimitry Andric   }
131480093f4SDimitry Andric   if (!root)
132480093f4SDimitry Andric     PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
133480093f4SDimitry Andric 
134480093f4SDimitry Andric   // Now visit the map recursively, starting at the root node.
135480093f4SDimitry Andric   visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
136480093f4SDimitry Andric }
137480093f4SDimitry Andric 
138480093f4SDimitry Andric void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
139480093f4SDimitry Andric                                               StringRef nodeClassName,
140480093f4SDimitry Andric                                       ASTNodeHierarchyVisitor<ASTNode> visit) {
141480093f4SDimitry Andric   visitHierarchy(records, nodeClassName, visit);
142480093f4SDimitry Andric }
143