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