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