summaryrefslogtreecommitdiff
path: root/clang/utils/TableGen/ASTTableGen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/utils/TableGen/ASTTableGen.cpp')
-rw-r--r--clang/utils/TableGen/ASTTableGen.cpp142
1 files changed, 142 insertions, 0 deletions
diff --git a/clang/utils/TableGen/ASTTableGen.cpp b/clang/utils/TableGen/ASTTableGen.cpp
new file mode 100644
index 000000000000..3f6da40964e0
--- /dev/null
+++ b/clang/utils/TableGen/ASTTableGen.cpp
@@ -0,0 +1,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 sanity 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);
+}