diff --git a/include/parser/argument_parser.hpp b/include/parser/argument_parser.hpp index bb97feb..ca60c74 100644 --- a/include/parser/argument_parser.hpp +++ b/include/parser/argument_parser.hpp @@ -12,64 +12,106 @@ #include #include #include -#include #include #include -#include namespace argument_parser { - template - class parametered_action { + class action_base { public: - // Type alias to expose the parameter type, crucial for the visitor. + virtual ~action_base() = default; + virtual bool expects_parameter() const = 0; + virtual void invoke() const = 0; + virtual void invoke_with_parameter(const std::string& param) const = 0; + virtual std::unique_ptr clone() const = 0; + }; + + template + class parametered_action : public action_base { + public: + explicit parametered_action(std::function const& handler) : handler(handler) {} + using parameter_type = T; - parametered_action(std::function const& function) : handler(function) {} - void invoke(const T& arg) const { handler(arg); } + bool expects_parameter() const override { return true; } + + void invoke() const override { + throw std::runtime_error("Parametered action requires a parameter"); + } + + void invoke_with_parameter(const std::string& param) const override { + T parsed_value = parsing_traits::parser_trait::parse(param); + invoke(parsed_value); + } + + std::unique_ptr clone() const override { + return std::make_unique>(handler); + } + private: std::function handler; }; - class non_parametered_action { + class non_parametered_action : public action_base { public: - non_parametered_action(std::function const& function) : handler(function) {} + explicit non_parametered_action(std::function const& handler) : handler(handler) {} - void invoke() const { + void invoke() const override { handler(); } + bool expects_parameter() const override { return false; } + + void invoke_with_parameter(const std::string& param) const override { + invoke(); + } + + std::unique_ptr clone() const override { + return std::make_unique(handler); + } + private: std::function handler; }; - using action_variant = std::variant< - non_parametered_action, - parametered_action, - parametered_action, - parametered_action, - parametered_action - >; - class base_parser; class argument { public: - argument() : id(0), name(), required(false), invoked(false), action(non_parametered_action([](){})) {} + argument() : id(0), name(), required(false), invoked(false), action(std::make_unique([](){})) {} template argument(int id, std::string const& name, ActionType const& action) - : id(id), name(name), action(action), required(false), invoked(false) {} + : id(id), name(name), action(action.clone()), required(false), invoked(false) {} + + argument(const argument& other) + : id(other.id), name(other.name), action(other.action->clone()), + required(other.required), invoked(other.invoked), help_text(other.help_text) {} + + argument& operator=(const argument& other) { + if (this != &other) { + id = other.id; + name = other.name; + action = other.action->clone(); + required = other.required; + invoked = other.invoked; + help_text = other.help_text; + } + return *this; + } + + argument(argument&& other) noexcept = default; + argument& operator=(argument&& other) noexcept = default; bool is_required() const { return required; } std::string get_name() const { return name; } bool is_invoked() const { return invoked; } bool expects_parameter() const { - return !std::holds_alternative(action); + return action->expects_parameter(); } private: @@ -81,7 +123,7 @@ namespace argument_parser { int id; std::string name; - action_variant action; + std::unique_ptr action; bool required; bool invoked; std::string help_text; @@ -138,24 +180,15 @@ namespace argument_parser { try { argument& corresponding_argument = get_argument(extracted); - std::visit([&](auto&& action) { - using ActionType = std::decay_t; - - if constexpr (std::is_same_v) { - action.invoke(); - } else { - if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) { - throw std::runtime_error("expected value for argument " + extracted.second); - } - auto value_raw = convention_type->requires_next_token() ? *(++it) : convention_type->extract_value(*it); - - using ParamType = typename ActionType::parameter_type; - - auto value = parsing_traits::parser_trait::parse(value_raw); - - action.invoke(value); + if (corresponding_argument.expects_parameter()) { + if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) { + throw std::runtime_error("expected value for argument " + extracted.second); } - }, corresponding_argument.action); + auto value_raw = convention_type->requires_next_token() ? *(++it) : convention_type->extract_value(*it); + corresponding_argument.action->invoke_with_parameter(value_raw); + } else { + corresponding_argument.action->invoke(); + } corresponding_argument.set_invoked(true); arg_correctly_handled = true; diff --git a/src/main.cpp b/src/main.cpp index 02d8af4..d6582b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,9 @@ -#include "argument_parser.hpp" -#include "fake_parser.hpp" #include #include #include #include #include #include -#include using namespace argument_parser::conventions; @@ -108,8 +105,9 @@ auto make_grep_action(argument_parser::base_parser& parser) { } int main() { - std::vector fake_args = { "-g", "add", "-f", "src/main.cpp", "-ep", "1,2" }; - auto parser = argument_parser::fake_parser{"test", std::move(fake_args)}; + // std::vector fake_args = { "-g", "add", "-f", "src/main.cpp", "-ep", "1,2" }; + // auto parser = argument_parser::fake_parser{"test", std::move(fake_args)}; + auto parser = argument_parser::parser{}; auto [file, grep] = make_grep_action(parser); parser.add_argument("e", "echo", "echoes given variable", echo, false); parser.add_argument("ep", "echo-point", "echoes given point", echo_point, false);