blob: d17b2af1d8c06ccc9778de5503de597bafa618af [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;
23
24/// Map of command names to their associated records. Also makes sure our
25/// commands are sorted in a deterministic way.
26typedef std::map<std::string, std::vector<Record *>> RecordsByCommand;
27
28/// Groups all records by their command.
29static RecordsByCommand getCommandList(std::vector<Record *> Options) {
30 RecordsByCommand result;
31 for (Record *Option : Options)
32 result[Option->getValueAsString("Command").str()].push_back(Option);
33 return result;
34}
35
Raphael Isemann4e44c772019-07-29 08:22:41 +000036namespace {
37struct CommandOption {
Jonas Devlieghere93f50592019-07-23 17:47:08 +000038 std::vector<std::string> GroupsArg;
Raphael Isemann4e44c772019-07-29 08:22:41 +000039 bool Required = false;
40 std::string FullName;
41 std::string ShortName;
42 std::string ArgType;
43 bool OptionalArg = false;
44 std::string Validator;
45 std::string ArgEnum;
46 std::vector<StringRef> Completions;
47 std::string Description;
Jonas Devlieghere93f50592019-07-23 17:47:08 +000048
Raphael Isemann4e44c772019-07-29 08:22:41 +000049 CommandOption() = default;
50 CommandOption(Record *Option) {
51 if (Option->getValue("Groups")) {
52 // The user specified a list of groups.
53 auto Groups = Option->getValueAsListOfInts("Groups");
54 for (int Group : Groups)
55 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group));
56 } else if (Option->getValue("GroupStart")) {
57 // The user specified a range of groups (with potentially only one
58 // element).
59 int GroupStart = Option->getValueAsInt("GroupStart");
60 int GroupEnd = Option->getValueAsInt("GroupEnd");
61 for (int i = GroupStart; i <= GroupEnd; ++i)
62 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i));
63 }
64
65 // Check if this option is required.
66 Required = Option->getValue("Required");
67
68 // Add the full and short name for this option.
69 FullName = Option->getValueAsString("FullName");
70 ShortName = Option->getValueAsString("ShortName");
71
72 if (auto A = Option->getValue("ArgType"))
73 ArgType = A->getValue()->getAsUnquotedString();
74 OptionalArg = Option->getValue("OptionalArg") != nullptr;
75
76 if (Option->getValue("Validator"))
77 Validator = Option->getValueAsString("Validator");
78
79 if (Option->getValue("ArgEnum"))
80 ArgEnum = Option->getValueAsString("ArgEnum");
81
82 if (Option->getValue("Completions"))
83 Completions = Option->getValueAsListOfStrings("Completions");
84
85 if (auto D = Option->getValue("Description"))
86 Description = D->getValue()->getAsUnquotedString();
Jonas Devlieghere93f50592019-07-23 17:47:08 +000087 }
Raphael Isemann4e44c772019-07-29 08:22:41 +000088};
89} // namespace
90
91static void emitOption(const CommandOption &O, raw_ostream &OS) {
92 OS << " {";
Jonas Devlieghere93f50592019-07-23 17:47:08 +000093
94 // If we have any groups, we merge them. Otherwise we move this option into
95 // the all group.
Raphael Isemann4e44c772019-07-29 08:22:41 +000096 if (O.GroupsArg.empty())
Jonas Devlieghere93f50592019-07-23 17:47:08 +000097 OS << "LLDB_OPT_SET_ALL";
98 else
Raphael Isemann4e44c772019-07-29 08:22:41 +000099 OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | ");
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000100
101 OS << ", ";
102
103 // Check if this option is required.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000104 OS << (O.Required ? "true" : "false");
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000105
106 // Add the full and short name for this option.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000107 OS << ", \"" << O.FullName << "\", ";
108 OS << '\'' << O.ShortName << "'";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000109
110 // Decide if we have either an option, required or no argument for this
111 // option.
112 OS << ", OptionParser::";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000113 if (!O.ArgType.empty()) {
114 if (O.OptionalArg)
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000115 OS << "eOptionalArgument";
116 else
117 OS << "eRequiredArgument";
118 } else
119 OS << "eNoArgument";
Raphael Isemann0ab0bb92019-07-26 11:46:21 +0000120 OS << ", ";
121
Raphael Isemann4e44c772019-07-29 08:22:41 +0000122 if (!O.Validator.empty())
123 OS << O.Validator;
Raphael Isemann0ab0bb92019-07-26 11:46:21 +0000124 else
125 OS << "nullptr";
126 OS << ", ";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000127
Raphael Isemann4e44c772019-07-29 08:22:41 +0000128 if (!O.ArgEnum.empty())
129 OS << O.ArgEnum;
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000130 else
131 OS << "{}";
132 OS << ", ";
133
134 // Read the tab completions we offer for this option (if there are any)
Raphael Isemann4e44c772019-07-29 08:22:41 +0000135 if (!O.Completions.empty()) {
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000136 std::vector<std::string> CompletionArgs;
Raphael Isemann4e44c772019-07-29 08:22:41 +0000137 for (llvm::StringRef Completion : O.Completions)
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000138 CompletionArgs.push_back("CommandCompletions::e" + Completion.str() +
139 "Completion");
140
141 OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | ");
Raphael Isemann4e44c772019-07-29 08:22:41 +0000142 } else
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000143 OS << "CommandCompletions::eNoCompletion";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000144
145 // Add the argument type.
146 OS << ", eArgType";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000147 if (!O.ArgType.empty()) {
148 OS << O.ArgType;
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000149 } else
150 OS << "None";
151 OS << ", ";
152
153 // Add the description if there is any.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000154 if (!O.Description.empty()) {
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000155 OS << "\"";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000156 llvm::printEscapedString(O.Description, OS);
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000157 OS << "\"";
158 } else
159 OS << "\"\"";
160 OS << "},\n";
161}
162
163/// Emits all option initializers to the raw_ostream.
Raphael Isemann4e44c772019-07-29 08:22:41 +0000164static void emitOptions(std::string Command, std::vector<Record *> Records,
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000165 raw_ostream &OS) {
Raphael Isemann4e44c772019-07-29 08:22:41 +0000166 std::vector<CommandOption> Options;
167 for (Record *R : Records)
168 Options.emplace_back(R);
169
Raphael Isemannbd68a052019-07-28 06:24:07 +0000170 std::string ID = Command;
171 std::replace(ID.begin(), ID.end(), ' ', '_');
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000172 // Generate the macro that the user needs to define before including the
173 // *.inc file.
Raphael Isemannbd68a052019-07-28 06:24:07 +0000174 std::string NeededMacro = "LLDB_OPTIONS_" + ID;
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000175
176 // All options are in one file, so we need put them behind macros and ask the
177 // user to define the macro for the options that are needed.
178 OS << "// Options for " << Command << "\n";
179 OS << "#ifdef " << NeededMacro << "\n";
Raphael Isemannbd68a052019-07-28 06:24:07 +0000180 OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n";
Raphael Isemann4e44c772019-07-29 08:22:41 +0000181 for (CommandOption &CO : Options)
182 emitOption(CO, OS);
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000183 // We undefine the macro for the user like Clang's include files are doing it.
Raphael Isemannbd68a052019-07-28 06:24:07 +0000184 OS << "};\n";
Jonas Devlieghere93f50592019-07-23 17:47:08 +0000185 OS << "#undef " << NeededMacro << "\n";
186 OS << "#endif // " << Command << " command\n\n";
187}
188
189void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) {
190
191 std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option");
192
193 emitSourceFileHeader("Options for LLDB command line commands.", OS);
194
195 RecordsByCommand ByCommand = getCommandList(Options);
196
197 for (auto &CommandRecordPair : ByCommand) {
198 emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS);
199 }
200}