diff options
Diffstat (limited to 'llvm/examples/OptSubcommand')
-rw-r--r-- | llvm/examples/OptSubcommand/CMakeLists.txt | 19 | ||||
-rw-r--r-- | llvm/examples/OptSubcommand/Opts.td | 18 | ||||
-rw-r--r-- | llvm/examples/OptSubcommand/llvm-hello-sub.cpp | 137 |
3 files changed, 174 insertions, 0 deletions
diff --git a/llvm/examples/OptSubcommand/CMakeLists.txt b/llvm/examples/OptSubcommand/CMakeLists.txt new file mode 100644 index 0000000..debc948 --- /dev/null +++ b/llvm/examples/OptSubcommand/CMakeLists.txt @@ -0,0 +1,19 @@ +# Set the .td file to be processed for this target. +set(LLVM_TARGET_DEFINITIONS Opts.td) + +tablegen(LLVM Opts.inc -gen-opt-parser-defs) +add_public_tablegen_target(HelloSubTableGen) + +set(LLVM_LINK_COMPONENTS + Support + Option + ) + +add_llvm_example(OptSubcommand + llvm-hello-sub.cpp + ) + +target_include_directories(OptSubcommand + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} + ) diff --git a/llvm/examples/OptSubcommand/Opts.td b/llvm/examples/OptSubcommand/Opts.td new file mode 100644 index 0000000..7c980ee --- /dev/null +++ b/llvm/examples/OptSubcommand/Opts.td @@ -0,0 +1,18 @@ +include "llvm/Option/OptParser.td" + +def sc_foo : SubCommand<"foo", "HelpText for SubCommand foo.">; + +def sc_bar : SubCommand<"bar", "HelpText for SubCommand bar.", + "OptSubcommand bar <options>">; + +def help : Flag<["--"], "help">, + HelpText<"OptSubcommand <subcommand> <options>">; + +def version : Flag<["-"], "version">, + HelpText<"Toplevel Display the version number">; + +def uppercase : Flag<["-"], "uppercase", [sc_foo, sc_bar]>, + HelpText<"Print in uppercase">; + +def lowercase : Flag<["-"], "lowercase", [sc_foo]>, + HelpText<"Print in lowercase">; diff --git a/llvm/examples/OptSubcommand/llvm-hello-sub.cpp b/llvm/examples/OptSubcommand/llvm-hello-sub.cpp new file mode 100644 index 0000000..8071f56 --- /dev/null +++ b/llvm/examples/OptSubcommand/llvm-hello-sub.cpp @@ -0,0 +1,137 @@ +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::opt; + +namespace { +enum ID { + OPT_INVALID = 0, +#define OPTION(PREFIXES, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ + VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \ + VALUES, SUBCOMMANDIDS_OFFSET) \ + OPT_##ID, +#include "Opts.inc" +#undef OPTION +}; +#define OPTTABLE_STR_TABLE_CODE +#include "Opts.inc" +#undef OPTTABLE_STR_TABLE_CODE + +#define OPTTABLE_PREFIXES_TABLE_CODE +#include "Opts.inc" +#undef OPTTABLE_PREFIXES_TABLE_CODE + +#define OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE +#include "Opts.inc" +#undef OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE + +#define OPTTABLE_SUBCOMMANDS_CODE +#include "Opts.inc" +#undef OPTTABLE_SUBCOMMANDS_CODE + +static constexpr OptTable::Info InfoTable[] = { +#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), +#include "Opts.inc" +#undef OPTION +}; + +class HelloSubOptTable : public GenericOptTable { +public: + HelloSubOptTable() + : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable, + /*IgnoreCase=*/false, OptionSubCommands, + OptionSubCommandIDsTable) {} +}; +} // namespace + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + HelloSubOptTable T; + unsigned MissingArgIndex, MissingArgCount; + + auto HandleMultipleSubcommands = [](ArrayRef<StringRef> SubCommands) { + assert(SubCommands.size() > 1); + llvm::errs() << "error: more than one subcommand passed [\n"; + for (auto SC : SubCommands) + llvm::errs() << " `" << SC << "`\n"; + llvm::errs() << "]\n"; + llvm::errs() << "See --help.\n"; + exit(1); + }; + + auto HandleOtherPositionals = [](ArrayRef<StringRef> Positionals) { + assert(!Positionals.empty()); + llvm::errs() << "error: unknown positional argument(s) [\n"; + for (auto SC : Positionals) + llvm::errs() << " `" << SC << "`\n"; + llvm::errs() << "]\n"; + llvm::errs() << "See --help.\n"; + exit(1); + }; + + InputArgList Args = T.ParseArgs(ArrayRef(argv + 1, argc - 1), MissingArgIndex, + MissingArgCount); + + StringRef SubCommand = Args.getSubCommand( + T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals); + // Handle help. When help options is found, ignore all other options and exit + // after printing help. + + if (Args.hasArg(OPT_help)) { + T.printHelp(llvm::outs(), "llvm-hello-sub [subcommand] [options]", + "LLVM Hello SubCommand Example", false, false, Visibility(), + SubCommand); + return 0; + } + + auto HandleSubCommandArg = [&](ID OptionType) { + if (!Args.hasArg(OptionType)) + return false; + auto O = T.getOption(OptionType); + if (!O.isRegisteredSC(SubCommand)) { + llvm::errs() << "Option [" << O.getName() + << "] is not valid for SubCommand [" << SubCommand << "]\n"; + return false; + } + return true; + }; + + bool HasUnknownOptions = false; + for (const Arg *A : Args.filtered(OPT_UNKNOWN)) { + HasUnknownOptions = true; + llvm::errs() << "Unknown option `" << A->getAsString(Args) << "'\n"; + } + if (HasUnknownOptions) { + llvm::errs() << "See `OptSubcommand --help`.\n"; + return 1; + } + if (SubCommand.empty()) { + if (Args.hasArg(OPT_version)) + llvm::outs() << "LLVM Hello SubCommand Example 1.0\n"; + } else if (SubCommand == "foo") { + if (HandleSubCommandArg(OPT_uppercase)) + llvm::outs() << "FOO\n"; + else if (HandleSubCommandArg(OPT_lowercase)) + llvm::outs() << "foo\n"; + + if (HandleSubCommandArg(OPT_version)) + llvm::outs() << "LLVM Hello SubCommand foo Example 1.0\n"; + + } else if (SubCommand == "bar") { + if (HandleSubCommandArg(OPT_lowercase)) + llvm::outs() << "bar\n"; + else if (HandleSubCommandArg(OPT_uppercase)) + llvm::outs() << "BAR\n"; + + if (HandleSubCommandArg(OPT_version)) + llvm::outs() << "LLVM Hello SubCommand bar Example 1.0\n"; + } + + return 0; +} |