gotta think of a way of handling the whole "templates are silly" thing

v2
Brett 2025-02-17 01:47:42 -05:00
parent 6e5caf3ac5
commit a78ad58479
3 changed files with 117 additions and 10 deletions

View File

@ -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)

View File

@ -22,6 +22,7 @@
#include <blt/std/types.h>
#include <blt/std/hashmap.h>
#include <blt/fs/path_helper.h>
#include <blt/meta/meta.h>
#include <string>
#include <string_view>
#include <vector>
@ -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<std::vector<std::string_view>> m_allowed_strings;
};
template <typename T>
constexpr auto invalid_option_lambda = [](const T)
{
std::cerr << "Invalid type - expected list type, found '" << blt::type_string<T>() << "'" << std::endl;
std::exit(1);
};
template <typename... Args>
struct arg_data_helper_t
{
using variant_t = std::variant<Args..., std::vector<Args>...>;
using arg_t = meta::arg_helper<Args...>;
using arg_vec_t = meta::arg_helper<std::vector<Args>...>;
template <template<typename> typename... Defaults>
static auto make_lists_only_visitor(Defaults<std::vector<Args>>&&... d)
{
return lambda_visitor{
invalid_option_lambda<Args...>,
std::forward<Defaults>(d)...
};
}
template <template<typename> typename... Defaults>
static auto make_reject_lists_visitor_t(Defaults<Args>&&... d)
{
return lambda_visitor{
invalid_option_lambda<std::vector<Args>...>,
std::forward<Defaults>(d)...
};
}
};
using arg_data_t = arg_data_helper_t<i8, i16, i32, i64, u8, u16, u32, u64, float, double, std::string_view>::variant_t;
using arg_meta_type_helper_t = arg_data_helper_t<i8, i16, i32, i64, u8, u16, u32, u64, float, double, std::string_view>;
using arg_data_t = arg_meta_type_helper_t::variant_t;
template <typename T>
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<std::string_view, argument_builder_t*>& arguments, const hashset_t<std::string_view>& found,
argument_storage_t& parsed_args, std::string_view type);
static void handle_missing_and_default_args(hashmap_t<std::string_view, argument_builder_t*>& arguments,
const hashset_t<std::string_view>& found,
argument_storage_t& parsed_args, std::string_view type);
std::optional<std::string> m_name;
std::optional<std::string> m_usage;

View File

@ -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<std::string_view> 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<std::string_view> 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);
}