1 //===-- ClangSyntaxEmitter.cpp - Generate clang Syntax Tree nodes ---------===//
3 // The LLVM Compiler Infrastructure
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
9 //===----------------------------------------------------------------------===//
11 // These backends consume the definitions of Syntax Tree nodes.
12 // See clang/include/clang/Tooling/Syntax/{Syntax,Nodes}.td
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.
19 // The -gen-clang-syntax-node-classes backend produces definitions for the
20 // syntax::Node subclasses (except those marked as External).
22 // In future, another backend will encode the structure of the various node
23 // types in tables so their invariants can be checked and enforced.
25 //===----------------------------------------------------------------------===//
26 #include "TableGenBackends.h"
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"
40 // The class hierarchy of Node types.
41 // We assemble this in order to be able to define the NodeKind enum in a
42 // stable and useful way, where abstract Node subclasses correspond to ranges.
45 Hierarchy(const RecordKeeper
&Records
) {
46 for (const Record
*T
: Records
.getAllDerivedDefinitions("NodeType"))
48 for (const Record
*Derived
: Records
.getAllDerivedDefinitions("NodeType"))
49 if (const Record
*Base
= Derived
->getValueAsOptionalDef("base"))
51 for (NodeType
&N
: AllTypes
) {
52 sort(N
.Derived
, [](const NodeType
*L
, const NodeType
*R
) {
53 return L
->Rec
->getName() < R
->Rec
->getName();
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());
63 const Record
*Rec
= nullptr;
64 const NodeType
*Base
= nullptr;
65 std::vector
<const NodeType
*> Derived
;
66 StringRef
name() const { return Rec
->getName(); }
69 NodeType
&get(StringRef Name
= "Node") {
70 auto NI
= ByName
.find(Name
);
71 assert(NI
!= ByName
.end() && "no such node");
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) {
81 for (const NodeType
*D
: Start
->Derived
)
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");
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
);
101 std::deque
<NodeType
> AllTypes
;
102 DenseMap
<StringRef
, NodeType
*> ByName
;
105 const Hierarchy::NodeType
&firstConcrete(const Hierarchy::NodeType
&N
) {
106 return N
.Derived
.empty() ? N
: firstConcrete(*N
.Derived
.front());
108 const Hierarchy::NodeType
&lastConcrete(const Hierarchy::NodeType
&N
) {
109 return N
.Derived
.empty() ? N
: lastConcrete(*N
.Derived
.back());
112 struct SyntaxConstraint
{
113 SyntaxConstraint(const Record
&R
) {
114 if (R
.isSubClassOf("Optional")) {
115 *this = SyntaxConstraint(*R
.getValueAsDef("inner"));
116 } else if (R
.isSubClassOf("AnyToken")) {
118 } else if (R
.isSubClassOf("NodeType")) {
119 NodeType
= R
.getName();
121 assert(false && "Unhandled Syntax kind");
126 // optional and leaf types also go here, once we want to use them.
131 void clang::EmitClangSyntaxNodeList(const RecordKeeper
&Records
,
133 emitSourceFileHeader("Syntax tree node list", OS
, Records
);
134 Hierarchy
H(Records
);
137 #define NODE(Kind, Base)
140 #ifndef CONCRETE_NODE
141 #define CONCRETE_NODE(Kind, Base) NODE(Kind, Base)
144 #ifndef ABSTRACT_NODE
145 #define ABSTRACT_NODE(Kind, Base, First, Last) NODE(Kind, Base)
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)
153 if (N
.Derived
.empty())
154 OS
<< formatv("CONCRETE_NODE({0},{1})\n", N
.name(), N
.Base
->name());
156 OS
<< formatv("ABSTRACT_NODE({0},{1},{2},{3})\n", N
.name(),
157 N
.Base
->name(), firstConcrete(N
).name(),
158 lastConcrete(N
).name());
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:
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.
178 static void printDoc(StringRef Doc
, raw_ostream
&OS
) {
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";
190 void clang::EmitClangSyntaxNodeClasses(const RecordKeeper
&Records
,
192 emitSourceFileHeader("Syntax tree node list", OS
, Records
);
193 Hierarchy
H(Records
);
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";
201 OS
<< "\n// Node definitions\n\n";
202 H
.visit([&](const Hierarchy::NodeType
&N
) {
203 if (N
.Rec
->isSubClassOf("External"))
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());
210 if (N
.Derived
.empty())
211 OS
<< formatv("public:\n {0}() : {1}(NodeKind::{0}) {{}\n", N
.name(),
214 OS
<< formatv("protected:\n {0}(NodeKind K) : {1}(K) {{}\npublic:\n",
215 N
.name(), N
.Base
->name());
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 "})
225 " {2}{1} *get{0}() {2} {{\n"
226 " return llvm::cast_or_null<{1}>(findChild(NodeRole::{0}));\n"
228 Role
, Constraint
.NodeType
, Const
);
232 // classof. FIXME: move definition inline once ~all nodes are generated.
233 OS
<< " static bool classof(const Node *N);\n";