Skip to content

Commit 4bf6c79

Browse files
committed
implement reset groups
1 parent 0e646f3 commit 4bf6c79

File tree

8 files changed

+174
-0
lines changed

8 files changed

+174
-0
lines changed

include/ctre/actions/capture.inc.hpp

+134
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,139 @@ template <auto... Str, auto V, typename... Content, size_t Id, typename... Ts, s
3636
return pcre_context{ctll::push_front(capture_with_name<Id, id<Str...>, Content...>(), ctll::list<Ts...>()), pcre_parameters<Counter>()};
3737
}
3838

39+
template<size_t To, auto... Str, typename T>
40+
static constexpr auto replace_captures_with_id(T, string<Str...>) { // fallback case, no transform
41+
return T{};
42+
}
43+
44+
template<size_t To, auto... Str, size_t From, typename... Content>
45+
static constexpr auto replace_captures_with_id(capture<From, Content...>, string<Str...>) {
46+
return capture<To, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
47+
}
48+
// named reseted captures must have same Str... for all instances inside the call (otherwise how would we know how to access which by name?)
49+
template<size_t To, auto... Str, size_t From, auto... Str2, typename... Content>
50+
static constexpr auto replace_captures_with_id(capture_with_name<From, id<Str2...>, Content...>, string<Str...>) {
51+
static_assert((id<Str...>{} == id<Str2...>{}) && "named captures must be the same");
52+
return capture_with_name<From, id<Str...>, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
53+
}
54+
55+
template<size_t To, auto... Str, typename... Content>
56+
static constexpr auto replace_captures_with_id(sequence<Content...>, string<Str...>) {
57+
return sequence<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
58+
}
59+
60+
template<size_t To, auto... Str, size_t Id, typename... Content>
61+
static constexpr auto replace_captures_with_id(reset_group<Id, Content...>, string<Str...>) {
62+
return reset_group<To, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
63+
}
64+
65+
template<size_t To, auto... Str, size_t Id, auto... Str2, typename... Content>
66+
static constexpr auto replace_captures_with_id(reset_group_with_name<Id, id<Str2...>, Content...>, string<Str...>) {
67+
return reset_group_with_name<To, id<Str...>, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
68+
}
69+
70+
template<size_t To, auto... Str, typename... Content>
71+
static constexpr auto replace_captures_with_id(atomic_group<Content...>, string<Str...>) {
72+
return atomic_group<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
73+
}
74+
75+
template<size_t To, auto... Str, typename... Content>
76+
static constexpr auto replace_captures_with_id(lookahead_positive<Content...>, string<Str...>) {
77+
return lookahead_positive<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
78+
}
79+
80+
template<size_t To, auto... Str, typename... Content>
81+
static constexpr auto replace_captures_with_id(lookahead_negative<Content...>, string<Str...>) {
82+
return lookahead_negative<decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
83+
}
84+
85+
template<size_t To, auto... Str, size_t A, size_t B, typename... Content>
86+
static constexpr auto replace_captures_with_id(possessive_repeat<A, B, Content...>, string<Str...>) {
87+
return possessive_repeat<A, B, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
88+
}
89+
90+
template<size_t To, auto... Str, size_t A, size_t B, typename... Content>
91+
static constexpr auto replace_captures_with_id(repeat<A, B, Content...>, string<Str...>) {
92+
return repeat<A, B, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
93+
}
94+
95+
template<size_t To, auto... Str, size_t A, size_t B, typename... Content>
96+
static constexpr auto replace_captures_with_id(lazy_repeat<A, B, Content...>, string<Str...>) {
97+
return lazy_repeat<A, B, decltype(replace_captures_with_id<To>(Content{}, string<Str...>{}))...>{};
98+
}
99+
100+
template<size_t To, auto... Str, typename... Opts>
101+
static constexpr auto replace_captures_with_id(select<Opts...>, string<Str...>) {
102+
return select<decltype(replace_captures_with_id<To>(Opts{}, string<Str...>{}))...>{};
103+
}
104+
105+
// get name (might be a utility already written)
106+
template<size_t Idx, auto... Str>
107+
static constexpr string<Str...> get_capture_name(captured_content<Idx, id<Str...>>) noexcept {
108+
return string<Str...>{};
109+
}
110+
111+
template<size_t Idx>
112+
static constexpr string<> get_capture_name(captured_content<Idx>) noexcept {
113+
return string<>{};
114+
}
115+
116+
template<auto... Str>
117+
static constexpr id<Str...> make_id_from_string(string<Str...>) noexcept {
118+
return id<Str...>{};
119+
}
120+
121+
// find the first named capture
122+
template<typename H, typename... Tail>
123+
static constexpr auto get_capture_with_name(ctll::list<H, Tail...>) noexcept {
124+
if constexpr (sizeof...(Tail))
125+
return get_capture_with_name(ctll::list<Tail...>{});
126+
else
127+
return ctll::list<>{};
128+
}
129+
130+
template<size_t Idx, typename Name, typename... Tail>
131+
static constexpr auto get_capture_with_name(ctll::list<captured_content<Idx, Name>, Tail...>) noexcept {
132+
return ctll::list<captured_content<Idx, Name>>{};
133+
}
134+
135+
// reset group start
136+
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>>) {
137+
return pcre_context{ ctll::push_front(reset_start<Counter+1>(), ctll::list<Ts...>()), pcre_parameters<Counter>() };
138+
//ctll::list<reset_start<Counter+1>(), Ts...>(), };
139+
}
140+
141+
// reset group end
142+
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>>) {
143+
using first_capture = decltype(ctll::front(find_captures(A{})));
144+
if constexpr (::std::is_same_v<first_capture, ctll::_nothing>) {
145+
//no captures to reset... easy case
146+
return pcre_context{ ctll::list<sequence<A>, Ts...>(), pcre_parameters<Counter>() };
147+
} else {
148+
using first_named_capture = decltype(ctll::front(get_capture_with_name(find_captures(A{}))));
149+
if constexpr (::std::is_same_v<first_named_capture, ctll::_nothing>) {
150+
return pcre_context{ ctll::list<reset_group<Id, decltype(replace_captures_with_id<Id>(A{}, string<>{}))>, Ts...>(), pcre_parameters<Counter>() };
151+
} else {
152+
return pcre_context{ ctll::list<reset_group_with_name<Id, decltype(make_id_from_string(get_capture_name(first_named_capture{}))), decltype(replace_captures_with_id<Id>(A{}, get_capture_name(first_named_capture{})))>, Ts...>(), pcre_parameters<Counter>() };
153+
}
154+
}
155+
}
156+
// reset group end (sequence)
157+
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>>) {
158+
using first_capture = decltype(ctll::front(find_captures(sequence<Content...>{})));
159+
if constexpr (::std::is_same_v<first_capture, ctll::_nothing>) {
160+
//no captures to reset... easy case
161+
return pcre_context{ ctll::list<sequence<Content...>, Ts...>(), pcre_parameters<Counter>() };
162+
} else {
163+
using first_named_capture = decltype(ctll::front(get_capture_with_name(find_captures(sequence<Content...>{}))));
164+
if constexpr (::std::is_same_v<first_named_capture, ctll::_nothing>) {
165+
return pcre_context{ ctll::list<reset_group<Id, decltype(replace_captures_with_id<Id>(Content{}, string<>{}))...>, Ts...>(), pcre_parameters<Counter>() };
166+
} else {
167+
return pcre_context{ ctll::list<reset_group<Id, decltype(make_id_from_string(get_capture_name(first_named_capture{}))), decltype(replace_captures_with_id<Id>(Content{}, get_capture_name(first_named_capture{})))...>, Ts...>(), pcre_parameters<Counter>() };
168+
}
169+
}
170+
}
171+
172+
39173

