164ada7acSJonas Devlieghere //===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
264ada7acSJonas Devlieghere //
364ada7acSJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ada7acSJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information.
564ada7acSJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ada7acSJonas Devlieghere //
764ada7acSJonas Devlieghere //===----------------------------------------------------------------------===//
864ada7acSJonas Devlieghere 
964ada7acSJonas Devlieghere #include "OptEmitter.h"
1064ada7acSJonas Devlieghere #include "llvm/ADT/STLExtras.h"
11af450eabSReid Kleckner #include "llvm/ADT/StringMap.h"
1264ada7acSJonas Devlieghere #include "llvm/TableGen/Record.h"
1364ada7acSJonas Devlieghere 
1464ada7acSJonas Devlieghere using namespace llvm;
1564ada7acSJonas Devlieghere 
1664ada7acSJonas Devlieghere /// OptParserEmitter - This tablegen backend takes an input .td file
1764ada7acSJonas Devlieghere /// describing a list of options and emits a RST man page.
1864ada7acSJonas Devlieghere namespace llvm {
EmitOptRST(RecordKeeper & Records,raw_ostream & OS)1964ada7acSJonas Devlieghere void EmitOptRST(RecordKeeper &Records, raw_ostream &OS) {
2064ada7acSJonas Devlieghere   llvm::StringMap<std::vector<Record *>> OptionsByGroup;
2164ada7acSJonas Devlieghere   std::vector<Record *> OptionsWithoutGroup;
2264ada7acSJonas Devlieghere 
2364ada7acSJonas Devlieghere   // Get the options.
2464ada7acSJonas Devlieghere   std::vector<Record *> Opts = Records.getAllDerivedDefinitions("Option");
2564ada7acSJonas Devlieghere   array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
2664ada7acSJonas Devlieghere 
2764ada7acSJonas Devlieghere   // Get the option groups.
2864ada7acSJonas Devlieghere   const std::vector<Record *> &Groups =
2964ada7acSJonas Devlieghere       Records.getAllDerivedDefinitions("OptionGroup");
3064ada7acSJonas Devlieghere   for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
3164ada7acSJonas Devlieghere     const Record &R = *Groups[i];
3264ada7acSJonas Devlieghere     OptionsByGroup.try_emplace(R.getValueAsString("Name"));
3364ada7acSJonas Devlieghere   }
3464ada7acSJonas Devlieghere 
3564ada7acSJonas Devlieghere   // Map options to their group.
3664ada7acSJonas Devlieghere   for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
3764ada7acSJonas Devlieghere     const Record &R = *Opts[i];
3864ada7acSJonas Devlieghere     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
3964ada7acSJonas Devlieghere       OptionsByGroup[DI->getDef()->getValueAsString("Name")].push_back(Opts[i]);
4064ada7acSJonas Devlieghere     } else {
4164ada7acSJonas Devlieghere       OptionsByGroup["options"].push_back(Opts[i]);
4264ada7acSJonas Devlieghere     }
4364ada7acSJonas Devlieghere   }
4464ada7acSJonas Devlieghere 
4564ada7acSJonas Devlieghere   // Print options under their group.
4664ada7acSJonas Devlieghere   for (const auto &KV : OptionsByGroup) {
4764ada7acSJonas Devlieghere     std::string GroupName = KV.getKey().upper();
4864ada7acSJonas Devlieghere     OS << GroupName << '\n';
4964ada7acSJonas Devlieghere     OS << std::string(GroupName.size(), '-') << '\n';
5064ada7acSJonas Devlieghere     OS << '\n';
5164ada7acSJonas Devlieghere 
5264ada7acSJonas Devlieghere     for (Record *R : KV.getValue()) {
5364ada7acSJonas Devlieghere       OS << ".. option:: ";
5464ada7acSJonas Devlieghere 
5564ada7acSJonas Devlieghere       // Print the prefix.
5664ada7acSJonas Devlieghere       std::vector<StringRef> Prefixes = R->getValueAsListOfStrings("Prefixes");
5764ada7acSJonas Devlieghere       if (!Prefixes.empty())
5864ada7acSJonas Devlieghere         OS << Prefixes[0];
5964ada7acSJonas Devlieghere 
6064ada7acSJonas Devlieghere       // Print the option name.
6164ada7acSJonas Devlieghere       OS << R->getValueAsString("Name");
6264ada7acSJonas Devlieghere 
63f5c66674Sserge-sans-paille       StringRef MetaVarName;
6464ada7acSJonas Devlieghere       // Print the meta-variable.
6564ada7acSJonas Devlieghere       if (!isa<UnsetInit>(R->getValueInit("MetaVarName"))) {
66f5c66674Sserge-sans-paille         MetaVarName = R->getValueAsString("MetaVarName");
67f5c66674Sserge-sans-paille       } else if (!isa<UnsetInit>(R->getValueInit("Values")))
68f5c66674Sserge-sans-paille         MetaVarName = "<value>";
69f5c66674Sserge-sans-paille 
70f5c66674Sserge-sans-paille       if (!MetaVarName.empty()) {
7164ada7acSJonas Devlieghere         OS << '=';
72f5c66674Sserge-sans-paille         OS.write_escaped(MetaVarName);
7364ada7acSJonas Devlieghere       }
7464ada7acSJonas Devlieghere 
7564ada7acSJonas Devlieghere       OS << "\n\n";
7664ada7acSJonas Devlieghere 
77f5c66674Sserge-sans-paille       std::string HelpText;
7864ada7acSJonas Devlieghere       // The option help text.
7964ada7acSJonas Devlieghere       if (!isa<UnsetInit>(R->getValueInit("HelpText"))) {
80f5c66674Sserge-sans-paille         HelpText = R->getValueAsString("HelpText").trim().str();
81f5c66674Sserge-sans-paille         if (!HelpText.empty() && HelpText.back() != '.')
82f5c66674Sserge-sans-paille           HelpText.push_back('.');
83f5c66674Sserge-sans-paille       }
84f5c66674Sserge-sans-paille 
85f5c66674Sserge-sans-paille       if (!isa<UnsetInit>(R->getValueInit("Values"))) {
86f5c66674Sserge-sans-paille         SmallVector<StringRef> Values;
87f5c66674Sserge-sans-paille         SplitString(R->getValueAsString("Values"), Values, ",");
88*af7b98c3Sserge-sans-paille         HelpText += (" " + MetaVarName + " must be '").str();
89f5c66674Sserge-sans-paille 
90*af7b98c3Sserge-sans-paille         if (Values.size() > 1) {
91f5c66674Sserge-sans-paille           HelpText += join(Values.begin(), Values.end() - 1, "', '");
92*af7b98c3Sserge-sans-paille           HelpText += "' or '";
93f5c66674Sserge-sans-paille         }
94*af7b98c3Sserge-sans-paille         HelpText += (Values.front() + "'.").str();
95f5c66674Sserge-sans-paille       }
96f5c66674Sserge-sans-paille 
97f5c66674Sserge-sans-paille       if (!HelpText.empty()) {
9864ada7acSJonas Devlieghere         OS << ' ';
99f5c66674Sserge-sans-paille         OS.write_escaped(HelpText);
10064ada7acSJonas Devlieghere         OS << "\n\n";
10164ada7acSJonas Devlieghere       }
10264ada7acSJonas Devlieghere     }
10364ada7acSJonas Devlieghere   }
10464ada7acSJonas Devlieghere }
10564ada7acSJonas Devlieghere } // end namespace llvm
106