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