19870f6adSJonas Devlieghere //===- LLDBOptionDefEmitter.cpp -------------------------------------------===//
293f50594SJonas Devlieghere //
393f50594SJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
493f50594SJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information.
593f50594SJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
693f50594SJonas Devlieghere //
793f50594SJonas Devlieghere //===----------------------------------------------------------------------===//
893f50594SJonas Devlieghere //
993f50594SJonas Devlieghere // These tablegen backends emits LLDB's OptionDefinition values for different
1093f50594SJonas Devlieghere // LLDB commands.
1193f50594SJonas Devlieghere //
1293f50594SJonas Devlieghere //===----------------------------------------------------------------------===//
1393f50594SJonas Devlieghere 
1493f50594SJonas Devlieghere #include "LLDBTableGenBackends.h"
15be019c7aSJonas Devlieghere #include "LLDBTableGenUtils.h"
1693f50594SJonas Devlieghere #include "llvm/ADT/StringExtras.h"
1793f50594SJonas Devlieghere #include "llvm/TableGen/Record.h"
1893f50594SJonas Devlieghere #include "llvm/TableGen/StringMatcher.h"
1993f50594SJonas Devlieghere #include "llvm/TableGen/TableGenBackend.h"
2093f50594SJonas Devlieghere #include <vector>
2193f50594SJonas Devlieghere 
2293f50594SJonas Devlieghere using namespace llvm;
23310f6b89SJonas Devlieghere using namespace lldb_private;
2493f50594SJonas Devlieghere 
254e44c77aSRaphael Isemann namespace {
264e44c77aSRaphael Isemann struct CommandOption {
2793f50594SJonas Devlieghere   std::vector<std::string> GroupsArg;
284e44c77aSRaphael Isemann   bool Required = false;
294e44c77aSRaphael Isemann   std::string FullName;
304e44c77aSRaphael Isemann   std::string ShortName;
314e44c77aSRaphael Isemann   std::string ArgType;
324e44c77aSRaphael Isemann   bool OptionalArg = false;
334e44c77aSRaphael Isemann   std::string Validator;
344e44c77aSRaphael Isemann   std::vector<StringRef> Completions;
354e44c77aSRaphael Isemann   std::string Description;
3693f50594SJonas Devlieghere 
374e44c77aSRaphael Isemann   CommandOption() = default;
CommandOption__anon2b7cd5ae0111::CommandOption384e44c77aSRaphael Isemann   CommandOption(Record *Option) {
3993f50594SJonas Devlieghere     if (Option->getValue("Groups")) {
4093f50594SJonas Devlieghere       // The user specified a list of groups.
4193f50594SJonas Devlieghere       auto Groups = Option->getValueAsListOfInts("Groups");
4293f50594SJonas Devlieghere       for (int Group : Groups)
4393f50594SJonas Devlieghere         GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group));
4493f50594SJonas Devlieghere     } else if (Option->getValue("GroupStart")) {
454e44c77aSRaphael Isemann       // The user specified a range of groups (with potentially only one
464e44c77aSRaphael Isemann       // element).
4793f50594SJonas Devlieghere       int GroupStart = Option->getValueAsInt("GroupStart");
4893f50594SJonas Devlieghere       int GroupEnd = Option->getValueAsInt("GroupEnd");
4993f50594SJonas Devlieghere       for (int i = GroupStart; i <= GroupEnd; ++i)
5093f50594SJonas Devlieghere         GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i));
5193f50594SJonas Devlieghere     }
5293f50594SJonas Devlieghere 
534e44c77aSRaphael Isemann     // Check if this option is required.
544e44c77aSRaphael Isemann     Required = Option->getValue("Required");
554e44c77aSRaphael Isemann 
564e44c77aSRaphael Isemann     // Add the full and short name for this option.
57adcd0268SBenjamin Kramer     FullName = std::string(Option->getValueAsString("FullName"));
58adcd0268SBenjamin Kramer     ShortName = std::string(Option->getValueAsString("ShortName"));
594e44c77aSRaphael Isemann 
604e44c77aSRaphael Isemann     if (auto A = Option->getValue("ArgType"))
614e44c77aSRaphael Isemann       ArgType = A->getValue()->getAsUnquotedString();
624e44c77aSRaphael Isemann     OptionalArg = Option->getValue("OptionalArg") != nullptr;
634e44c77aSRaphael Isemann 
644e44c77aSRaphael Isemann     if (Option->getValue("Validator"))
65adcd0268SBenjamin Kramer       Validator = std::string(Option->getValueAsString("Validator"));
664e44c77aSRaphael Isemann 
674e44c77aSRaphael Isemann     if (Option->getValue("Completions"))
684e44c77aSRaphael Isemann       Completions = Option->getValueAsListOfStrings("Completions");
694e44c77aSRaphael Isemann 
704e44c77aSRaphael Isemann     if (auto D = Option->getValue("Description"))
714e44c77aSRaphael Isemann       Description = D->getValue()->getAsUnquotedString();
724e44c77aSRaphael Isemann   }
734e44c77aSRaphael Isemann };
744e44c77aSRaphael Isemann } // namespace
754e44c77aSRaphael Isemann 
emitOption(const CommandOption & O,raw_ostream & OS)764e44c77aSRaphael Isemann static void emitOption(const CommandOption &O, raw_ostream &OS) {
774e44c77aSRaphael Isemann   OS << "  {";
784e44c77aSRaphael Isemann 
7993f50594SJonas Devlieghere   // If we have any groups, we merge them. Otherwise we move this option into
8093f50594SJonas Devlieghere   // the all group.
814e44c77aSRaphael Isemann   if (O.GroupsArg.empty())
8293f50594SJonas Devlieghere     OS << "LLDB_OPT_SET_ALL";
8393f50594SJonas Devlieghere   else
844e44c77aSRaphael Isemann     OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | ");
8593f50594SJonas Devlieghere 
8693f50594SJonas Devlieghere   OS << ", ";
8793f50594SJonas Devlieghere 
8893f50594SJonas Devlieghere   // Check if this option is required.
894e44c77aSRaphael Isemann   OS << (O.Required ? "true" : "false");
9093f50594SJonas Devlieghere 
9193f50594SJonas Devlieghere   // Add the full and short name for this option.
924e44c77aSRaphael Isemann   OS << ", \"" << O.FullName << "\", ";
934e44c77aSRaphael Isemann   OS << '\'' << O.ShortName << "'";
9493f50594SJonas Devlieghere 
9593f50594SJonas Devlieghere   // Decide if we have either an option, required or no argument for this
9693f50594SJonas Devlieghere   // option.
9793f50594SJonas Devlieghere   OS << ", OptionParser::";
984e44c77aSRaphael Isemann   if (!O.ArgType.empty()) {
994e44c77aSRaphael Isemann     if (O.OptionalArg)
10093f50594SJonas Devlieghere       OS << "eOptionalArgument";
10193f50594SJonas Devlieghere     else
10293f50594SJonas Devlieghere       OS << "eRequiredArgument";
10393f50594SJonas Devlieghere   } else
10493f50594SJonas Devlieghere     OS << "eNoArgument";
1050ab0bb91SRaphael Isemann   OS << ", ";
1060ab0bb91SRaphael Isemann 
1074e44c77aSRaphael Isemann   if (!O.Validator.empty())
1084e44c77aSRaphael Isemann     OS << O.Validator;
1090ab0bb91SRaphael Isemann   else
1100ab0bb91SRaphael Isemann     OS << "nullptr";
1110ab0bb91SRaphael Isemann   OS << ", ";
11293f50594SJonas Devlieghere 
113*7ced9fffSJonas Devlieghere   if (!O.ArgType.empty())
114*7ced9fffSJonas Devlieghere     OS << "g_argument_table[eArgType" << O.ArgType << "].enum_values";
11593f50594SJonas Devlieghere   else
11693f50594SJonas Devlieghere     OS << "{}";
11793f50594SJonas Devlieghere   OS << ", ";
11893f50594SJonas Devlieghere 
11993f50594SJonas Devlieghere   // Read the tab completions we offer for this option (if there are any)
1204e44c77aSRaphael Isemann   if (!O.Completions.empty()) {
12193f50594SJonas Devlieghere     std::vector<std::string> CompletionArgs;
1224e44c77aSRaphael Isemann     for (llvm::StringRef Completion : O.Completions)
12393f50594SJonas Devlieghere       CompletionArgs.push_back("CommandCompletions::e" + Completion.str() +
12493f50594SJonas Devlieghere                                "Completion");
12593f50594SJonas Devlieghere 
12693f50594SJonas Devlieghere     OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | ");
1274e44c77aSRaphael Isemann   } else
12893f50594SJonas Devlieghere     OS << "CommandCompletions::eNoCompletion";
12993f50594SJonas Devlieghere 
13093f50594SJonas Devlieghere   // Add the argument type.
13193f50594SJonas Devlieghere   OS << ", eArgType";
1324e44c77aSRaphael Isemann   if (!O.ArgType.empty()) {
1334e44c77aSRaphael Isemann     OS << O.ArgType;
13493f50594SJonas Devlieghere   } else
13593f50594SJonas Devlieghere     OS << "None";
13693f50594SJonas Devlieghere   OS << ", ";
13793f50594SJonas Devlieghere 
13893f50594SJonas Devlieghere   // Add the description if there is any.
1394e44c77aSRaphael Isemann   if (!O.Description.empty()) {
14093f50594SJonas Devlieghere     OS << "\"";
1414e44c77aSRaphael Isemann     llvm::printEscapedString(O.Description, OS);
14293f50594SJonas Devlieghere     OS << "\"";
14393f50594SJonas Devlieghere   } else
14493f50594SJonas Devlieghere     OS << "\"\"";
14593f50594SJonas Devlieghere   OS << "},\n";
14693f50594SJonas Devlieghere }
14793f50594SJonas Devlieghere 
14893f50594SJonas Devlieghere /// Emits all option initializers to the raw_ostream.
emitOptions(std::string Command,std::vector<Record * > Records,raw_ostream & OS)1494e44c77aSRaphael Isemann static void emitOptions(std::string Command, std::vector<Record *> Records,
15093f50594SJonas Devlieghere                         raw_ostream &OS) {
1514e44c77aSRaphael Isemann   std::vector<CommandOption> Options;
1524e44c77aSRaphael Isemann   for (Record *R : Records)
1534e44c77aSRaphael Isemann     Options.emplace_back(R);
1544e44c77aSRaphael Isemann 
155bd68a052SRaphael Isemann   std::string ID = Command;
156bd68a052SRaphael Isemann   std::replace(ID.begin(), ID.end(), ' ', '_');
15793f50594SJonas Devlieghere   // Generate the macro that the user needs to define before including the
15893f50594SJonas Devlieghere   // *.inc file.
159bd68a052SRaphael Isemann   std::string NeededMacro = "LLDB_OPTIONS_" + ID;
16093f50594SJonas Devlieghere 
16193f50594SJonas Devlieghere   // All options are in one file, so we need put them behind macros and ask the
16293f50594SJonas Devlieghere   // user to define the macro for the options that are needed.
16393f50594SJonas Devlieghere   OS << "// Options for " << Command << "\n";
16493f50594SJonas Devlieghere   OS << "#ifdef " << NeededMacro << "\n";
165bd68a052SRaphael Isemann   OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n";
1664e44c77aSRaphael Isemann   for (CommandOption &CO : Options)
1674e44c77aSRaphael Isemann     emitOption(CO, OS);
16893f50594SJonas Devlieghere   // We undefine the macro for the user like Clang's include files are doing it.
169bd68a052SRaphael Isemann   OS << "};\n";
17093f50594SJonas Devlieghere   OS << "#undef " << NeededMacro << "\n";
17193f50594SJonas Devlieghere   OS << "#endif // " << Command << " command\n\n";
17293f50594SJonas Devlieghere }
17393f50594SJonas Devlieghere 
EmitOptionDefs(RecordKeeper & Records,raw_ostream & OS)17493f50594SJonas Devlieghere void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) {
17593f50594SJonas Devlieghere   emitSourceFileHeader("Options for LLDB command line commands.", OS);
17693f50594SJonas Devlieghere 
177310f6b89SJonas Devlieghere   std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option");
178be019c7aSJonas Devlieghere   for (auto &CommandRecordPair : getRecordsByName(Options, "Command")) {
17993f50594SJonas Devlieghere     emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS);
18093f50594SJonas Devlieghere   }
18193f50594SJonas Devlieghere }
182