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