7 #include "arg_router/parsing/unknown_argument_handling.hpp"
8 #include "arg_router/policy/description.hpp"
9 #include "arg_router/policy/error_name.hpp"
10 #include "arg_router/policy/multi_stage_value.hpp"
11 #include "arg_router/policy/no_result_value.hpp"
12 #include "arg_router/policy/none_name.hpp"
13 #include "arg_router/tree_node.hpp"
14 #include "arg_router/utility/string_to_policy.hpp"
15 #include "arg_router/utility/tree_recursor.hpp"
23 template <
typename... Params>
24 class add_anonymous_error_name_to_mode
26 using params_tuple = std::tuple<std::decay_t<Params>...>;
27 using policies_tuple = boost::mp11::mp_remove_if<params_tuple, is_tree_node>;
30 constexpr
static auto has_none_or_error_name =
31 (boost::mp11::mp_find_if<policies_tuple, traits::has_none_name_method>::value !=
32 std::tuple_size_v<policies_tuple>) ||
33 (boost::mp11::mp_find_if<policies_tuple, traits::has_error_name_method>::value !=
34 std::tuple_size_v<policies_tuple>);
36 using error_name_type = policy::error_name_t<AR_STRING(
"(Anon mode)")>;
38 using type = std::conditional_t<
39 has_none_or_error_name,
40 boost::mp11::mp_rename<params_tuple, tree_node>,
41 boost::mp11::mp_rename<boost::mp11::mp_push_front<params_tuple, error_name_type>,
55 template <
typename... Params>
57 public detail::add_anonymous_error_name_to_mode<policy::no_result_value<>,
58 std::decay_t<Params>...>::type
60 using add_missing_error_name_type =
61 detail::add_anonymous_error_name_to_mode<policy::no_result_value<>,
62 std::decay_t<Params>...>;
63 using parent_type =
typename add_missing_error_name_type::type;
65 static_assert((std::tuple_size_v<typename mode_t::children_type> > 0),
66 "Mode must have at least one child node");
67 static_assert(!traits::has_long_name_method_v<mode_t>,
"Mode must not have a long name policy");
68 static_assert(!traits::has_short_name_method_v<mode_t>,
69 "Mode must not have a short name policy");
70 static_assert(!traits::has_display_name_method_v<mode_t>,
71 "Mode must not have a display name policy");
77 using is_skip_tag = std::is_same<std::decay_t<T>, skip_tag>;
80 constexpr
static bool is_skip_tag_v = is_skip_tag<T>::value;
83 using optional_value_type_or_skip = boost::mp11::mp_eval_if_c<
84 policy::has_no_result_value_v<T>,
88 boost::mp11::mp_bind<traits::get_value_type, boost::mp11::_1>>::template fn,
91 template <
typename Child>
95 using typename parent_type::policies_type;
96 using typename parent_type::children_type;
101 boost::mp11::mp_remove_if<children_type, policy::has_no_result_value>>;
104 constexpr
static bool is_anonymous = !traits::has_none_name_method_v<mode_t>;
106 static_assert(!
is_anonymous || !traits::has_description_method_v<mode_t>,
107 "Anonymous modes cannot have a description policy");
109 "Named modes must not have an error name policy");
112 template <
bool Flatten>
119 using label = std::conditional_t<
122 typename parent_type::template default_leaf_help_data_type<Flatten>::label>;
125 typename parent_type::template default_leaf_help_data_type<Flatten>::description;
127 using children = std::conditional_t<
129 typename parent_type::template default_leaf_help_data_type<Flatten>::all_children_help,
132 template <
typename OwnerNode,
typename FilterFn>
137 return parent_type::template default_leaf_help_data_type<true>::runtime_children(
139 std::forward<FilterFn>(f));
150 template <auto has_none_or_error_name = add_missing_error_name_type::has_none_or_error_name>
151 constexpr
explicit mode_t(Params... params,
153 std::enable_if_t<has_none_or_error_name>* =
nullptr) noexcept :
158 template <auto has_none_or_error_name = add_missing_error_name_type::has_none_or_error_name>
159 constexpr
explicit mode_t(Params... params,
161 std::enable_if_t<!has_none_or_error_name>* =
nullptr) noexcept :
162 parent_type{
typename add_missing_error_name_type::error_name_type{},
163 policy::no_result_value<>{},
164 std::move(params)...}
183 template <
typename Validator,
bool HasTarget,
typename... Parents>
184 [[nodiscard]] std::optional<parsing::parse_target>
pre_parse(
186 const Parents&... parents)
const
189 [&](
auto&&... ancestors) {
return pre_parse_impl(pre_parse_data, ancestors.get()...); },
203 template <
typename... Parents>
207 [&](
auto&&... ancestors) {
return parse_impl(target, ancestors.get()...); },
212 static_assert(!
is_anonymous || boost::mp11::mp_none_of<children_type, is_child_mode>::value,
213 "Anonymous mode cannot have a child mode");
215 static_assert(!parent_type::template any_phases_v<
value_type,
219 "Mode does not support policies with parse, validation, or missing phases; as it "
220 "delegates those to its children");
222 template <
typename Child>
223 struct child_has_routing_phase {
224 using type =
typename Child::template phase_finder_t<policy::has_routing_phase_method>;
226 constexpr
static bool value = !std::is_void_v<type>;
228 static_assert(boost::mp11::mp_none_of<boost::mp11::mp_remove_if<children_type, is_child_mode>,
229 child_has_routing_phase>::value,
230 "Non-mode children cannot have routing");
232 template <
typename Validator,
bool HasTarget,
typename DerivedMode,
typename... Parents>
233 [[nodiscard]] std::optional<parsing::parse_target> pre_parse_impl(
234 parsing::pre_parse_data<Validator, HasTarget> pre_parse_data,
235 const DerivedMode& this_mode,
236 const Parents&... parents)
const
238 using namespace utility::string_view_ops;
239 using namespace std::string_literals;
241 static_assert(!HasTarget,
242 "Modes cannot receive pre_parse_data containing parent "
244 static_assert(!
is_anonymous || (
sizeof...(Parents) <= 1),
245 "Anonymous modes can only exist under the root");
247 auto& args = pre_parse_data.args();
252 auto match = parent_type::pre_parse(pre_parse_data, this_mode, parents...);
261 [&](
auto ,
const auto& child) {
262 using child_type = std::decay_t<decltype(child)>;
263 if constexpr (traits::is_specialisation_of_v<child_type, mode_t>) {
265 match = child.pre_parse(pre_parse_data, this_mode, parents...);
276 if (!pre_parse_data.validator()(this_mode, parents...)) {
280 auto target = parsing::parse_target{this_mode, parents...};
284 auto matched = std::bitset<std::tuple_size_v<children_type>>{};
285 while (!args.empty()) {
287 const auto front_token = args.front();
289 auto match = std::optional<parsing::parse_target>{};
291 [&]([[maybe_unused]]
auto i,
const auto& child) {
292 using child_type = std::decay_t<decltype(child)>;
300 if constexpr (!traits::is_specialisation_of_v<child_type, mode_t>) {
301 match = child.pre_parse(
302 parsing::pre_parse_data{
305 [&](
const auto& real_child,
const auto&...) {
306 using real_child_type = std::decay_t<decltype(real_child)>;
307 return verify_match<real_child_type>(matched[i], front_token);
328 if (
match->sub_targets().empty()) {
329 target.add_sub_target(std::move(*match));
331 for (
auto& sub_target :
match->sub_targets()) {
332 target.add_sub_target(std::move(sub_target));
340 template <
typename DerivedMode,
typename... Parents>
341 void parse_impl(parsing::parse_target target,
342 const DerivedMode& this_mode,
343 const Parents&... parents)
const
348 using results_type = boost::mp11::mp_transform<optional_value_type_or_skip, children_type>;
349 auto results = results_type{};
351 for (
auto& sub_target : target.sub_targets()) {
352 const auto node_hash = sub_target.node_type();
353 auto result = sub_target();
355 if (result.has_value()) {
361 [&](
auto i,
const auto& child) {
366 match_child(child, node_hash, [&](
const auto& sub_child) {
368 process_result<i>(results, result, sub_child);
377 [&]([[maybe_unused]]
auto i,
auto& result) {
378 if constexpr (!is_skip_tag_v<std::decay_t<decltype(result)>>) {
380 const auto& child = std::get<i>(this->children());
381 process_missing_token(result, child, this_mode, parents...);
391 multi_stage_validation(results, this_mode, parents...);
394 using routing_policy =
395 typename parent_type::template phase_finder_t<policy::has_routing_phase_method>;
396 if constexpr (!std::is_void_v<routing_policy>) {
399 boost::mp11::mp_not_fn<is_skip_tag>::template fn>(std::move(results));
402 [&](
auto&&... args) {
403 this->routing_phase(std::forward<std::decay_t<decltype(*args)>>(*args)...);
405 std::move(stripped_results));
407 static_assert(traits::always_false_v<Params...>,
"Anonymous modes must have routing");
408 }
else if constexpr (!boost::mp11::mp_all_of<children_type, is_child_mode>::value) {
409 static_assert(traits::always_false_v<Params...>,
410 "Mode must have a router or all its children are modes");
414 parsing::node_token_type<mode_t>()};
418 template <
typename Child,
typename Handler>
419 static void match_child(
const Child& child, std::size_t hash, Handler handler)
423 [&](
const auto& node,
const auto&...) {
424 using node_type = std::decay_t<decltype(node)>;
428 if constexpr (!traits::is_specialisation_of_v<node_type, mode_t> &&
429 traits::has_parse_method_v<node_type>) {
430 if (!found && (utility::type_hash<node_type>() == hash)) {
439 template <
typename Child>
440 [[nodiscard]]
static bool verify_match(
bool already_matched,
441 [[maybe_unused]] parsing::token_type token)
443 if constexpr (!Child::is_named && !policy::has_multi_stage_value_v<Child>) {
446 return !already_matched;
447 }
else if constexpr (Child::is_named && !policy::has_multi_stage_value_v<Child>) {
450 if (already_matched) {
461 template <std::
size_t I,
typename ResultsType,
typename ChildType>
462 void process_result(ResultsType& results,
464 const ChildType& child)
const
466 using optional_result_type = std::tuple_element_t<I, ResultsType>;
469 if constexpr (!is_skip_tag_v<optional_result_type>) {
470 auto& result = std::get<I>(results);
472 if constexpr (policy::has_multi_stage_value_v<ChildType>) {
474 child.merge(result, std::move(parse_result.get<result_type>()));
478 parsing::node_token_type<ChildType>()};
481 using result_type = decltype(std::declval<ChildType>().
parse(
482 std::declval<parsing::parse_target>()));
483 result = std::move(parse_result.get<result_type>());
489 # pragma warning(push)
490 # pragma warning(disable : 4702)
492 template <
typename ValueType,
typename ChildType,
typename... Parents>
493 void process_missing_token(std::optional<ValueType>& result,
494 const ChildType& child,
495 const Parents&... parents)
const
497 utility::tuple_type_iterator<typename ChildType::policies_type>([&](
auto i) {
498 using policy_type = std::tuple_element_t<i, typename ChildType::policies_type>;
499 if constexpr (policy::has_missing_phase_method_v<policy_type, ValueType>) {
500 result = child.policy_type::template missing_phase<ValueType>(child, parents...);
504 # pragma warning(pop)
511 result = ValueType{};
515 utility::tuple_type_iterator<typename ChildType::policies_type>([&](
auto i) {
516 using policy_type = std::tuple_element_t<i, typename ChildType::policies_type>;
517 if constexpr (policy::has_validation_phase_method_v<policy_type, ValueType>) {
518 child.policy_type::template validation_phase(*result, child, parents...);
523 template <
typename ResultsType,
typename... Parents>
524 void multi_stage_validation(
const ResultsType& results,
const Parents&... parents)
const
529 [&](
auto i,
const auto& child) {
530 using child_type = std::decay_t<decltype(child)>;
531 using child_policies_type =
typename child_type::policies_type;
532 using optional_result_type = std::tuple_element_t<i, ResultsType>;
534 constexpr
auto msv = policy::has_multi_stage_value_v<child_type> ||
535 boost::mp11::mp_any_of<
typename child_type::children_type,
536 policy::has_multi_stage_value>::value;
538 if constexpr (!is_skip_tag_v<optional_result_type> && msv) {
539 using result_type =
typename optional_result_type::value_type;
540 const auto& result = *std::get<i>(results);
542 utility::tuple_type_iterator<child_policies_type>([&](
auto j) {
543 using policy_type = std::tuple_element_t<j, child_policies_type>;
544 if constexpr (policy::has_validation_phase_method_v<policy_type,
546 child.policy_type::template validation_phase(result, child, parents...);
569 template <
typename... Params>
570 constexpr
auto mode(Params... params)
573 [](
auto... converted_params) {
574 return mode_t<std::decay_t<decltype(converted_params)>...>{
575 std::move(converted_params)...};
580 std::move(params)...));
void parse(parsing::parse_target target, const Parents &... parents) const
std::optional< parsing::parse_target > pre_parse(parsing::pre_parse_data< Validator, HasTarget > pre_parse_data, const Parents &... parents) const
constexpr static bool is_anonymous
boost::mp11::mp_transform< traits::get_value_type, boost::mp11::mp_remove_if< children_type, policy::has_no_result_value > > value_type
constexpr mode_t(Params... params, std::enable_if_t< has_none_or_error_name > *=nullptr) noexcept
constexpr auto tuple_filter_and_construct(U &&input) noexcept
void unknown_argument_exception(const Node &node, token_type unknown_token)
constexpr bool match(token_type token) noexcept
constexpr auto clean_node_ancestry_list(const BaseNode &base_node, const DerivedAndParents &... derived_and_parents)
typename add_optional< T >::type add_optional_t
typename T::value_type get_value_type
std::tuple_element_t< I+1, arg_extractor_t< T > > arg_type_at_index
constexpr auto convert(Params &&... params) noexcept
constexpr void tree_recursor(Visitor visitor, const Root &root)
constexpr std::enable_if_t< traits::is_tuple_like_v< std::decay_t< Tuple > > > tuple_iterator(F &&f, Tuple &&tuple)
unsafe_any_t< sizeof(std::string_view)> unsafe_any
std::vector< T, config::allocator< T > > vector
@ argument_has_already_been_set
@ mode_requires_arguments
constexpr auto mode(Params... params)