1 //===- ClangSyntaxEmitter.cpp - Generate clang Syntax Tree nodes ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
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-exception
8 //
9 //===----------------------------------------------------------------------===//
10 //
11 // These backends consume the definitions of Syntax Tree nodes.
12 // See clang/include/clang/Tooling/Syntax/{Syntax,Nodes}.td
13 //
14 // The -gen-clang-syntax-node-list backend produces a .inc with macro calls
15 //   NODE(Kind, BaseKind)
16 //   ABSTRACT_NODE(Type, Base, FirstKind, LastKind)
17 // similar to those for AST nodes such as AST/DeclNodes.inc.
18 //
19 // In future, the class definitions will be produced by additional backends.
20 //
21 //===----------------------------------------------------------------------===//
22 #include "TableGenBackends.h"
23 
24 #include <deque>
25 
26 #include "llvm/Support/FormatVariadic.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include "llvm/TableGen/Record.h"
29 #include "llvm/TableGen/TableGenBackend.h"
30 
31 namespace {
32 
33 // The class hierarchy of Node types.
34 // We assemble this in order to be able to define the NodeKind enum in a
35 // stable and useful way, where abstract Node subclasses correspond to ranges.
36 class Hierarchy {
37 public:
38   Hierarchy(const llvm::RecordKeeper &Records) {
39     for (llvm::Record *T : Records.getAllDerivedDefinitions("NodeType"))
40       add(T);
41     for (llvm::Record *Derived : Records.getAllDerivedDefinitions("NodeType"))
42       if (llvm::Record *Base = Derived->getValueAsOptionalDef("base"))
43         link(Derived, Base);
44     for (NodeType &N : AllTypes)
45       llvm::sort(N.Derived, [](const NodeType *L, const NodeType *R) {
46         return L->Record->getName() < R->Record->getName();
47       });
48   }
49 
50   struct NodeType {
51     const llvm::Record *Record = nullptr;
52     const NodeType *Base = nullptr;
53     std::vector<const NodeType *> Derived;
54     llvm::StringRef name() const { return Record->getName(); }
55   };
56 
57   NodeType &get(llvm::StringRef Name = "Node") {
58     auto NI = ByName.find(Name);
59     assert(NI != ByName.end() && "no such node");
60     return *NI->second;
61   }
62 
63 private:
64   void add(const llvm::Record *R) {
65     AllTypes.emplace_back();
66     AllTypes.back().Record = R;
67     bool Inserted = ByName.try_emplace(R->getName(), &AllTypes.back()).second;
68     assert(Inserted && "Duplicate node name");
69     (void)Inserted;
70   }
71 
72   void link(const llvm::Record *Derived, const llvm::Record *Base) {
73     auto &CN = get(Derived->getName()), &PN = get(Base->getName());
74     assert(CN.Base == nullptr && "setting base twice");
75     PN.Derived.push_back(&CN);
76     CN.Base = &PN;
77   }
78 
79   std::deque<NodeType> AllTypes;
80   llvm::DenseMap<llvm::StringRef, NodeType *> ByName;
81 };
82 
83 const Hierarchy::NodeType &firstConcrete(const Hierarchy::NodeType &N) {
84   return N.Derived.empty() ? N : firstConcrete(*N.Derived.front());
85 }
86 const Hierarchy::NodeType &lastConcrete(const Hierarchy::NodeType &N) {
87   return N.Derived.empty() ? N : lastConcrete(*N.Derived.back());
88 }
89 
90 void emitNodeList(const Hierarchy::NodeType &N, llvm::raw_ostream &OS) {
91   // Don't emit ABSTRACT_NODE for node itself, which has no parent.
92   if (N.Base != nullptr) {
93     if (N.Derived.empty())
94       OS << llvm::formatv("CONCRETE_NODE({0},{1})\n", N.name(), N.Base->name());
95     else
96       OS << llvm::formatv("ABSTRACT_NODE({0},{1},{2},{3})\n", N.name(),
97                           N.Base->name(), firstConcrete(N).name(),
98                           lastConcrete(N).name());
99   }
100   for (const auto *C : N.Derived)
101     emitNodeList(*C, OS);
102 }
103 
104 } // namespace
105 
106 void clang::EmitClangSyntaxNodeList(llvm::RecordKeeper &Records,
107                                     llvm::raw_ostream &OS) {
108   llvm::emitSourceFileHeader("Syntax tree node list", OS);
109   OS << "// Generated from " << Records.getInputFilename() << "\n";
110   OS << R"cpp(
111 #ifndef NODE
112 #define NODE(Kind, Base)
113 #endif
114 
115 #ifndef CONCRETE_NODE
116 #define CONCRETE_NODE(Kind, Base) NODE(Kind, Base)
117 #endif
118 
119 #ifndef ABSTRACT_NODE
120 #define ABSTRACT_NODE(Kind, Base, First, Last) NODE(Kind, Base)
121 #endif
122 
123 )cpp";
124   emitNodeList(Hierarchy(Records).get(), OS);
125   OS << R"cpp(
126 #undef NODE
127 #undef CONCRETE_NODE
128 #undef ABSTRACT_NODE
129 )cpp";
130 }
131