blob: 01eacbad7717f2d381a0c0a9bc9dc2a5a8e5d4d0 [file] [log] [blame]
Jonas Devlieghere9870f6a2019-07-25 04:38:46 +00001//===- LLDBOptionDefEmitter.cpp -------------------------------------------===//
Jonas Devlieghere93f50592019-07-23 17:47:08 +00002//
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 "llvm/ADT/StringExtras.h"
16#include "llvm/TableGen/Record.h"
17#include "llvm/TableGen/StringMatcher.h"
18#include "llvm/TableGen/TableGenBackend.h"
19#include <map>
20#include <vector>
21
22using namespace llvm;
Jonas Devlieghere310f6b82019-07-30 22:50:37 +000023using namespace lldb_private;
Jonas Devlieghere93f50592019-07-23 17:47:08 +000024
25/// Groups all records by their command.
Jonas Devlieghere310f6b82019-07-30 22:50:37 +000026static RecordsByName getCommandList(std::vector<Record *> Options) {
27 RecordsByName result;
Jonas Devlieghere93f50592019-07-23 17:47:08 +000028 for (Record *Option : Options)
29 result[Option->getValueAsString("Command").str()].push_back(Option);
30 return result;
31}
32
Raphael Isemann4e44c772019-07-29 08:22:41 +000033namespace {
34struct CommandOption {
Jonas Devlieghere93f50592019-07-23 17:47:08 +000035 std::vector<std::string> GroupsArg;
Raphael Isemann4e44c772019-07-29 08:22:41 +000036 bool Required = false;
37 std::string FullName;
38 std::string ShortName;
39 std::string ArgType;
40 bool OptionalArg = false;
41 std::string Validator;
42 std::string ArgEnum;
43 std::vector<StringRef> Completions;
44 std::string Description;
Jonas Devlieghere93f50592019-07-23 17:47:08 +000045
Raphael Isemann4e44c772019-07-29 08:22:41 +000046 CommandOption() = default;
47 CommandOption(Record *Option) {
48 if (Option->getValue("Groups")) {
49 // The user specified a list of groups.
50 auto Groups = Option->getValueAsListOfInts("Groups");
51 for (int Group : Groups)
52 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group));
53 } else if (Option->getValue("GroupStart")) {
54 // The user specified a range of groups (with potentially only one
55 // element).
56 int GroupStart = Option->getValueAsInt("GroupStart");
57 int GroupEnd = Option->getValueAsInt("GroupEnd");
58 for (int i = GroupStart; i <= GroupEnd; ++i)
59 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i));
60 }
61
62 // Check if this option is required.
63 Required = Option->getValue("Required");
64
65 // Add the full and short name for this option.
66 FullName = Option->getValueAsString("FullName");
67 ShortName = Option->getValueAsString("ShortName");
68
69 if (auto A = Option->getValue("ArgType"))
70 ArgType = A->getValue()->getAsUnquotedString();
71 OptionalArg = Option->getValue("OptionalArg") != nullptr;
72
73 if (Option->getValue("Validator"))
74 Validator = Option->getValueAsString("Validator");
75
76 if (Option->getValue("ArgEnum"))
77 ArgEnum = Option->getValueAsString("ArgEnum");
78
79 if (Option->getValue("Completions"))
80 Completions = Option->getValueAsListOfStrings("Completions");
81
82 if (auto D = Option->getValue("Description"))
83 Description = D->getValue()->getAsUnquotedString();
Jonas Devlieghere93f50592019-07-23 17:47:08 +000084 }
Raphael Isemann4e44c772019-07-29 08:22:41 +000085};
86} // namespace
87
88static void emitOption(const CommandOption &O, raw_ostream &OS) {
89 OS << " {";
Jonas Devlieghere93f50592019-07-23 17:47:08 +000090
91 // If we have any groups, we merge them. Otherwise we move this option into
92 // the all group.
Raphael Isemann4e44c772019-07-29 08:22:41 +000093 if (O.GroupsArg.empty())
Jonas Devlieghere93f50592019-07-23 17:47:08 +000094 OS << "LLDB_OPT_SET_ALL";
95 else
Raphael Isemann4e44c772019-07-29 08:22:41 +000096 OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | ");
Jonas Devlieghere93f50592019-07-23 17:47:08 +000097
98 OS << ", ";
99
100 // Check if this option is required.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000101 OS << (O.Required ? "true" : "false");
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000102
103 // Add the full and short name for this option.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000104 OS << ", \"" << O.FullName << "\", ";
105 OS << '\'' << O.ShortName << "'";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000106
107 // Decide if we have either an option, required or no argument for this
108 // option.
109 OS << ", OptionParser::";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000110 if (!O.ArgType.empty()) {
111 if (O.OptionalArg)
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000112 OS << "eOptionalArgument";
113 else
114 OS << "eRequiredArgument";
115 } else
116 OS << "eNoArgument";
Raphael Isemann0ab0bb92019-07-26 11:46:21 +0000117 OS << ", ";
118
Raphael Isemann4e44c772019-07-29 08:22:41 +0000119 if (!O.Validator.empty())
120 OS << O.Validator;
Raphael Isemann0ab0bb92019-07-26 11:46:21 +0000121 else
122 OS << "nullptr";
123 OS << ", ";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000124
Raphael Isemann4e44c772019-07-29 08:22:41 +0000125 if (!O.ArgEnum.empty())
126 OS << O.ArgEnum;
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000127 else
128 OS << "{}";
129 OS << ", ";
130
131 // Read the tab completions we offer for this option (if there are any)
Raphael Isemann4e44c772019-07-29 08:22:41 +0000132 if (!O.Completions.empty()) {
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000133 std::vector<std::string> CompletionArgs;
Raphael Isemann4e44c772019-07-29 08:22:41 +0000134 for (llvm::StringRef Completion : O.Completions)
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000135 CompletionArgs.push_back("CommandCompletions::e" + Completion.str() +
136 "Completion");
137
138 OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | ");
Raphael Isemann4e44c772019-07-29 08:22:41 +0000139 } else
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000140 OS << "CommandCompletions::eNoCompletion";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000141
142 // Add the argument type.
143 OS << ", eArgType";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000144 if (!O.ArgType.empty()) {
145 OS << O.ArgType;
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000146 } else
147 OS << "None";
148 OS << ", ";
149
150 // Add the description if there is any.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000151 if (!O.Description.empty()) {
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000152 OS << "\"";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000153 llvm::printEscapedString(O.Description, OS);
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000154 OS << "\"";
155 } else
156 OS << "\"\"";
157 OS << "},\n";
158}
159
160/// Emits all option initializers to the raw_ostream.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000161static void emitOptions(std::string Command, std::vector<Record *> Records,
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000162 raw_ostream &OS) {
Raphael Isemann4e44c772019-07-29 08:22:41 +0000163 std::vector<CommandOption> Options;
164 for (Record *R : Records)
165 Options.emplace_back(R);
166
Raphael Isemannbd68a052019-07-28 06:24:07 +0000167 std::string ID = Command;
168 std::replace(ID.begin(), ID.end(), ' ', '_');
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000169 // Generate the macro that the user needs to define before including the
170 // *.inc file.
Raphael Isemannbd68a052019-07-28 06:24:07 +0000171 std::string NeededMacro = "LLDB_OPTIONS_" + ID;
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000172
173 // All options are in one file, so we need put them behind macros and ask the
174 // user to define the macro for the options that are needed.
175 OS << "// Options for " << Command << "\n";
176 OS << "#ifdef " << NeededMacro << "\n";
Raphael Isemannbd68a052019-07-28 06:24:07 +0000177 OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000178 for (CommandOption &CO : Options)
179 emitOption(CO, OS);
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000180 // We undefine the macro for the user like Clang's include files are doing it.
Raphael Isemannbd68a052019-07-28 06:24:07 +0000181 OS << "};\n";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000182 OS << "#undef " << NeededMacro << "\n";
183 OS << "#endif // " << Command << " command\n\n";
184}
185
186void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) {
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000187 emitSourceFileHeader("Options for LLDB command line commands.", OS);
188
Jonas Devlieghere310f6b82019-07-30 22:50:37 +0000189 std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option");
190 for (auto &CommandRecordPair : getCommandList(Options)) {
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000191 emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS);
192 }
193}