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