diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 479f8d2..c716c96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,8 @@ PRIVATE yycc/carton/clap/summary.cpp yycc/carton/clap/application.cpp yycc/carton/clap/manual.cpp + yycc/carton/clap/parser.cpp + yycc/carton/clap/resolver.cpp ) target_sources(YYCCommonplace PUBLIC @@ -97,6 +99,8 @@ FILES yycc/carton/clap/application.hpp yycc/carton/clap/manual.hpp yycc/carton/clap/validator.hpp + yycc/carton/clap/parser.hpp + yycc/carton/clap/resolver.hpp yycc/carton/fft.hpp ) # Setup header infomations diff --git a/src/yycc/carton/clap/parser.cpp b/src/yycc/carton/clap/parser.cpp new file mode 100644 index 0000000..4102d21 --- /dev/null +++ b/src/yycc/carton/clap/parser.cpp @@ -0,0 +1,3 @@ +#include "parser.hpp" + +namespace yycc::carton::clap::parser {} diff --git a/src/yycc/carton/clap/parser.hpp b/src/yycc/carton/clap/parser.hpp new file mode 100644 index 0000000..9446226 --- /dev/null +++ b/src/yycc/carton/clap/parser.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace yycc::carton::clap::parser { + +} diff --git a/src/yycc/carton/clap/resolver.cpp b/src/yycc/carton/clap/resolver.cpp new file mode 100644 index 0000000..6bfd614 --- /dev/null +++ b/src/yycc/carton/clap/resolver.cpp @@ -0,0 +1,81 @@ +#include "resolver.hpp" +#include "types.hpp" +#include + +#define TYPES ::yycc::carton::clap::types + +namespace yycc::carton::clap::resolver { + +#pragma region Misc + + /// @brief The states of parser internal state machine. + enum class ParserState { + Normal, ///< Normal state. Expect an option. + WaitingValue, ///< Waiting an associated value. + }; + /// @brief The state machine context prepared for parser. + struct ParserContext { + ParserContext() : state(ParserState::Normal), opt_waiting(std::nullopt) {} + YYCC_DEFAULT_COPY_MOVE(ParserContext) + + ParserState state; ///< Current state. + std::optional opt_waiting; ///< The token to the option waiting for associated value. + }; + + /// @brief The kind of argument. + enum class ArgumentKind { LongName, ShortName, Value }; + /// @brief Representing a classified argument. + struct ClassifiedArgument { + ClassifiedArgument(const std::u8string_view& arg) { + if (arg.starts_with(TYPES::DOUBLE_DASH)) { + kind = ArgumentKind::LongName; + content = arg.substr(TYPES::DOUBLE_DASH.length()); + } else if (arg.starts_with(TYPES::DASH)) { + kind = ArgumentKind::ShortName; + content = arg.substr(TYPES::DASH.length()); + } else { + kind = ArgumentKind::Value; + content = arg; + } + } + YYCC_DEFAULT_COPY_MOVE(ClassifiedArgument) + + /// @brief The kind of argument. + ArgumentKind kind; + /** + * @brief The data of argument. + * @details For long and short name, it is the body of option, the words removing any leading dash. + * For value, it just the value self. + */ + std::u8string_view content; + }; + +#pragma endregion + +#pragma region Core + +#pragma endregion + +#pragma region Parser Class + + Parser::Parser(const NS_YYCC_CLAP_APPLICATION::Application& app) {} + + Parser::~Parser() {} + + bool Parser::has_option(TYPES::Token token) const { + // TODO: + return false; + } + + TYPES::ClapResult Parser::get_flag_option(TYPES::Token token) const { + // TODO: + return TYPES::ClapResult(); + } + + TYPES::ClapResult Parser::get_raw_value_option(TYPES::Token token) const { + // TODO: + return TYPES::ClapResult(); + } +#pragma endregion + +} // namespace yycc::carton::clap::resolver diff --git a/src/yycc/carton/clap/resolver.hpp b/src/yycc/carton/clap/resolver.hpp new file mode 100644 index 0000000..50488b8 --- /dev/null +++ b/src/yycc/carton/clap/resolver.hpp @@ -0,0 +1,53 @@ +#pragma once +#include "../../macro/class_copy_move.hpp" +#include "application.hpp" +#include "validator.hpp" +#include +#include +#include + +#define NS_YYCC_CLAP_TYPES ::yycc::carton::clap::types +#define NS_YYCC_CLAP_APPLICATION ::yycc::carton::clap::application +#define NS_YYCC_CLAP_VALIDATOR ::yycc::carton::clap::validator + +namespace yycc::carton::clap::resolver { + + class Parser { + public: + Parser(const NS_YYCC_CLAP_APPLICATION::Application& app); + ~Parser(); + YYCC_DEFAULT_COPY_MOVE(Parser) + + private: + NS_YYCC_CLAP_TYPES::ClapResult get_raw_value_option(NS_YYCC_CLAP_TYPES::Token token) const; + + public: + bool has_option(NS_YYCC_CLAP_TYPES::Token token) const; + NS_YYCC_CLAP_TYPES::ClapResult get_flag_option(NS_YYCC_CLAP_TYPES::Token token) const; + template + NS_YYCC_CLAP_TYPES::ClapResult> get_value_option( + NS_YYCC_CLAP_TYPES::Token token) const { + auto raw_value = this->get_raw_value_option(token); + if (raw_value.has_value()) { + T validator{}; + auto value = validator.validate(raw_value.value()); + if (value.has_value()) return value.value(); + else return std::unexpected(NS_YYCC_CLAP_TYPES::ClapError::BadCast); + } else { + return std::unexpected(raw_value.error()) + } + } + + private: + /** + * @brief All captured commandline argument. + * @details Key is the token to already registered option. + * Value is the associated value for key token. + * If it is no-value option, the value will be \c std::nullopt. + */ + std::map> values; + }; + +} // namespace yycc::carton::clap::resolver + +#undef NS_YYCC_CLAP_TYPES diff --git a/src/yycc/carton/clap/types.hpp b/src/yycc/carton/clap/types.hpp index 0d6f1b8..edaa891 100644 --- a/src/yycc/carton/clap/types.hpp +++ b/src/yycc/carton/clap/types.hpp @@ -6,7 +6,12 @@ namespace yycc::carton::clap::types { /// @brief All possible error kind occurs in this module. enum class ClapError { - + InvalidName, ///< When parsing commandline argument, given option name is invalid. + DuplicatedAssign, ///< When parsing commandline argument, multiple assign for a single option. + UnexpectedValue, ///< When parsing commandline argument, reach associated value unexpected. + LostValue, ///< When parsing commandline argument, fail to find associated value. + NotCaptured, ///< When fetching option or variable, given option or variable is not captured. + BadCast ///< When fetching option or variable, the content of given option or variable can not be cast into expected type. }; /// @brief The result type used in this module. diff --git a/src/yycc/carton/clap/validator.hpp b/src/yycc/carton/clap/validator.hpp index 0946b14..d5ca76d 100644 --- a/src/yycc/carton/clap/validator.hpp +++ b/src/yycc/carton/clap/validator.hpp @@ -19,17 +19,23 @@ namespace yycc::carton::clap::validator { * And, it also should have an member function called "validate" * which receive const std::string_view& as its only argument, * and return std::optional as result. - * If this \t std::optional is empty, it means that there is some error occurs when validating, + * If this \c std::optional is empty, it means that there is some error occurs when validating, * otherwise, it is the validated value. + * + * Finally, it must can be default initialized. */ template - concept Validator = requires(const T& t, const std::u8string_view& sv) { + concept Validator = std::default_initializable && requires(const T& t, const std::u8string_view& sv) { // Check whether there is T::ReturnType type typename T::ReturnType; // Check whether there is "validate" member function and it has correct signature. { t.validate(sv) } -> std::same_as>; }; + /// @brief A convenient alias to the return type of validator. + template + using ValidatorReturnType = T::ReturnType; + template::min(), auto TMax = std::numeric_limits::max()> struct IntegralValidator { static_assert(TMin <= TMax);