File Coverage

blib/lib/PPIx/Regexp/Token/GroupType.pm
Criterion Covered Total %
statement 83 85 97.6
branch 12 16 75.0
condition 12 14 85.7
subroutine 18 19 94.7
pod 1 1 100.0
total 126 135 93.3


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             PPIx::Regexp::Token::GroupType - Represent a grouping parenthesis type.
4              
5             =head1 SYNOPSIS
6              
7             use PPIx::Regexp::Dumper;
8             PPIx::Regexp::Dumper->new( 'qr{(?i:foo)}smx' )
9             ->print();
10              
11             =head1 INHERITANCE
12              
13             C<PPIx::Regexp::Token::GroupType> is a
14             L<PPIx::Regexp::Token|PPIx::Regexp::Token>.
15              
16             C<PPIx::Regexp::Token::GroupType> is the parent of
17             L<PPIx::Regexp::Token::GroupType::Assertion|PPIx::Regexp::Token::GroupType::Assertion>,
18             L<PPIx::Regexp::Token::GroupType::Atomic_Script_Run|PPIx::Regexp::Token::GroupType::Atomic_Script_Run>,
19             L<PPIx::Regexp::Token::GroupType::BranchReset|PPIx::Regexp::Token::GroupType::BranchReset>,
20             L<PPIx::Regexp::Token::GroupType::Code|PPIx::Regexp::Token::GroupType::Code>,
21             L<PPIx::Regexp::Token::GroupType::Modifier|PPIx::Regexp::Token::GroupType::Modifier>,
22             L<PPIx::Regexp::Token::GroupType::NamedCapture|PPIx::Regexp::Token::GroupType::NamedCapture>,
23             L<PPIx::Regexp::Token::GroupType::Script_Run|PPIx::Regexp::Token::GroupType::Script_Run>,
24             L<PPIx::Regexp::Token::GroupType::Subexpression|PPIx::Regexp::Token::GroupType::Subexpression>
25             and
26             L<PPIx::Regexp::Token::GroupType::Switch|PPIx::Regexp::Token::GroupType::Switch>.
27              
28             =head1 DESCRIPTION
29              
30             This class represents any of the magic sequences of characters that can
31             follow an open parenthesis. This particular class is intended to be
32             abstract.
33              
34             =head1 METHODS
35              
36             This class provides no public methods beyond those provided by its
37             superclass.
38              
39             =cut
40              
41             package PPIx::Regexp::Token::GroupType;
42              
43 9     9   63 use strict;
  9         16  
  9         270  
44 9     9   33 use warnings;
  9         15  
  9         341  
45              
46 9     9   34 use base qw{ PPIx::Regexp::Token };
  9         15  
  9         802  
47              
48 9     9   40 use PPIx::Regexp::Constant qw{ MINIMUM_PERL @CARP_NOT };
  9         15  
  9         900  
49 9     9   44 use PPIx::Regexp::Util qw{ __ns_can };
  9         19  
  9         3969  
