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