xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--- ClangCommentCommandInfoEmitter.cpp - Generate command lists -----====//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This tablegen backend emits command lists and efficient matchers for command
10*0b57cec5SDimitry Andric // names that are used in documentation comments.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
15*0b57cec5SDimitry Andric #include "llvm/TableGen/StringMatcher.h"
16*0b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
17*0b57cec5SDimitry Andric #include <vector>
18*0b57cec5SDimitry Andric 
19*0b57cec5SDimitry Andric using namespace llvm;
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric namespace clang {
22*0b57cec5SDimitry Andric void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
23*0b57cec5SDimitry Andric   emitSourceFileHeader("A list of commands useable in documentation "
24*0b57cec5SDimitry Andric                        "comments", OS);
25*0b57cec5SDimitry Andric 
26*0b57cec5SDimitry Andric   OS << "namespace {\n"
27*0b57cec5SDimitry Andric         "const CommandInfo Commands[] = {\n";
28*0b57cec5SDimitry Andric   std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
29*0b57cec5SDimitry Andric   for (size_t i = 0, e = Tags.size(); i != e; ++i) {
30*0b57cec5SDimitry Andric     Record &Tag = *Tags[i];
31*0b57cec5SDimitry Andric     OS << "  { "
32*0b57cec5SDimitry Andric        << "\"" << Tag.getValueAsString("Name") << "\", "
33*0b57cec5SDimitry Andric        << "\"" << Tag.getValueAsString("EndCommandName") << "\", "
34*0b57cec5SDimitry Andric        << i << ", "
35*0b57cec5SDimitry Andric        << Tag.getValueAsInt("NumArgs") << ", "
36*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsInlineCommand") << ", "
37*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsBlockCommand") << ", "
38*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsBriefCommand") << ", "
39*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsReturnsCommand") << ", "
40*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsParamCommand") << ", "
41*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsTParamCommand") << ", "
42*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsThrowsCommand") << ", "
43*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsDeprecatedCommand") << ", "
44*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsHeaderfileCommand") << ", "
45*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
46*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
47*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "
48*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
49*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsDeclarationCommand") << ", "
50*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsFunctionDeclarationCommand") << ", "
51*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsRecordLikeDetailCommand") << ", "
52*0b57cec5SDimitry Andric        << Tag.getValueAsBit("IsRecordLikeDeclarationCommand") << ", "
53*0b57cec5SDimitry Andric        << /* IsUnknownCommand = */ "0"
54*0b57cec5SDimitry Andric        << " }";
55*0b57cec5SDimitry Andric     if (i + 1 != e)
56*0b57cec5SDimitry Andric       OS << ",";
57*0b57cec5SDimitry Andric     OS << "\n";
58*0b57cec5SDimitry Andric   }
59*0b57cec5SDimitry Andric   OS << "};\n"
60*0b57cec5SDimitry Andric         "} // unnamed namespace\n\n";
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric   std::vector<StringMatcher::StringPair> Matches;
63*0b57cec5SDimitry Andric   for (size_t i = 0, e = Tags.size(); i != e; ++i) {
64*0b57cec5SDimitry Andric     Record &Tag = *Tags[i];
65*0b57cec5SDimitry Andric     std::string Name = Tag.getValueAsString("Name");
66*0b57cec5SDimitry Andric     std::string Return;
67*0b57cec5SDimitry Andric     raw_string_ostream(Return) << "return &Commands[" << i << "];";
68*0b57cec5SDimitry Andric     Matches.emplace_back(std::move(Name), std::move(Return));
69*0b57cec5SDimitry Andric   }
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric   OS << "const CommandInfo *CommandTraits::getBuiltinCommandInfo(\n"
72*0b57cec5SDimitry Andric      << "                                         StringRef Name) {\n";
73*0b57cec5SDimitry Andric   StringMatcher("Name", Matches, OS).Emit();
74*0b57cec5SDimitry Andric   OS << "  return nullptr;\n"
75*0b57cec5SDimitry Andric      << "}\n\n";
76*0b57cec5SDimitry Andric }
77*0b57cec5SDimitry Andric 
78*0b57cec5SDimitry Andric static std::string MangleName(StringRef Str) {
79*0b57cec5SDimitry Andric   std::string Mangled;
80*0b57cec5SDimitry Andric   for (unsigned i = 0, e = Str.size(); i != e; ++i) {
81*0b57cec5SDimitry Andric     switch (Str[i]) {
82*0b57cec5SDimitry Andric     default:
83*0b57cec5SDimitry Andric       Mangled += Str[i];
84*0b57cec5SDimitry Andric       break;
85*0b57cec5SDimitry Andric     case '[':
86*0b57cec5SDimitry Andric       Mangled += "lsquare";
87*0b57cec5SDimitry Andric       break;
88*0b57cec5SDimitry Andric     case ']':
89*0b57cec5SDimitry Andric       Mangled += "rsquare";
90*0b57cec5SDimitry Andric       break;
91*0b57cec5SDimitry Andric     case '{':
92*0b57cec5SDimitry Andric       Mangled += "lbrace";
93*0b57cec5SDimitry Andric       break;
94*0b57cec5SDimitry Andric     case '}':
95*0b57cec5SDimitry Andric       Mangled += "rbrace";
96*0b57cec5SDimitry Andric       break;
97*0b57cec5SDimitry Andric     case '$':
98*0b57cec5SDimitry Andric       Mangled += "dollar";
99*0b57cec5SDimitry Andric       break;
100*0b57cec5SDimitry Andric     case '/':
101*0b57cec5SDimitry Andric       Mangled += "slash";
102*0b57cec5SDimitry Andric       break;
103*0b57cec5SDimitry Andric     }
104*0b57cec5SDimitry Andric   }
105*0b57cec5SDimitry Andric   return Mangled;
106*0b57cec5SDimitry Andric }
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
109*0b57cec5SDimitry Andric   emitSourceFileHeader("A list of commands useable in documentation "
110*0b57cec5SDimitry Andric                        "comments", OS);
111*0b57cec5SDimitry Andric 
112*0b57cec5SDimitry Andric   OS << "#ifndef COMMENT_COMMAND\n"
113*0b57cec5SDimitry Andric      << "#  define COMMENT_COMMAND(NAME)\n"
114*0b57cec5SDimitry Andric      << "#endif\n";
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric   std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
117*0b57cec5SDimitry Andric   for (size_t i = 0, e = Tags.size(); i != e; ++i) {
118*0b57cec5SDimitry Andric     Record &Tag = *Tags[i];
119*0b57cec5SDimitry Andric     std::string MangledName = MangleName(Tag.getValueAsString("Name"));
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric     OS << "COMMENT_COMMAND(" << MangledName << ")\n";
122*0b57cec5SDimitry Andric   }
123*0b57cec5SDimitry Andric }
124*0b57cec5SDimitry Andric } // end namespace clang
125