50              
51             our $VERSION = '0.091';
52              
53             # Return true if the token can be quantified, and false otherwise
54 19     19 1 93 sub can_be_quantified { return };
55              
56             =head2 __defining_string
57              
58             my $string = $class->__defining_string();
59              
60             This method is private to the C<PPIx-Regexp> package, and is documented
61             for the author's benefit only. It may be changed or revoked without
62             notice.
63              
64             This method returns an array of strings that define the specific group
65             type. These strings will normally start with C<'?'>.
66              
67             Optionally, the first returned item may be a hash reference. The only
68             supported key is C<{suffix}>, which is a string to be suffixed to each
69             of the regular expressions made by C<__make_group_type_matcher()> out of
70             the defining strings, inside a C<(?= ... )>, so that it is not included
71             in the match.
72              
73             This method B<must> be overridden, unless C<__make_group_type_matcher()>
74             is. The override B<must> return the same thing each time, since the
75             results of C<__make_group_type_matcher()> are cached.
76              
77             =cut
78              
79             sub __defining_string {
80 0     0   0 require Carp;
81 0         0 Carp::confess(
82             'Programming error - __defining_string() must be overridden' );
83             }
84              
85             =head2 __make_group_type_matcher
86              
87             my $hash_ref = $class->__make_group_type_matcher();
88              
89             This method is private to the C<PPIx-Regexp> package, and is documented
90             for the author's benefit only. It may be changed or revoked without
91             notice.
92              
93             This method returns a reference to a hash. The keys are regexp delimiter
94             characters which appear in the defining strings for the group type. For
95             each key, the value is a reference to an array of C<Regexp> objects,
96             properly escaped for the key character. Key C<''> provides the regular
97             expressions to be used if the regexp delimiter does not appear in any of
98             the defining strings.
99              
100             If this method is overridden by the subclass, method
101             C<__defining_string()> need not be, unless the overridden
102             C<__make_group_type_matcher()> calls C<__defining_string()>.
103              
104             =cut
105              
106             sub __make_group_type_matcher {
107 63     63   376 my ( $class ) = @_;
108              
109 63         205 my @defs = $class->__defining_string();
110              
111 63 100       132 my $opt = ref $defs[0] ? shift @defs : {};
112              
113             my $suffix = defined $opt->{suffix} ?
114 63 100       259 qr/ (?= \Q$opt->{suffix}\E ) /smx :
115             '';
116              
117 63         76 my %seen;
118 63         634 my @chars = grep { ! $seen{$_}++ } split qr{}smx, join '', @defs;
  2553         3337  
119              
120 63         207 my %rslt;
121 63         315 foreach my $str ( @defs ) {
122 318   100     358 push @{ $rslt{''} ||= [] }, qr{ \A \Q$str\E $suffix }smx;
  318         2751  
123 318         677 foreach my $chr ( @chars ) {
124 5505         36209 ( my $expr = $str ) =~ s/ (?= \Q$chr\E ) /\\/smxg;
125 5505   100     6061 push @{ $rslt{$chr} ||= [] }, qr{ \A \Q$expr\E $suffix }smx;
  5505         26117  
126             }
127             }
128 63         1554 return \%rslt;
129             }
130              
131             =head2 __match_setup
132              
133             $class->__match_setup( $tokenizer );
134              
135             This method is private to the C<PPIx-Regexp> package, and is documented
136             for the author's benefit only. It may be changed or revoked without
137             notice.
138              
139             This method performs whatever setup is needed once it is determined that
140             the given group type has been detected. This method is called only if
141             the class matched at the current position in the string being parsed. It
142             must perform whatever extra setup is needed for the match. It returns
143             nothing.
144              
145             This method need not be overridden. The default does nothing.
146              
147             =cut
148              
149             sub __match_setup {
150 67     67   122 return;
151             }
152              
153             =head2 __setup_class
154              
155             $class->__setup_class( \%definition, \%opt );
156              
157             This method is private to the C<PPIx-Regexp> package, and is documented
158             for the author's benefit only. It may be changed or revoked without
159             notice.
160              
161             This method uses the C<%definition> hash to create the
162             C<__defining_string()>, C<explain()>, C<perl_version_introduced()>, and
163             C<perl_version_removed()> methods for the calling class. Any of these
164             that already exist will B<not> be replaced.
165              
166             The C<%definition> hash defines all the strings that specify tokens of
167             the invoking class. You can not (unfortunately) use this mechanism if
168             you need a regular expression to recognize a token that belongs to this
169             class. The keys of the C<%definition> hash are strings that specify
170             members of this class. The values are hashes that define the specific
171             member of the class. The following values are supported:
172              
173             =over
174              
175             =item {expl}
176              
177             This is the explanation of the element, to be returned by the
178             C<explain()> method.
179              
180             =item {intro}
181              
182             This is the Perl version that introduced the element, as a string. The
183             default is the value of constant
184             L<MINIMUM_PERL|PPIx::Regexp::Constant/MINIMUM_PERL>.
185              
186             =item {remov}
187              
188             This is the Perl version that removed the element, as a string. The
189             default is C<undef>, meaning that the element is still present in the
190             highest released version of Perl, whether development or production.
191              
192             =back
193              
194             The C<%opt> hash is optional, and defaults to the empty hash. It is
195             used, basically, for ad-hocery. The supported keys are:
196              
197             =over
198              
199             =item {suffix}
200              
201             If this element is defined, the first element returned by the generated
202             L<__defining_string()|/__defining_string> method is a hash containing
203             this key and value.
204              
205             =back
206              
207             =cut
208              
209             sub __setup_class {
210 63     63   165 my ( $class, $opt ) = @_;
211              
212 63   100     304 $opt ||= {};
213              
214 63 50       284 unless ( $class->__ns_can( '__defining_string' ) ) {
215 63         112 my $method = "${class}::__defining_string";
216 63         78 my @def_str = sort keys %{ $class->DEF };
  63         632  
217             defined $opt->{suffix}
218             and unshift @def_str, {
219             suffix => $opt->{suffix},
220 63 100       190 };
221 63         143 $class->DEF->{__defining_string} = \@def_str;
222 9     9   64 no strict qw{ refs };
  9         14  
  9         947  
223             *$method = sub {
224 63     63   96 my ( $self ) = @_;
225 63         71 return @{ $self->DEF->{__defining_string} };
  63         288  
226 63         396 };
227             }
228              
229 63 50       166 unless ( $class->__ns_can( 'explain' ) ) {
230 63         84 my $method = "${class}::explain";
231 9     9   43 no strict qw{ refs };
  9         13  
  9         973  
232             *$method = sub {
233 10     10   23 my ( $self ) = @_;
234 10         30 $DB::single = 1;
235 10         80 return $self->DEF->{ $self->unescaped_content() }{expl};
236 63         272 };
237             }
238              
239 63 50       109 unless ( $class->__ns_can( 'perl_version_introduced' ) ) {
240 63         80 my $method = "${class}::perl_version_introduced";
241 9     9   44 no strict qw{ refs };
  9         12  
  9         831  
242             *$method = sub {
243 40     40   7549 my ( $self ) = @_;
244 40   100     236 return $self->DEF->{ $self->unescaped_content() }{intro} || MINIMUM_PERL;
245 63         279 };
246             }
247              
248 63 50       107 unless ( $class->__ns_can( 'perl_version_removed' ) ) {
249 63         78 my $method = "${class}::perl_version_removed";
250 9     9   42 no strict qw{ refs };
  9         14  
  9         1885  
251             *$method = sub {
252 50     50   15435 my ( $self ) = @_;
253 50         224 return $self->DEF->{ $self->unescaped_content() }{remov};
254 63         251 };
255             }
256              
257 63         144 return;
258             }
259              
260             my %matcher;
261              
262             sub __PPIX_TOKENIZER__regexp {
263 1794     1794   2434 my ( $class, $tokenizer ) = @_; # $character unused
264              
265 1794   66     3399 my $mtch = $matcher{$class} ||= $class->__make_group_type_matcher();
266              
267             my $re_list = $mtch->{ $tokenizer->get_start_delimiter() } ||
268 1794   66     3022 $mtch->{''};
269              
270 1794         1945 foreach my $re ( @{ $re_list } ) {
  1794         2346  
271 5990 100       7872 my $accept = $tokenizer->find_regexp( $re )
272             or next;
273 161         956 $class->__match_setup( $tokenizer );
274 161         444 return $accept;
275             }
276              
277 1633         2439 return;
278             }
279              
280             1;
281              
282             __END__
283              
284             =head1 SUPPORT
285              
286             Support is by the author. Please file bug reports at
287             L<https://rt.cpan.org/Public/Dist/Display.html?Name=PPIx-Regexp>,
288             L<https://github.com/trwyant/perl-PPIx-Regexp/issues>, or in
289             electronic mail to the author.
290              
291             =head1 AUTHOR
292              
293             Thomas R. Wyant, III F<wyant at cpan dot org>
294              
295             =head1 COPYRIGHT AND LICENSE
296              
297             Copyright (C) 2009-2023, 2025 by Thomas R. Wyant, III
298              
299             This program is free software; you can redistribute it and/or modify it
300             under the same terms as Perl 5.10.0. For more details, see the full text
301             of the licenses in the directory LICENSES.
302              
303             This program is distributed in the hope that it will be useful, but
304             without any warranty; without even the implied warranty of
305             merchantability or fitness for a particular purpose.
306              
307             =cut
308              
309             # ex: set textwidth=72 :