1 //===- TableGen.cpp - Top-Level TableGen implementation for Clang ---------===// 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 "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 22 using namespace llvm; 23 24 /// Map of command names to their associated records. Also makes sure our 25 /// commands are sorted in a deterministic way. 26 typedef std::map<std::string, std::vector<Record *>> RecordsByCommand; 27 28 /// Groups all records by their command. 29 static 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 36 static void emitOption(Record *Option, raw_ostream &OS) { 37 OS << " {"; 38 39 // List of option groups this option is in. 40 std::vector<std::string> GroupsArg; 41 42 if (Option->getValue("Groups")) { 43 // The user specified a list of groups. 44 auto Groups = Option->getValueAsListOfInts("Groups"); 45 for (int Group : Groups) 46 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group)); 47 } else if (Option->getValue("GroupStart")) { 48 // The user specified a range of groups (with potentially only one element). 49 int GroupStart = Option->getValueAsInt("GroupStart"); 50 int GroupEnd = Option->getValueAsInt("GroupEnd"); 51 for (int i = GroupStart; i <= GroupEnd; ++i) 52 GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i)); 53 } 54 55 // If we have any groups, we merge them. Otherwise we move this option into 56 // the all group. 57 if (GroupsArg.empty()) 58 OS << "LLDB_OPT_SET_ALL"; 59 else 60 OS << llvm::join(GroupsArg.begin(), GroupsArg.end(), " | "); 61 62 OS << ", "; 63 64 // Check if this option is required. 65 OS << (Option->getValue("Required") ? "true" : "false"); 66 67 // Add the full and short name for this option. 68 OS << ", \"" << Option->getValueAsString("FullName") << "\", "; 69 OS << '\'' << Option->getValueAsString("ShortName") << "'"; 70 71 auto ArgType = Option->getValue("ArgType"); 72 bool IsOptionalArg = Option->getValue("OptionalArg") != nullptr; 73 74 // Decide if we have either an option, required or no argument for this 75 // option. 76 OS << ", OptionParser::"; 77 if (ArgType) { 78 if (IsOptionalArg) 79 OS << "eOptionalArgument"; 80 else 81 OS << "eRequiredArgument"; 82 } else 83 OS << "eNoArgument"; 84 OS << ", nullptr, "; 85 86 if (Option->getValue("ArgEnum")) 87 OS << Option->getValueAsString("ArgEnum"); 88 else 89 OS << "{}"; 90 OS << ", "; 91 92 // Read the tab completions we offer for this option (if there are any) 93 if (Option->getValue("Completions")) { 94 auto Completions = Option->getValueAsListOfStrings("Completions"); 95 std::vector<std::string> CompletionArgs; 96 for (llvm::StringRef Completion : Completions) 97 CompletionArgs.push_back("CommandCompletions::e" + Completion.str() + 98 "Completion"); 99 100 OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | "); 101 } else { 102 OS << "CommandCompletions::eNoCompletion"; 103 } 104 105 // Add the argument type. 106 OS << ", eArgType"; 107 if (ArgType) { 108 OS << ArgType->getValue()->getAsUnquotedString(); 109 } else 110 OS << "None"; 111 OS << ", "; 112 113 // Add the description if there is any. 114 if (auto D = Option->getValue("Description")) 115 OS << D->getValue()->getAsString(); 116 else 117 OS << "\"\""; 118 OS << "},\n"; 119 } 120 121 /// Emits all option initializers to the raw_ostream. 122 static void emitOptions(std::string Command, std::vector<Record *> Option, 123 raw_ostream &OS) { 124 // Generate the macro that the user needs to define before including the 125 // *.inc file. 126 std::string NeededMacro = "LLDB_OPTIONS_" + Command; 127 std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); 128 129 // All options are in one file, so we need put them behind macros and ask the 130 // user to define the macro for the options that are needed. 131 OS << "// Options for " << Command << "\n"; 132 OS << "#ifdef " << NeededMacro << "\n"; 133 for (Record *R : Option) 134 emitOption(R, OS); 135 // We undefine the macro for the user like Clang's include files are doing it. 136 OS << "#undef " << NeededMacro << "\n"; 137 OS << "#endif // " << Command << " command\n\n"; 138 } 139 140 void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) { 141 142 std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option"); 143 144 emitSourceFileHeader("Options for LLDB command line commands.", OS); 145 146 RecordsByCommand ByCommand = getCommandList(Options); 147 148 for (auto &CommandRecordPair : ByCommand) { 149 emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS); 150 } 151 } 152