1*700637cbSDimitry Andric //===- OptionRSTEmitter.cpp - Table Driven Command Line Option Parsing ----===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric
9*700637cbSDimitry Andric #include "Common/OptEmitter.h"
10*700637cbSDimitry Andric #include "llvm/ADT/STLExtras.h"
11*700637cbSDimitry Andric #include "llvm/ADT/StringMap.h"
12*700637cbSDimitry Andric #include "llvm/TableGen/Record.h"
13*700637cbSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
14*700637cbSDimitry Andric
15*700637cbSDimitry Andric using namespace llvm;
16*700637cbSDimitry Andric
17*700637cbSDimitry Andric /// This tablegen backend takes an input .td file describing a list of options
18*700637cbSDimitry Andric /// and emits a RST man page.
emitOptionRst(const RecordKeeper & Records,raw_ostream & OS)19*700637cbSDimitry Andric static void emitOptionRst(const RecordKeeper &Records, raw_ostream &OS) {
20*700637cbSDimitry Andric llvm::StringMap<std::vector<const Record *>> OptionsByGroup;
21*700637cbSDimitry Andric
22*700637cbSDimitry Andric // Get the options.
23*700637cbSDimitry Andric std::vector<const Record *> Opts = Records.getAllDerivedDefinitions("Option");
24*700637cbSDimitry Andric llvm::sort(Opts, IsOptionRecordsLess);
25*700637cbSDimitry Andric
26*700637cbSDimitry Andric // Get the option groups.
27*700637cbSDimitry Andric for (const Record *R : Records.getAllDerivedDefinitions("OptionGroup"))
28*700637cbSDimitry Andric OptionsByGroup.try_emplace(R->getValueAsString("Name"));
29*700637cbSDimitry Andric
30*700637cbSDimitry Andric // Map options to their group.
31*700637cbSDimitry Andric for (const Record *R : Opts) {
32*700637cbSDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")))
33*700637cbSDimitry Andric OptionsByGroup[DI->getDef()->getValueAsString("Name")].push_back(R);
34*700637cbSDimitry Andric else
35*700637cbSDimitry Andric OptionsByGroup["options"].push_back(R);
36*700637cbSDimitry Andric }
37*700637cbSDimitry Andric
38*700637cbSDimitry Andric // Print options under their group.
39*700637cbSDimitry Andric for (const auto &KV : OptionsByGroup) {
40*700637cbSDimitry Andric std::string GroupName = KV.getKey().upper();
41*700637cbSDimitry Andric OS << GroupName << '\n';
42*700637cbSDimitry Andric OS << std::string(GroupName.size(), '-') << '\n';
43*700637cbSDimitry Andric OS << '\n';
44*700637cbSDimitry Andric
45*700637cbSDimitry Andric for (const Record *R : KV.getValue()) {
46*700637cbSDimitry Andric OS << ".. option:: ";
47*700637cbSDimitry Andric
48*700637cbSDimitry Andric // Print the prefix.
49*700637cbSDimitry Andric std::vector<StringRef> Prefixes = R->getValueAsListOfStrings("Prefixes");
50*700637cbSDimitry Andric if (!Prefixes.empty())
51*700637cbSDimitry Andric OS << Prefixes[0];
52*700637cbSDimitry Andric
53*700637cbSDimitry Andric // Print the option name.
54*700637cbSDimitry Andric OS << R->getValueAsString("Name");
55*700637cbSDimitry Andric
56*700637cbSDimitry Andric StringRef MetaVarName;
57*700637cbSDimitry Andric // Print the meta-variable.
58*700637cbSDimitry Andric if (!isa<UnsetInit>(R->getValueInit("MetaVarName"))) {
59*700637cbSDimitry Andric MetaVarName = R->getValueAsString("MetaVarName");
60*700637cbSDimitry Andric } else if (!isa<UnsetInit>(R->getValueInit("Values")))
61*700637cbSDimitry Andric MetaVarName = "<value>";
62*700637cbSDimitry Andric
63*700637cbSDimitry Andric if (!MetaVarName.empty()) {
64*700637cbSDimitry Andric OS << '=';
65*700637cbSDimitry Andric OS.write_escaped(MetaVarName);
66*700637cbSDimitry Andric }
67*700637cbSDimitry Andric
68*700637cbSDimitry Andric OS << "\n\n";
69*700637cbSDimitry Andric
70*700637cbSDimitry Andric std::string HelpText;
71*700637cbSDimitry Andric // The option help text.
72*700637cbSDimitry Andric if (!isa<UnsetInit>(R->getValueInit("HelpText"))) {
73*700637cbSDimitry Andric HelpText = R->getValueAsString("HelpText").trim().str();
74*700637cbSDimitry Andric if (!HelpText.empty() && HelpText.back() != '.')
75*700637cbSDimitry Andric HelpText.push_back('.');
76*700637cbSDimitry Andric }
77*700637cbSDimitry Andric
78*700637cbSDimitry Andric if (!isa<UnsetInit>(R->getValueInit("Values"))) {
79*700637cbSDimitry Andric SmallVector<StringRef> Values;
80*700637cbSDimitry Andric SplitString(R->getValueAsString("Values"), Values, ",");
81*700637cbSDimitry Andric HelpText += (" " + MetaVarName + " must be '").str();
82*700637cbSDimitry Andric
83*700637cbSDimitry Andric if (Values.size() > 1) {
84*700637cbSDimitry Andric HelpText += join(Values.begin(), Values.end() - 1, "', '");
85*700637cbSDimitry Andric HelpText += "' or '";
86*700637cbSDimitry Andric }
87*700637cbSDimitry Andric HelpText += (Values.back() + "'.").str();
88*700637cbSDimitry Andric }
89*700637cbSDimitry Andric
90*700637cbSDimitry Andric if (!HelpText.empty()) {
91*700637cbSDimitry Andric OS << ' ';
92*700637cbSDimitry Andric OS.write_escaped(HelpText);
93*700637cbSDimitry Andric OS << "\n\n";
94*700637cbSDimitry Andric }
95*700637cbSDimitry Andric }
96*700637cbSDimitry Andric }
97*700637cbSDimitry Andric }
98*700637cbSDimitry Andric
99*700637cbSDimitry Andric static TableGen::Emitter::Opt X("gen-opt-rst", emitOptionRst,
100*700637cbSDimitry Andric "Generate option RST");
101