123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- //===- 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.
- //
- // The -gen-clang-syntax-node-classes backend produces definitions for the
- // syntax::Node subclasses (except those marked as External).
- //
- // In future, another backend will encode the structure of the various node
- // types in tables so their invariants can be checked and enforced.
- //
- //===----------------------------------------------------------------------===//
- #include "TableGenBackends.h"
- #include <deque>
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/Support/FormatVariadic.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/TableGen/Record.h"
- #include "llvm/TableGen/TableGenBackend.h"
- namespace {
- using llvm::formatv;
- // 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();
- });
- // Alternatives nodes must have subclasses, External nodes may do.
- assert(N.Record->isSubClassOf("Alternatives") ||
- N.Record->isSubClassOf("External") || N.Derived.empty());
- assert(!N.Record->isSubClassOf("Alternatives") || !N.Derived.empty());
- }
- }
- 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;
- }
- // Traverse the hierarchy in pre-order (base classes before derived).
- void visit(llvm::function_ref<void(const NodeType &)> CB,
- const NodeType *Start = nullptr) {
- if (Start == nullptr)
- Start = &get();
- CB(*Start);
- for (const NodeType *D : Start->Derived)
- visit(CB, D);
- }
- 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());
- }
- struct SyntaxConstraint {
- SyntaxConstraint(const llvm::Record &R) {
- if (R.isSubClassOf("Optional")) {
- *this = SyntaxConstraint(*R.getValueAsDef("inner"));
- } else if (R.isSubClassOf("AnyToken")) {
- NodeType = "Leaf";
- } else if (R.isSubClassOf("NodeType")) {
- NodeType = R.getName().str();
- } else {
- assert(false && "Unhandled Syntax kind");
- }
- }
- std::string NodeType;
- // optional and leaf types also go here, once we want to use them.
- };
- } // namespace
- void clang::EmitClangSyntaxNodeList(llvm::RecordKeeper &Records,
- llvm::raw_ostream &OS) {
- llvm::emitSourceFileHeader("Syntax tree node list", OS);
- Hierarchy H(Records);
- 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";
- H.visit([&](const Hierarchy::NodeType &N) {
- // Don't emit ABSTRACT_NODE for node itself, which has no parent.
- if (N.Base == nullptr)
- return;
- if (N.Derived.empty())
- OS << formatv("CONCRETE_NODE({0},{1})\n", N.name(), N.Base->name());
- else
- OS << formatv("ABSTRACT_NODE({0},{1},{2},{3})\n", N.name(),
- N.Base->name(), firstConcrete(N).name(),
- lastConcrete(N).name());
- });
- OS << R"cpp(
- #undef NODE
- #undef CONCRETE_NODE
- #undef ABSTRACT_NODE
- )cpp";
- }
- // Format a documentation string as a C++ comment.
- // Trims leading whitespace handling since comments come from a TableGen file:
- // documentation = [{
- // This is a widget. Example:
- // widget.explode()
- // }];
- // and should be formatted as:
- // /// This is a widget. Example:
- // /// widget.explode()
- // Leading and trailing whitespace lines are stripped.
- // The indentation of the first line is stripped from all lines.
- static void printDoc(llvm::StringRef Doc, llvm::raw_ostream &OS) {
- Doc = Doc.rtrim();
- llvm::StringRef Line;
- while (Line.trim().empty() && !Doc.empty())
- std::tie(Line, Doc) = Doc.split('\n');
- llvm::StringRef Indent = Line.take_while(llvm::isSpace);
- for (; !Line.empty() || !Doc.empty(); std::tie(Line, Doc) = Doc.split('\n')) {
- Line.consume_front(Indent);
- OS << "/// " << Line << "\n";
- }
- }
- void clang::EmitClangSyntaxNodeClasses(llvm::RecordKeeper &Records,
- llvm::raw_ostream &OS) {
- llvm::emitSourceFileHeader("Syntax tree node list", OS);
- Hierarchy H(Records);
- OS << "\n// Forward-declare node types so we don't have to carefully "
- "sequence definitions.\n";
- H.visit([&](const Hierarchy::NodeType &N) {
- OS << "class " << N.name() << ";\n";
- });
- OS << "\n// Node definitions\n\n";
- H.visit([&](const Hierarchy::NodeType &N) {
- if (N.Record->isSubClassOf("External"))
- return;
- printDoc(N.Record->getValueAsString("documentation"), OS);
- OS << formatv("class {0}{1} : public {2} {{\n", N.name(),
- N.Derived.empty() ? " final" : "", N.Base->name());
- // Constructor.
- if (N.Derived.empty())
- OS << formatv("public:\n {0}() : {1}(NodeKind::{0}) {{}\n", N.name(),
- N.Base->name());
- else
- OS << formatv("protected:\n {0}(NodeKind K) : {1}(K) {{}\npublic:\n",
- N.name(), N.Base->name());
- if (N.Record->isSubClassOf("Sequence")) {
- // Getters for sequence elements.
- for (const auto &C : N.Record->getValueAsListOfDefs("children")) {
- assert(C->isSubClassOf("Role"));
- llvm::StringRef Role = C->getValueAsString("role");
- SyntaxConstraint Constraint(*C->getValueAsDef("syntax"));
- for (const char *Const : {"", "const "})
- OS << formatv(
- " {2}{1} *get{0}() {2} {{\n"
- " return llvm::cast_or_null<{1}>(findChild(NodeRole::{0}));\n"
- " }\n",
- Role, Constraint.NodeType, Const);
- }
- }
- // classof. FIXME: move definition inline once ~all nodes are generated.
- OS << " static bool classof(const Node *N);\n";
- OS << "};\n\n";
- });
- }
|