xref: /llvm-project/clang/utils/TableGen/ClangSyntaxEmitter.cpp (revision 63aa8cf6becbeb4983e3d1a7fa3cd8a7c7147118)
1*63aa8cf6SRahul Joshi //===-- ClangSyntaxEmitter.cpp - Generate clang Syntax Tree nodes ---------===//
2454579e4SSam McCall //
3454579e4SSam McCall //                     The LLVM Compiler Infrastructure
4454579e4SSam McCall //
5454579e4SSam McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6454579e4SSam McCall // See https://llvm.org/LICENSE.txt for license information.
7454579e4SSam McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8454579e4SSam McCall //
9454579e4SSam McCall //===----------------------------------------------------------------------===//
10454579e4SSam McCall //
11454579e4SSam McCall // These backends consume the definitions of Syntax Tree nodes.
12454579e4SSam McCall // See clang/include/clang/Tooling/Syntax/{Syntax,Nodes}.td
13454579e4SSam McCall //
14454579e4SSam McCall // The -gen-clang-syntax-node-list backend produces a .inc with macro calls
15454579e4SSam McCall //   NODE(Kind, BaseKind)
16454579e4SSam McCall //   ABSTRACT_NODE(Type, Base, FirstKind, LastKind)
17454579e4SSam McCall // similar to those for AST nodes such as AST/DeclNodes.inc.
18454579e4SSam McCall //
1998aa0671SSam McCall // The -gen-clang-syntax-node-classes backend produces definitions for the
2098aa0671SSam McCall // syntax::Node subclasses (except those marked as External).
2198aa0671SSam McCall //
2298aa0671SSam McCall // In future, another backend will encode the structure of the various node
2398aa0671SSam McCall // types in tables so their invariants can be checked and enforced.
24454579e4SSam McCall //
25454579e4SSam McCall //===----------------------------------------------------------------------===//
26454579e4SSam McCall #include "TableGenBackends.h"
27454579e4SSam McCall 
28454579e4SSam McCall #include <deque>
29454579e4SSam McCall 
3098aa0671SSam McCall #include "llvm/ADT/StringExtras.h"
31454579e4SSam McCall #include "llvm/Support/FormatVariadic.h"
32454579e4SSam McCall #include "llvm/Support/raw_ostream.h"
33454579e4SSam McCall #include "llvm/TableGen/Record.h"
34454579e4SSam McCall #include "llvm/TableGen/TableGenBackend.h"
35454579e4SSam McCall 
360e948bfdSRahul Joshi using namespace llvm;
370e948bfdSRahul Joshi 
38454579e4SSam McCall namespace {
39454579e4SSam McCall 
40454579e4SSam McCall // The class hierarchy of Node types.
41454579e4SSam McCall // We assemble this in order to be able to define the NodeKind enum in a
42454579e4SSam McCall // stable and useful way, where abstract Node subclasses correspond to ranges.
43454579e4SSam McCall class Hierarchy {
44454579e4SSam McCall public:
450e948bfdSRahul Joshi   Hierarchy(const RecordKeeper &Records) {
460e948bfdSRahul Joshi     for (const Record *T : Records.getAllDerivedDefinitions("NodeType"))
47454579e4SSam McCall       add(T);
480e948bfdSRahul Joshi     for (const Record *Derived : Records.getAllDerivedDefinitions("NodeType"))
490e948bfdSRahul Joshi       if (const Record *Base = Derived->getValueAsOptionalDef("base"))
50454579e4SSam McCall         link(Derived, Base);
5198aa0671SSam McCall     for (NodeType &N : AllTypes) {
520e948bfdSRahul Joshi       sort(N.Derived, [](const NodeType *L, const NodeType *R) {
53adb70045SRahul Joshi         return L->Rec->getName() < R->Rec->getName();
54454579e4SSam McCall       });
5598aa0671SSam McCall       // Alternatives nodes must have subclasses, External nodes may do.
56adb70045SRahul Joshi       assert(N.Rec->isSubClassOf("Alternatives") ||
57adb70045SRahul Joshi              N.Rec->isSubClassOf("External") || N.Derived.empty());
58adb70045SRahul Joshi       assert(!N.Rec->isSubClassOf("Alternatives") || !N.Derived.empty());
5998aa0671SSam McCall     }
60454579e4SSam McCall   }
61454579e4SSam McCall 
62454579e4SSam McCall   struct NodeType {
63adb70045SRahul Joshi     const Record *Rec = nullptr;
64454579e4SSam McCall     const NodeType *Base = nullptr;
65454579e4SSam McCall     std::vector<const NodeType *> Derived;
66adb70045SRahul Joshi     StringRef name() const { return Rec->getName(); }
67454579e4SSam McCall   };
68454579e4SSam McCall 
690e948bfdSRahul Joshi   NodeType &get(StringRef Name = "Node") {
70454579e4SSam McCall     auto NI = ByName.find(Name);
71454579e4SSam McCall     assert(NI != ByName.end() && "no such node");
72454579e4SSam McCall     return *NI->second;
73454579e4SSam McCall   }
74454579e4SSam McCall 
7598aa0671SSam McCall   // Traverse the hierarchy in pre-order (base classes before derived).
760e948bfdSRahul Joshi   void visit(function_ref<void(const NodeType &)> CB,
7798aa0671SSam McCall              const NodeType *Start = nullptr) {
7898aa0671SSam McCall     if (Start == nullptr)
7998aa0671SSam McCall       Start = &get();
8098aa0671SSam McCall     CB(*Start);
8198aa0671SSam McCall     for (const NodeType *D : Start->Derived)
8298aa0671SSam McCall       visit(CB, D);
8398aa0671SSam McCall   }
8498aa0671SSam McCall 
85454579e4SSam McCall private:
860e948bfdSRahul Joshi   void add(const Record *R) {
87454579e4SSam McCall     AllTypes.emplace_back();
88adb70045SRahul Joshi     AllTypes.back().Rec = R;
89454579e4SSam McCall     bool Inserted = ByName.try_emplace(R->getName(), &AllTypes.back()).second;
90454579e4SSam McCall     assert(Inserted && "Duplicate node name");
91454579e4SSam McCall     (void)Inserted;
92454579e4SSam McCall   }
93454579e4SSam McCall 
940e948bfdSRahul Joshi   void link(const Record *Derived, const Record *Base) {
95454579e4SSam McCall     auto &CN = get(Derived->getName()), &PN = get(Base->getName());
96454579e4SSam McCall     assert(CN.Base == nullptr && "setting base twice");
97454579e4SSam McCall     PN.Derived.push_back(&CN);
98454579e4SSam McCall     CN.Base = &PN;
99454579e4SSam McCall   }
100454579e4SSam McCall 
101454579e4SSam McCall   std::deque<NodeType> AllTypes;
1020e948bfdSRahul Joshi   DenseMap<StringRef, NodeType *> ByName;
103454579e4SSam McCall };
104454579e4SSam McCall 
105454579e4SSam McCall const Hierarchy::NodeType &firstConcrete(const Hierarchy::NodeType &N) {
106454579e4SSam McCall   return N.Derived.empty() ? N : firstConcrete(*N.Derived.front());
107454579e4SSam McCall }
108454579e4SSam McCall const Hierarchy::NodeType &lastConcrete(const Hierarchy::NodeType &N) {
109454579e4SSam McCall   return N.Derived.empty() ? N : lastConcrete(*N.Derived.back());
110454579e4SSam McCall }
111454579e4SSam McCall 
112ea4d24c8SSam McCall struct SyntaxConstraint {
1130e948bfdSRahul Joshi   SyntaxConstraint(const Record &R) {
114ea4d24c8SSam McCall     if (R.isSubClassOf("Optional")) {
115ea4d24c8SSam McCall       *this = SyntaxConstraint(*R.getValueAsDef("inner"));
116ea4d24c8SSam McCall     } else if (R.isSubClassOf("AnyToken")) {
117ea4d24c8SSam McCall       NodeType = "Leaf";
118ea4d24c8SSam McCall     } else if (R.isSubClassOf("NodeType")) {
11946b27571SRahul Joshi       NodeType = R.getName();
120ea4d24c8SSam McCall     } else {
121ea4d24c8SSam McCall       assert(false && "Unhandled Syntax kind");
122ea4d24c8SSam McCall     }
123ea4d24c8SSam McCall   }
124ea4d24c8SSam McCall 
12546b27571SRahul Joshi   StringRef NodeType;
126ea4d24c8SSam McCall   // optional and leaf types also go here, once we want to use them.
127ea4d24c8SSam McCall };
128ea4d24c8SSam McCall 
129454579e4SSam McCall } // namespace
130454579e4SSam McCall 
1310e948bfdSRahul Joshi void clang::EmitClangSyntaxNodeList(const RecordKeeper &Records,
1320e948bfdSRahul Joshi                                     raw_ostream &OS) {
1330e948bfdSRahul Joshi   emitSourceFileHeader("Syntax tree node list", OS, Records);
13498aa0671SSam McCall   Hierarchy H(Records);
135454579e4SSam McCall   OS << R"cpp(
136454579e4SSam McCall #ifndef NODE
137454579e4SSam McCall #define NODE(Kind, Base)
138454579e4SSam McCall #endif
139454579e4SSam McCall 
140454579e4SSam McCall #ifndef CONCRETE_NODE
141454579e4SSam McCall #define CONCRETE_NODE(Kind, Base) NODE(Kind, Base)
142454579e4SSam McCall #endif
143454579e4SSam McCall 
144454579e4SSam McCall #ifndef ABSTRACT_NODE
145454579e4SSam McCall #define ABSTRACT_NODE(Kind, Base, First, Last) NODE(Kind, Base)
146454579e4SSam McCall #endif
147454579e4SSam McCall 
148454579e4SSam McCall )cpp";
14998aa0671SSam McCall   H.visit([&](const Hierarchy::NodeType &N) {
15098aa0671SSam McCall     // Don't emit ABSTRACT_NODE for node itself, which has no parent.
15198aa0671SSam McCall     if (N.Base == nullptr)
15298aa0671SSam McCall       return;
15398aa0671SSam McCall     if (N.Derived.empty())
15498aa0671SSam McCall       OS << formatv("CONCRETE_NODE({0},{1})\n", N.name(), N.Base->name());
15598aa0671SSam McCall     else
15698aa0671SSam McCall       OS << formatv("ABSTRACT_NODE({0},{1},{2},{3})\n", N.name(),
15798aa0671SSam McCall                     N.Base->name(), firstConcrete(N).name(),
15898aa0671SSam McCall                     lastConcrete(N).name());
15998aa0671SSam McCall   });
160454579e4SSam McCall   OS << R"cpp(
161454579e4SSam McCall #undef NODE
162454579e4SSam McCall #undef CONCRETE_NODE
163454579e4SSam McCall #undef ABSTRACT_NODE
164454579e4SSam McCall )cpp";
165454579e4SSam McCall }
16698aa0671SSam McCall 
16798aa0671SSam McCall // Format a documentation string as a C++ comment.
16898aa0671SSam McCall // Trims leading whitespace handling since comments come from a TableGen file:
16998aa0671SSam McCall //    documentation = [{
17098aa0671SSam McCall //      This is a widget. Example:
17198aa0671SSam McCall //        widget.explode()
17298aa0671SSam McCall //    }];
17398aa0671SSam McCall // and should be formatted as:
17498aa0671SSam McCall //    /// This is a widget. Example:
17598aa0671SSam McCall //    ///   widget.explode()
17698aa0671SSam McCall // Leading and trailing whitespace lines are stripped.
17798aa0671SSam McCall // The indentation of the first line is stripped from all lines.
1780e948bfdSRahul Joshi static void printDoc(StringRef Doc, raw_ostream &OS) {
17998aa0671SSam McCall   Doc = Doc.rtrim();
1800e948bfdSRahul Joshi   StringRef Line;
18198aa0671SSam McCall   while (Line.trim().empty() && !Doc.empty())
18298aa0671SSam McCall     std::tie(Line, Doc) = Doc.split('\n');
1830e948bfdSRahul Joshi   StringRef Indent = Line.take_while(isSpace);
18498aa0671SSam McCall   for (; !Line.empty() || !Doc.empty(); std::tie(Line, Doc) = Doc.split('\n')) {
18598aa0671SSam McCall     Line.consume_front(Indent);
18698aa0671SSam McCall     OS << "/// " << Line << "\n";
18798aa0671SSam McCall   }
18898aa0671SSam McCall }
18998aa0671SSam McCall 
1900e948bfdSRahul Joshi void clang::EmitClangSyntaxNodeClasses(const RecordKeeper &Records,
1910e948bfdSRahul Joshi                                        raw_ostream &OS) {
1920e948bfdSRahul Joshi   emitSourceFileHeader("Syntax tree node list", OS, Records);
19398aa0671SSam McCall   Hierarchy H(Records);
19498aa0671SSam McCall 
19598aa0671SSam McCall   OS << "\n// Forward-declare node types so we don't have to carefully "
19698aa0671SSam McCall         "sequence definitions.\n";
19798aa0671SSam McCall   H.visit([&](const Hierarchy::NodeType &N) {
19898aa0671SSam McCall     OS << "class " << N.name() << ";\n";
19998aa0671SSam McCall   });
20098aa0671SSam McCall 
20198aa0671SSam McCall   OS << "\n// Node definitions\n\n";
20298aa0671SSam McCall   H.visit([&](const Hierarchy::NodeType &N) {
203adb70045SRahul Joshi     if (N.Rec->isSubClassOf("External"))
20498aa0671SSam McCall       return;
205adb70045SRahul Joshi     printDoc(N.Rec->getValueAsString("documentation"), OS);
20698aa0671SSam McCall     OS << formatv("class {0}{1} : public {2} {{\n", N.name(),
20798aa0671SSam McCall                   N.Derived.empty() ? " final" : "", N.Base->name());
20898aa0671SSam McCall 
20998aa0671SSam McCall     // Constructor.
21098aa0671SSam McCall     if (N.Derived.empty())
21198aa0671SSam McCall       OS << formatv("public:\n  {0}() : {1}(NodeKind::{0}) {{}\n", N.name(),
21298aa0671SSam McCall                     N.Base->name());
21398aa0671SSam McCall     else
21498aa0671SSam McCall       OS << formatv("protected:\n  {0}(NodeKind K) : {1}(K) {{}\npublic:\n",
21598aa0671SSam McCall                     N.name(), N.Base->name());
21698aa0671SSam McCall 
217adb70045SRahul Joshi     if (N.Rec->isSubClassOf("Sequence")) {
218ea4d24c8SSam McCall       // Getters for sequence elements.
219adb70045SRahul Joshi       for (const auto &C : N.Rec->getValueAsListOfDefs("children")) {
220ea4d24c8SSam McCall         assert(C->isSubClassOf("Role"));
2210e948bfdSRahul Joshi         StringRef Role = C->getValueAsString("role");
222ea4d24c8SSam McCall         SyntaxConstraint Constraint(*C->getValueAsDef("syntax"));
223ea4d24c8SSam McCall         for (const char *Const : {"", "const "})
224ea4d24c8SSam McCall           OS << formatv(
225ea4d24c8SSam McCall               "  {2}{1} *get{0}() {2} {{\n"
226ea4d24c8SSam McCall               "    return llvm::cast_or_null<{1}>(findChild(NodeRole::{0}));\n"
227ea4d24c8SSam McCall               "  }\n",
228ea4d24c8SSam McCall               Role, Constraint.NodeType, Const);
229ea4d24c8SSam McCall       }
230ea4d24c8SSam McCall     }
231ea4d24c8SSam McCall 
23298aa0671SSam McCall     // classof. FIXME: move definition inline once ~all nodes are generated.
23398aa0671SSam McCall     OS << "  static bool classof(const Node *N);\n";
23498aa0671SSam McCall 
23598aa0671SSam McCall     OS << "};\n\n";
23698aa0671SSam McCall   });
23798aa0671SSam McCall }
238