command_line.cpp 50 KB

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