//===- LLDBOptionDefEmitter.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // These tablegen backends emits LLDB's OptionDefinition values for different // LLDB commands. // //===----------------------------------------------------------------------===// #include "LLDBTableGenBackends.h" #include "LLDBTableGenUtils.h" #include "llvm/ADT/StringExtras.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringMatcher.h" #include "llvm/TableGen/TableGenBackend.h" #include using namespace llvm; using namespace lldb_private; namespace { struct CommandOption { std::vector GroupsArg; bool Required = false; std::string FullName; std::string ShortName; std::string ArgType; bool OptionalArg = false; std::string Validator; std::vector Completions; std::string Description; CommandOption() = default; CommandOption(Record *Option) { if (Option->getValue("Groups")) { // The user specified a list of groups. auto Groups = Option->getValueAsListOfInts("Groups"); for (int Group : Groups) GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group)); } else if (Option->getValue("GroupStart")) { // The user specified a range of groups (with potentially only one // element). int GroupStart = Option->getValueAsInt("GroupStart"); int GroupEnd = Option->getValueAsInt("GroupEnd"); for (int i = GroupStart; i <= GroupEnd; ++i) GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i)); } // Check if this option is required. Required = Option->getValue("Required"); // Add the full and short name for this option. FullName = std::string(Option->getValueAsString("FullName")); ShortName = std::string(Option->getValueAsString("ShortName")); if (auto A = Option->getValue("ArgType")) ArgType = A->getValue()->getAsUnquotedString(); OptionalArg = Option->getValue("OptionalArg") != nullptr; if (Option->getValue("Validator")) Validator = std::string(Option->getValueAsString("Validator")); if (Option->getValue("Completions")) Completions = Option->getValueAsListOfStrings("Completions"); if (auto D = Option->getValue("Description")) Description = D->getValue()->getAsUnquotedString(); } }; } // namespace static void emitOption(const CommandOption &O, raw_ostream &OS) { OS << " {"; // If we have any groups, we merge them. Otherwise we move this option into // the all group. if (O.GroupsArg.empty()) OS << "LLDB_OPT_SET_ALL"; else OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | "); OS << ", "; // Check if this option is required. OS << (O.Required ? "true" : "false"); // Add the full and short name for this option. OS << ", \"" << O.FullName << "\", "; OS << '\'' << O.ShortName << "'"; // Decide if we have either an option, required or no argument for this // option. OS << ", OptionParser::"; if (!O.ArgType.empty()) { if (O.OptionalArg) OS << "eOptionalArgument"; else OS << "eRequiredArgument"; } else OS << "eNoArgument"; OS << ", "; if (!O.Validator.empty()) OS << O.Validator; else OS << "nullptr"; OS << ", "; if (!O.ArgType.empty()) OS << "g_argument_table[eArgType" << O.ArgType << "].enum_values"; else OS << "{}"; OS << ", "; // Read the tab completions we offer for this option (if there are any) if (!O.Completions.empty()) { std::vector CompletionArgs; for (llvm::StringRef Completion : O.Completions) CompletionArgs.push_back("e" + Completion.str() + "Completion"); OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | "); } else OS << "CompletionType::eNoCompletion"; // Add the argument type. OS << ", eArgType"; if (!O.ArgType.empty()) { OS << O.ArgType; } else OS << "None"; OS << ", "; // Add the description if there is any. if (!O.Description.empty()) { OS << "\""; llvm::printEscapedString(O.Description, OS); OS << "\""; } else OS << "\"\""; OS << "},\n"; } /// Emits all option initializers to the raw_ostream. static void emitOptions(std::string Command, std::vector Records, raw_ostream &OS) { std::vector Options; for (Record *R : Records) Options.emplace_back(R); std::string ID = Command; std::replace(ID.begin(), ID.end(), ' ', '_'); // Generate the macro that the user needs to define before including the // *.inc file. std::string NeededMacro = "LLDB_OPTIONS_" + ID; // All options are in one file, so we need put them behind macros and ask the // user to define the macro for the options that are needed. OS << "// Options for " << Command << "\n"; OS << "#ifdef " << NeededMacro << "\n"; OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n"; for (CommandOption &CO : Options) emitOption(CO, OS); // We undefine the macro for the user like Clang's include files are doing it. OS << "};\n"; OS << "#undef " << NeededMacro << "\n"; OS << "#endif // " << Command << " command\n\n"; } void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Options for LLDB command line commands.", OS, Records); std::vector Options = Records.getAllDerivedDefinitions("Option"); for (auto &CommandRecordPair : getRecordsByName(Options, "Command")) { emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS); } }