brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.5 KiB · e6d5b7b Raw
207 lines · cpp
1//===- LLDBOptionDefEmitter.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// These tablegen backends emits LLDB's OptionDefinition values for different10// LLDB commands.11//12//===----------------------------------------------------------------------===//13 14#include "LLDBTableGenBackends.h"15#include "LLDBTableGenUtils.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/TableGen/Record.h"18#include "llvm/TableGen/StringMatcher.h"19#include "llvm/TableGen/TableGenBackend.h"20#include <vector>21 22using namespace llvm;23using namespace lldb_private;24 25namespace {26/// Parses curly braces and replaces them with ANSI underline formatting.27std::string underline(llvm::StringRef Str) {28  llvm::StringRef OpeningHead, OpeningTail, ClosingHead, ClosingTail;29  std::string Result;30  llvm::raw_string_ostream Stream(Result);31  while (!Str.empty()) {32    // Find the opening brace.33    std::tie(OpeningHead, OpeningTail) = Str.split("${");34    Stream << OpeningHead;35 36    // No opening brace: we're done.37    if (OpeningHead == Str)38      break;39 40    assert(!OpeningTail.empty());41 42    // Find the closing brace.43    std::tie(ClosingHead, ClosingTail) = OpeningTail.split('}');44    assert(!ClosingTail.empty() &&45           "unmatched curly braces in command option description");46 47    Stream << "${ansi.underline}" << ClosingHead << "${ansi.normal}";48    Str = ClosingTail;49  }50  return Result;51}52 53struct CommandOption {54  std::vector<std::string> GroupsArg;55  bool Required = false;56  std::string FullName;57  std::string ShortName;58  std::string ArgType;59  bool OptionalArg = false;60  std::string Validator;61  std::vector<StringRef> Completions;62  std::string Description;63 64  CommandOption() = default;65  CommandOption(const Record *Option) {66    if (Option->getValue("Groups")) {67      // The user specified a list of groups.68      auto Groups = Option->getValueAsListOfInts("Groups");69      for (int Group : Groups)70        GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group));71    } else if (Option->getValue("GroupStart")) {72      // The user specified a range of groups (with potentially only one73      // element).74      int GroupStart = Option->getValueAsInt("GroupStart");75      int GroupEnd = Option->getValueAsInt("GroupEnd");76      for (int i = GroupStart; i <= GroupEnd; ++i)77        GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i));78    }79 80    // Check if this option is required.81    Required = Option->getValue("Required");82 83    // Add the full and short name for this option.84    FullName = std::string(Option->getValueAsString("FullName"));85    ShortName = std::string(Option->getValueAsString("ShortName"));86 87    if (auto A = Option->getValue("ArgType"))88      ArgType = A->getValue()->getAsUnquotedString();89    OptionalArg = Option->getValue("OptionalArg") != nullptr;90 91    if (Option->getValue("Validator"))92      Validator = std::string(Option->getValueAsString("Validator"));93 94    if (Option->getValue("Completions"))95      Completions = Option->getValueAsListOfStrings("Completions");96 97    if (auto D = Option->getValue("Description"))98      Description = underline(D->getValue()->getAsUnquotedString());99  }100};101} // namespace102 103static void emitOption(const CommandOption &O, raw_ostream &OS) {104  OS << "  {";105 106  // If we have any groups, we merge them. Otherwise we move this option into107  // the all group.108  if (O.GroupsArg.empty())109    OS << "LLDB_OPT_SET_ALL";110  else111    OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | ");112 113  OS << ", ";114 115  // Check if this option is required.116  OS << (O.Required ? "true" : "false");117 118  // Add the full and short name for this option.119  OS << ", \"" << O.FullName << "\", ";120  OS << '\'' << O.ShortName << "'";121 122  // Decide if we have either an option, required or no argument for this123  // option.124  OS << ", OptionParser::";125  if (!O.ArgType.empty()) {126    if (O.OptionalArg)127      OS << "eOptionalArgument";128    else129      OS << "eRequiredArgument";130  } else131    OS << "eNoArgument";132  OS << ", ";133 134  if (!O.Validator.empty())135    OS << O.Validator;136  else137    OS << "nullptr";138  OS << ", ";139 140  if (!O.ArgType.empty())141    OS << "g_argument_table[eArgType" << O.ArgType << "].enum_values";142  else143    OS << "{}";144  OS << ", ";145 146  // Read the tab completions we offer for this option (if there are any)147  if (!O.Completions.empty()) {148    std::vector<std::string> CompletionArgs;149    for (llvm::StringRef Completion : O.Completions)150      CompletionArgs.push_back("e" + Completion.str() + "Completion");151 152    OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | ");153  } else154    OS << "CompletionType::eNoCompletion";155 156  // Add the argument type.157  OS << ", eArgType";158  if (!O.ArgType.empty()) {159    OS << O.ArgType;160  } else161    OS << "None";162  OS << ", ";163 164  // Add the description if there is any.165  if (!O.Description.empty()) {166    OS << "\"";167    llvm::printEscapedString(O.Description, OS);168    OS << "\"";169  } else170    OS << "\"\"";171  OS << "},\n";172}173 174/// Emits all option initializers to the raw_ostream.175static void emitOptions(std::string Command, ArrayRef<const Record *> Records,176                        raw_ostream &OS) {177  std::vector<CommandOption> Options(Records.begin(), Records.end());178 179  std::string ID = Command;180  llvm::replace(ID, ' ', '_');181  // Generate the macro that the user needs to define before including the182  // *.inc file.183  std::string NeededMacro = "LLDB_OPTIONS_" + ID;184 185  // All options are in one file, so we need put them behind macros and ask the186  // user to define the macro for the options that are needed.187  OS << "// Options for " << Command << "\n";188  OS << "#ifdef " << NeededMacro << "\n";189  OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n";190  for (CommandOption &CO : Options)191    emitOption(CO, OS);192  // We undefine the macro for the user like Clang's include files are doing it.193  OS << "};\n";194  OS << "#undef " << NeededMacro << "\n";195  OS << "#endif // " << Command << " command\n\n";196}197 198void lldb_private::EmitOptionDefs(const RecordKeeper &Records,199                                  raw_ostream &OS) {200  emitSourceFileHeader("Options for LLDB command line commands.", OS, Records);201 202  ArrayRef<const Record *> Options = Records.getAllDerivedDefinitions("Option");203  for (auto &CommandRecordPair : getRecordsByName(Options, "Command")) {204    emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS);205  }206}207