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