1 //===- LLDBOptionDefEmitter.cpp -------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // These tablegen backends emits LLDB's OptionDefinition values for different 10 // LLDB commands. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "LLDBTableGenBackends.h" 15 #include "llvm/ADT/StringExtras.h" 16 #include "llvm/TableGen/Record.h" 17 #include "llvm/TableGen/StringMatcher.h" 18 #include "llvm/TableGen/TableGenBackend.h" 19 #include <map> 20 #include <vector> 21 22 using namespace llvm; 23 using namespace lldb_private; 24 25 /// Groups all records by their command. 26 static RecordsByName getCommandList(std::vector<Record *> Options) { 27 RecordsByName result; 28 for (Record *Option : Options) 29 result[Option->getValueAsString("Command").str()].push_back(Option); 30 return result; 31 } 32 33 namespace { 34 struct CommandOption { 35 std::vector<std::string> GroupsArg; 36 bool Required = false; 37 std::string FullName; 38 std::string ShortName; 39 std::string ArgType; 40 bool OptionalArg = false; 41 std::string Validator; 42 std::string ArgEnum; 43 std::vector<StringRef> Completions; 44 std::string Description; 45 46 CommandOption() = default; 47 CommandOption(Record *Option) { 48 if (Option->getValue("Groups")) { 49 // The user specified a list of groups. 50 auto Groups = Option->getValueAsListOfInts("Groups"); 51 for (int Group : Groups) 52 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group)); 53 } else if (Option->getValue("GroupStart")) { 54 // The user specified a range of groups (with potentially only one 55 // element). 56 int GroupStart = Option->getValueAsInt("GroupStart"); 57 int GroupEnd = Option->getValueAsInt("GroupEnd"); 58 for (int i = GroupStart; i <= GroupEnd; ++i) 59 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i)); 60 } 61 62 // Check if this option is required. 63 Required = Option->getValue("Required"); 64 65 // Add the full and short name for this option. 66 FullName = Option->getValueAsString("FullName"); 67 ShortName = Option->getValueAsString("ShortName"); 68 69 if (auto A = Option->getValue("ArgType")) 70 ArgType = A->getValue()->getAsUnquotedString(); 71 OptionalArg = Option->getValue("OptionalArg") != nullptr; 72 73 if (Option->getValue("Validator")) 74 Validator = Option->getValueAsString("Validator"); 75 76 if (Option->getValue("ArgEnum")) 77 ArgEnum = Option->getValueAsString("ArgEnum"); 78 79 if (Option->getValue("Completions")) 80 Completions = Option->getValueAsListOfStrings("Completions"); 81 82 if (auto D = Option->getValue("Description")) 83 Description = D->getValue()->getAsUnquotedString(); 84 } 85 }; 86 } // namespace 87 88 static void emitOption(const CommandOption &O, raw_ostream &OS) { 89 OS << " {"; 90 91 // If we have any groups, we merge them. Otherwise we move this option into 92 // the all group. 93 if (O.GroupsArg.empty()) 94 OS << "LLDB_OPT_SET_ALL"; 95 else 96 OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | "); 97 98 OS << ", "; 99 100 // Check if this option is required. 101 OS << (O.Required ? "true" : "false"); 102 103 // Add the full and short name for this option. 104 OS << ", \"" << O.FullName << "\", "; 105 OS << '\'' << O.ShortName << "'"; 106 107 // Decide if we have either an option, required or no argument for this 108 // option. 109 OS << ", OptionParser::"; 110 if (!O.ArgType.empty()) { 111 if (O.OptionalArg) 112 OS << "eOptionalArgument"; 113 else 114 OS << "eRequiredArgument"; 115 } else 116 OS << "eNoArgument"; 117 OS << ", "; 118 119 if (!O.Validator.empty()) 120 OS << O.Validator; 121 else 122 OS << "nullptr"; 123 OS << ", "; 124 125 if (!O.ArgEnum.empty()) 126 OS << O.ArgEnum; 127 else 128 OS << "{}"; 129 OS << ", "; 130 131 // Read the tab completions we offer for this option (if there are any) 132 if (!O.Completions.empty()) { 133 std::vector<std::string> CompletionArgs; 134 for (llvm::StringRef Completion : O.Completions) 135 CompletionArgs.push_back("CommandCompletions::e" + Completion.str() + 136 "Completion"); 137 138 OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | "); 139 } else 140 OS << "CommandCompletions::eNoCompletion"; 141 142 // Add the argument type. 143 OS << ", eArgType"; 144 if (!O.ArgType.empty()) { 145 OS << O.ArgType; 146 } else 147 OS << "None"; 148 OS << ", "; 149 150 // Add the description if there is any. 151 if (!O.Description.empty()) { 152 OS << "\""; 153 llvm::printEscapedString(O.Description, OS); 154 OS << "\""; 155 } else 156 OS << "\"\""; 157 OS << "},\n"; 158 } 159 160 /// Emits all option initializers to the raw_ostream. 161 static void emitOptions(std::string Command, std::vector<Record *> Records, 162 raw_ostream &OS) { 163 std::vector<CommandOption> Options; 164 for (Record *R : Records) 165 Options.emplace_back(R); 166 167 std::string ID = Command; 168 std::replace(ID.begin(), ID.end(), ' ', '_'); 169 // Generate the macro that the user needs to define before including the 170 // *.inc file. 171 std::string NeededMacro = "LLDB_OPTIONS_" + ID; 172 173 // All options are in one file, so we need put them behind macros and ask the 174 // user to define the macro for the options that are needed. 175 OS << "// Options for " << Command << "\n"; 176 OS << "#ifdef " << NeededMacro << "\n"; 177 OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n"; 178 for (CommandOption &CO : Options) 179 emitOption(CO, OS); 180 // We undefine the macro for the user like Clang's include files are doing it. 181 OS << "};\n"; 182 OS << "#undef " << NeededMacro << "\n"; 183 OS << "#endif // " << Command << " command\n\n"; 184 } 185 186 void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) { 187 emitSourceFileHeader("Options for LLDB command line commands.", OS); 188 189 std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option"); 190 for (auto &CommandRecordPair : getCommandList(Options)) { 191 emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS); 192 } 193 } 194