command_line.cpp 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "common/command_line.h"
  5. #include <memory>
  6. #include "common/raw_string_ostream.h"
  7. #include "llvm/ADT/DenseMap.h"
  8. #include "llvm/ADT/PointerIntPair.h"
  9. #include "llvm/Support/FormatVariadic.h"
  10. // Recursion is used for subcommands. This should be okay since recursion is
  11. // limited by command line architecture.
  12. // NOLINTBEGIN(misc-no-recursion)
  13. namespace Carbon::CommandLine {
  14. auto operator<<(llvm::raw_ostream& output, ParseResult result)
  15. -> llvm::raw_ostream& {
  16. switch (result) {
  17. case ParseResult::MetaSuccess:
  18. return output << "MetaSuccess";
  19. case ParseResult::Success:
  20. return output << "Success";
  21. }
  22. CARBON_FATAL("Corrupt parse result!");
  23. }
  24. auto operator<<(llvm::raw_ostream& output, ArgKind kind) -> llvm::raw_ostream& {
  25. switch (kind) {
  26. case ArgKind::Flag:
  27. return output << "Boolean";
  28. case ArgKind::Integer:
  29. return output << "Integer";
  30. case ArgKind::String:
  31. return output << "String";
  32. case ArgKind::OneOf:
  33. return output << "OneOf";
  34. case ArgKind::MetaActionOnly:
  35. return output << "MetaActionOnly";
  36. case ArgKind::Invalid:
  37. return output << "Invalid";
  38. }
  39. CARBON_FATAL("Corrupt argument kind!");
  40. }
  41. auto operator<<(llvm::raw_ostream& output, CommandKind kind)
  42. -> llvm::raw_ostream& {
  43. switch (kind) {
  44. case CommandKind::Invalid:
  45. return output << "Invalid";
  46. case CommandKind::RequiresSubcommand:
  47. return output << "RequiresSubcommand";
  48. case CommandKind::Action:
  49. return output << "Action";
  50. case CommandKind::MetaAction:
  51. return output << "MetaAction";
  52. }
  53. CARBON_FATAL("Corrupt command kind!");
  54. }
  55. template <typename T, typename ToPrintable>
  56. static auto PrintListOfAlternatives(llvm::raw_ostream& output,
  57. llvm::ArrayRef<T> alternatives,
  58. ToPrintable to_printable) -> void {
  59. for (const auto& alternative : alternatives.drop_back()) {
  60. output << "`" << to_printable(alternative)
  61. << (alternatives.size() > 2 ? "`, " : "` ");
  62. }
  63. if (alternatives.size() > 1) {
  64. output << "or ";
  65. }
  66. output << "`" << to_printable(alternatives.back()) << "`";
  67. }
  68. Arg::Arg(ArgInfo info) : info(info) {}
  69. Arg::~Arg() {
  70. switch (kind) {
  71. case Kind::Flag:
  72. case Kind::Integer:
  73. case Kind::String:
  74. case Kind::MetaActionOnly:
  75. case Kind::Invalid:
  76. // Nothing to do!
  77. break;
  78. case Kind::OneOf:
  79. value_strings.~decltype(value_strings)();
  80. value_action.~ValueActionT();
  81. if (has_default) {
  82. default_action.~DefaultActionT();
  83. }
  84. break;
  85. }
  86. }
  87. Command::Command(CommandInfo info, Command* parent)
  88. : info(info), parent(parent) {}
  89. class MetaPrinter {
  90. public:
  91. // `out` must not be null.
  92. explicit MetaPrinter(llvm::raw_ostream* out) : out_(out) {}
  93. // Registers this meta printer with a command through the provided builder.
  94. //
  95. // This adds meta subcommands or options to print both help and version
  96. // information for the command.
  97. void RegisterWithCommand(const Command& command, CommandBuilder& builder);
  98. void PrintHelp(const Command& command) const;
  99. void PrintHelpForSubcommandName(const Command& command,
  100. llvm::StringRef subcommand_name) const;
  101. void PrintVersion(const Command& command) const;
  102. void PrintSubcommands(const Command& command) const;
  103. private:
  104. // The indent is calibrated to allow a short and long option after a two
  105. // character indent on the prior line to be visually recognized as separate
  106. // from the hanging indent.
  107. //
  108. // Visual guide: | -x, --extract
  109. // | Hanging indented.
  110. static constexpr llvm::StringRef BlockIndent = " ";
  111. // Width limit for parent command options in usage rendering.
  112. static constexpr int MaxParentOptionUsageWidth = 8;
  113. // Width limit for the leaf command options in usage rendering.
  114. static constexpr int MaxLeafOptionUsageWidth = 16;
  115. static constexpr CommandInfo HelpCommandInfo = {
  116. .name = "help",
  117. .help = R"""(
  118. Prints help information for the command, including a description, command line
  119. usage, and details of each subcommand and option that can be provided.
  120. )""",
  121. .help_short = R"""(
  122. Prints help information.
  123. )""",
  124. };
  125. static constexpr ArgInfo HelpArgInfo = {
  126. .name = "help",
  127. .value_name = "(full|short)",
  128. .help = R"""(
  129. Prints help information for the command, including a description, command line
  130. usage, and details of each option that can be provided.
  131. )""",
  132. .help_short = HelpCommandInfo.help_short,
  133. };
  134. // Provide a customized description for help on a subcommand to avoid
  135. // confusion with the top-level help.
  136. static constexpr CommandInfo SubHelpCommandInfo = {
  137. .name = "help",
  138. .help = R"""(
  139. Prints help information for the subcommand, including a description, command
  140. line usage, and details of each further subcommand and option that can be
  141. provided.
  142. )""",
  143. .help_short = R"""(
  144. Prints subcommand help information.
  145. )""",
  146. };
  147. static constexpr ArgInfo SubHelpArgInfo = {
  148. .name = "help",
  149. .value_name = "(full|short)",
  150. .help = R"""(
  151. Prints help information for the subcommand, including a description, command
  152. line usage, and details of each option that can be provided.
  153. )""",
  154. .help_short = SubHelpCommandInfo.help_short,
  155. };
  156. static constexpr ArgInfo HelpSubcommandArgInfo = {
  157. .name = "subcommand",
  158. .help = R"""(
  159. Which subcommand to print help information for.
  160. )""",
  161. };
  162. static constexpr CommandInfo VersionCommandInfo = {
  163. .name = "version",
  164. .help = R"""(
  165. Prints the version of this command.
  166. )""",
  167. };
  168. static constexpr ArgInfo VersionArgInfo = {
  169. .name = "version",
  170. .help = VersionCommandInfo.help,
  171. };
  172. // A general helper for rendering a text block.
  173. void PrintTextBlock(llvm::StringRef indent, llvm::StringRef text) const;
  174. // Helpers for version and build information printing.
  175. void PrintRawVersion(const Command& command, llvm::StringRef indent) const;
  176. void PrintRawBuildInfo(const Command& command, llvm::StringRef indent) const;
  177. // Helpers for printing components of help and usage output for arguments,
  178. // including options and positional arguments.
  179. void PrintArgValueUsage(const Arg& arg) const;
  180. void PrintOptionUsage(const Arg& option) const;
  181. void PrintOptionShortName(const Arg& arg) const;
  182. void PrintArgShortValues(const Arg& arg) const;
  183. void PrintArgLongValues(const Arg& arg, llvm::StringRef indent) const;
  184. void PrintArgHelp(const Arg& arg, llvm::StringRef indent) const;
  185. // Helpers for printing command usage summaries.
  186. void PrintRawUsageCommandAndOptions(
  187. const Command& command,
  188. int max_option_width = MaxLeafOptionUsageWidth) const;
  189. void PrintRawUsage(const Command& command, llvm::StringRef indent) const;
  190. void PrintUsage(const Command& command) const;
  191. // Helpers to print various sections of `PrintHelp` that only occur within
  192. // that output.
  193. void PrintHelpSubcommands(const Command& command) const;
  194. void PrintHelpPositionalArgs(const Command& command) const;
  195. void PrintHelpOptions(const Command& command) const;
  196. llvm::raw_ostream* out_;
  197. // A flag that may be configured during command line parsing to select between
  198. // long and short form help output.
  199. bool short_help_ = false;
  200. // The requested subcommand to print help information for.
  201. llvm::StringRef help_subcommand_;
  202. };
  203. void MetaPrinter::RegisterWithCommand(const Command& command,
  204. CommandBuilder& builder) {
  205. bool is_subcommand = command.parent;
  206. bool has_subcommands = !command.subcommands.empty();
  207. // If this command has subcommands, we prefer that model for access meta
  208. // actions, but still silently support using the flags. But we never want to
  209. // *add* subcommands if they aren't already being used.
  210. if (has_subcommands) {
  211. builder.AddSubcommand(
  212. is_subcommand ? SubHelpCommandInfo : HelpCommandInfo,
  213. [&](CommandBuilder& sub_b) {
  214. sub_b.AddStringPositionalArg(HelpSubcommandArgInfo, [&](auto& arg_b) {
  215. arg_b.Set(&help_subcommand_);
  216. });
  217. sub_b.Meta([this, &command]() {
  218. if (help_subcommand_.empty()) {
  219. PrintHelp(command);
  220. } else {
  221. PrintHelpForSubcommandName(command, help_subcommand_);
  222. }
  223. });
  224. });
  225. // Only add version printing support if there is a version string
  226. // configured for this command.
  227. if (!command.info.version.empty()) {
  228. builder.AddSubcommand(VersionCommandInfo, [&](CommandBuilder& sub_b) {
  229. sub_b.Meta([this, &command]() { PrintVersion(command); });
  230. });
  231. }
  232. }
  233. builder.AddOneOfOption(
  234. is_subcommand ? SubHelpArgInfo : HelpArgInfo, [&](auto& arg_b) {
  235. arg_b.HelpHidden(has_subcommands);
  236. arg_b.SetOneOf(
  237. {
  238. arg_b.OneOfValue("full", false).Default(true),
  239. arg_b.OneOfValue("short", true),
  240. },
  241. &short_help_);
  242. arg_b.MetaAction([this, &command]() { PrintHelp(command); });
  243. });
  244. // Only add version printing support if there is a version string configured
  245. // for this command.
  246. if (!command.info.version.empty()) {
  247. builder.AddMetaActionOption(VersionArgInfo, [&](auto& arg_b) {
  248. arg_b.HelpHidden(has_subcommands);
  249. arg_b.MetaAction([this, &command]() { PrintVersion(command); });
  250. });
  251. }
  252. }
  253. void MetaPrinter::PrintHelp(const Command& command) const {
  254. // TODO: begin using the short setting to customize the output.
  255. (void)short_help_;
  256. const CommandInfo& info = command.info;
  257. if (!info.version.empty()) {
  258. // We use the version string as a header for the command help when present.
  259. PrintRawVersion(command, /*indent=*/"");
  260. *out_ << "\n";
  261. }
  262. if (!command.info.help.empty()) {
  263. PrintTextBlock("", info.help);
  264. *out_ << "\n";
  265. }
  266. if (!info.build_info.empty()) {
  267. *out_ << "Build info:\n";
  268. PrintRawBuildInfo(command, /*indent=*/" ");
  269. *out_ << "\n";
  270. }
  271. PrintUsage(command);
  272. PrintHelpSubcommands(command);
  273. PrintHelpPositionalArgs(command);
  274. PrintHelpOptions(command);
  275. if (!info.help_epilogue.empty()) {
  276. *out_ << "\n";
  277. PrintTextBlock("", info.help_epilogue);
  278. }
  279. // End with a blank line for the long help to make it easier to separate from
  280. // anything that follows in the shell.
  281. *out_ << "\n";
  282. }
  283. void MetaPrinter::PrintHelpForSubcommandName(
  284. const Command& command, llvm::StringRef subcommand_name) const {
  285. for (const auto& subcommand : command.subcommands) {
  286. if (subcommand->info.name == subcommand_name) {
  287. PrintHelp(*subcommand);
  288. return;
  289. }
  290. }
  291. // TODO: This should really be connected up so that parsing can return an
  292. // Error instead of ParseResult::MetaSuccess in this case.
  293. *out_ << "error: could not find a subcommand named '" << subcommand_name
  294. << "'\n";
  295. }
  296. void MetaPrinter::PrintVersion(const Command& command) const {
  297. CARBON_CHECK(
  298. !command.info.version.empty(),
  299. "Printing should not be enabled without a version string configured.");
  300. PrintRawVersion(command, /*indent=*/"");
  301. if (!command.info.build_info.empty()) {
  302. *out_ << "\n";
  303. // If there is build info to print, we also render that without any indent.
  304. PrintRawBuildInfo(command, /*indent=*/"");
  305. }
  306. }
  307. void MetaPrinter::PrintSubcommands(const Command& command) const {
  308. PrintListOfAlternatives(*out_, llvm::ArrayRef(command.subcommands),
  309. [](const std::unique_ptr<Command>& subcommand) {
  310. return subcommand->info.name;
  311. });
  312. }
  313. void MetaPrinter::PrintRawVersion(const Command& command,
  314. llvm::StringRef indent) const {
  315. // Newlines are trimmed from the version string an a closing newline added but
  316. // no other formatting is performed.
  317. *out_ << indent << command.info.version.trim('\n') << "\n";
  318. }
  319. void MetaPrinter::PrintRawBuildInfo(const Command& command,
  320. llvm::StringRef indent) const {
  321. // Print the build info line-by-line without any wrapping in case it
  322. // contains line-oriented formatted text, but drop leading and trailing blank
  323. // lines.
  324. llvm::SmallVector<llvm::StringRef, 128> lines;
  325. command.info.build_info.trim('\n').split(lines, "\n");
  326. for (auto line : lines) {
  327. *out_ << indent << line << "\n";
  328. }
  329. }
  330. void MetaPrinter::PrintTextBlock(llvm::StringRef indent,
  331. llvm::StringRef text) const {
  332. // Strip leading and trailing newlines to make it easy to use multiline raw
  333. // string literals that will naturally have those.
  334. text = text.trim('\n');
  335. // For empty text, print nothing at all. The caller formatting will work to
  336. // handle this gracefully.
  337. if (text.empty()) {
  338. return;
  339. }
  340. // Remove line breaks from the text that would typically be removed when
  341. // rendering it as Markdown. The goal is to preserve:
  342. //
  343. // - Blank lines as paragraph separators.
  344. // - Line breaks after list items or other structural components in Markdown.
  345. // - Fenced regions exactly as they appear.
  346. //
  347. // And within paragraphs (including those nested in lists), reflow the
  348. // paragraph intelligently to the column width. There are TODOs below about
  349. // both lists and reflowing.
  350. llvm::SmallVector<llvm::StringRef, 128> input_lines;
  351. text.split(input_lines, "\n");
  352. for (int i = 0, size = input_lines.size(); i < size;) {
  353. if (input_lines[i].empty()) {
  354. // Blank lines are preserved.
  355. *out_ << "\n";
  356. ++i;
  357. continue;
  358. }
  359. if (input_lines[i].starts_with("```")) {
  360. // Fenced regions are preserved verbatim.
  361. llvm::StringRef fence =
  362. input_lines[i].slice(0, input_lines[i].find_first_not_of("`"));
  363. do {
  364. *out_ << indent << input_lines[i] << "\n";
  365. ++i;
  366. } while (i < size && !input_lines[i].starts_with(fence));
  367. if (i >= size) {
  368. // Don't error on malformed text blocks, just print what we've got.
  369. break;
  370. }
  371. // Including the close of the fence.
  372. *out_ << indent << input_lines[i] << "\n";
  373. ++i;
  374. continue;
  375. }
  376. if (input_lines[i].starts_with(" ")) {
  377. // Indented code blocks ar preserved verbatim, but we don't support tabs
  378. // in the indent for simplicity.
  379. do {
  380. *out_ << indent << input_lines[i] << "\n";
  381. ++i;
  382. } while (i < size && input_lines[i].starts_with(" "));
  383. continue;
  384. }
  385. // TODO: Detect other Markdown structures, especially lists and tables.
  386. // Otherwise, collect all of the lines until the end or the next blank line
  387. // as a block of text.
  388. //
  389. // TODO: This is where we should re-flow.
  390. llvm::StringRef space = indent;
  391. do {
  392. *out_ << space << input_lines[i].trim();
  393. space = " ";
  394. ++i;
  395. } while (i < size && !input_lines[i].empty());
  396. *out_ << "\n";
  397. }
  398. }
  399. void MetaPrinter::PrintArgValueUsage(const Arg& arg) const {
  400. if (!arg.info.value_name.empty()) {
  401. *out_ << arg.info.value_name;
  402. return;
  403. }
  404. if (arg.kind == Arg::Kind::OneOf) {
  405. *out_ << "(";
  406. llvm::ListSeparator sep("|");
  407. for (llvm::StringRef value_string : arg.value_strings) {
  408. *out_ << sep << value_string;
  409. }
  410. *out_ << ")";
  411. return;
  412. }
  413. *out_ << "...";
  414. }
  415. void MetaPrinter::PrintOptionUsage(const Arg& option) const {
  416. if (option.kind == Arg::Kind::Flag) {
  417. *out_ << "--" << (option.default_flag ? "no-" : "") << option.info.name;
  418. return;
  419. }
  420. *out_ << "--" << option.info.name;
  421. if (option.kind != Arg::Kind::MetaActionOnly) {
  422. *out_ << (option.has_default ? "[" : "") << "=";
  423. PrintArgValueUsage(option);
  424. if (option.has_default) {
  425. *out_ << "]";
  426. }
  427. }
  428. }
  429. void MetaPrinter::PrintOptionShortName(const Arg& arg) const {
  430. CARBON_CHECK(!arg.info.short_name.empty(), "No short name to use.");
  431. *out_ << "-" << arg.info.short_name;
  432. }
  433. void MetaPrinter::PrintArgShortValues(const Arg& arg) const {
  434. CARBON_CHECK(
  435. arg.kind == Arg::Kind::OneOf,
  436. "Only one-of arguments have interesting value snippets to print.");
  437. llvm::ListSeparator sep;
  438. for (llvm::StringRef value_string : arg.value_strings) {
  439. *out_ << sep << value_string;
  440. }
  441. }
  442. void MetaPrinter::PrintArgLongValues(const Arg& arg,
  443. llvm::StringRef indent) const {
  444. *out_ << indent << "Possible values:\n";
  445. // TODO: It would be good to add help text for each value and then print it
  446. // here.
  447. for (int i : llvm::seq<int>(0, arg.value_strings.size())) {
  448. llvm::StringRef value_string = arg.value_strings[i];
  449. *out_ << indent << "- " << value_string;
  450. if (arg.has_default && i == arg.default_value_index) {
  451. *out_ << " (default)";
  452. }
  453. *out_ << "\n";
  454. }
  455. }
  456. void MetaPrinter::PrintArgHelp(const Arg& arg, llvm::StringRef indent) const {
  457. // Print out the main help text.
  458. PrintTextBlock(indent, arg.info.help);
  459. // Then print out any help based on the values.
  460. switch (arg.kind) {
  461. case Arg::Kind::Integer:
  462. if (arg.has_default) {
  463. *out_ << "\n";
  464. *out_ << indent << "Default value: " << arg.default_integer << "\n";
  465. }
  466. break;
  467. case Arg::Kind::String:
  468. if (arg.has_default) {
  469. *out_ << "\n";
  470. *out_ << indent << "Default value: " << arg.default_string << "\n";
  471. }
  472. break;
  473. case Arg::Kind::OneOf:
  474. *out_ << "\n";
  475. PrintArgLongValues(arg, indent);
  476. break;
  477. case Arg::Kind::Flag:
  478. case Arg::Kind::MetaActionOnly:
  479. // No value help.
  480. break;
  481. case Arg::Kind::Invalid:
  482. CARBON_FATAL("Argument configured without any action or kind!");
  483. }
  484. }
  485. void MetaPrinter::PrintRawUsageCommandAndOptions(const Command& command,
  486. int max_option_width) const {
  487. // Recursively print parent usage first with a compressed width.
  488. if (command.parent) {
  489. PrintRawUsageCommandAndOptions(*command.parent, MaxParentOptionUsageWidth);
  490. *out_ << " ";
  491. }
  492. *out_ << command.info.name;
  493. // Buffer the options rendering so we can limit its length.
  494. RawStringOstream buffer_out;
  495. MetaPrinter buffer_printer(&buffer_out);
  496. bool have_short_flags = false;
  497. for (const auto& arg : command.options) {
  498. if (static_cast<int>(buffer_out.size()) > max_option_width) {
  499. break;
  500. }
  501. // We can summarize positive boolean flags with a short name using a
  502. // sequence of short names in a single rendered argument.
  503. if (arg->kind == Arg::Kind::Flag && !arg->default_flag &&
  504. !arg->info.short_name.empty()) {
  505. if (!have_short_flags) {
  506. have_short_flags = true;
  507. buffer_out << "-";
  508. }
  509. buffer_out << arg->info.short_name;
  510. }
  511. }
  512. llvm::StringRef space = have_short_flags ? " " : "";
  513. for (const auto& option : command.options) {
  514. if (static_cast<int>(buffer_out.size()) > max_option_width) {
  515. break;
  516. }
  517. if (option->is_help_hidden || option->meta_action) {
  518. // Skip hidden and options with meta actions attached.
  519. continue;
  520. }
  521. if (option->kind == Arg::Kind::Flag && !option->default_flag &&
  522. !option->info.short_name.empty()) {
  523. // Handled with short names above.
  524. continue;
  525. }
  526. buffer_out << space;
  527. buffer_printer.PrintOptionUsage(*option);
  528. space = " ";
  529. }
  530. if (!buffer_out.empty()) {
  531. if (static_cast<int>(buffer_out.size()) <= max_option_width) {
  532. *out_ << " [" << buffer_out.TakeStr() << "]";
  533. } else {
  534. buffer_out.clear();
  535. *out_ << " [OPTIONS]";
  536. }
  537. }
  538. }
  539. void MetaPrinter::PrintRawUsage(const Command& command,
  540. llvm::StringRef indent) const {
  541. if (!command.info.usage.empty()) {
  542. PrintTextBlock(indent, command.info.usage);
  543. return;
  544. }
  545. if (command.kind != Command::Kind::RequiresSubcommand) {
  546. // We're a valid leaf command, so synthesize a full usage line.
  547. *out_ << indent;
  548. PrintRawUsageCommandAndOptions(command);
  549. if (!command.positional_args.empty()) {
  550. bool open_optional = false;
  551. for (int i : llvm::seq<int>(0, command.positional_args.size())) {
  552. *out_ << " ";
  553. if (i != 0 && command.positional_args[i - 1]->is_append) {
  554. *out_ << "-- ";
  555. }
  556. const auto& arg = command.positional_args[i];
  557. if (!arg->is_required && !open_optional) {
  558. *out_ << "[";
  559. open_optional = true;
  560. }
  561. *out_ << "<" << arg->info.name << ">";
  562. if (arg->is_append) {
  563. *out_ << "...";
  564. }
  565. }
  566. if (open_optional) {
  567. *out_ << "]";
  568. }
  569. }
  570. *out_ << "\n";
  571. }
  572. // If we have subcommands, also recurse into them so each one can print their
  573. // usage lines.
  574. for (const auto& subcommand : command.subcommands) {
  575. if (subcommand->is_help_hidden ||
  576. subcommand->kind == Command::Kind::MetaAction) {
  577. continue;
  578. }
  579. PrintRawUsage(*subcommand, indent);
  580. }
  581. }
  582. void MetaPrinter::PrintUsage(const Command& command) const {
  583. if (!command.parent) {
  584. *out_ << "Usage:\n";
  585. } else {
  586. *out_ << "Subcommand `" << command.info.name << "` usage:\n";
  587. }
  588. PrintRawUsage(command, " ");
  589. }
  590. void MetaPrinter::PrintHelpSubcommands(const Command& command) const {
  591. bool first_subcommand = true;
  592. for (const auto& subcommand : command.subcommands) {
  593. if (subcommand->is_help_hidden) {
  594. continue;
  595. }
  596. if (first_subcommand) {
  597. first_subcommand = false;
  598. if (!command.parent) {
  599. *out_ << "\nSubcommands:";
  600. } else {
  601. *out_ << "\nSubcommand `" << command.info.name << "` subcommands:";
  602. }
  603. }
  604. *out_ << "\n";
  605. *out_ << " " << subcommand->info.name << "\n";
  606. PrintTextBlock(BlockIndent, subcommand->info.help);
  607. }
  608. }
  609. void MetaPrinter::PrintHelpPositionalArgs(const Command& command) const {
  610. bool first_positional_arg = true;
  611. for (const auto& positional_arg : command.positional_args) {
  612. if (positional_arg->is_help_hidden) {
  613. continue;
  614. }
  615. if (first_positional_arg) {
  616. first_positional_arg = false;
  617. if (!command.parent) {
  618. *out_ << "\nPositional arguments:";
  619. } else {
  620. *out_ << "\nSubcommand `" << command.info.name
  621. << "` positional arguments:";
  622. }
  623. }
  624. *out_ << "\n";
  625. *out_ << " " << positional_arg->info.name << "\n";
  626. PrintArgHelp(*positional_arg, BlockIndent);
  627. }
  628. }
  629. void MetaPrinter::PrintHelpOptions(const Command& command) const {
  630. bool first_option = true;
  631. for (const auto& option : command.options) {
  632. if (option->is_help_hidden) {
  633. continue;
  634. }
  635. if (first_option) {
  636. first_option = false;
  637. if (!command.parent && command.subcommands.empty()) {
  638. // Only one command level.
  639. *out_ << "\nOptions:";
  640. } else if (!command.parent) {
  641. *out_ << "\nCommand options:";
  642. } else {
  643. *out_ << "\nSubcommand `" << command.info.name << "` options:";
  644. }
  645. }
  646. *out_ << "\n";
  647. *out_ << " ";
  648. if (!option->info.short_name.empty()) {
  649. PrintOptionShortName(*option);
  650. *out_ << ", ";
  651. } else {
  652. *out_ << " ";
  653. }
  654. PrintOptionUsage(*option);
  655. *out_ << "\n";
  656. PrintArgHelp(*option, BlockIndent);
  657. }
  658. }
  659. class Parser {
  660. public:
  661. // `out` must not be null.
  662. explicit Parser(llvm::raw_ostream* out, CommandInfo command_info,
  663. llvm::function_ref<void(CommandBuilder&)> build);
  664. auto Parse(llvm::ArrayRef<llvm::StringRef> unparsed_args)
  665. -> ErrorOr<ParseResult>;
  666. private:
  667. friend CommandBuilder;
  668. // For the option and subcommand maps, we use somewhat large small size
  669. // buffers (16) as there is no real size pressure on these and its nice to
  670. // avoid heap allocation in the small cases.
  671. using OptionMapT =
  672. llvm::SmallDenseMap<llvm::StringRef, llvm::PointerIntPair<Arg*, 1, bool>,
  673. 16>;
  674. using SubcommandMapT = llvm::SmallDenseMap<llvm::StringRef, Command*, 16>;
  675. // This table is sized to be 128 so that it can hold ASCII characters. We
  676. // don't need any more than this and using a direct table indexed by the
  677. // character's numeric value makes for a convenient map.
  678. using ShortOptionTableT = std::array<OptionMapT::mapped_type*, 128>;
  679. void PopulateMaps(const Command& command);
  680. void SetOptionDefault(const Arg& option);
  681. auto ParseNegatedFlag(const Arg& flag, std::optional<llvm::StringRef> value)
  682. -> ErrorOr<Success>;
  683. auto ParseFlag(const Arg& flag, std::optional<llvm::StringRef> value)
  684. -> ErrorOr<Success>;
  685. auto ParseIntegerArgValue(const Arg& arg, llvm::StringRef value)
  686. -> ErrorOr<Success>;
  687. auto ParseStringArgValue(const Arg& arg, llvm::StringRef value)
  688. -> ErrorOr<Success>;
  689. auto ParseOneOfArgValue(const Arg& arg, llvm::StringRef value)
  690. -> ErrorOr<Success>;
  691. auto ParseArg(const Arg& arg, bool short_spelling,
  692. std::optional<llvm::StringRef> value, bool negated_name = false)
  693. -> ErrorOr<Success>;
  694. auto SplitValue(llvm::StringRef& unparsed_arg)
  695. -> std::optional<llvm::StringRef>;
  696. auto ParseLongOption(llvm::StringRef unparsed_arg) -> ErrorOr<Success>;
  697. auto ParseShortOptionSeq(llvm::StringRef unparsed_arg) -> ErrorOr<Success>;
  698. auto FinalizeParsedOptions() -> ErrorOr<Success>;
  699. auto ParsePositionalArg(llvm::StringRef unparsed_arg) -> ErrorOr<Success>;
  700. auto ParseSubcommand(llvm::StringRef unparsed_arg) -> ErrorOr<Success>;
  701. auto ParsePositionalSuffix(llvm::ArrayRef<llvm::StringRef> unparsed_args)
  702. -> ErrorOr<Success>;
  703. auto FinalizeParse() -> ErrorOr<ParseResult>;
  704. // When building a command, it registers arguments and potentially subcommands
  705. // that are meta actions to print things to standard out, so we build a meta
  706. // printer for that here.
  707. MetaPrinter meta_printer_;
  708. Command root_command_;
  709. const Command* command_;
  710. OptionMapT option_map_;
  711. ShortOptionTableT short_option_table_;
  712. SubcommandMapT subcommand_map_;
  713. int positional_arg_index_ = 0;
  714. bool appending_to_positional_arg_ = false;
  715. ActionT arg_meta_action_;
  716. };
  717. void Parser::PopulateMaps(const Command& command) {
  718. option_map_.clear();
  719. for (const auto& option : command.options) {
  720. option_map_.insert({option->info.name, {option.get(), false}});
  721. }
  722. short_option_table_.fill(nullptr);
  723. for (auto& map_entry : option_map_) {
  724. const Arg* option = map_entry.second.getPointer();
  725. if (option->info.short_name.empty()) {
  726. continue;
  727. }
  728. CARBON_CHECK(option->info.short_name.size() == 1,
  729. "Short option names must have exactly one character.");
  730. unsigned char short_char = option->info.short_name[0];
  731. CARBON_CHECK(short_char < short_option_table_.size(),
  732. "Short option name outside of the expected range.");
  733. short_option_table_[short_char] = &map_entry.second;
  734. }
  735. subcommand_map_.clear();
  736. for (const auto& subcommand : command.subcommands) {
  737. subcommand_map_.insert({subcommand->info.name, subcommand.get()});
  738. }
  739. }
  740. void Parser::SetOptionDefault(const Arg& option) {
  741. CARBON_CHECK(option.has_default, "No default value available!");
  742. switch (option.kind) {
  743. case Arg::Kind::Flag:
  744. *option.flag_storage = option.default_flag;
  745. break;
  746. case Arg::Kind::Integer:
  747. *option.integer_storage = option.default_integer;
  748. break;
  749. case Arg::Kind::String:
  750. *option.string_storage = option.default_string;
  751. break;
  752. case Arg::Kind::OneOf:
  753. option.default_action(option);
  754. break;
  755. case Arg::Kind::MetaActionOnly:
  756. CARBON_FATAL("Can't set a default value for a meta action!");
  757. case Arg::Kind::Invalid:
  758. CARBON_FATAL("Option configured without any action or kind!");
  759. }
  760. }
  761. auto Parser::ParseNegatedFlag(const Arg& flag,
  762. std::optional<llvm::StringRef> value)
  763. -> ErrorOr<Success> {
  764. if (flag.kind != Arg::Kind::Flag) {
  765. return Error(
  766. "cannot use a negated flag name by prefixing it with `no-` when it "
  767. "isn't a boolean flag argument");
  768. }
  769. if (value) {
  770. return Error(
  771. "cannot specify a value when using a flag name prefixed with `no-` -- "
  772. "that prefix implies a value of `false`");
  773. }
  774. *flag.flag_storage = false;
  775. return Success();
  776. }
  777. auto Parser::ParseFlag(const Arg& flag, std::optional<llvm::StringRef> value)
  778. -> ErrorOr<Success> {
  779. CARBON_CHECK(flag.kind == Arg::Kind::Flag, "Incorrect kind: {0}", flag.kind);
  780. if (!value || *value == "true") {
  781. *flag.flag_storage = true;
  782. } else if (*value == "false") {
  783. *flag.flag_storage = false;
  784. } else {
  785. return Error(llvm::formatv(
  786. "invalid value specified for the boolean flag `--{0}`: {1}",
  787. flag.info.name, *value));
  788. }
  789. return Success();
  790. }
  791. auto Parser::ParseIntegerArgValue(const Arg& arg, llvm::StringRef value)
  792. -> ErrorOr<Success> {
  793. CARBON_CHECK(arg.kind == Arg::Kind::Integer, "Incorrect kind: {0}", arg.kind);
  794. int integer_value;
  795. // Note that this method returns *true* on error!
  796. if (value.getAsInteger(/*Radix=*/0, integer_value)) {
  797. return Error(llvm::formatv(
  798. "cannot parse value for option `--{0}` as an integer: {1}",
  799. arg.info.name, value));
  800. }
  801. if (!arg.is_append) {
  802. *arg.integer_storage = integer_value;
  803. } else {
  804. arg.integer_sequence->push_back(integer_value);
  805. }
  806. return Success();
  807. }
  808. auto Parser::ParseStringArgValue(const Arg& arg, llvm::StringRef value)
  809. -> ErrorOr<Success> {
  810. CARBON_CHECK(arg.kind == Arg::Kind::String, "Incorrect kind: {0}", arg.kind);
  811. if (!arg.is_append) {
  812. *arg.string_storage = value;
  813. } else {
  814. arg.string_sequence->push_back(value);
  815. }
  816. return Success();
  817. }
  818. auto Parser::ParseOneOfArgValue(const Arg& arg, llvm::StringRef value)
  819. -> ErrorOr<Success> {
  820. CARBON_CHECK(arg.kind == Arg::Kind::OneOf, "Incorrect kind: {0}", arg.kind);
  821. if (!arg.value_action(arg, value)) {
  822. RawStringOstream error;
  823. error << "option `--" << arg.info.name << "=";
  824. llvm::printEscapedString(value, error);
  825. error << "` has an invalid value `";
  826. llvm::printEscapedString(value, error);
  827. error << "`; valid values are: ";
  828. PrintListOfAlternatives(error, arg.value_strings,
  829. [](llvm::StringRef x) { return x; });
  830. return Error(error.TakeStr());
  831. }
  832. return Success();
  833. }
  834. auto Parser::ParseArg(const Arg& arg, bool short_spelling,
  835. std::optional<llvm::StringRef> value, bool negated_name)
  836. -> ErrorOr<Success> {
  837. // If this argument has a meta action, replace the current meta action with
  838. // it.
  839. if (arg.meta_action) {
  840. arg_meta_action_ = arg.meta_action;
  841. }
  842. // Boolean flags have special parsing logic.
  843. if (negated_name) {
  844. return ParseNegatedFlag(arg, value);
  845. }
  846. if (arg.kind == Arg::Kind::Flag) {
  847. return ParseFlag(arg, value);
  848. }
  849. std::string name;
  850. if (short_spelling) {
  851. name = llvm::formatv("`-{0}` (short for `--{1}`)", arg.info.short_name,
  852. arg.info.name);
  853. } else {
  854. name = llvm::formatv("`--{0}`", arg.info.name);
  855. }
  856. if (!value) {
  857. // We can't have a positional argument without a value, so we know this is
  858. // an option and handle it as such.
  859. if (arg.kind == Arg::Kind::MetaActionOnly) {
  860. // Nothing further to do here, this is only a meta-action.
  861. return Success();
  862. }
  863. if (!arg.has_default) {
  864. return Error(llvm::formatv(
  865. "option {0} requires a value to be provided and none was", name));
  866. }
  867. SetOptionDefault(arg);
  868. return Success();
  869. }
  870. // There is a value to parse as part of the argument.
  871. switch (arg.kind) {
  872. case Arg::Kind::Integer:
  873. return ParseIntegerArgValue(arg, *value);
  874. case Arg::Kind::String:
  875. return ParseStringArgValue(arg, *value);
  876. case Arg::Kind::OneOf:
  877. return ParseOneOfArgValue(arg, *value);
  878. case Arg::Kind::MetaActionOnly:
  879. // TODO: Improve message.
  880. return Error(llvm::formatv(
  881. "option {0} cannot be used with a value, and '{1}' was provided",
  882. name, value));
  883. case Arg::Kind::Flag:
  884. case Arg::Kind::Invalid:
  885. CARBON_FATAL("Invalid kind!");
  886. }
  887. }
  888. auto Parser::SplitValue(llvm::StringRef& unparsed_arg)
  889. -> std::optional<llvm::StringRef> {
  890. // Split out a value if present.
  891. std::optional<llvm::StringRef> value;
  892. auto index = unparsed_arg.find('=');
  893. if (index != llvm::StringRef::npos) {
  894. value = unparsed_arg.substr(index + 1);
  895. unparsed_arg = unparsed_arg.substr(0, index);
  896. }
  897. return value;
  898. }
  899. auto Parser::ParseLongOption(llvm::StringRef unparsed_arg) -> ErrorOr<Success> {
  900. CARBON_CHECK(unparsed_arg.starts_with("--") && unparsed_arg.size() > 2,
  901. "Must only be called on a potential long option.");
  902. // Walk past the double dash.
  903. unparsed_arg = unparsed_arg.drop_front(2);
  904. bool negated_name = unparsed_arg.consume_front("no-");
  905. std::optional<llvm::StringRef> value = SplitValue(unparsed_arg);
  906. auto option_it = option_map_.find(unparsed_arg);
  907. if (option_it == option_map_.end()) {
  908. // TODO: Improve error.
  909. return Error(llvm::formatv("unknown option `--{0}{1}`",
  910. negated_name ? "no-" : "", unparsed_arg));
  911. }
  912. // Mark this option as parsed.
  913. option_it->second.setInt(true);
  914. // Parse this specific option and any value.
  915. const Arg& option = *option_it->second.getPointer();
  916. return ParseArg(option, /*short_spelling=*/false, value, negated_name);
  917. }
  918. auto Parser::ParseShortOptionSeq(llvm::StringRef unparsed_arg)
  919. -> ErrorOr<Success> {
  920. CARBON_CHECK(unparsed_arg.starts_with("-") && unparsed_arg.size() > 1,
  921. "Must only be called on a potential short option sequence.");
  922. unparsed_arg = unparsed_arg.drop_front();
  923. std::optional<llvm::StringRef> value = SplitValue(unparsed_arg);
  924. if (value && unparsed_arg.size() != 1) {
  925. return Error(llvm::formatv(
  926. "cannot provide a value to the group of multiple short options "
  927. "`-{0}=...`; values must be provided to a single option, using "
  928. "either the short or long spelling",
  929. unparsed_arg));
  930. }
  931. for (unsigned char c : unparsed_arg) {
  932. auto* arg_entry =
  933. (c < short_option_table_.size()) ? short_option_table_[c] : nullptr;
  934. if (!arg_entry) {
  935. return Error(
  936. llvm::formatv("unknown short option `-{0}`", static_cast<char>(c)));
  937. }
  938. // Mark this argument as parsed.
  939. arg_entry->setInt(true);
  940. // Parse the argument, including the value if this is the last.
  941. const Arg& arg = *arg_entry->getPointer();
  942. CARBON_RETURN_IF_ERROR(ParseArg(arg, /*short_spelling=*/true, value));
  943. }
  944. return Success();
  945. }
  946. auto Parser::FinalizeParsedOptions() -> ErrorOr<Success> {
  947. llvm::SmallVector<const Arg*> missing_options;
  948. for (const auto& option_entry : option_map_) {
  949. const Arg* option = option_entry.second.getPointer();
  950. if (!option_entry.second.getInt()) {
  951. // If the argument has a default value and isn't a meta-action, we need to
  952. // act on that when it isn't passed.
  953. if (option->has_default && !option->meta_action) {
  954. SetOptionDefault(*option);
  955. }
  956. // Remember any missing required arguments, we'll diagnose those.
  957. if (option->is_required) {
  958. missing_options.push_back(option);
  959. }
  960. }
  961. }
  962. if (missing_options.empty()) {
  963. return Success();
  964. }
  965. // Sort the missing arguments by name to provide a stable and deterministic
  966. // error message. We know there can't be duplicate names because these came
  967. // from a may keyed on the name, so this provides a total ordering.
  968. llvm::sort(missing_options, [](const Arg* lhs, const Arg* rhs) {
  969. return lhs->info.name < rhs->info.name;
  970. });
  971. RawStringOstream error;
  972. error << "required options not provided: ";
  973. llvm::ListSeparator sep;
  974. for (const Arg* option : missing_options) {
  975. error << sep << "--" << option->info.name;
  976. }
  977. return Error(error.TakeStr());
  978. }
  979. auto Parser::ParsePositionalArg(llvm::StringRef unparsed_arg)
  980. -> ErrorOr<Success> {
  981. if (static_cast<size_t>(positional_arg_index_) >=
  982. command_->positional_args.size()) {
  983. return Error(llvm::formatv(
  984. "completed parsing all {0} configured positional arguments, and found "
  985. "an additional positional argument: `{1}`",
  986. command_->positional_args.size(), unparsed_arg));
  987. }
  988. const Arg& arg = *command_->positional_args[positional_arg_index_];
  989. // Mark that we'll keep appending here until a `--` marker. When already
  990. // appending this is redundant but harmless.
  991. appending_to_positional_arg_ = arg.is_append;
  992. if (!appending_to_positional_arg_) {
  993. // If we're not continuing to append to a current positional arg,
  994. // increment the positional arg index to find the next argument we
  995. // should use here.
  996. ++positional_arg_index_;
  997. }
  998. return ParseArg(arg, /*short_spelling=*/false, unparsed_arg);
  999. }
  1000. auto Parser::ParseSubcommand(llvm::StringRef unparsed_arg) -> ErrorOr<Success> {
  1001. auto subcommand_it = subcommand_map_.find(unparsed_arg);
  1002. if (subcommand_it == subcommand_map_.end()) {
  1003. RawStringOstream error;
  1004. error << "invalid subcommand `" << unparsed_arg
  1005. << "`; available subcommands: ";
  1006. MetaPrinter(&error).PrintSubcommands(*command_);
  1007. return Error(error.TakeStr());
  1008. }
  1009. // Before we recurse into the subcommand, verify that all the required
  1010. // arguments for this command were in fact parsed.
  1011. CARBON_RETURN_IF_ERROR(FinalizeParsedOptions());
  1012. // Recurse into the subcommand, tracking the active command.
  1013. command_ = subcommand_it->second;
  1014. PopulateMaps(*command_);
  1015. return Success();
  1016. }
  1017. auto Parser::FinalizeParse() -> ErrorOr<ParseResult> {
  1018. // If an argument action is provided, we run that and consider the parse
  1019. // meta-successful rather than verifying required arguments were provided and
  1020. // the (sub)command action.
  1021. if (arg_meta_action_) {
  1022. arg_meta_action_();
  1023. return ParseResult::MetaSuccess;
  1024. }
  1025. // Verify we're not missing any arguments.
  1026. CARBON_RETURN_IF_ERROR(FinalizeParsedOptions());
  1027. // If we were appending to a positional argument, mark that as complete.
  1028. llvm::ArrayRef positional_args = command_->positional_args;
  1029. if (appending_to_positional_arg_) {
  1030. CARBON_CHECK(
  1031. static_cast<size_t>(positional_arg_index_) < positional_args.size(),
  1032. "Appending to a positional argument with an invalid index: {0}",
  1033. positional_arg_index_);
  1034. ++positional_arg_index_;
  1035. }
  1036. // See if any positional args are required and unparsed.
  1037. auto unparsed_positional_args = positional_args.slice(positional_arg_index_);
  1038. if (!unparsed_positional_args.empty()) {
  1039. // There are un-parsed positional arguments, make sure they aren't required.
  1040. const Arg& missing_arg = *unparsed_positional_args.front();
  1041. if (missing_arg.is_required) {
  1042. return Error(
  1043. llvm::formatv("not all required positional arguments were provided; "
  1044. "first missing and required positional argument: `{0}`",
  1045. missing_arg.info.name));
  1046. }
  1047. for (const auto& arg_ptr : unparsed_positional_args) {
  1048. CARBON_CHECK(
  1049. !arg_ptr->is_required,
  1050. "Cannot have required positional parameters after an optional one.");
  1051. }
  1052. }
  1053. switch (command_->kind) {
  1054. case Command::Kind::Invalid:
  1055. CARBON_FATAL("Should never have a parser with an invalid command!");
  1056. case Command::Kind::RequiresSubcommand: {
  1057. RawStringOstream error;
  1058. error << "no subcommand specified; available subcommands: ";
  1059. MetaPrinter(&error).PrintSubcommands(*command_);
  1060. return Error(error.TakeStr());
  1061. }
  1062. case Command::Kind::Action:
  1063. // All arguments have been successfully parsed, run any action for the
  1064. // most specific selected command. Only the leaf command's action is run.
  1065. command_->action();
  1066. return ParseResult::Success;
  1067. case Command::Kind::MetaAction:
  1068. command_->action();
  1069. return ParseResult::MetaSuccess;
  1070. }
  1071. }
  1072. auto Parser::ParsePositionalSuffix(
  1073. llvm::ArrayRef<llvm::StringRef> unparsed_args) -> ErrorOr<Success> {
  1074. CARBON_CHECK(
  1075. !command_->positional_args.empty(),
  1076. "Cannot do positional suffix parsing without positional arguments!");
  1077. CARBON_CHECK(
  1078. !unparsed_args.empty() && unparsed_args.front() == "--",
  1079. "Must be called with a suffix of arguments starting with a `--` that "
  1080. "switches to positional suffix parsing.");
  1081. // Once we're in the positional suffix, we can track empty positional
  1082. // arguments.
  1083. bool empty_positional = false;
  1084. while (!unparsed_args.empty()) {
  1085. llvm::StringRef unparsed_arg = unparsed_args.front();
  1086. unparsed_args = unparsed_args.drop_front();
  1087. if (unparsed_arg != "--") {
  1088. CARBON_RETURN_IF_ERROR(ParsePositionalArg(unparsed_arg));
  1089. empty_positional = false;
  1090. continue;
  1091. }
  1092. if (appending_to_positional_arg_ || empty_positional) {
  1093. ++positional_arg_index_;
  1094. if (static_cast<size_t>(positional_arg_index_) >=
  1095. command_->positional_args.size()) {
  1096. return Error(
  1097. llvm::formatv("completed parsing all {0} configured positional "
  1098. "arguments, but found a subsequent `--` and have no "
  1099. "further positional arguments to parse beyond it",
  1100. command_->positional_args.size()));
  1101. }
  1102. }
  1103. appending_to_positional_arg_ = false;
  1104. empty_positional = true;
  1105. }
  1106. return Success();
  1107. }
  1108. Parser::Parser(llvm::raw_ostream* out, CommandInfo command_info,
  1109. llvm::function_ref<void(CommandBuilder&)> build)
  1110. : meta_printer_(out), root_command_(command_info) {
  1111. // Run the command building lambda on a builder for the root command.
  1112. CommandBuilder builder(&root_command_, &meta_printer_);
  1113. build(builder);
  1114. builder.Finalize();
  1115. command_ = &root_command_;
  1116. }
  1117. auto Parser::Parse(llvm::ArrayRef<llvm::StringRef> unparsed_args)
  1118. -> ErrorOr<ParseResult> {
  1119. PopulateMaps(*command_);
  1120. while (!unparsed_args.empty()) {
  1121. llvm::StringRef unparsed_arg = unparsed_args.front();
  1122. // Peak at the front for an exact `--` argument that switches to a
  1123. // positional suffix parsing without dropping this argument.
  1124. if (unparsed_arg == "--") {
  1125. if (command_->positional_args.empty()) {
  1126. return Error(
  1127. "cannot meaningfully end option and subcommand arguments with a "
  1128. "`--` argument when there are no positional arguments to parse");
  1129. }
  1130. if (static_cast<size_t>(positional_arg_index_) >=
  1131. command_->positional_args.size()) {
  1132. return Error(
  1133. "switched to purely positional arguments with a `--` argument "
  1134. "despite already having parsed all positional arguments for this "
  1135. "command");
  1136. }
  1137. CARBON_RETURN_IF_ERROR(ParsePositionalSuffix(unparsed_args));
  1138. // No more unparsed arguments to handle.
  1139. break;
  1140. }
  1141. // Now that we're not switching parse modes, drop the current unparsed
  1142. // argument and parse it.
  1143. unparsed_args = unparsed_args.drop_front();
  1144. if (unparsed_arg.starts_with("--")) {
  1145. // Note that the exact argument "--" has been handled above already.
  1146. CARBON_RETURN_IF_ERROR(ParseLongOption(unparsed_arg));
  1147. continue;
  1148. }
  1149. if (unparsed_arg.starts_with("-") && unparsed_arg.size() > 1) {
  1150. CARBON_RETURN_IF_ERROR(ParseShortOptionSeq(unparsed_arg));
  1151. continue;
  1152. }
  1153. CARBON_CHECK(
  1154. command_->positional_args.empty() || command_->subcommands.empty(),
  1155. "Cannot have both positional arguments and subcommands!");
  1156. if (command_->positional_args.empty() && command_->subcommands.empty()) {
  1157. return Error(llvm::formatv(
  1158. "found unexpected positional argument or subcommand: `{0}`",
  1159. unparsed_arg));
  1160. }
  1161. if (!command_->positional_args.empty()) {
  1162. CARBON_RETURN_IF_ERROR(ParsePositionalArg(unparsed_arg));
  1163. continue;
  1164. }
  1165. CARBON_RETURN_IF_ERROR(ParseSubcommand(unparsed_arg));
  1166. }
  1167. return FinalizeParse();
  1168. }
  1169. void ArgBuilder::Required(bool is_required) { arg_->is_required = is_required; }
  1170. void ArgBuilder::HelpHidden(bool is_help_hidden) {
  1171. arg_->is_help_hidden = is_help_hidden;
  1172. }
  1173. ArgBuilder::ArgBuilder(Arg* arg) : arg_(arg) {}
  1174. void FlagBuilder::Default(bool flag_value) {
  1175. arg()->has_default = true;
  1176. arg()->default_flag = flag_value;
  1177. }
  1178. void FlagBuilder::Set(bool* flag) { arg()->flag_storage = flag; }
  1179. void IntegerArgBuilder::Default(int integer_value) {
  1180. arg()->has_default = true;
  1181. arg()->default_integer = integer_value;
  1182. }
  1183. void IntegerArgBuilder::Set(int* integer) {
  1184. arg()->is_append = false;
  1185. arg()->integer_storage = integer;
  1186. }
  1187. void IntegerArgBuilder::Append(llvm::SmallVectorImpl<int>* sequence) {
  1188. arg()->is_append = true;
  1189. arg()->integer_sequence = sequence;
  1190. }
  1191. void StringArgBuilder::Default(llvm::StringRef string_value) {
  1192. arg()->has_default = true;
  1193. arg()->default_string = string_value;
  1194. }
  1195. void StringArgBuilder::Set(llvm::StringRef* string) {
  1196. arg()->is_append = false;
  1197. arg()->string_storage = string;
  1198. }
  1199. void StringArgBuilder::Append(
  1200. llvm::SmallVectorImpl<llvm::StringRef>* sequence) {
  1201. arg()->is_append = true;
  1202. arg()->string_sequence = sequence;
  1203. }
  1204. static auto IsValidName(llvm::StringRef name) -> bool {
  1205. if (name.size() <= 1) {
  1206. return false;
  1207. }
  1208. if (!llvm::isAlnum(name.front())) {
  1209. return false;
  1210. }
  1211. if (!llvm::isAlnum(name.back())) {
  1212. return false;
  1213. }
  1214. for (char c : name.drop_front().drop_back()) {
  1215. if (c != '-' && c != '_' && !llvm::isAlnum(c)) {
  1216. return false;
  1217. }
  1218. }
  1219. // We disallow names starting with "no-" as we will parse those for boolean
  1220. // flags.
  1221. return !name.starts_with("no-");
  1222. }
  1223. void CommandBuilder::AddFlag(const ArgInfo& info,
  1224. llvm::function_ref<void(FlagBuilder&)> build) {
  1225. FlagBuilder builder(AddArgImpl(info, Arg::Kind::Flag));
  1226. // All boolean flags have an implicit default of `false`, although it can be
  1227. // overridden in the build callback.
  1228. builder.Default(false);
  1229. build(builder);
  1230. }
  1231. void CommandBuilder::AddIntegerOption(
  1232. const ArgInfo& info, llvm::function_ref<void(IntegerArgBuilder&)> build) {
  1233. IntegerArgBuilder builder(AddArgImpl(info, Arg::Kind::Integer));
  1234. build(builder);
  1235. }
  1236. void CommandBuilder::AddStringOption(
  1237. const ArgInfo& info, llvm::function_ref<void(StringArgBuilder&)> build) {
  1238. StringArgBuilder builder(AddArgImpl(info, Arg::Kind::String));
  1239. build(builder);
  1240. }
  1241. void CommandBuilder::AddOneOfOption(
  1242. const ArgInfo& info, llvm::function_ref<void(OneOfArgBuilder&)> build) {
  1243. OneOfArgBuilder builder(AddArgImpl(info, Arg::Kind::OneOf));
  1244. build(builder);
  1245. }
  1246. void CommandBuilder::AddMetaActionOption(
  1247. const ArgInfo& info, llvm::function_ref<void(ArgBuilder&)> build) {
  1248. ArgBuilder builder(AddArgImpl(info, Arg::Kind::MetaActionOnly));
  1249. build(builder);
  1250. }
  1251. void CommandBuilder::AddIntegerPositionalArg(
  1252. const ArgInfo& info, llvm::function_ref<void(IntegerArgBuilder&)> build) {
  1253. AddPositionalArgImpl(info, Arg::Kind::Integer, [build](Arg& arg) {
  1254. IntegerArgBuilder builder(&arg);
  1255. build(builder);
  1256. });
  1257. }
  1258. void CommandBuilder::AddStringPositionalArg(
  1259. const ArgInfo& info, llvm::function_ref<void(StringArgBuilder&)> build) {
  1260. AddPositionalArgImpl(info, Arg::Kind::String, [build](Arg& arg) {
  1261. StringArgBuilder builder(&arg);
  1262. build(builder);
  1263. });
  1264. }
  1265. void CommandBuilder::AddOneOfPositionalArg(
  1266. const ArgInfo& info, llvm::function_ref<void(OneOfArgBuilder&)> build) {
  1267. AddPositionalArgImpl(info, Arg::Kind::OneOf, [build](Arg& arg) {
  1268. OneOfArgBuilder builder(&arg);
  1269. build(builder);
  1270. });
  1271. }
  1272. void CommandBuilder::AddSubcommand(
  1273. const CommandInfo& info, llvm::function_ref<void(CommandBuilder&)> build) {
  1274. CARBON_CHECK(IsValidName(info.name), "Invalid subcommand name: {0}",
  1275. info.name);
  1276. CARBON_CHECK(subcommand_names_.insert(info.name).second,
  1277. "Added a duplicate subcommand: {0}", info.name);
  1278. CARBON_CHECK(
  1279. command_->positional_args.empty(),
  1280. "Cannot add subcommands to a command with a positional argument.");
  1281. command_->subcommands.emplace_back(new Command(info, command_));
  1282. CommandBuilder builder(command_->subcommands.back().get(), meta_printer_);
  1283. build(builder);
  1284. builder.Finalize();
  1285. }
  1286. void CommandBuilder::HelpHidden(bool is_help_hidden) {
  1287. command_->is_help_hidden = is_help_hidden;
  1288. }
  1289. void CommandBuilder::RequiresSubcommand() {
  1290. CARBON_CHECK(!command_->subcommands.empty(),
  1291. "Cannot require subcommands unless there are subcommands.");
  1292. CARBON_CHECK(command_->positional_args.empty(),
  1293. "Cannot require subcommands and have a positional argument.");
  1294. CARBON_CHECK(command_->kind == Kind::Invalid,
  1295. "Already established the kind of this command as: {0}",
  1296. command_->kind);
  1297. command_->kind = Kind::RequiresSubcommand;
  1298. }
  1299. void CommandBuilder::Do(ActionT action) {
  1300. CARBON_CHECK(command_->kind == Kind::Invalid,
  1301. "Already established the kind of this command as: {0}",
  1302. command_->kind);
  1303. command_->kind = Kind::Action;
  1304. command_->action = std::move(action);
  1305. }
  1306. void CommandBuilder::Meta(ActionT action) {
  1307. CARBON_CHECK(command_->kind == Kind::Invalid,
  1308. "Already established the kind of this command as: {0}",
  1309. command_->kind);
  1310. command_->kind = Kind::MetaAction;
  1311. command_->action = std::move(action);
  1312. }
  1313. CommandBuilder::CommandBuilder(Command* command, MetaPrinter* meta_printer)
  1314. : command_(command), meta_printer_(meta_printer) {}
  1315. auto CommandBuilder::AddArgImpl(const ArgInfo& info, Arg::Kind kind) -> Arg* {
  1316. CARBON_CHECK(IsValidName(info.name), "Invalid argument name: {0}", info.name);
  1317. CARBON_CHECK(arg_names_.insert(info.name).second,
  1318. "Added a duplicate argument name: {0}", info.name);
  1319. command_->options.emplace_back(new Arg(info));
  1320. Arg* arg = command_->options.back().get();
  1321. arg->kind = kind;
  1322. return arg;
  1323. }
  1324. void CommandBuilder::AddPositionalArgImpl(
  1325. const ArgInfo& info, Arg::Kind kind, llvm::function_ref<void(Arg&)> build) {
  1326. CARBON_CHECK(IsValidName(info.name), "Invalid argument name: {0}", info.name);
  1327. CARBON_CHECK(
  1328. command_->subcommands.empty(),
  1329. "Cannot add a positional argument to a command with subcommands.");
  1330. command_->positional_args.emplace_back(new Arg(info));
  1331. Arg& arg = *command_->positional_args.back();
  1332. arg.kind = kind;
  1333. build(arg);
  1334. CARBON_CHECK(!arg.is_help_hidden,
  1335. "Cannot have a help-hidden positional argument.");
  1336. if (arg.is_required && command_->positional_args.size() > 1) {
  1337. CARBON_CHECK((*std::prev(command_->positional_args.end(), 2))->is_required,
  1338. "A required positional argument cannot be added after an "
  1339. "optional one.");
  1340. }
  1341. }
  1342. void CommandBuilder::Finalize() {
  1343. meta_printer_->RegisterWithCommand(*command_, *this);
  1344. }
  1345. auto Parse(llvm::ArrayRef<llvm::StringRef> unparsed_args,
  1346. llvm::raw_ostream& out, CommandInfo command_info,
  1347. llvm::function_ref<void(CommandBuilder&)> build)
  1348. -> ErrorOr<ParseResult> {
  1349. // Build a parser, which includes building the command description provided by
  1350. // the user.
  1351. Parser parser(&out, command_info, build);
  1352. // Now parse the arguments provided using that parser.
  1353. return parser.Parse(unparsed_args);
  1354. }
  1355. } // namespace Carbon::CommandLine
  1356. // NOLINTEND(misc-no-recursion)