xref: /freebsd/contrib/llvm-project/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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