1480093f4SDimitry Andric //===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric 9*0fca6ea1SDimitry Andric #include "Common/OptEmitter.h" 10480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h" 115ffd83dbSDimitry Andric #include "llvm/ADT/StringMap.h" 12480093f4SDimitry Andric #include "llvm/TableGen/Record.h" 1306c3fb27SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 14480093f4SDimitry Andric 15480093f4SDimitry Andric using namespace llvm; 16480093f4SDimitry Andric 17480093f4SDimitry Andric /// OptParserEmitter - This tablegen backend takes an input .td file 18480093f4SDimitry Andric /// describing a list of options and emits a RST man page. 1906c3fb27SDimitry Andric static void EmitOptRST(RecordKeeper &Records, raw_ostream &OS) { 20480093f4SDimitry Andric llvm::StringMap<std::vector<Record *>> OptionsByGroup; 21480093f4SDimitry Andric std::vector<Record *> OptionsWithoutGroup; 22480093f4SDimitry Andric 23480093f4SDimitry Andric // Get the options. 24480093f4SDimitry Andric std::vector<Record *> Opts = Records.getAllDerivedDefinitions("Option"); 25480093f4SDimitry Andric array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); 26480093f4SDimitry Andric 27480093f4SDimitry Andric // Get the option groups. 28480093f4SDimitry Andric const std::vector<Record *> &Groups = 29480093f4SDimitry Andric Records.getAllDerivedDefinitions("OptionGroup"); 30480093f4SDimitry Andric for (unsigned i = 0, e = Groups.size(); i != e; ++i) { 31480093f4SDimitry Andric const Record &R = *Groups[i]; 32480093f4SDimitry Andric OptionsByGroup.try_emplace(R.getValueAsString("Name")); 33480093f4SDimitry Andric } 34480093f4SDimitry Andric 35480093f4SDimitry Andric // Map options to their group. 36480093f4SDimitry Andric for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 37480093f4SDimitry Andric const Record &R = *Opts[i]; 38480093f4SDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 39480093f4SDimitry Andric OptionsByGroup[DI->getDef()->getValueAsString("Name")].push_back(Opts[i]); 40480093f4SDimitry Andric } else { 41480093f4SDimitry Andric OptionsByGroup["options"].push_back(Opts[i]); 42480093f4SDimitry Andric } 43480093f4SDimitry Andric } 44480093f4SDimitry Andric 45480093f4SDimitry Andric // Print options under their group. 46480093f4SDimitry Andric for (const auto &KV : OptionsByGroup) { 47480093f4SDimitry Andric std::string GroupName = KV.getKey().upper(); 48480093f4SDimitry Andric OS << GroupName << '\n'; 49480093f4SDimitry Andric OS << std::string(GroupName.size(), '-') << '\n'; 50480093f4SDimitry Andric OS << '\n'; 51480093f4SDimitry Andric 52480093f4SDimitry Andric for (Record *R : KV.getValue()) { 53480093f4SDimitry Andric OS << ".. option:: "; 54480093f4SDimitry Andric 55480093f4SDimitry Andric // Print the prefix. 56480093f4SDimitry Andric std::vector<StringRef> Prefixes = R->getValueAsListOfStrings("Prefixes"); 57480093f4SDimitry Andric if (!Prefixes.empty()) 58480093f4SDimitry Andric OS << Prefixes[0]; 59480093f4SDimitry Andric 60480093f4SDimitry Andric // Print the option name. 61480093f4SDimitry Andric OS << R->getValueAsString("Name"); 62480093f4SDimitry Andric 6381ad6265SDimitry Andric StringRef MetaVarName; 64480093f4SDimitry Andric // Print the meta-variable. 65480093f4SDimitry Andric if (!isa<UnsetInit>(R->getValueInit("MetaVarName"))) { 6681ad6265SDimitry Andric MetaVarName = R->getValueAsString("MetaVarName"); 6781ad6265SDimitry Andric } else if (!isa<UnsetInit>(R->getValueInit("Values"))) 6881ad6265SDimitry Andric MetaVarName = "<value>"; 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric if (!MetaVarName.empty()) { 71480093f4SDimitry Andric OS << '='; 7281ad6265SDimitry Andric OS.write_escaped(MetaVarName); 73480093f4SDimitry Andric } 74480093f4SDimitry Andric 75480093f4SDimitry Andric OS << "\n\n"; 76480093f4SDimitry Andric 7781ad6265SDimitry Andric std::string HelpText; 78480093f4SDimitry Andric // The option help text. 79480093f4SDimitry Andric if (!isa<UnsetInit>(R->getValueInit("HelpText"))) { 8081ad6265SDimitry Andric HelpText = R->getValueAsString("HelpText").trim().str(); 8181ad6265SDimitry Andric if (!HelpText.empty() && HelpText.back() != '.') 8281ad6265SDimitry Andric HelpText.push_back('.'); 8381ad6265SDimitry Andric } 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric if (!isa<UnsetInit>(R->getValueInit("Values"))) { 8681ad6265SDimitry Andric SmallVector<StringRef> Values; 8781ad6265SDimitry Andric SplitString(R->getValueAsString("Values"), Values, ","); 8881ad6265SDimitry Andric HelpText += (" " + MetaVarName + " must be '").str(); 8981ad6265SDimitry Andric 9081ad6265SDimitry Andric if (Values.size() > 1) { 9181ad6265SDimitry Andric HelpText += join(Values.begin(), Values.end() - 1, "', '"); 9281ad6265SDimitry Andric HelpText += "' or '"; 9381ad6265SDimitry Andric } 945f757f3fSDimitry Andric HelpText += (Values.back() + "'.").str(); 9581ad6265SDimitry Andric } 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric if (!HelpText.empty()) { 98480093f4SDimitry Andric OS << ' '; 9981ad6265SDimitry Andric OS.write_escaped(HelpText); 100480093f4SDimitry Andric OS << "\n\n"; 101480093f4SDimitry Andric } 102480093f4SDimitry Andric } 103480093f4SDimitry Andric } 104480093f4SDimitry Andric } 10506c3fb27SDimitry Andric 10606c3fb27SDimitry Andric static TableGen::Emitter::Opt X("gen-opt-rst", EmitOptRST, 10706c3fb27SDimitry Andric "Generate option RST"); 108