143 lines
5.0 KiB
C++
143 lines
5.0 KiB
C++
|
//=== 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);
|
||
|
}
|