Skip to content

[WIP] Reset Groups #163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions include/ctre/actions/capture.inc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,145 @@ template <auto... Str, auto V, typename... Content, size_t Id, typename... Ts, s
return pcre_context{ctll::push_front(capture_with_name<Id, id<Str...>, Content...>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
}

template<size_t To, auto... Str, typename T>
static constexpr auto replace_captures_with_id(T, string<Str...>) { // fallback case, no transform
return T{};
}

template<size_t To, auto... Str, size_t From, typename... Content>
static constexpr auto replace_captures_with_id(capture<From, Content...>, string<Str...>) {
return capture<To, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}
// named reseted captures must have same Str... for all instances inside the call (otherwise how would we know how to access which by name?)
template<size_t To, auto... Str, size_t From, auto... Str2, typename... Content>
static constexpr auto replace_captures_with_id(capture_with_name<From, id<Str2...>, Content...>, string<Str...>) {
static_assert((id<Str...>{} == id<Str2...>{}) && "named captures must be named the same in reset group");
return capture_with_name<To, id<Str...>, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, typename... Content>
static constexpr auto replace_captures_with_id(sequence<Content...>, string<Str...>) {
return sequence<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, size_t Id, typename... Content>
static constexpr auto replace_captures_with_id(reset_group<Id, Content...>, string<Str...>) {
return reset_group<To, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, size_t Id, auto... Str2, typename... Content>
static constexpr auto replace_captures_with_id(reset_group_with_name<Id, id<Str2...>, Content...>, string<Str...>) {
return reset_group_with_name<To, id<Str...>, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, typename... Content>
static constexpr auto replace_captures_with_id(atomic_group<Content...>, string<Str...>) {
return atomic_group<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, typename... Content>
static constexpr auto replace_captures_with_id(lookahead_positive<Content...>, string<Str...>) {
return lookahead_positive<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, typename... Content>
static constexpr auto replace_captures_with_id(lookahead_negative<Content...>, string<Str...>) {
return lookahead_negative<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, size_t A, size_t B, typename... Content>
static constexpr auto replace_captures_with_id(possessive_repeat<A, B, Content...>, string<Str...>) {
return possessive_repeat<A, B, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, size_t A, size_t B, typename... Content>
static constexpr auto replace_captures_with_id(repeat<A, B, Content...>, string<Str...>) {
return repeat<A, B, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, size_t A, size_t B, typename... Content>
static constexpr auto replace_captures_with_id(lazy_repeat<A, B, Content...>, string<Str...>) {
return lazy_repeat<A, B, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
}

template<size_t To, auto... Str, typename... Opts>
static constexpr auto replace_captures_with_id(select<Opts...>, string<Str...>) {
return select<decltype(replace_captures_with_id<To>(Opts{}, string<Str...>{}))...>{};
}

// get name (might be a utility already written)
template<size_t Idx, auto... Str>
static constexpr string<Str...> get_capture_name(captured_content<Idx, id<Str...>>) noexcept {
return string<Str...>{};
}

template<size_t Idx>
static constexpr string<> get_capture_name(captured_content<Idx>) noexcept {
return string<>{};
}

template<typename T>
static constexpr string<> get_capture_name(T) noexcept {
return string<>{};
}

template<auto... Str>
static constexpr id<Str...> make_id_from_string(string<Str...>) noexcept {
return id<Str...>{};
}

// find the first named capture
template<typename H, typename... Tail>
static constexpr auto get_capture_with_name(ctll::list<H, Tail...>) noexcept {
if constexpr (sizeof...(Tail))
return get_capture_with_name(ctll::list<Tail...>{});
else
return ctll::list<>{};
}

template<size_t Idx, typename Name, typename... Tail>
static constexpr auto get_capture_with_name(ctll::list<captured_content<Idx, Name>, Tail...>) noexcept {
return ctll::list<captured_content<Idx, Name>>{};
}

// reset group start
template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_reset_group, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
return pcre_context{ ctll::push_front(reset_start<Counter+1>(), ctll::list<Ts...>()), pcre_parameters<Counter>() };
}

// reset group end
template <auto V, typename A, typename... Ts, size_t Id, size_t Counter> static constexpr auto apply(pcre::make_reset_group, ctll::term<V>, pcre_context<ctll::list<A, reset_start<Id>, Ts...>, pcre_parameters<Counter>>) {
using first_capture = decltype(ctll::front(find_captures(A{})));
if constexpr (::std::is_same_v<first_capture, ctll::_nothing>) {
//no captures to reset... easy case
return pcre_context{ ctll::list<sequence<A>, Ts...>(), pcre_parameters<Counter>() };
} else {
using first_named_capture = decltype(ctll::front(get_capture_with_name(find_captures(A{}))));
using capture_name = decltype(get_capture_name(first_named_capture{}));
if constexpr (::std::is_same_v<first_named_capture, ctll::_nothing> || ::std::is_same_v<capture_name, string<>>) {
return pcre_context{ ctll::list<reset_group<Id, decltype(replace_captures_with_id<Id>(A{}, string<>{}))>, Ts...>(), pcre_parameters<Counter>() };
} else {
return pcre_context{ ctll::list<reset_group_with_name<Id, decltype(make_id_from_string(capture_name{})), decltype(replace_captures_with_id<Id>(A{}, capture_name{}))>, Ts...>(), pcre_parameters<Counter>() };
}
}
}
// reset group end (sequence)
template <auto V, typename... Content, typename... Ts, size_t Id, size_t Counter> static constexpr auto apply(pcre::make_reset_group, ctll::term<V>, pcre_context<ctll::list<ctre::sequence<Content...>, reset_start<Id>, Ts...>, pcre_parameters<Counter>>) {
using first_capture = decltype(ctll::front(find_captures(sequence<Content...>{})));
if constexpr (::std::is_same_v<first_capture, ctll::_nothing>) {
//no captures to reset... easy case
return pcre_context{ ctll::list<sequence<Content...>, Ts...>(), pcre_parameters<Counter>() };
} else {
using first_named_capture = decltype(ctll::front(get_capture_with_name(find_captures(sequence<Content...>{}))));
using capture_name = decltype(get_capture_name(first_named_capture{}));
if constexpr (::std::is_same_v<first_named_capture, ctll::_nothing> || ::std::is_same_v<capture_name, string<>>) {
return pcre_context{ ctll::list<reset_group<Id, decltype(replace_captures_with_id<Id>(Content{}, string<>{}))...>, Ts...>(), pcre_parameters<Counter>() };
} else {
return pcre_context{ ctll::list<reset_group_with_name<Id, decltype(make_id_from_string(capture_name{})), decltype(replace_captures_with_id<Id>(Content{}, capture_name{}))...>, Ts...>(), pcre_parameters<Counter>() };
}
}
}



#endif
4 changes: 4 additions & 0 deletions include/ctre/atoms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ template <size_t Index, typename... Content> struct capture { };

template <size_t Index, typename Name, typename... Content> struct capture_with_name { };

template <size_t Index, typename... Content> struct reset_group { };
template <size_t Index, typename Name, typename... Content> struct reset_group_with_name { };

template <size_t Index> struct back_reference { };
template <typename Name> struct back_reference_with_name { };

template <size_t Idx> struct reset_start { };
template <typename Type> struct look_start { };

template <typename... Content> struct lookahead_positive { };
Expand Down
10 changes: 10 additions & 0 deletions include/ctre/evaluation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, c
}
}

template <typename R, typename Iterator, typename EndIterator, size_t Id, typename... Content, typename... Tail>
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, const flags & f, R captures, ctll::list<reset_group<Id, Content...>, Tail...>) noexcept {
return evaluate(begin, current, end, f, captures, ctll::list<sequence<Content...>, Tail...>{});
}

template <typename R, typename Iterator, typename EndIterator, size_t Id, typename Name, typename... Content, typename... Tail>
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, const flags& f, R captures, ctll::list<reset_group_with_name<Id, Name, Content...>, Tail...>) noexcept {
return evaluate(begin, current, end, f, captures, ctll::list<sequence<Content...>, Tail...>{});
}

// matching empty in patterns
template <typename R, typename Iterator, typename EndIterator, typename... Tail>
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, const flags & f, R captures, ctll::list<empty, Tail...>) noexcept {
Expand Down
7 changes: 7 additions & 0 deletions include/ctre/find_captures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ template <size_t Id, typename Name, typename... Content, typename... Tail, typen
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id, Name>>());
}

template <size_t Id, typename... Content, typename... Tail, typename... Output> constexpr auto find_captures(ctll::list<reset_group<Id, Content...>, Tail...>, ctll::list<Output...>) noexcept {
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id>>());
}

template <size_t Id, typename Name, typename... Content, typename... Tail, typename... Output> constexpr auto find_captures(ctll::list<reset_group_with_name<Id, Name, Content...>, Tail...>, ctll::list<Output...>) noexcept {
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id, Name>>());
}


}
Expand Down
11 changes: 11 additions & 0 deletions include/ctre/first.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ constexpr auto first(ctll::list<Content...> l, ctll::list<capture_with_name<Id,
return first(l, ctll::list<Seq..., Tail...>{});
}

