19dba64beSDimitry Andric //===- LLDBOptionDefEmitter.cpp -------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // These tablegen backends emits LLDB's OptionDefinition values for different 100b57cec5SDimitry Andric // LLDB commands. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "LLDBTableGenBackends.h" 159dba64beSDimitry Andric #include "LLDBTableGenUtils.h" 160b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 170b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 180b57cec5SDimitry Andric #include "llvm/TableGen/StringMatcher.h" 190b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 200b57cec5SDimitry Andric #include <vector> 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 239dba64beSDimitry Andric using namespace lldb_private; 240b57cec5SDimitry Andric 259dba64beSDimitry Andric namespace { 269dba64beSDimitry Andric struct CommandOption { 270b57cec5SDimitry Andric std::vector<std::string> GroupsArg; 289dba64beSDimitry Andric bool Required = false; 299dba64beSDimitry Andric std::string FullName; 309dba64beSDimitry Andric std::string ShortName; 319dba64beSDimitry Andric std::string ArgType; 329dba64beSDimitry Andric bool OptionalArg = false; 339dba64beSDimitry Andric std::string Validator; 349dba64beSDimitry Andric std::vector<StringRef> Completions; 359dba64beSDimitry Andric std::string Description; 360b57cec5SDimitry Andric 379dba64beSDimitry Andric CommandOption() = default; 389dba64beSDimitry Andric CommandOption(Record *Option) { 390b57cec5SDimitry Andric if (Option->getValue("Groups")) { 400b57cec5SDimitry Andric // The user specified a list of groups. 410b57cec5SDimitry Andric auto Groups = Option->getValueAsListOfInts("Groups"); 420b57cec5SDimitry Andric for (int Group : Groups) 430b57cec5SDimitry Andric GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group)); 440b57cec5SDimitry Andric } else if (Option->getValue("GroupStart")) { 459dba64beSDimitry Andric // The user specified a range of groups (with potentially only one 469dba64beSDimitry Andric // element). 470b57cec5SDimitry Andric int GroupStart = Option->getValueAsInt("GroupStart"); 480b57cec5SDimitry Andric int GroupEnd = Option->getValueAsInt("GroupEnd"); 490b57cec5SDimitry Andric for (int i = GroupStart; i <= GroupEnd; ++i) 500b57cec5SDimitry Andric GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i)); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 539dba64beSDimitry Andric // Check if this option is required. 549dba64beSDimitry Andric Required = Option->getValue("Required"); 559dba64beSDimitry Andric 569dba64beSDimitry Andric // Add the full and short name for this option. 575ffd83dbSDimitry Andric FullName = std::string(Option->getValueAsString("FullName")); 585ffd83dbSDimitry Andric ShortName = std::string(Option->getValueAsString("ShortName")); 599dba64beSDimitry Andric 609dba64beSDimitry Andric if (auto A = Option->getValue("ArgType")) 619dba64beSDimitry Andric ArgType = A->getValue()->getAsUnquotedString(); 629dba64beSDimitry Andric OptionalArg = Option->getValue("OptionalArg") != nullptr; 639dba64beSDimitry Andric 649dba64beSDimitry Andric if (Option->getValue("Validator")) 655ffd83dbSDimitry Andric Validator = std::string(Option->getValueAsString("Validator")); 669dba64beSDimitry Andric 679dba64beSDimitry Andric if (Option->getValue("Completions")) 689dba64beSDimitry Andric Completions = Option->getValueAsListOfStrings("Completions"); 699dba64beSDimitry Andric 709dba64beSDimitry Andric if (auto D = Option->getValue("Description")) 719dba64beSDimitry Andric Description = D->getValue()->getAsUnquotedString(); 729dba64beSDimitry Andric } 739dba64beSDimitry Andric }; 749dba64beSDimitry Andric } // namespace 759dba64beSDimitry Andric 769dba64beSDimitry Andric static void emitOption(const CommandOption &O, raw_ostream &OS) { 779dba64beSDimitry Andric OS << " {"; 789dba64beSDimitry Andric 790b57cec5SDimitry Andric // If we have any groups, we merge them. Otherwise we move this option into 800b57cec5SDimitry Andric // the all group. 819dba64beSDimitry Andric if (O.GroupsArg.empty()) 820b57cec5SDimitry Andric OS << "LLDB_OPT_SET_ALL"; 830b57cec5SDimitry Andric else 849dba64beSDimitry Andric OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | "); 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric OS << ", "; 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // Check if this option is required. 899dba64beSDimitry Andric OS << (O.Required ? "true" : "false"); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric // Add the full and short name for this option. 929dba64beSDimitry Andric OS << ", \"" << O.FullName << "\", "; 939dba64beSDimitry Andric OS << '\'' << O.ShortName << "'"; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric // Decide if we have either an option, required or no argument for this 960b57cec5SDimitry Andric // option. 970b57cec5SDimitry Andric OS << ", OptionParser::"; 989dba64beSDimitry Andric if (!O.ArgType.empty()) { 999dba64beSDimitry Andric if (O.OptionalArg) 1000b57cec5SDimitry Andric OS << "eOptionalArgument"; 1010b57cec5SDimitry Andric else 1020b57cec5SDimitry Andric OS << "eRequiredArgument"; 1030b57cec5SDimitry Andric } else 1040b57cec5SDimitry Andric OS << "eNoArgument"; 1059dba64beSDimitry Andric OS << ", "; 1060b57cec5SDimitry Andric 1079dba64beSDimitry Andric if (!O.Validator.empty()) 1089dba64beSDimitry Andric OS << O.Validator; 1099dba64beSDimitry Andric else 1109dba64beSDimitry Andric OS << "nullptr"; 1119dba64beSDimitry Andric OS << ", "; 1129dba64beSDimitry Andric 113fcaf7f86SDimitry Andric if (!O.ArgType.empty()) 114fcaf7f86SDimitry Andric OS << "g_argument_table[eArgType" << O.ArgType << "].enum_values"; 1150b57cec5SDimitry Andric else 1160b57cec5SDimitry Andric OS << "{}"; 1170b57cec5SDimitry Andric OS << ", "; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric // Read the tab completions we offer for this option (if there are any) 1209dba64beSDimitry Andric if (!O.Completions.empty()) { 1210b57cec5SDimitry Andric std::vector<std::string> CompletionArgs; 1229dba64beSDimitry Andric for (llvm::StringRef Completion : O.Completions) 12306c3fb27SDimitry Andric CompletionArgs.push_back("e" + Completion.str() + "Completion"); 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | "); 1269dba64beSDimitry Andric } else 12706c3fb27SDimitry Andric OS << "CompletionType::eNoCompletion"; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // Add the argument type. 1300b57cec5SDimitry Andric OS << ", eArgType"; 1319dba64beSDimitry Andric if (!O.ArgType.empty()) { 1329dba64beSDimitry Andric OS << O.ArgType; 1330b57cec5SDimitry Andric } else 1340b57cec5SDimitry Andric OS << "None"; 1350b57cec5SDimitry Andric OS << ", "; 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric // Add the description if there is any. 1389dba64beSDimitry Andric if (!O.Description.empty()) { 1399dba64beSDimitry Andric OS << "\""; 1409dba64beSDimitry Andric llvm::printEscapedString(O.Description, OS); 1419dba64beSDimitry Andric OS << "\""; 1429dba64beSDimitry Andric } else 1430b57cec5SDimitry Andric OS << "\"\""; 1440b57cec5SDimitry Andric OS << "},\n"; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric /// Emits all option initializers to the raw_ostream. 1489dba64beSDimitry Andric static void emitOptions(std::string Command, std::vector<Record *> Records, 1490b57cec5SDimitry Andric raw_ostream &OS) { 1509dba64beSDimitry Andric std::vector<CommandOption> Options; 1519dba64beSDimitry Andric for (Record *R : Records) 1529dba64beSDimitry Andric Options.emplace_back(R); 1539dba64beSDimitry Andric 1549dba64beSDimitry Andric std::string ID = Command; 1559dba64beSDimitry Andric std::replace(ID.begin(), ID.end(), ' ', '_'); 1560b57cec5SDimitry Andric // Generate the macro that the user needs to define before including the 1570b57cec5SDimitry Andric // *.inc file. 1589dba64beSDimitry Andric std::string NeededMacro = "LLDB_OPTIONS_" + ID; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric // All options are in one file, so we need put them behind macros and ask the 1610b57cec5SDimitry Andric // user to define the macro for the options that are needed. 1620b57cec5SDimitry Andric OS << "// Options for " << Command << "\n"; 1630b57cec5SDimitry Andric OS << "#ifdef " << NeededMacro << "\n"; 1649dba64beSDimitry Andric OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n"; 1659dba64beSDimitry Andric for (CommandOption &CO : Options) 1669dba64beSDimitry Andric emitOption(CO, OS); 1670b57cec5SDimitry Andric // We undefine the macro for the user like Clang's include files are doing it. 1689dba64beSDimitry Andric OS << "};\n"; 1690b57cec5SDimitry Andric OS << "#undef " << NeededMacro << "\n"; 1700b57cec5SDimitry Andric OS << "#endif // " << Command << " command\n\n"; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) { 174*5f757f3fSDimitry Andric emitSourceFileHeader("Options for LLDB command line commands.", OS, Records); 1750b57cec5SDimitry Andric 1769dba64beSDimitry Andric std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option"); 1779dba64beSDimitry Andric for (auto &CommandRecordPair : getRecordsByName(Options, "Command")) { 1780b57cec5SDimitry Andric emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric } 181