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

source code of lldb/utils/TableGen/LLDBOptionDefEmitter.cpp