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