xref: /freebsd/contrib/llvm-project/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp (revision 924226fba12cc9a228c73b956e1b7fa24c60b055)
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 
22 using namespace llvm;
23 using namespace lldb_private;
24 
25 namespace {
26 struct 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 
80 static 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.
153 static 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 
178 void 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