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