1249259Sdim//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
2249259Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6249259Sdim//
7249259Sdim//===----------------------------------------------------------------------===//
8249259Sdim
9360784Sdim#include "OptEmitter.h"
10249259Sdim#include "llvm/ADT/STLExtras.h"
11249259Sdim#include "llvm/ADT/SmallString.h"
12249259Sdim#include "llvm/ADT/Twine.h"
13249259Sdim#include "llvm/TableGen/Record.h"
14249259Sdim#include "llvm/TableGen/TableGenBackend.h"
15276479Sdim#include <cctype>
16261991Sdim#include <cstring>
17249259Sdim#include <map>
18249259Sdim
19249259Sdimusing namespace llvm;
20249259Sdim
21249259Sdimstatic const std::string getOptionName(const Record &R) {
22249259Sdim  // Use the record name unless EnumName is defined.
23249259Sdim  if (isa<UnsetInit>(R.getValueInit("EnumName")))
24249259Sdim    return R.getName();
25249259Sdim
26249259Sdim  return R.getValueAsString("EnumName");
27249259Sdim}
28249259Sdim
29249259Sdimstatic raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
30249259Sdim  OS << '"';
31249259Sdim  OS.write_escaped(Str);
32249259Sdim  OS << '"';
33249259Sdim  return OS;
34249259Sdim}
35249259Sdim
36249259Sdim/// OptParserEmitter - This tablegen backend takes an input .td file
37249259Sdim/// describing a list of options and emits a data structure for parsing and
38249259Sdim/// working with those options when given an input command line.
39249259Sdimnamespace llvm {
40249259Sdimvoid EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
41249259Sdim  // Get the option groups and options.
42249259Sdim  const std::vector<Record*> &Groups =
43249259Sdim    Records.getAllDerivedDefinitions("OptionGroup");
44249259Sdim  std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
45249259Sdim
46249259Sdim  emitSourceFileHeader("Option Parsing Definitions", OS);
47249259Sdim
48249259Sdim  array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
49249259Sdim  // Generate prefix groups.
50249259Sdim  typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
51249259Sdim  typedef std::map<PrefixKeyT, std::string> PrefixesT;
52249259Sdim  PrefixesT Prefixes;
53249259Sdim  Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
54249259Sdim  unsigned CurPrefix = 0;
55249259Sdim  for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
56249259Sdim    const Record &R = *Opts[i];
57321369Sdim    std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes");
58249259Sdim    PrefixKeyT prfkey(prf.begin(), prf.end());
59249259Sdim    unsigned NewPrefix = CurPrefix + 1;
60249259Sdim    if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") +
61249259Sdim                                              Twine(NewPrefix)).str())).second)
62249259Sdim      CurPrefix = NewPrefix;
63249259Sdim  }
64249259Sdim
65249259Sdim  // Dump prefixes.
66249259Sdim
67249259Sdim  OS << "/////////\n";
68249259Sdim  OS << "// Prefixes\n\n";
69249259Sdim  OS << "#ifdef PREFIX\n";
70249259Sdim  OS << "#define COMMA ,\n";
71249259Sdim  for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end();
72249259Sdim                                  I != E; ++I) {
73249259Sdim    OS << "PREFIX(";
74249259Sdim
75249259Sdim    // Prefix name.
76249259Sdim    OS << I->second;
77249259Sdim
78249259Sdim    // Prefix values.
79249259Sdim    OS << ", {";
80249259Sdim    for (PrefixKeyT::const_iterator PI = I->first.begin(),
81249259Sdim                                    PE = I->first.end(); PI != PE; ++PI) {
82249259Sdim      OS << "\"" << *PI << "\" COMMA ";
83249259Sdim    }
84296417Sdim    OS << "nullptr})\n";
85249259Sdim  }
86249259Sdim  OS << "#undef COMMA\n";
87296417Sdim  OS << "#endif // PREFIX\n\n";
88249259Sdim
89249259Sdim  OS << "/////////\n";
90249259Sdim  OS << "// Groups\n\n";
91249259Sdim  OS << "#ifdef OPTION\n";
92249259Sdim  for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
93249259Sdim    const Record &R = *Groups[i];
94249259Sdim
95249259Sdim    // Start a single option entry.
96249259Sdim    OS << "OPTION(";
97249259Sdim
98249259Sdim    // The option prefix;
99296417Sdim    OS << "nullptr";
100249259Sdim
101249259Sdim    // The option string.
102249259Sdim    OS << ", \"" << R.getValueAsString("Name") << '"';
103249259Sdim
104249259Sdim    // The option identifier name.
105249259Sdim    OS  << ", "<< getOptionName(R);
106249259Sdim
107249259Sdim    // The option kind.
108249259Sdim    OS << ", Group";
109249259Sdim
110249259Sdim    // The containing option group (if any).
111249259Sdim    OS << ", ";
112249259Sdim    if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
113249259Sdim      OS << getOptionName(*DI->getDef());
114249259Sdim    else
115249259Sdim      OS << "INVALID";
116249259Sdim
117249259Sdim    // The other option arguments (unused for groups).
118296417Sdim    OS << ", INVALID, nullptr, 0, 0";
119249259Sdim
120249259Sdim    // The option help text.
121249259Sdim    if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
122249259Sdim      OS << ",\n";
123249259Sdim      OS << "       ";
124249259Sdim      write_cstring(OS, R.getValueAsString("HelpText"));
125249259Sdim    } else
126296417Sdim      OS << ", nullptr";
127249259Sdim
128249259Sdim    // The option meta-variable name (unused).
129321369Sdim    OS << ", nullptr";
130321369Sdim
131321369Sdim    // The option Values (unused for groups).
132296417Sdim    OS << ", nullptr)\n";
133249259Sdim  }
134249259Sdim  OS << "\n";
135249259Sdim
136249259Sdim  OS << "//////////\n";
137249259Sdim  OS << "// Options\n\n";
138249259Sdim  for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
139249259Sdim    const Record &R = *Opts[i];
140249259Sdim
141249259Sdim    // Start a single option entry.
142249259Sdim    OS << "OPTION(";
143249259Sdim
144249259Sdim    // The option prefix;
145321369Sdim    std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes");
146249259Sdim    OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", ";
147249259Sdim
148249259Sdim    // The option string.
149249259Sdim    write_cstring(OS, R.getValueAsString("Name"));
150249259Sdim
151249259Sdim    // The option identifier name.
152249259Sdim    OS  << ", "<< getOptionName(R);
153249259Sdim
154249259Sdim    // The option kind.
155249259Sdim    OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
156249259Sdim
157249259Sdim    // The containing option group (if any).
158249259Sdim    OS << ", ";
159276479Sdim    const ListInit *GroupFlags = nullptr;
160276479Sdim    if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
161276479Sdim      GroupFlags = DI->getDef()->getValueAsListInit("Flags");
162249259Sdim      OS << getOptionName(*DI->getDef());
163276479Sdim    } else
164249259Sdim      OS << "INVALID";
165249259Sdim
166249259Sdim    // The option alias (if any).
167249259Sdim    OS << ", ";
168249259Sdim    if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
169249259Sdim      OS << getOptionName(*DI->getDef());
170249259Sdim    else
171249259Sdim      OS << "INVALID";
172249259Sdim
173261991Sdim    // The option alias arguments (if any).
174261991Sdim    // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]
175261991Sdim    // would become "foo\0bar\0". Note that the compiler adds an implicit
176261991Sdim    // terminating \0 at the end.
177261991Sdim    OS << ", ";
178321369Sdim    std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs");
179261991Sdim    if (AliasArgs.size() == 0) {
180296417Sdim      OS << "nullptr";
181261991Sdim    } else {
182261991Sdim      OS << "\"";
183261991Sdim      for (size_t i = 0, e = AliasArgs.size(); i != e; ++i)
184261991Sdim        OS << AliasArgs[i] << "\\0";
185261991Sdim      OS << "\"";
186261991Sdim    }
187261991Sdim
188249259Sdim    // The option flags.
189276479Sdim    OS << ", ";
190276479Sdim    int NumFlags = 0;
191249259Sdim    const ListInit *LI = R.getValueAsListInit("Flags");
192276479Sdim    for (Init *I : *LI)
193276479Sdim      OS << (NumFlags++ ? " | " : "")
194276479Sdim         << cast<DefInit>(I)->getDef()->getName();
195276479Sdim    if (GroupFlags) {
196276479Sdim      for (Init *I : *GroupFlags)
197276479Sdim        OS << (NumFlags++ ? " | " : "")
198276479Sdim           << cast<DefInit>(I)->getDef()->getName();
199249259Sdim    }
200276479Sdim    if (NumFlags == 0)
201276479Sdim      OS << '0';
202249259Sdim
203249259Sdim    // The option parameter field.
204249259Sdim    OS << ", " << R.getValueAsInt("NumArgs");
205249259Sdim
206249259Sdim    // The option help text.
207249259Sdim    if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
208249259Sdim      OS << ",\n";
209249259Sdim      OS << "       ";
210249259Sdim      write_cstring(OS, R.getValueAsString("HelpText"));
211249259Sdim    } else
212296417Sdim      OS << ", nullptr";
213249259Sdim
214249259Sdim    // The option meta-variable name.
215249259Sdim    OS << ", ";
216249259Sdim    if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
217249259Sdim      write_cstring(OS, R.getValueAsString("MetaVarName"));
218249259Sdim    else
219296417Sdim      OS << "nullptr";
220249259Sdim
221321369Sdim    // The option Values. Used for shell autocompletion.
222321369Sdim    OS << ", ";
223321369Sdim    if (!isa<UnsetInit>(R.getValueInit("Values")))
224321369Sdim      write_cstring(OS, R.getValueAsString("Values"));
225321369Sdim    else
226321369Sdim      OS << "nullptr";
227321369Sdim
228249259Sdim    OS << ")\n";
229249259Sdim  }
230296417Sdim  OS << "#endif // OPTION\n";
231327952Sdim
232327952Sdim  OS << "\n";
233327952Sdim  OS << "#ifdef OPTTABLE_ARG_INIT\n";
234327952Sdim  OS << "//////////\n";
235327952Sdim  OS << "// Option Values\n\n";
236327952Sdim  for (unsigned I = 0, E = Opts.size(); I != E; ++I) {
237327952Sdim    const Record &R = *Opts[I];
238327952Sdim    if (isa<UnsetInit>(R.getValueInit("ValuesCode")))
239327952Sdim      continue;
240327952Sdim    OS << "{\n";
241327952Sdim    OS << "bool ValuesWereAdded;\n";
242327952Sdim    OS << R.getValueAsString("ValuesCode");
243327952Sdim    OS << "\n";
244360784Sdim    for (std::string S : R.getValueAsListOfStrings("Prefixes")) {
245327952Sdim      OS << "ValuesWereAdded = Opt.addValues(";
246360784Sdim      S += R.getValueAsString("Name");
247327952Sdim      write_cstring(OS, S);
248327952Sdim      OS << ", Values);\n";
249327952Sdim      OS << "(void)ValuesWereAdded;\n";
250327952Sdim      OS << "assert(ValuesWereAdded && \"Couldn't add values to "
251327952Sdim            "OptTable!\");\n";
252327952Sdim    }
253327952Sdim    OS << "}\n";
254327952Sdim  }
255327952Sdim  OS << "\n";
256327952Sdim  OS << "#endif // OPTTABLE_ARG_INIT\n";
257249259Sdim}
258249259Sdim} // end namespace llvm
259