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