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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// These tablegen backends emits LLDB's OptionDefinition values for different
10// 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 {
26struct CommandOption {
27  std::vector<std::string> GroupsArg;
28  bool Required = false;
29  std::string FullName;
30  std::string ShortName;
31  std::string ArgType;
32  bool OptionalArg = false;
33  std::string Validator;
34  std::string ArgEnum;
35  std::vector<StringRef> Completions;
36  std::string Description;
37
38  CommandOption() = default;
39  CommandOption(Record *Option) {
40    if (Option->getValue("Groups")) {
41      // The user specified a list of groups.
42      auto Groups = Option->getValueAsListOfInts("Groups");
43      for (int Group : Groups)
44        GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group));
45    } else if (Option->getValue("GroupStart")) {
46      // The user specified a range of groups (with potentially only one
47      // element).
48      int GroupStart = Option->getValueAsInt("GroupStart");
49      int GroupEnd = Option->getValueAsInt("GroupEnd");
50      for (int i = GroupStart; i <= GroupEnd; ++i)
51        GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i));
52    }
53
54    // Check if this option is required.
55    Required = Option->getValue("Required");
56
57    // Add the full and short name for this option.
58    FullName = std::string(Option->getValueAsString("FullName"));
59    ShortName = std::string(Option->getValueAsString("ShortName"));
60
61    if (auto A = Option->getValue("ArgType"))
62      ArgType = A->getValue()->getAsUnquotedString();
63    OptionalArg = Option->getValue("OptionalArg") != nullptr;
64
65    if (Option->getValue("Validator"))
66      Validator = std::string(Option->getValueAsString("Validator"));
67
68    if (Option->getValue("ArgEnum"))
69      ArgEnum = std::string(Option->getValueAsString("ArgEnum"));
70
71    if (Option->getValue("Completions"))
72      Completions = Option->getValueAsListOfStrings("Completions");
73
74    if (auto D = Option->getValue("Description"))
75      Description = D->getValue()->getAsUnquotedString();
76  }
77};
78} // namespace
79
80static void emitOption(const CommandOption &O, raw_ostream &OS) {
81  OS << "  {";
82
83  // If we have any groups, we merge them. Otherwise we move this option into
84  // the all group.
85  if (O.GroupsArg.empty())
86    OS << "LLDB_OPT_SET_ALL";
87  else
88    OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | ");
89
90  OS << ", ";
91
92  // Check if this option is required.
93  OS << (O.Required ? "true" : "false");
94
95  // Add the full and short name for this option.
96  OS << ", \"" << O.FullName << "\", ";
97  OS << '\'' << O.ShortName << "'";
98
99  // Decide if we have either an option, required or no argument for this
100  // option.
101  OS << ", OptionParser::";
102  if (!O.ArgType.empty()) {
103    if (O.OptionalArg)
104      OS << "eOptionalArgument";
105    else
106      OS << "eRequiredArgument";
107  } else
108    OS << "eNoArgument";
109  OS << ", ";
110
111  if (!O.Validator.empty())
112    OS << O.Validator;
113  else
114    OS << "nullptr";
115  OS << ", ";
116
117  if (!O.ArgEnum.empty())
118    OS << O.ArgEnum;
119  else
120    OS << "{}";
121  OS << ", ";
122
123  // Read the tab completions we offer for this option (if there are any)
124  if (!O.Completions.empty()) {
125    std::vector<std::string> CompletionArgs;
126    for (llvm::StringRef Completion : O.Completions)
127      CompletionArgs.push_back("CommandCompletions::e" + Completion.str() +
128                               "Completion");
129
130    OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | ");
131  } else
132    OS << "CommandCompletions::eNoCompletion";
133
134  // Add the argument type.
135  OS << ", eArgType";
136  if (!O.ArgType.empty()) {
137    OS << O.ArgType;
138  } else
139    OS << "None";
140  OS << ", ";
141
142  // Add the description if there is any.
143  if (!O.Description.empty()) {
144    OS << "\"";
145    llvm::printEscapedString(O.Description, OS);
146    OS << "\"";
147  } else
148    OS << "\"\"";
149  OS << "},\n";
150}
151
152/// Emits all option initializers to the raw_ostream.
153static void emitOptions(std::string Command, std::vector<Record *> Records,
154                        raw_ostream &OS) {
155  std::vector<CommandOption> Options;
156  for (Record *R : Records)
157    Options.emplace_back(R);
158
159  std::string ID = Command;
160  std::replace(ID.begin(), ID.end(), ' ', '_');
161  // Generate the macro that the user needs to define before including the
162  // *.inc file.
163  std::string NeededMacro = "LLDB_OPTIONS_" + ID;
164
165  // All options are in one file, so we need put them behind macros and ask the
166  // user to define the macro for the options that are needed.
167  OS << "// Options for " << Command << "\n";
168  OS << "#ifdef " << NeededMacro << "\n";
169  OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n";
170  for (CommandOption &CO : Options)
171    emitOption(CO, OS);
172  // We undefine the macro for the user like Clang's include files are doing it.
173  OS << "};\n";
174  OS << "#undef " << NeededMacro << "\n";
175  OS << "#endif // " << Command << " command\n\n";
176}
177
178void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) {
179  emitSourceFileHeader("Options for LLDB command line commands.", OS);
180
181  std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option");
182  for (auto &CommandRecordPair : getRecordsByName(Options, "Command")) {
183    emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS);
184  }
185}
186