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;
CommandOption__anonfa5c5c740111::CommandOption389dba64beSDimitry 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
emitOption(const CommandOption & O,raw_ostream & OS)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)
123fe013be4SDimitry Andric CompletionArgs.push_back("e" + Completion.str() + "Completion");
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | ");
1269dba64beSDimitry Andric } else
127fe013be4SDimitry 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.
emitOptions(std::string Command,std::vector<Record * > Records,raw_ostream & OS)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
EmitOptionDefs(RecordKeeper & Records,raw_ostream & OS)1730b57cec5SDimitry Andric void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) {
174*c9157d92SDimitry 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