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