40174
#endif

include/ctre/atoms.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,13 @@ template <size_t Index, typename... Content> struct capture { };
4242

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

45+
template <size_t Index, typename... Content> struct reset_group { };
46+
template <size_t Index, typename Name, typename... Content> struct reset_group_with_name { };
47+
4548
template <size_t Index> struct back_reference { };
4649
template <typename Name> struct back_reference_with_name { };
4750

51+
template <size_t Idx> struct reset_start { };
4852
template <typename Type> struct look_start { };
4953

5054
template <typename... Content> struct lookahead_positive { };

include/ctre/evaluation.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, c
159159
}
160160
}
161161

162+
template <typename R, typename Iterator, typename EndIterator, size_t Id, typename... Content, typename... Tail>
163+
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 {
164+
return evaluate(begin, current, end, f, captures, ctll::list<sequence<Content...>, Tail...>{});
165+
}
166+
167+
template <typename R, typename Iterator, typename EndIterator, size_t Id, typename Name, typename... Content, typename... Tail>
168+
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 {
169+
return evaluate(begin, current, end, f, captures, ctll::list<sequence<Content...>, Tail...>{});
170+
}
171+
162172
// matching empty in patterns
163173
template <typename R, typename Iterator, typename EndIterator, typename... Tail>
164174
constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, const flags & f, R captures, ctll::list<empty, Tail...>) noexcept {

include/ctre/find_captures.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ template <size_t Id, typename Name, typename... Content, typename... Tail, typen
120120
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id, Name>>());
121121
}
122122

