Files
clang-p2996/clang/utils/TableGen/ClangSyntaxEmitter.cpp
Sam McCall 454579e46a Reland [Syntax] Add minimal TableGen for syntax nodes. NFC
This reverts commit 09c6259d6d.
(Fixed side-effecting code being buried in an assert)
2020-11-11 11:24:47 +01:00

131 lines
4.2 KiB
C++

//===- ClangSyntaxEmitter.cpp - Generate clang Syntax Tree nodes ----------===//
//
// The LLVM Compiler Infrastructure
//
// 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
//
//===----------------------------------------------------------------------===//
//
// These backends consume the definitions of Syntax Tree nodes.
// See clang/include/clang/Tooling/Syntax/{Syntax,Nodes}.td
//
// The -gen-clang-syntax-node-list backend produces a .inc with macro calls
// NODE(Kind, BaseKind)
// ABSTRACT_NODE(Type, Base, FirstKind, LastKind)
// similar to those for AST nodes such as AST/DeclNodes.inc.
//
// In future, the class definitions will be produced by additional backends.
//
//===----------------------------------------------------------------------===//
#include "TableGenBackends.h"
#include <deque>
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
namespace {
// The class hierarchy of Node types.
// We assemble this in order to be able to define the NodeKind enum in a
// stable and useful way, where abstract Node subclasses correspond to ranges.
class Hierarchy {
public:
Hierarchy(const llvm::RecordKeeper &Records) {
for (llvm::Record *T : Records.getAllDerivedDefinitions("NodeType"))
add(T);
for (llvm::Record *Derived : Records.getAllDerivedDefinitions("NodeType"))
if (llvm::Record *Base = Derived->getValueAsOptionalDef("base"))
link(Derived, Base);
for (NodeType &N : AllTypes)
llvm::sort(N.Derived, [](const NodeType *L, const NodeType *R) {
return L->Record->getName() < R->Record->getName();
});
}
struct NodeType {
const llvm::Record *Record = nullptr;
const NodeType *Base = nullptr;
std::vector<const NodeType *> Derived;
llvm::StringRef name() const { return Record->getName(); }
};
NodeType &get(llvm::StringRef Name = "Node") {
auto NI = ByName.find(Name);
assert(NI != ByName.end() && "no such node");
return *NI->second;
}
private:
void add(const llvm::Record *R) {
AllTypes.emplace_back();
AllTypes.back().Record = R;
bool Inserted = ByName.try_emplace(R->getName(), &AllTypes.back()).second;
assert(Inserted && "Duplicate node name");
(void)Inserted;
}
void link(const llvm::Record *Derived, const llvm::Record *Base) {
auto &CN = get(Derived->getName()), &PN = get(Base->getName());
assert(CN.Base == nullptr && "setting base twice");
PN.Derived.push_back(&CN);
CN.Base = &PN;
}
std::deque<NodeType> AllTypes;
llvm::DenseMap<llvm::StringRef, NodeType *> ByName;
};
const Hierarchy::NodeType &firstConcrete(const Hierarchy::NodeType &N) {
return N.Derived.empty() ? N : firstConcrete(*N.Derived.front());
}
const Hierarchy::NodeType &lastConcrete(const Hierarchy::NodeType &N) {
return N.Derived.empty() ? N : lastConcrete(*N.Derived.back());
}
void emitNodeList(const Hierarchy::NodeType &N, llvm::raw_ostream &OS) {
// Don't emit ABSTRACT_NODE for node itself, which has no parent.
if (N.Base != nullptr) {
if (N.Derived.empty())
OS << llvm::formatv("CONCRETE_NODE({0},{1})\n", N.name(), N.Base->name());
else
OS << llvm::formatv("ABSTRACT_NODE({0},{1},{2},{3})\n", N.name(),
N.Base->name(), firstConcrete(N).name(),
lastConcrete(N).name());
}
for (const auto *C : N.Derived)
emitNodeList(*C, OS);
}
} // namespace
void clang::EmitClangSyntaxNodeList(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS) {
llvm::emitSourceFileHeader("Syntax tree node list", OS);
OS << "// Generated from " << Records.getInputFilename() << "\n";
OS << R"cpp(
#ifndef NODE
#define NODE(Kind, Base)
#endif
#ifndef CONCRETE_NODE
#define CONCRETE_NODE(Kind, Base) NODE(Kind, Base)
#endif
#ifndef ABSTRACT_NODE
#define ABSTRACT_NODE(Kind, Base, First, Last) NODE(Kind, Base)
#endif
)cpp";
emitNodeList(Hierarchy(Records).get(), OS);
OS << R"cpp(
#undef NODE
#undef CONCRETE_NODE
#undef ABSTRACT_NODE
)cpp";
}