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"
18bdd1243dSDimitry Andric #include <optional>
19480093f4SDimitry Andric 
20480093f4SDimitry Andric using namespace llvm;
21480093f4SDimitry Andric using namespace clang;
22480093f4SDimitry Andric using namespace clang::tblgen;
23480093f4SDimitry Andric 
getName() const24480093f4SDimitry Andric llvm::StringRef clang::tblgen::HasProperties::getName() const {
25480093f4SDimitry Andric   if (auto node = getAs<ASTNode>()) {
26480093f4SDimitry Andric     return node.getName();
27480093f4SDimitry Andric   } else if (auto typeCase = getAs<TypeCase>()) {
28480093f4SDimitry Andric     return typeCase.getCaseName();
29480093f4SDimitry Andric   } else {
30480093f4SDimitry Andric     PrintFatalError(getLoc(), "unexpected node declaring properties");
31480093f4SDimitry Andric   }
32480093f4SDimitry Andric }
33480093f4SDimitry Andric 
removeExpectedNodeNameSuffix(Record * node,StringRef suffix)34480093f4SDimitry Andric static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) {
35480093f4SDimitry Andric   StringRef nodeName = node->getName();
36*5f757f3fSDimitry Andric   if (!nodeName.ends_with(suffix)) {
37480093f4SDimitry Andric     PrintFatalError(node->getLoc(),
38480093f4SDimitry Andric                     Twine("name of node doesn't end in ") + suffix);
39480093f4SDimitry Andric   }
40480093f4SDimitry Andric   return nodeName.drop_back(suffix.size());
41480093f4SDimitry Andric }
42480093f4SDimitry Andric 
43480093f4SDimitry Andric // Decl node names don't end in Decl for historical reasons, and it would
44480093f4SDimitry Andric // be somewhat annoying to fix now.  Conveniently, this means the ID matches
45480093f4SDimitry Andric // is exactly the node name, and the class name is simply that plus Decl.
getClassName() const46480093f4SDimitry Andric std::string clang::tblgen::DeclNode::getClassName() const {
47480093f4SDimitry Andric   return (Twine(getName()) + "Decl").str();
48480093f4SDimitry Andric }
getId() const49480093f4SDimitry Andric StringRef clang::tblgen::DeclNode::getId() const {
50480093f4SDimitry Andric   return getName();
51480093f4SDimitry Andric }
52480093f4SDimitry Andric 
53480093f4SDimitry Andric // Type nodes are all named ending in Type, just like the corresponding
54480093f4SDimitry Andric // C++ class, and the ID just strips this suffix.
getClassName() const55480093f4SDimitry Andric StringRef clang::tblgen::TypeNode::getClassName() const {
56480093f4SDimitry Andric   return getName();
57480093f4SDimitry Andric }
getId() const58480093f4SDimitry Andric StringRef clang::tblgen::TypeNode::getId() const {
59480093f4SDimitry Andric   return removeExpectedNodeNameSuffix(getRecord(), "Type");
60480093f4SDimitry Andric }
61480093f4SDimitry Andric 
62480093f4SDimitry Andric // Stmt nodes are named the same as the C++ class, which has no regular
63480093f4SDimitry Andric // naming convention (all the non-expression statements end in Stmt,
64480093f4SDimitry Andric // and *many* expressions end in Expr, but there are also several
65480093f4SDimitry Andric // core expression classes like IntegerLiteral and BinaryOperator with
66480093f4SDimitry Andric // no standard suffix).  The ID adds "Class" for historical reasons.
getClassName() const67480093f4SDimitry Andric StringRef clang::tblgen::StmtNode::getClassName() const {
68480093f4SDimitry Andric   return getName();
69480093f4SDimitry Andric }
getId() const70480093f4SDimitry Andric std::string clang::tblgen::StmtNode::getId() const {
71480093f4SDimitry Andric   return (Twine(getName()) + "Class").str();
72480093f4SDimitry Andric }
73480093f4SDimitry Andric 
74480093f4SDimitry Andric /// Emit a string spelling out the C++ value type.
emitCXXValueTypeName(bool forRead,raw_ostream & out) const75480093f4SDimitry Andric void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const {
76480093f4SDimitry Andric   if (!isGenericSpecialization()) {
77480093f4SDimitry Andric     if (!forRead && isConstWhenWriting())
78480093f4SDimitry Andric       out << "const ";
79480093f4SDimitry Andric     out << getCXXTypeName();
80480093f4SDimitry Andric   } else if (auto elementType = getArrayElementType()) {
81480093f4SDimitry Andric     out << "llvm::ArrayRef<";
82480093f4SDimitry Andric     elementType.emitCXXValueTypeName(forRead, out);
83480093f4SDimitry Andric     out << ">";
84480093f4SDimitry Andric   } else if (auto valueType = getOptionalElementType()) {
85bdd1243dSDimitry Andric     out << "std::optional<";
86480093f4SDimitry Andric     valueType.emitCXXValueTypeName(forRead, out);
87480093f4SDimitry Andric     out << ">";
88480093f4SDimitry Andric   } else {
89480093f4SDimitry Andric     //PrintFatalError(getLoc(), "unexpected generic property type");
90480093f4SDimitry Andric     abort();
91480093f4SDimitry Andric   }
92480093f4SDimitry Andric }
93480093f4SDimitry Andric 
94480093f4SDimitry Andric // A map from a node to each of its child nodes.
95480093f4SDimitry Andric using ChildMap = std::multimap<ASTNode, ASTNode>;
96480093f4SDimitry Andric 
visitASTNodeRecursive(ASTNode node,ASTNode base,const ChildMap & map,ASTNodeHierarchyVisitor<ASTNode> visit)97480093f4SDimitry Andric static void visitASTNodeRecursive(ASTNode node, ASTNode base,
98480093f4SDimitry Andric                                   const ChildMap &map,
99480093f4SDimitry Andric                                   ASTNodeHierarchyVisitor<ASTNode> visit) {
100480093f4SDimitry Andric   visit(node, base);
101480093f4SDimitry Andric 
102480093f4SDimitry Andric   auto i = map.lower_bound(node), e = map.upper_bound(node);
103480093f4SDimitry Andric   for (; i != e; ++i) {
104480093f4SDimitry Andric     visitASTNodeRecursive(i->second, node, map, visit);
105480093f4SDimitry Andric   }
106480093f4SDimitry Andric }
107480093f4SDimitry Andric 
visitHierarchy(RecordKeeper & records,StringRef nodeClassName,ASTNodeHierarchyVisitor<ASTNode> visit)108480093f4SDimitry Andric static void visitHierarchy(RecordKeeper &records,
109480093f4SDimitry Andric                            StringRef nodeClassName,
110480093f4SDimitry Andric                            ASTNodeHierarchyVisitor<ASTNode> visit) {
1114824e7fdSDimitry Andric   // Check for the node class, just as a basic correctness check.
112480093f4SDimitry Andric   if (!records.getClass(nodeClassName)) {
113480093f4SDimitry Andric     PrintFatalError(Twine("cannot find definition for node class ")
114480093f4SDimitry Andric                       + nodeClassName);
115480093f4SDimitry Andric   }
116480093f4SDimitry Andric 
117480093f4SDimitry Andric   // Find all the nodes in the hierarchy.
118480093f4SDimitry Andric   auto nodes = records.getAllDerivedDefinitions(nodeClassName);
119480093f4SDimitry Andric 
120480093f4SDimitry Andric   // Derive the child map.
121480093f4SDimitry Andric   ChildMap hierarchy;
122480093f4SDimitry Andric   ASTNode root;
123480093f4SDimitry Andric   for (ASTNode node : nodes) {
124480093f4SDimitry Andric     if (auto base = node.getBase())
125480093f4SDimitry Andric       hierarchy.insert(std::make_pair(base, node));
126480093f4SDimitry Andric     else if (root)
127480093f4SDimitry Andric       PrintFatalError(node.getLoc(),
128480093f4SDimitry Andric                       "multiple root nodes in " + nodeClassName + " hierarchy");
129480093f4SDimitry Andric     else
130480093f4SDimitry Andric       root = node;
131480093f4SDimitry Andric   }
132480093f4SDimitry Andric   if (!root)
133480093f4SDimitry Andric     PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy");
134480093f4SDimitry Andric 
135480093f4SDimitry Andric   // Now visit the map recursively, starting at the root node.
136480093f4SDimitry Andric   visitASTNodeRecursive(root, ASTNode(), hierarchy, visit);
137480093f4SDimitry Andric }
138480093f4SDimitry Andric 
visitASTNodeHierarchyImpl(RecordKeeper & records,StringRef nodeClassName,ASTNodeHierarchyVisitor<ASTNode> visit)139480093f4SDimitry Andric void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records,
140480093f4SDimitry Andric                                               StringRef nodeClassName,
141480093f4SDimitry Andric                                       ASTNodeHierarchyVisitor<ASTNode> visit) {
142480093f4SDimitry Andric   visitHierarchy(records, nodeClassName, visit);
143480093f4SDimitry Andric }
144