diff options
Diffstat (limited to 'clang/utils/TableGen/ASTTableGen.cpp')
-rw-r--r-- | clang/utils/TableGen/ASTTableGen.cpp | 142 |
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); +} |