17acbf00fSDmitri Gribenko //===--- ClangCommentCommandInfoEmitter.cpp - Generate command lists -----====//
27acbf00fSDmitri Gribenko //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67acbf00fSDmitri Gribenko //
77acbf00fSDmitri Gribenko //===----------------------------------------------------------------------===//
87acbf00fSDmitri Gribenko //
96b11fca8SDmitri Gribenko // This tablegen backend emits command lists and efficient matchers for command
107acbf00fSDmitri Gribenko // names that are used in documentation comments.
117acbf00fSDmitri Gribenko //
127acbf00fSDmitri Gribenko //===----------------------------------------------------------------------===//
137acbf00fSDmitri Gribenko 
14c45f8d49SJohn McCall #include "TableGenBackends.h"
15c45f8d49SJohn McCall 
167acbf00fSDmitri Gribenko #include "llvm/TableGen/Record.h"
177acbf00fSDmitri Gribenko #include "llvm/TableGen/StringMatcher.h"
186b11fca8SDmitri Gribenko #include "llvm/TableGen/TableGenBackend.h"
197acbf00fSDmitri Gribenko #include <vector>
207acbf00fSDmitri Gribenko 
217acbf00fSDmitri Gribenko using namespace llvm;
227acbf00fSDmitri Gribenko 
EmitClangCommentCommandInfo(RecordKeeper & Records,raw_ostream & OS)23c45f8d49SJohn McCall void clang::EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
246b11fca8SDmitri Gribenko   emitSourceFileHeader("A list of commands useable in documentation "
256b11fca8SDmitri Gribenko                        "comments", OS);
267acbf00fSDmitri Gribenko 
277acbf00fSDmitri Gribenko   OS << "namespace {\n"
287acbf00fSDmitri Gribenko         "const CommandInfo Commands[] = {\n";
297acbf00fSDmitri Gribenko   std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
307acbf00fSDmitri Gribenko   for (size_t i = 0, e = Tags.size(); i != e; ++i) {
317acbf00fSDmitri Gribenko     Record &Tag = *Tags[i];
327acbf00fSDmitri Gribenko     OS << "  { "
337acbf00fSDmitri Gribenko        << "\"" << Tag.getValueAsString("Name") << "\", "
347acbf00fSDmitri Gribenko        << "\"" << Tag.getValueAsString("EndCommandName") << "\", "
357acbf00fSDmitri Gribenko        << i << ", "
367acbf00fSDmitri Gribenko        << Tag.getValueAsInt("NumArgs") << ", "
377acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsInlineCommand") << ", "
387acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsBlockCommand") << ", "
397acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsBriefCommand") << ", "
407acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsReturnsCommand") << ", "
417acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsParamCommand") << ", "
427acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsTParamCommand") << ", "
43d9febeb8SDmitri Gribenko        << Tag.getValueAsBit("IsThrowsCommand") << ", "
441da88869SDmitri Gribenko        << Tag.getValueAsBit("IsDeprecatedCommand") << ", "
451a0cf805SFariborz Jahanian        << Tag.getValueAsBit("IsHeaderfileCommand") << ", "
46b37d5e8aSDmitri Gribenko        << Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
477acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
487acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "
497acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
507acbf00fSDmitri Gribenko        << Tag.getValueAsBit("IsDeclarationCommand") << ", "
518a7a5922SFariborz Jahanian        << Tag.getValueAsBit("IsFunctionDeclarationCommand") << ", "
52cfbac5d3SFariborz Jahanian        << Tag.getValueAsBit("IsRecordLikeDetailCommand") << ", "
53cfbac5d3SFariborz Jahanian        << Tag.getValueAsBit("IsRecordLikeDeclarationCommand") << ", "
547acbf00fSDmitri Gribenko        << /* IsUnknownCommand = */ "0"
557acbf00fSDmitri Gribenko        << " }";
567acbf00fSDmitri Gribenko     if (i + 1 != e)
577acbf00fSDmitri Gribenko       OS << ",";
587acbf00fSDmitri Gribenko     OS << "\n";
597acbf00fSDmitri Gribenko   }
607acbf00fSDmitri Gribenko   OS << "};\n"
617acbf00fSDmitri Gribenko         "} // unnamed namespace\n\n";
627acbf00fSDmitri Gribenko 
637acbf00fSDmitri Gribenko   std::vector<StringMatcher::StringPair> Matches;
647acbf00fSDmitri Gribenko   for (size_t i = 0, e = Tags.size(); i != e; ++i) {
657acbf00fSDmitri Gribenko     Record &Tag = *Tags[i];
66adcd0268SBenjamin Kramer     std::string Name = std::string(Tag.getValueAsString("Name"));
677acbf00fSDmitri Gribenko     std::string Return;
687acbf00fSDmitri Gribenko     raw_string_ostream(Return) << "return &Commands[" << i << "];";
693204b152SBenjamin Kramer     Matches.emplace_back(std::move(Name), std::move(Return));
707acbf00fSDmitri Gribenko   }
717acbf00fSDmitri Gribenko 
727acbf00fSDmitri Gribenko   OS << "const CommandInfo *CommandTraits::getBuiltinCommandInfo(\n"
737acbf00fSDmitri Gribenko      << "                                         StringRef Name) {\n";
747acbf00fSDmitri Gribenko   StringMatcher("Name", Matches, OS).Emit();
7559dbe863SHans Wennborg   OS << "  return nullptr;\n"
767acbf00fSDmitri Gribenko      << "}\n\n";
777acbf00fSDmitri Gribenko }
782e72dd4aSDmitri Gribenko 
MangleName(StringRef Str)792e72dd4aSDmitri Gribenko static std::string MangleName(StringRef Str) {
802e72dd4aSDmitri Gribenko   std::string Mangled;
812e72dd4aSDmitri Gribenko   for (unsigned i = 0, e = Str.size(); i != e; ++i) {
822e72dd4aSDmitri Gribenko     switch (Str[i]) {
832e72dd4aSDmitri Gribenko     default:
842e72dd4aSDmitri Gribenko       Mangled += Str[i];
852e72dd4aSDmitri Gribenko       break;
86*196554d4SAaron Puchert     case '(':
87*196554d4SAaron Puchert       Mangled += "lparen";
88*196554d4SAaron Puchert       break;
89*196554d4SAaron Puchert     case ')':
90*196554d4SAaron Puchert       Mangled += "rparen";
91*196554d4SAaron Puchert       break;
922e72dd4aSDmitri Gribenko     case '[':
932e72dd4aSDmitri Gribenko       Mangled += "lsquare";
942e72dd4aSDmitri Gribenko       break;
952e72dd4aSDmitri Gribenko     case ']':
962e72dd4aSDmitri Gribenko       Mangled += "rsquare";
972e72dd4aSDmitri Gribenko       break;
982e72dd4aSDmitri Gribenko     case '{':
992e72dd4aSDmitri Gribenko       Mangled += "lbrace";
1002e72dd4aSDmitri Gribenko       break;
1012e72dd4aSDmitri Gribenko     case '}':
1022e72dd4aSDmitri Gribenko       Mangled += "rbrace";
1032e72dd4aSDmitri Gribenko       break;
1042e72dd4aSDmitri Gribenko     case '$':
1052e72dd4aSDmitri Gribenko       Mangled += "dollar";
1062e72dd4aSDmitri Gribenko       break;
107745bf62dSFariborz Jahanian     case '/':
108745bf62dSFariborz Jahanian       Mangled += "slash";
109745bf62dSFariborz Jahanian       break;
1102e72dd4aSDmitri Gribenko     }
1112e72dd4aSDmitri Gribenko   }
1122e72dd4aSDmitri Gribenko   return Mangled;
1132e72dd4aSDmitri Gribenko }
1142e72dd4aSDmitri Gribenko 
EmitClangCommentCommandList(RecordKeeper & Records,raw_ostream & OS)115c45f8d49SJohn McCall void clang::EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
1162e72dd4aSDmitri Gribenko   emitSourceFileHeader("A list of commands useable in documentation "
1172e72dd4aSDmitri Gribenko                        "comments", OS);
1182e72dd4aSDmitri Gribenko 
1192e72dd4aSDmitri Gribenko   OS << "#ifndef COMMENT_COMMAND\n"
1202e72dd4aSDmitri Gribenko      << "#  define COMMENT_COMMAND(NAME)\n"
1212e72dd4aSDmitri Gribenko      << "#endif\n";
1222e72dd4aSDmitri Gribenko 
1232e72dd4aSDmitri Gribenko   std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
1242e72dd4aSDmitri Gribenko   for (size_t i = 0, e = Tags.size(); i != e; ++i) {
1252e72dd4aSDmitri Gribenko     Record &Tag = *Tags[i];
1262e72dd4aSDmitri Gribenko     std::string MangledName = MangleName(Tag.getValueAsString("Name"));
1272e72dd4aSDmitri Gribenko 
1282e72dd4aSDmitri Gribenko     OS << "COMMENT_COMMAND(" << MangledName << ")\n";
1292e72dd4aSDmitri Gribenko   }
1302e72dd4aSDmitri Gribenko }
131