brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · a519ab6 Raw
238 lines · cpp
1//===-- ClangSyntaxEmitter.cpp - Generate clang Syntax Tree nodes ---------===//2//3//                     The LLVM Compiler Infrastructure4//5// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.6// See https://llvm.org/LICENSE.txt for license information.7// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception8//9//===----------------------------------------------------------------------===//10//11// These backends consume the definitions of Syntax Tree nodes.12// See clang/include/clang/Tooling/Syntax/{Syntax,Nodes}.td13//14// The -gen-clang-syntax-node-list backend produces a .inc with macro calls15//   NODE(Kind, BaseKind)16//   ABSTRACT_NODE(Type, Base, FirstKind, LastKind)17// similar to those for AST nodes such as AST/DeclNodes.inc.18//19// The -gen-clang-syntax-node-classes backend produces definitions for the20// syntax::Node subclasses (except those marked as External).21//22// In future, another backend will encode the structure of the various node23// types in tables so their invariants can be checked and enforced.24//25//===----------------------------------------------------------------------===//26#include "TableGenBackends.h"27 28#include <deque>29 30#include "llvm/ADT/StringExtras.h"31#include "llvm/Support/FormatVariadic.h"32#include "llvm/Support/raw_ostream.h"33#include "llvm/TableGen/Record.h"34#include "llvm/TableGen/TableGenBackend.h"35 36using namespace llvm;37 38namespace {39 40// The class hierarchy of Node types.41// We assemble this in order to be able to define the NodeKind enum in a42// stable and useful way, where abstract Node subclasses correspond to ranges.43class Hierarchy {44public:45  Hierarchy(const RecordKeeper &Records) {46    for (const Record *T : Records.getAllDerivedDefinitions("NodeType"))47      add(T);48    for (const Record *Derived : Records.getAllDerivedDefinitions("NodeType"))49      if (const Record *Base = Derived->getValueAsOptionalDef("base"))50        link(Derived, Base);51    for (NodeType &N : AllTypes) {52      sort(N.Derived, [](const NodeType *L, const NodeType *R) {53        return L->Rec->getName() < R->Rec->getName();54      });55      // Alternatives nodes must have subclasses, External nodes may do.56      assert(N.Rec->isSubClassOf("Alternatives") ||57             N.Rec->isSubClassOf("External") || N.Derived.empty());58      assert(!N.Rec->isSubClassOf("Alternatives") || !N.Derived.empty());59    }60  }61 62  struct NodeType {63    const Record *Rec = nullptr;64    const NodeType *Base = nullptr;65    std::vector<const NodeType *> Derived;66    StringRef name() const { return Rec->getName(); }67  };68 69  NodeType &get(StringRef Name = "Node") {70    auto NI = ByName.find(Name);71    assert(NI != ByName.end() && "no such node");72    return *NI->second;73  }74 75  // Traverse the hierarchy in pre-order (base classes before derived).76  void visit(function_ref<void(const NodeType &)> CB,77             const NodeType *Start = nullptr) {78    if (Start == nullptr)79      Start = &get();80    CB(*Start);81    for (const NodeType *D : Start->Derived)82      visit(CB, D);83  }84 85private:86  void add(const Record *R) {87    AllTypes.emplace_back();88    AllTypes.back().Rec = R;89    bool Inserted = ByName.try_emplace(R->getName(), &AllTypes.back()).second;90    assert(Inserted && "Duplicate node name");91    (void)Inserted;92  }93 94  void link(const Record *Derived, const Record *Base) {95    auto &CN = get(Derived->getName()), &PN = get(Base->getName());96    assert(CN.Base == nullptr && "setting base twice");97    PN.Derived.push_back(&CN);98    CN.Base = &PN;99  }100 101  std::deque<NodeType> AllTypes;102  DenseMap<StringRef, NodeType *> ByName;103};104 105const Hierarchy::NodeType &firstConcrete(const Hierarchy::NodeType &N) {106  return N.Derived.empty() ? N : firstConcrete(*N.Derived.front());107}108const Hierarchy::NodeType &lastConcrete(const Hierarchy::NodeType &N) {109  return N.Derived.empty() ? N : lastConcrete(*N.Derived.back());110}111 112struct SyntaxConstraint {113  SyntaxConstraint(const Record &R) {114    if (R.isSubClassOf("Optional")) {115      *this = SyntaxConstraint(*R.getValueAsDef("inner"));116    } else if (R.isSubClassOf("AnyToken")) {117      NodeType = "Leaf";118    } else if (R.isSubClassOf("NodeType")) {119      NodeType = R.getName();120    } else {121      assert(false && "Unhandled Syntax kind");122    }123  }124 125  StringRef NodeType;126  // optional and leaf types also go here, once we want to use them.127};128 129} // namespace130 131void clang::EmitClangSyntaxNodeList(const RecordKeeper &Records,132                                    raw_ostream &OS) {133  emitSourceFileHeader("Syntax tree node list", OS, Records);134  Hierarchy H(Records);135  OS << R"cpp(136#ifndef NODE137#define NODE(Kind, Base)138#endif139 140#ifndef CONCRETE_NODE141#define CONCRETE_NODE(Kind, Base) NODE(Kind, Base)142#endif143 144#ifndef ABSTRACT_NODE145#define ABSTRACT_NODE(Kind, Base, First, Last) NODE(Kind, Base)146#endif147 148)cpp";149  H.visit([&](const Hierarchy::NodeType &N) {150    // Don't emit ABSTRACT_NODE for node itself, which has no parent.151    if (N.Base == nullptr)152      return;153    if (N.Derived.empty())154      OS << formatv("CONCRETE_NODE({0},{1})\n", N.name(), N.Base->name());155    else156      OS << formatv("ABSTRACT_NODE({0},{1},{2},{3})\n", N.name(),157                    N.Base->name(), firstConcrete(N).name(),158                    lastConcrete(N).name());159  });160  OS << R"cpp(161#undef NODE162#undef CONCRETE_NODE163#undef ABSTRACT_NODE164)cpp";165}166 167// Format a documentation string as a C++ comment.168// Trims leading whitespace handling since comments come from a TableGen file:169//    documentation = [{170//      This is a widget. Example:171//        widget.explode()172//    }];173// and should be formatted as:174//    /// This is a widget. Example:175//    ///   widget.explode()176// Leading and trailing whitespace lines are stripped.177// The indentation of the first line is stripped from all lines.178static void printDoc(StringRef Doc, raw_ostream &OS) {179  Doc = Doc.rtrim();180  StringRef Line;181  while (Line.trim().empty() && !Doc.empty())182    std::tie(Line, Doc) = Doc.split('\n');183  StringRef Indent = Line.take_while(isSpace);184  for (; !Line.empty() || !Doc.empty(); std::tie(Line, Doc) = Doc.split('\n')) {185    Line.consume_front(Indent);186    OS << "/// " << Line << "\n";187  }188}189 190void clang::EmitClangSyntaxNodeClasses(const RecordKeeper &Records,191                                       raw_ostream &OS) {192  emitSourceFileHeader("Syntax tree node list", OS, Records);193  Hierarchy H(Records);194 195  OS << "\n// Forward-declare node types so we don't have to carefully "196        "sequence definitions.\n";197  H.visit([&](const Hierarchy::NodeType &N) {198    OS << "class " << N.name() << ";\n";199  });200 201  OS << "\n// Node definitions\n\n";202  H.visit([&](const Hierarchy::NodeType &N) {203    if (N.Rec->isSubClassOf("External"))204      return;205    printDoc(N.Rec->getValueAsString("documentation"), OS);206    OS << formatv("class {0}{1} : public {2} {{\n", N.name(),207                  N.Derived.empty() ? " final" : "", N.Base->name());208 209    // Constructor.210    if (N.Derived.empty())211      OS << formatv("public:\n  {0}() : {1}(NodeKind::{0}) {{}\n", N.name(),212                    N.Base->name());213    else214      OS << formatv("protected:\n  {0}(NodeKind K) : {1}(K) {{}\npublic:\n",215                    N.name(), N.Base->name());216 217    if (N.Rec->isSubClassOf("Sequence")) {218      // Getters for sequence elements.219      for (const auto &C : N.Rec->getValueAsListOfDefs("children")) {220        assert(C->isSubClassOf("Role"));221        StringRef Role = C->getValueAsString("role");222        SyntaxConstraint Constraint(*C->getValueAsDef("syntax"));223        for (const char *Const : {"", "const "})224          OS << formatv(225              "  {2}{1} *get{0}() {2} {{\n"226              "    return llvm::cast_or_null<{1}>(findChild(NodeRole::{0}));\n"227              "  }\n",228              Role, Constraint.NodeType, Const);229      }230    }231 232    // classof. FIXME: move definition inline once ~all nodes are generated.233    OS << "  static bool classof(const Node *N);\n";234 235    OS << "};\n\n";236  });237}238