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" 18*bdd1243dSDimitry Andric #include <optional> 19480093f4SDimitry Andric 20480093f4SDimitry Andric using namespace llvm; 21480093f4SDimitry Andric using namespace clang; 22480093f4SDimitry Andric using namespace clang::tblgen; 23480093f4SDimitry Andric 24480093f4SDimitry 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 34480093f4SDimitry Andric static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) { 35480093f4SDimitry Andric StringRef nodeName = node->getName(); 36480093f4SDimitry Andric if (!nodeName.endswith(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. 46480093f4SDimitry Andric std::string clang::tblgen::DeclNode::getClassName() const { 47480093f4SDimitry Andric return (Twine(getName()) + "Decl").str(); 48480093f4SDimitry Andric } 49480093f4SDimitry 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. 55480093f4SDimitry Andric StringRef clang::tblgen::TypeNode::getClassName() const { 56480093f4SDimitry Andric return getName(); 57480093f4SDimitry Andric } 58480093f4SDimitry 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. 67480093f4SDimitry Andric StringRef clang::tblgen::StmtNode::getClassName() const { 68480093f4SDimitry Andric return getName(); 69480093f4SDimitry Andric } 70480093f4SDimitry 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. 75480093f4SDimitry 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()) { 85*bdd1243dSDimitry 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 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 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 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