diff --git a/include/ctre/actions/options.inc.hpp b/include/ctre/actions/options.inc.hpp index 93ef48ac..5684d464 100644 --- a/include/ctre/actions/options.inc.hpp +++ b/include/ctre/actions/options.inc.hpp @@ -13,13 +13,33 @@ template <typename Parameters> static constexpr auto apply(pcre::push_empty, ctl // make_alternate (A|B) template <auto V, typename A, typename B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<B, A, Ts...>, Parameters> subject) { - return pcre_context{ctll::push_front(select<A,B>(), ctll::list<Ts...>()), subject.parameters}; + if constexpr (MatchesCharacter<A>::template value<char32_t> && MatchesCharacter<B>::template value<char32_t>) { + auto new_set = push_front_into_set(A{}, B{}); + return pcre_context{ ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters }; + } else { + return pcre_context{ ctll::push_front(select<A,B>(), ctll::list<Ts...>()), subject.parameters }; + } } + // make_alternate (As..)|B => (As..|B) -template <auto V, typename A, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<ctre::select<Bs...>, A, Ts...>, Parameters> subject) { - return pcre_context{ctll::push_front(select<A,Bs...>(), ctll::list<Ts...>()), subject.parameters}; +template <auto V, typename A, typename B, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<ctre::select<B, Bs...>, A, Ts...>, Parameters> subject) { + if constexpr (MatchesCharacter<A>::template value<char32_t> && MatchesCharacter<B>::template value<char32_t>) { + auto new_set = push_front_into_set(A{}, B{}); + return pcre_context{ ctll::push_front(select<decltype(new_set),Bs...>(), ctll::list<Ts...>()), subject.parameters }; + } else { + return pcre_context{ ctll::push_front(select<A,B,Bs...>(), ctll::list<Ts...>()), subject.parameters }; + } } +// make_alternate [As..]|B => ([As..]|B) +template <auto V, typename A, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<ctre::set<Bs...>, A, Ts...>, Parameters> subject) { + if constexpr (MatchesCharacter<A>::template value<char32_t>) { + auto new_set = push_front_into_set(A{}, ctre::set<Bs...>{}); + return pcre_context{ ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters }; + } else { + return pcre_context{ ctll::push_front(select<A, ctre::set<Bs...>>(), ctll::list<Ts...>()), subject.parameters }; + } +} // make_optional template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) { diff --git a/include/ctre/actions/set.inc.hpp b/include/ctre/actions/set.inc.hpp index a5a08d14..05d5280a 100644 --- a/include/ctre/actions/set.inc.hpp +++ b/include/ctre/actions/set.inc.hpp @@ -4,7 +4,53 @@ // UTILITY // add into set if not exists template <template <typename...> typename SetType, typename T, typename... As, bool Exists = (std::is_same_v<T, As> || ... || false)> static constexpr auto push_back_into_set(T, SetType<As...>) -> ctll::conditional<Exists, SetType<As...>, SetType<As...,T>> { return {}; } +template <template <typename...> typename SetType, typename T, typename... As, bool Exists = (std::is_same_v<T, As> || ... || false)> static constexpr auto push_front_into_set(T, SetType<As...>) -> ctll::conditional<Exists, SetType<As...>, SetType<T, As...>> { return {}; } +// merge two sets +template<typename B, typename... As> +static constexpr auto push_back_into_set(B, ctre::set<As...>) { + return push_back_into_set<ctre::set>(B{}, ctre::set<As...>{}); +} + +template<typename B, typename... As> +static constexpr auto push_back_into_set(ctre::set<As...>, B) { + return push_back_into_set<ctre::set>(B{}, ctre::set<As...>{}); +} + +template<typename B, typename... Bs, typename... As> +static constexpr auto push_back_into_set(ctre::set<B, Bs...>, ctre::set<As...>) { + if constexpr (sizeof...(Bs) == 0) + return push_back_into_set<ctre::set>(B{}, ctre::set<As...>{}); + else + return push_back_into_set(ctre::set<Bs...>{}, push_back_into_set<ctre::set>(B{}, ctre::set<As...>{})); +} + +template<typename A, typename B> +static constexpr auto push_back_into_set(A, B) { + return push_back_into_set(A{}, ctre::set<B>{}); +} +template<typename B, typename... As> +static constexpr auto push_front_into_set(B, ctre::set<As...>) { + return push_front_into_set<ctre::set>(B{}, ctre::set<As...>{}); +} + +template<typename B, typename... As> +static constexpr auto push_front_into_set(ctre::set<As...>, B) { + return push_front_into_set(ctre::set<As...>{}, ctre::set<B>{}); +} + +template<typename B, typename... Bs, typename... As> +static constexpr auto push_front_into_set(ctre::set<Bs..., B>, ctre::set<As...>) { + if constexpr (sizeof...(Bs) == 0) + return push_front_into_set<ctre::set>(B{}, ctre::set<As...>{}); + else + return push_front_into_set(ctre::set<Bs...>{}, push_front_into_set<ctre::set>(B{}, ctre::set<As...>{})); +} + +template<typename A, typename B> +static constexpr auto push_front_into_set(A, B) { + return push_front_into_set(A{}, ctre::set<B>{}); +} //template <template <typename...> typename SetType, typename A, typename BHead, typename... Bs> struct set_merge_helper { // using step = decltype(push_back_into_set<SetType>(BHead(), A())); // using type = ctll::conditional<(sizeof...(Bs) > 0), set_merge_helper<SetType, step, Bs...>, step>; diff --git a/tests/generating.cpp b/tests/generating.cpp index ee6cf80c..2cc95e0e 100644 --- a/tests/generating.cpp +++ b/tests/generating.cpp @@ -99,8 +99,8 @@ static_assert(same_f(CTRE_GEN("[\\x30-\\x39]"), ctre::set<ctre::char_range<'\x30 // alternation static_assert(same_f(CTRE_GEN("(?:abc|def)"), ctre::select<ctre::string<'a','b','c'>,ctre::string<'d','e','f'>>())); static_assert(same_f(CTRE_GEN("(?:abc|def|ghi)"), ctre::select<ctre::string<'a','b','c'>,ctre::string<'d','e','f'>,ctre::string<'g','h','i'>>())); -static_assert(same_f(CTRE_GEN("(?:a|b|c|d)"), ctre::select<ctre::character<'a'>,ctre::character<'b'>,ctre::character<'c'>,ctre::character<'d'>>())); -static_assert(same_f(CTRE_GEN("(?:a|b|c|)"), ctre::select<ctre::character<'a'>,ctre::character<'b'>,ctre::character<'c'>,ctre::empty>())); +static_assert(same_f(CTRE_GEN("(?:a|b|c|d)"), ctre::set<ctre::character<'a'>,ctre::character<'b'>,ctre::character<'c'>,ctre::character<'d'>>())); +static_assert(same_f(CTRE_GEN("(?:a|b|c|)"), ctre::select<ctre::set<ctre::character<'a'>,ctre::character<'b'>,ctre::character<'c'>>,ctre::empty>())); // optional static_assert(same_f(CTRE_GEN("xx?"), ctre::sequence<ctre::character<'x'>,ctre::optional<ctre::character<'x'>>>())); @@ -197,7 +197,7 @@ static_assert(same_f(CTRE_GEN("(x[cd])(ab)+"), ctre::sequence<ctre::capture<1,ct static_assert(same_f(CTRE_GEN("(?<n>x)"), ctre::capture_with_name<1,ctre::id<'n'>,ctre::character<'x'>>())); static_assert(same_f(CTRE_GEN("(?<name>x)"), ctre::capture_with_name<1,ctre::id<'n','a','m','e'>,ctre::character<'x'>>())); static_assert(same_f(CTRE_GEN("(?<name>xy)"), ctre::capture_with_name<1,ctre::id<'n','a','m','e'>,ctre::string<'x','y'>>())); -static_assert(same_f(CTRE_GEN("(?<name>x|y)"), ctre::capture_with_name<1,ctre::id<'n','a','m','e'>,ctre::select<ctre::character<'x'>,ctre::character<'y'>>>())); +static_assert(same_f(CTRE_GEN("(?<name>x|y)"), ctre::capture_with_name<1,ctre::id<'n','a','m','e'>,ctre::set<ctre::character<'x'>,ctre::character<'y'>>>())); static_assert(same_f(CTRE_GEN("(?<xy>[x]y)"), ctre::capture_with_name<1,ctre::id<'x','y'>,ctre::set<ctre::character<'x'>>,ctre::character<'y'>>())); static_assert(same_f(CTRE_GEN("(?<xy>[x]y)(a)"), ctre::sequence<ctre::capture_with_name<1,ctre::id<'x','y'>,ctre::set<ctre::character<'x'>>,ctre::character<'y'>>, ctre::capture<2,ctre::character<'a'>>>()));