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