1
0

feat: finish clap parser basic layout

This commit is contained in:
2025-12-08 15:16:28 +08:00
parent 8b7ab2c870
commit eb9e576d33
7 changed files with 160 additions and 3 deletions

View File

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

View File

@ -0,0 +1,3 @@
#include "parser.hpp"
namespace yycc::carton::clap::parser {}

View File

@ -0,0 +1,5 @@
#pragma once
namespace yycc::carton::clap::parser {
}

View File

@ -0,0 +1,81 @@
#include "resolver.hpp"
#include "types.hpp"
#include <string_view>
#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<TYPES::Token> 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<bool> Parser::get_flag_option(TYPES::Token token) const {
// TODO:
return TYPES::ClapResult<bool>();
}
TYPES::ClapResult<std::u8string_view> Parser::get_raw_value_option(TYPES::Token token) const {
// TODO:
return TYPES::ClapResult<std::u8string_view>();
}
#pragma endregion
} // namespace yycc::carton::clap::resolver

View File

@ -0,0 +1,53 @@
#pragma once
#include "../../macro/class_copy_move.hpp"
#include "application.hpp"
#include "validator.hpp"
#include <map>
#include <optional>
#include <string>
#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<std::u8string_view> 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<bool> get_flag_option(NS_YYCC_CLAP_TYPES::Token token) const;
template<NS_YYCC_CLAP_VALIDATOR::Validator T>
NS_YYCC_CLAP_TYPES::ClapResult<NS_YYCC_CLAP_VALIDATOR::ValidatorReturnType<T>> 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<NS_YYCC_CLAP_TYPES::Token, std::optional<std::u8string>> values;
};
} // namespace yycc::carton::clap::resolver
#undef NS_YYCC_CLAP_TYPES

View File

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

View File

@ -19,17 +19,23 @@ namespace yycc::carton::clap::validator {
* And, it also should have an member function called "validate"
* which receive <TT>const std::string_view&</TT> as its only argument,
* and return <TT>std::optional<ReturnType></TT> 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<typename T>
concept Validator = requires(const T& t, const std::u8string_view& sv) {
concept Validator = std::default_initializable<T> && 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<std::optional<typename T::ReturnType>>;
};
/// @brief A convenient alias to the return type of validator.
template<Validator T>
using ValidatorReturnType = T::ReturnType;
template<std::integral T, auto TMin = std::numeric_limits<T>::min(), auto TMax = std::numeric_limits<T>::max()>
struct IntegralValidator {
static_assert(TMin <= TMax);