// reset groups
template <typename... Content, size_t Id, typename... Seq, typename... Tail>
constexpr auto first(ctll::list<Content...> l, ctll::list<reset_group<Id, Seq...>, Tail...>) noexcept {
return first(l, ctll::list<Seq..., Tail...>{});
}

template <typename... Content, size_t Id, typename Name, typename... Seq, typename... Tail>
constexpr auto first(ctll::list<Content...> l, ctll::list<reset_group_with_name<Id, Name, Seq...>, Tail...>) noexcept {
return first(l, ctll::list<Seq..., Tail...>{});
}

// backreference
template <typename... Content, size_t Id, typename... Tail>
constexpr auto first(ctll::list<Content...>, ctll::list<back_reference<Id>, Tail...>) noexcept {
Expand Down
3 changes: 3 additions & 0 deletions include/ctre/pcre.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ struct pcre {
struct make_property: ctll::action {};
struct make_property_negative: ctll::action {};
struct make_range: ctll::action {};
struct make_reset_group: ctll::action {};
struct make_relative_back_reference: ctll::action {};
struct make_sequence: ctll::action {};
struct negate_class_named: ctll::action {};
Expand Down Expand Up @@ -132,6 +133,7 @@ struct pcre {
struct start_atomic: ctll::action {};
struct start_lookahead_negative: ctll::action {};
struct start_lookahead_positive: ctll::action {};
struct start_reset_group: ctll::action {};

// (q)LL1 function:
using _others = ctll::neg_set<'!','$','\x28','\x29','*','+',',','-','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','0','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D','1','2','3','4','5','6','7','8','9'>;
Expand Down Expand Up @@ -272,6 +274,7 @@ struct pcre {
static constexpr auto rule(d, ctll::term<'>'>) -> ctll::push<reset_capture, ctll::anything, start_atomic, content_in_capture, make_atomic, ctll::term<'\x29'>>;
static constexpr auto rule(d, ctll::term<'!'>) -> ctll::push<reset_capture, ctll::anything, start_lookahead_negative, content_in_capture, look_finish, ctll::term<'\x29'>>;
static constexpr auto rule(d, ctll::term<'='>) -> ctll::push<reset_capture, ctll::anything, start_lookahead_positive, content_in_capture, look_finish, ctll::term<'\x29'>>;
static constexpr auto rule(d, ctll::term<'|'>) -> ctll::push<reset_capture, ctll::anything, start_reset_group, content_in_capture, make_reset_group, ctll::term<'\x29'>>;

static constexpr auto rule(e, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>;
static constexpr auto rule(e, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>;
Expand Down
2 changes: 2 additions & 0 deletions include/ctre/pcre_actions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "atoms.hpp"
#include "atoms_unicode.hpp"
#include "id.hpp"
#include "first.hpp"
#include "return_type.hpp"
#include <cstdint>
#include <limits>

Expand Down
3 changes: 3 additions & 0 deletions tests/generating.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ static_assert(same_f(CTRE_GEN("(((a)(b)))"),ctre::capture<1, ctre::capture<2,ctr

static_assert(same_f(CTRE_GEN("((?:a)(b))"), ctre::capture<1,ctre::character<'a'>,ctre::capture<2,ctre::character<'b'>>>()));

// reset groups
static_assert(same_f(CTRE_GEN("(?|(?<name>a)|(b))"), ctre::reset_group_with_name<1,ctre::id<'n','a','m','e'>,ctre::select<ctre::capture_with_name<1,ctre::id<'n','a','m','e'>, ctre::character<'a'>>,ctre::capture<1, ctre::character<'b'>>>>()));
static_assert(same_f(CTRE_GEN("(?|(b)|(a))"), ctre::reset_group<1,ctre::select<ctre::capture<1, ctre::character<'b'>>, ctre::capture<1, ctre::character<'a'>>>>()));

// backreference
static_assert(same_f(CTRE_GEN("(a)\\g{1}"), ctre::sequence<ctre::capture<1,ctre::character<'a'>>, ctre::back_reference<1>>()));
Expand Down