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