From 89d95dfec4e0edad1d2800fcc3d53eeb6bed8384 Mon Sep 17 00:00:00 2001 From: Brett Date: Thu, 13 Feb 2025 13:59:59 -0500 Subject: [PATCH] working on subparsers --- CMakeLists.txt | 2 +- include/blt/parse/argparse_v2.h | 93 +++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26d0783..2767fd3 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.4) +set(BLT_VERSION 4.0.5) set(BLT_TARGET BLT) diff --git a/include/blt/parse/argparse_v2.h b/include/blt/parse/argparse_v2.h index 3ef50d8..720db6d 100644 --- a/include/blt/parse/argparse_v2.h +++ b/include/blt/parse/argparse_v2.h @@ -56,6 +56,49 @@ namespace blt::argparse } }; + class subparse_error final : public std::exception + { + public: + explicit subparse_error(const std::string_view found_string, std::vector allowed_strings): m_found_string(found_string), + m_allowed_strings(std::move(allowed_strings)) + { + } + + [[nodiscard]] const std::vector& get_allowed_strings() const + { + return m_allowed_strings; + } + + [[nodiscard]] std::string_view get_found_string() const + { + return m_found_string; + } + + [[nodiscard]] std::string error_string() const + { + std::string message = "Subparser Error: "; + message += m_found_string; + message += " is not a valid command. Allowed commands are: {"; + for (const auto [i, allowed_string] : enumerate(m_allowed_strings)) + { + message += allowed_string; + if (i != m_allowed_strings.size() - 1) + message += ' '; + } + message += "}"; + return message; + } + + [[nodiscard]] const char* what() const override + { + return "Please use error_string() method instead of what(). This exception should *always* be caught!"; + } + + private: + std::string_view m_found_string; + std::vector m_allowed_strings; + }; + template struct arg_data_helper_t { @@ -207,6 +250,8 @@ namespace blt::argparse class argument_parser_t { + friend argument_subparser_t; + public: explicit argument_parser_t(const std::optional name = {}, const std::optional usage = {}): m_name(name), m_usage(usage) @@ -219,6 +264,10 @@ namespace blt::argparse return *this; } + void parse(argument_consumer_t& consumer) // NOLINT + { + } + private: std::optional m_name; std::optional m_usage; @@ -229,17 +278,51 @@ namespace blt::argparse class argument_subparser_t { public: - - argument_parser_t add_subparser(const std::string_view dest) + explicit argument_subparser_t(const argument_parser_t& parent): m_parent(&parent) { - } - argument_parser_t add_subparser(std::string& dest) + argument_parser_t& add_parser(const std::string_view name) { - + m_parsers.emplace(name); + return m_parsers[name]; } + + + /** + * Parses the next argument using the provided argument consumer. + * + * This function uses an argument consumer to extract and process the next argument. + * If the argument is a flag or if it cannot be matched against the available parsers, + * an exception is thrown. + * + * @param consumer Reference to an argument_consumer_t object, which handles argument parsing. + * The consumer provides the next argument to be parsed. + * + * @throws detail::subparse_error If the argument is a flag or does not match any known parser. + */ + void parse(argument_consumer_t& consumer) // NOLINT + { + const auto key = consumer.consume(); + if (key.is_flag()) + throw detail::subparse_error(key.get_argument(), get_allowed_strings()); + const auto it = m_parsers.find(key.get_name()); + if (it == m_parsers.end()) + throw detail::subparse_error(key.get_argument(), get_allowed_strings()); + it->second.parse(consumer); + } + private: + [[nodiscard]] std::vector get_allowed_strings() const + { + std::vector vec; + for (const auto& [key, value] : m_parsers) + vec.push_back(key); + return vec; + } + + const argument_parser_t* m_parent; + hashmap_t m_parsers; }; }