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