123+
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 {
124+
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id>>());
125+
}
126+
127+
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 {
128+
return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id, Name>>());
129+
}
123130

124131

125132
}

include/ctre/first.hpp

+11
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,17 @@ constexpr auto first(ctll::list<Content...> l, ctll::list<capture_with_name<Id,
178178
return first(l, ctll::list<Seq..., Tail...>{});
179179
}
180180

181+
// reset groups
182+
template <typename... Content, size_t Id, typename... Seq, typename... Tail>
183+
constexpr auto first(ctll::list<Content...> l, ctll::list<reset_group<Id, Seq...>, Tail...>) noexcept {
184+
return first(l, ctll::list<Seq..., Tail...>{});
185+
}
186+
187+
template <typename... Content, size_t Id, typename Name, typename... Seq, typename... Tail>
188+
constexpr auto first(ctll::list<Content...> l, ctll::list<reset_group_with_name<Id, Name, Seq...>, Tail...>) noexcept {
189+
return first(l, ctll::list<Seq..., Tail...>{});
190+
}
191+
181192
// backreference
182193
template <typename... Content, size_t Id, typename... Tail>
183194
constexpr auto first(ctll::list<Content...>, ctll::list<back_reference<Id>, Tail...>) noexcept {

include/ctre/pcre.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct pcre {
9393
struct make_property: ctll::action {};
9494
struct make_property_negative: ctll::action {};
9595
struct make_range: ctll::action {};
96+
struct make_reset_group: ctll::action {};
9697
struct make_relative_back_reference: ctll::action {};
9798
struct make_sequence: ctll::action {};
9899
struct negate_class_named: ctll::action {};
@@ -132,6 +133,7 @@ struct pcre {
132133
struct start_atomic: ctll::action {};
133134
struct start_lookahead_negative: ctll::action {};
134135
struct start_lookahead_positive: ctll::action {};
136+
struct start_reset_group: ctll::action {};
135137

136138
// (q)LL1 function:
137139
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'>;
@@ -272,6 +274,7 @@ struct pcre {
272274
static constexpr auto rule(d, ctll::term<'>'>) -> ctll::push<reset_capture, ctll::anything, start_atomic, content_in_capture, make_atomic, ctll::term<'\x29'>>;
273275
static constexpr auto rule(d, ctll::term<'!'>) -> ctll::push<reset_capture, ctll::anything, start_lookahead_negative, content_in_capture, look_finish, ctll::term<'\x29'>>;
274276
static constexpr auto rule(d, ctll::term<'='>) -> ctll::push<reset_capture, ctll::anything, start_lookahead_positive, content_in_capture, look_finish, ctll::term<'\x29'>>;
277+
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'>>;
275278

276279
static constexpr auto rule(e, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>;
277280
static constexpr auto rule(e, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>;

include/ctre/pcre_actions.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include "atoms.hpp"
66
#include "atoms_unicode.hpp"
77
#include "id.hpp"
8+
#include "first.hpp"
9+
#include "return_type.hpp"
810
#include <cstdint>
911
#include <limits>
1012

tests/generating.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ static_assert(same_f(CTRE_GEN("(((a)(b)))"),ctre::capture<1, ctre::capture<2,ctr
208208

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

211+
// reset groups
212+
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'>>>>()));
213+
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'>>>>()));
211214

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

0 commit comments

Comments
 (0)