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::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 | |
76 | static 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. |
148 | static 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 | |
173 | void 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 | |