diff --git a/CMakeLists.txt b/CMakeLists.txt index ae8b177..19ad666 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.20) include(cmake/color.cmake) -set(BLT_VERSION 4.0.8) +set(BLT_VERSION 4.0.9) set(BLT_TARGET BLT) diff --git a/include/blt/parse/argparse_v2.h b/include/blt/parse/argparse_v2.h index 359750a..184cd7f 100644 --- a/include/blt/parse/argparse_v2.h +++ b/include/blt/parse/argparse_v2.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -51,11 +52,10 @@ namespace blt::argparse STORE_FALSE, APPEND, APPEND_CONST, + EXTEND, COUNT, HELP, - VERSION, - EXTEND, - SUBCOMMAND + VERSION }; enum class nargs_t @@ -120,13 +120,41 @@ namespace blt::argparse std::vector> m_allowed_strings; }; + template + constexpr auto invalid_option_lambda = [](const T) + { + std::cerr << "Invalid type - expected list type, found '" << blt::type_string() << "'" << std::endl; + std::exit(1); + }; + template struct arg_data_helper_t { using variant_t = std::variant...>; + using arg_t = meta::arg_helper; + using arg_vec_t = meta::arg_helper...>; + + template typename... Defaults> + static auto make_lists_only_visitor(Defaults>&&... d) + { + return lambda_visitor{ + invalid_option_lambda, + std::forward(d)... + }; + } + + template typename... Defaults> + static auto make_reject_lists_visitor_t(Defaults&&... d) + { + return lambda_visitor{ + invalid_option_lambda...>, + std::forward(d)... + }; + } }; - using arg_data_t = arg_data_helper_t::variant_t; + using arg_meta_type_helper_t = arg_data_helper_t; + using arg_data_t = arg_meta_type_helper_t::variant_t; template struct arg_string_converter_t @@ -414,6 +442,8 @@ namespace blt::argparse void print_usage(); + void print_version(); + argument_parser_t& set_name(const std::string_view name) { m_name = name; @@ -456,8 +486,9 @@ namespace blt::argparse private: void parse_flag(argument_storage_t& parsed_args, argument_consumer_t& consumer, std::string_view arg); void parse_positional(argument_storage_t& parsed_args, argument_consumer_t& consumer, std::string_view arg); - static void handle_missing_and_default_args(hashmap_t& arguments, const hashset_t& found, - argument_storage_t& parsed_args, std::string_view type); + static void handle_missing_and_default_args(hashmap_t& arguments, + const hashset_t& found, + argument_storage_t& parsed_args, std::string_view type); std::optional m_name; std::optional m_usage; diff --git a/src/blt/parse/argparse_v2.cpp b/src/blt/parse/argparse_v2.cpp index 6eb054c..c0d3491 100644 --- a/src/blt/parse/argparse_v2.cpp +++ b/src/blt/parse/argparse_v2.cpp @@ -21,6 +21,7 @@ namespace blt::argparse { + namespace detail { // Unit Tests for class argument_string_t @@ -248,6 +249,10 @@ namespace blt::argparse { } + void argument_parser_t::print_version() + { + } + void argument_parser_t::parse_flag(argument_storage_t& parsed_args, argument_consumer_t& consumer, const std::string_view arg) { auto& flag = m_flag_arguments[arg]; @@ -266,9 +271,9 @@ namespace blt::argparse parsed_args.m_data.insert({dest, *flag->m_const_value}); } break; - [[fallthrough]] case nargs_t::ALL_AT_LEAST_ONE: + [[fallthrough]] case nargs_t::ALL_AT_LEAST_ONE: if (!consumer.can_consume()) - std::cout << "Error expected at least one argument to be consumed by '" << arg << '\'' << std::endl; + std::cerr << "Error expected at least one argument to be consumed by '" << arg << '\'' << std::endl; case nargs_t::ALL: std::vector args; while (consumer.can_consume() && !consumer.peek().is_flag()) @@ -277,8 +282,79 @@ namespace blt::argparse break; } }, - [](const i32 argc) + [&parsed_args, &consumer, &dest, &flag, arg, this](const i32 argc) { + std::vector args; + for (i32 i = 0; i < argc; ++i) + { + if (!consumer.can_consume()) + { + std::cerr << "Error expected " << argc << " arguments to be consumed by '" << arg << "' but found " << i << + std::endl; + std::exit(1); + } + if (consumer.peek().is_flag()) + { + std::cerr << "Error expected " << argc << " arguments to be consumed by '" << arg << "' but found a flag '" << + consumer.peek().get_argument() << "' instead!" << std::endl; + std::exit(1); + } + args.push_back(consumer.consume().get_argument()); + } + if (args.size() != argc) + { + std::cerr << + "This error condition should not be possible. " + "Args consumed didn't equal the arguments requested and previous checks didn't fail. " + "Please report as an issue on the GitHub" + << std::endl; + std::exit(1); + } + if (argc == 0) + { + } + else if (argc == 1) + { + switch (flag->m_action) + { + case action_t::STORE: + break; + case action_t::APPEND: + case action_t::EXTEND: + { + break; + } + case action_t::APPEND_CONST: + // if (parsed_args.contains(dest)) + // { + // std::visit(detail::arg_meta_type_helper_t::make_lists_only_visitor(handle_insert), parsed_args.m_data[dest]); + // } + case action_t::STORE_CONST: + std::cerr << "Store const flag called with an argument. This condition doesn't make sense." << std::endl; + print_usage(); + std::exit(1); + case action_t::STORE_TRUE: + std::cerr << "Store true flag called with an argument. This condition doesn't make sense." << std::endl; + print_usage(); + std::exit(1); + case action_t::STORE_FALSE: + std::cerr << "Store false flag called with an argument. This condition doesn't make sense." << std::endl; + print_usage(); + std::exit(1); + case action_t::COUNT: + parsed_args.m_data.insert({dest, args.size()}); + break; + case action_t::HELP: + print_help(); + std::exit(1); + case action_t::VERSION: + print_version(); + break; + } + flag->m_dest_func(dest, parsed_args, args.front()); + } + else + flag->m_dest_vec_func(dest, parsed_args, args); } }, flag->m_nargs); }