1*63aa8cf6SRahul Joshi //===-- ASTTableGen.cpp - Helper functions for working with AST records ---===// 291dd67efSJohn McCall // 391dd67efSJohn McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 491dd67efSJohn McCall // See https://llvm.org/LICENSE.txt for license information. 591dd67efSJohn McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 691dd67efSJohn McCall // 791dd67efSJohn McCall //===----------------------------------------------------------------------===// 891dd67efSJohn McCall // 991dd67efSJohn McCall // This file defines some helper functions for working with tblegen reocrds 1091dd67efSJohn McCall // for the Clang AST: that is, the contents of files such as DeclNodes.td, 1191dd67efSJohn McCall // StmtNodes.td, and TypeNodes.td. 1291dd67efSJohn McCall // 1391dd67efSJohn McCall //===----------------------------------------------------------------------===// 1491dd67efSJohn McCall 1591dd67efSJohn McCall #include "ASTTableGen.h" 1691dd67efSJohn McCall #include "llvm/TableGen/Error.h" 17a8a1e903SKazu Hirata #include "llvm/TableGen/Record.h" 1891dd67efSJohn McCall 1991dd67efSJohn McCall using namespace llvm; 2091dd67efSJohn McCall using namespace clang; 2191dd67efSJohn McCall using namespace clang::tblgen; 2291dd67efSJohn McCall 230e948bfdSRahul Joshi StringRef clang::tblgen::HasProperties::getName() const { 24efd0dfbdSJohn McCall if (auto node = getAs<ASTNode>()) { 25efd0dfbdSJohn McCall return node.getName(); 26efd0dfbdSJohn McCall } else if (auto typeCase = getAs<TypeCase>()) { 27efd0dfbdSJohn McCall return typeCase.getCaseName(); 28efd0dfbdSJohn McCall } else { 29efd0dfbdSJohn McCall PrintFatalError(getLoc(), "unexpected node declaring properties"); 30efd0dfbdSJohn McCall } 31efd0dfbdSJohn McCall } 32efd0dfbdSJohn McCall 33463c9d29SRahul Joshi static StringRef removeExpectedNodeNameSuffix(const Record *node, 34463c9d29SRahul Joshi StringRef suffix) { 3591dd67efSJohn McCall StringRef nodeName = node->getName(); 36f3dcc235SKazu Hirata if (!nodeName.ends_with(suffix)) { 3791dd67efSJohn McCall PrintFatalError(node->getLoc(), 3891dd67efSJohn McCall Twine("name of node doesn't end in ") + suffix); 3991dd67efSJohn McCall } 4091dd67efSJohn McCall return nodeName.drop_back(suffix.size()); 4191dd67efSJohn McCall } 4291dd67efSJohn McCall 4391dd67efSJohn McCall // Decl node names don't end in Decl for historical reasons, and it would 4491dd67efSJohn McCall // be somewhat annoying to fix now. Conveniently, this means the ID matches 4591dd67efSJohn McCall // is exactly the node name, and the class name is simply that plus Decl. 4691dd67efSJohn McCall std::string clang::tblgen::DeclNode::getClassName() const { 4791dd67efSJohn McCall return (Twine(getName()) + "Decl").str(); 4891dd67efSJohn McCall } 4991dd67efSJohn McCall StringRef clang::tblgen::DeclNode::getId() const { 5091dd67efSJohn McCall return getName(); 5191dd67efSJohn McCall } 5291dd67efSJohn McCall 5391dd67efSJohn McCall // Type nodes are all named ending in Type, just like the corresponding 5491dd67efSJohn McCall // C++ class, and the ID just strips this suffix. 5591dd67efSJohn McCall StringRef clang::tblgen::TypeNode::getClassName() const { 5691dd67efSJohn McCall return getName(); 5791dd67efSJohn McCall } 5891dd67efSJohn McCall StringRef clang::tblgen::TypeNode::getId() const { 5991dd67efSJohn McCall return removeExpectedNodeNameSuffix(getRecord(), "Type"); 6091dd67efSJohn McCall } 6191dd67efSJohn McCall 6291dd67efSJohn McCall // Stmt nodes are named the same as the C++ class, which has no regular 6391dd67efSJohn McCall // naming convention (all the non-expression statements end in Stmt, 6491dd67efSJohn McCall // and *many* expressions end in Expr, but there are also several 6591dd67efSJohn McCall // core expression classes like IntegerLiteral and BinaryOperator with 6691dd67efSJohn McCall // no standard suffix). The ID adds "Class" for historical reasons. 6791dd67efSJohn McCall StringRef clang::tblgen::StmtNode::getClassName() const { 6891dd67efSJohn McCall return getName(); 6991dd67efSJohn McCall } 7091dd67efSJohn McCall std::string clang::tblgen::StmtNode::getId() const { 7191dd67efSJohn McCall return (Twine(getName()) + "Class").str(); 7291dd67efSJohn McCall } 7391dd67efSJohn McCall 746404bd23SJohn McCall /// Emit a string spelling out the C++ value type. 756404bd23SJohn McCall void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const { 766404bd23SJohn McCall if (!isGenericSpecialization()) { 776404bd23SJohn McCall if (!forRead && isConstWhenWriting()) 786404bd23SJohn McCall out << "const "; 796404bd23SJohn McCall out << getCXXTypeName(); 806404bd23SJohn McCall } else if (auto elementType = getArrayElementType()) { 816404bd23SJohn McCall out << "llvm::ArrayRef<"; 826404bd23SJohn McCall elementType.emitCXXValueTypeName(forRead, out); 836404bd23SJohn McCall out << ">"; 846404bd23SJohn McCall } else if (auto valueType = getOptionalElementType()) { 856ad0788cSKazu Hirata out << "std::optional<"; 866404bd23SJohn McCall valueType.emitCXXValueTypeName(forRead, out); 876404bd23SJohn McCall out << ">"; 886404bd23SJohn McCall } else { 896404bd23SJohn McCall //PrintFatalError(getLoc(), "unexpected generic property type"); 906404bd23SJohn McCall abort(); 916404bd23SJohn McCall } 926404bd23SJohn McCall } 936404bd23SJohn McCall 9491dd67efSJohn McCall // A map from a node to each of its child nodes. 95f6da0cf3SJohn McCall using ChildMap = std::multimap<ASTNode, ASTNode>; 9691dd67efSJohn McCall 97f6da0cf3SJohn McCall static void visitASTNodeRecursive(ASTNode node, ASTNode base, 98f6da0cf3SJohn McCall const ChildMap &map, 99f6da0cf3SJohn McCall ASTNodeHierarchyVisitor<ASTNode> visit) { 10091dd67efSJohn McCall visit(node, base); 10191dd67efSJohn McCall 10291dd67efSJohn McCall auto i = map.lower_bound(node), e = map.upper_bound(node); 10391dd67efSJohn McCall for (; i != e; ++i) { 10491dd67efSJohn McCall visitASTNodeRecursive(i->second, node, map, visit); 10591dd67efSJohn McCall } 10691dd67efSJohn McCall } 10791dd67efSJohn McCall 108463c9d29SRahul Joshi static void visitHierarchy(const RecordKeeper &records, StringRef nodeClassName, 109f6da0cf3SJohn McCall ASTNodeHierarchyVisitor<ASTNode> visit) { 110d42a6432SZarko Todorovski // Check for the node class, just as a basic correctness check. 11191dd67efSJohn McCall if (!records.getClass(nodeClassName)) { 11291dd67efSJohn McCall PrintFatalError(Twine("cannot find definition for node class ") 11391dd67efSJohn McCall + nodeClassName); 11491dd67efSJohn McCall } 11591dd67efSJohn McCall 116463c9d29SRahul Joshi // Derive the child map for all nodes in the hierarchy. 117f6da0cf3SJohn McCall ChildMap hierarchy; 118f6da0cf3SJohn McCall ASTNode root; 119463c9d29SRahul Joshi for (ASTNode node : records.getAllDerivedDefinitions(nodeClassName)) { 12091dd67efSJohn McCall if (auto base = node.getBase()) 12191dd67efSJohn McCall hierarchy.insert(std::make_pair(base, node)); 12291dd67efSJohn McCall else if (root) 12391dd67efSJohn McCall PrintFatalError(node.getLoc(), 12491dd67efSJohn McCall "multiple root nodes in " + nodeClassName + " hierarchy"); 12591dd67efSJohn McCall else 12691dd67efSJohn McCall root = node; 12791dd67efSJohn McCall } 12891dd67efSJohn McCall if (!root) 12991dd67efSJohn McCall PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy"); 13091dd67efSJohn McCall 13191dd67efSJohn McCall // Now visit the map recursively, starting at the root node. 132f6da0cf3SJohn McCall visitASTNodeRecursive(root, ASTNode(), hierarchy, visit); 13391dd67efSJohn McCall } 13491dd67efSJohn McCall 135463c9d29SRahul Joshi void clang::tblgen::visitASTNodeHierarchyImpl( 136463c9d29SRahul Joshi const RecordKeeper &records, StringRef nodeClassName, 13791dd67efSJohn McCall ASTNodeHierarchyVisitor<ASTNode> visit) { 13891dd67efSJohn McCall visitHierarchy(records, nodeClassName, visit); 13991dd67efSJohn McCall } 140