File Coverage

blib/lib/Regexp/Parser/Objects.pm
Criterion Covered Total %
statement 455 678 67.1
branch 103 218 47.2
condition 39 69 56.5
subroutine 137 189 72.4
pod n/a
total 734 1154 63.6


line stmt bran cond sub pod time code
1 14     14   8014 use NEXT;
  14         98396  
  14         169711  
2              
3             {
4             package Regexp::Parser::__object__;
5              
6             sub class {
7 0     0   0 my $self = shift;
8 0         0 Carp::carp("class() deprecated; use family() instead");
9 0         0 $self->family(@_);
10             }
11              
12             sub flags {
13 0     0   0 my $self = shift;
14 0         0 $self->{flags};
15             }
16              
17             sub family {
18 620     620   1776 my $self = shift;
19 620         3115 $self->{family};
20             }
21              
22             sub type {
23 194     194   919 my $self = shift;
24 194         771 $self->{type};
25             }
26              
27             sub qr {
28 106     106   145 my $self = shift;
29 106         276 $self->visual(@_);
30             }
31              
32             sub visual {
33 185     185   282 my $self = shift;
34 185 100       739 exists $self->{vis} ? $self->{vis} : '';
35             }
36              
37             sub raw {
38 187     187   323 my $self = shift;
39 187 50       584 exists $self->{raw} ? $self->{raw} : $self->visual(@_);
40             }
41              
42             sub data {
43 53     53   131 my $self = shift;
44 53         130 return $self->{data};
45             }
46              
47             sub ender {
48 11     11   17 my $self = shift;
49 11 50       34 unless ($self->{down}) {
50 0         0 Carp::carp("ender() ignored for ", $self->family, "/", $self->type);
51 0         0 return;
52             }
53 11         57 [ 'tail' ];
54             }
55              
56             sub walk {
57 66     66   114 my $self = shift;
58 66         137 return;
59             }
60              
61             sub omit {
62 894     894   1269 my $self = shift;
63 894 100       1628 $self->{omit} = shift if @_;
64 894         2094 $self->{omit};
65             }
66              
67             sub insert {
68 707     707   1163 my ($self, $tree) = @_;
69 707         1200 my $rx = $self->{rx};
70 707         937 my $merged = 0;
71 707 50       1460 return if $self->omit;
72 707         1188 push @$tree, $self;
73 707         1472 $self->merge;
74             }
75              
76             sub merge {
77 194     194   299 my ($self) = @_;
78 194         440 return;
79             }
80             }
81              
82              
83             {
84             # \A ^ \B \b \G \Z \z $
85             package Regexp::Parser::anchor;
86             our @ISA = qw( Regexp::Parser::__object__ );
87             push @Regexp::Parser::bol::ISA, __PACKAGE__;
88             push @Regexp::Parser::bound::ISA, __PACKAGE__;
89             push @Regexp::Parser::gpos::ISA, __PACKAGE__;
90             push @Regexp::Parser::eol::ISA, __PACKAGE__;
91              
92             sub new {
93 36     36   104 my ($class, $rx, $type, $vis) = @_;
94 36 50       205 Carp::croak("anchor is an abstract class") if $class =~ /::anchor$/;
95              
96             my $self = bless {
97             rx => $rx,
98 36         197 flags => $rx->{flags}[-1],
99             family => 'anchor',
100             type => $type,
101             vis => $vis,
102             zerolen => 1,
103             }, $class;
104 36         142 return $self;
105             }
106             }
107              
108              
109             {
110             # . \C
111             package Regexp::Parser::reg_any;
112             our @ISA = qw( Regexp::Parser::__object__ );
113              
114             sub new {
115 9     9   24 my ($class, $rx, $type, $vis) = @_;
116             my $self = bless {
117             rx => $rx,
118 9         44 flags => $rx->{flags}[-1],
119             family => 'reg_any',
120             type => $type,
121             vis => $vis,
122             }, $class;
123 9         38 return $self;
124             }
125             }
126              
127              
128             {
129             # \w \W
130             package Regexp::Parser::alnum;
131             our @ISA = qw( Regexp::Parser::__object__ );
132              
133             sub new {
134 19     19   42 my ($class, $rx, $neg) = @_;
135             my $self = bless {
136             rx => $rx,
137 19         68 flags => $rx->{flags}[-1],
138             neg => $neg,
139             }, $class;
140 19         66 return $self;
141             }
142              
143             sub neg {
144 0     0   0 my $self = shift;
145 0 0       0 $self->{neg} = shift if @_;
146 0         0 $self->{neg};
147             }
148              
149 30     30   166 sub family { 'alnum' }
150              
151             sub type {
152 2     2   4 my $self = shift;
153 2 50       6 ($self->{neg} ? 'n' : '') . $self->family;
154             }
155              
156             sub visual {
157 12     12   69 my $self = shift;
158 12 100       139 $self->{neg} ? '\W' : '\w';
159             }
160             }
161              
162              
163             {
164             # \s \S
165             package Regexp::Parser::space;
166             our @ISA = qw( Regexp::Parser::__object__ );
167              
168             sub new {
169 16     16   28 my ($class, $rx, $neg) = @_;
170             my $self = bless {
171             rx => $rx,
172 16         60 flags => $rx->{flags}[-1],
173             neg => $neg,
174             }, $class;
175 16         76 return $self;
176             }
177              
178             sub neg {
179 0     0   0 my $self = shift;
180 0 0       0 $self->{neg} = shift if @_;
181 0         0 $self->{neg};
182             }
183              
184             sub type {
185 0     0   0 my $self = shift;
186 0 0       0 ($self->{neg} ? 'n' : '') . $self->family;
187             }
188              
189 32     32   132 sub family { 'space' }
190              
191             sub visual {
192 12     12   17 my $self = shift;
193 12 100       46 $self->{neg} ? '\S' : '\s';
194             }
195             }
196              
197              
198             {
199             # \d \D
200             package Regexp::Parser::digit;
201             our @ISA = qw( Regexp::Parser::__object__ );
202              
203             sub new {
204 19     19   41 my ($class, $rx, $neg) = @_;
205             my $self = bless {
206             rx => $rx,
207 19         78 flags => $rx->{flags}[-1],
208             neg => $neg,
209             }, $class;
210 19         84 return $self;
211             }
212              
213             sub neg {
214 0     0   0 my $self = shift;
215 0 0       0 $self->{neg} = shift if @_;
216 0         0 $self->{neg};
217             }
218              
219             sub type {
220 0     0   0 my $self = shift;
221 0 0       0 ($self->{neg} ? 'n' : '') . $self->family;
222             }
223              
224 44     44   146 sub family { 'digit' }
225              
226             sub visual {
227 27     27   35 my $self = shift;
228 27 100       79 $self->{neg} ? '\D' : '\d';
229             }
230             }
231              
232              
233             {
234             package Regexp::Parser::anyof;
235             our @ISA = qw( Regexp::Parser::__object__ );
236              
237             sub new {
238 38     38   86 my ($class, $rx, $neg, @data) = @_;
239             my $self = bless {
240             rx => $rx,
241 38         241 flags => $rx->{flags}[-1],
242             family => 'anyof',
243             type => 'anyof',
244             neg => $neg,
245             data => \@data,
246             down => 1,
247             }, $class;
248 38         197 return $self;
249             }
250              
251             sub qr {
252 0     0   0 my $self = shift;
253 0         0 join "", $self->raw, map($_->qr, @{ $self->{data} }), "]";
  0         0  
254             }
255              
256             sub visual {
257 38     38   54 my $self = shift;
258 38         79 join "", $self->raw, map($_->visual, @{ $self->{data} }), "]";
  38         119  
259             }
260              
261             sub raw {
262 38     38   52 my $self = shift;
263 38 100       146 join "", "[", $self->{neg} ? "^" : "";
264             }
265              
266             sub neg {
267 0     0   0 my $self = shift;
268 0 0       0 $self->{neg} = shift if @_;
269 0         0 $self->{neg};
270             }
271              
272             sub ender {
273 0     0   0 my $self = shift;
274 0         0 [ 'anyof_close' ];
275             }
276              
277             sub data {
278 0     0   0 my $self = shift;
279 0 0       0 if (@_) {
280 0         0 my $how = shift;
281 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
282 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
283             else {
284 0         0 my $t = $self->type;
285 0         0 Carp::croak("\$$t->data([+=], \@data)");
286             }
287             }
288 0         0 $self->{data};
289             }
290              
291             sub walk {
292 0     0   0 my ($self, $ws, $d) = @_;
293 0         0 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  0         0  
294 0 0   0   0 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  0         0  
  0         0  
  0         0  
295             }
296              
297             sub insert {
298 38     38   72 my ($self, $tree) = @_;
299 38         72 my $rx = $self->{rx};
300 38         84 push @$tree, $self;
301 38         95 push @{ $rx->{stack} }, $tree;
  38         71  
302 38         114 $rx->{tree} = $self->{data};
303             }
304             }
305              
306              
307             {
308             package Regexp::Parser::anyof_char;
309             our @ISA = qw( Regexp::Parser::__object__ );
310              
311             sub new {
312 107     107   216 my ($class, $rx, $data, $vis) = @_;
313 107 100       190 $vis = $data if not defined $vis;
314             my $self = bless {
315             rx => $rx,
316 107         692 flags => $rx->{flags}[-1],
317             family => 'anyof_char',
318             type => 'anyof_char',
319             data => $data,
320             vis => $vis,
321             }, $class;
322             }
323             }
324              
325              
326             {
327             package Regexp::Parser::anyof_range;
328             our @ISA = qw( Regexp::Parser::__object__ );
329              
330             sub new {
331 8     8   13 my ($class, $rx, $lhs, $rhs) = @_;
332             my $self = bless {
333             rx => $rx,
334 8         36 flags => $rx->{flags}[-1],
335             family => 'anyof_range',
336             type => 'anyof_range',
337             data => [$lhs, $rhs],
338             }, $class;
339             }
340              
341             sub qr {
342 0     0   0 my $self = shift;
343 0         0 join "-", $self->{data}[0]->qr, $self->{data}[1]->qr;
344             }
345              
346             sub visual {
347 8     8   10 my $self = shift;
348 8         16 join "-", $self->{data}[0]->visual, $self->{data}[1]->visual;
349             }
350             }
351              
352              
353             {
354             package Regexp::Parser::anyof_class;
355             our @ISA = qw( Regexp::Parser::__object__ );
356              
357             sub new {
358 48     48   189 my ($class, $rx, $type, $neg, $how) = @_;
359             my $self = bless {
360             rx => $rx,
361 48         146 flags => $rx->{flags}[-1],
362             family => 'anyof_class',
363             }, $class;
364              
365 48 100       170 if (ref $type) {
366 34         53 $self->{data} = $type;
367             }
368             else {
369 14         41 $self->{type} = $type;
370 14         36 $self->{data} = 'POSIX';
371 14         58 $self->{neg} = $neg;
372 14         30 $self->{how} = $how;
373             }
374              
375 48         150 return $self;
376             }
377              
378             sub type {
379 2     2   3 my $self = shift;
380 2 50       7 if (ref $self->{data}) {
381 2         5 $self->{data}->type;
382             }
383             else {
384             my $how = ref $self->{how} eq 'SCALAR' ?
385 0         0 ${ $self->{how} } :
386 0 0       0 $self->{how};
387             join "", $how, ($self->{neg} ? '^' : ''),
388 0 0       0 $self->{type}, $how;
389             }
390             }
391              
392             sub neg {
393 0     0   0 my $self = shift;
394 0 0       0 if (ref $self->{data}) {
395 0 0       0 $self->{data}->neg = shift if @_;
396 0         0 $self->{data}->neg;
397             }
398             else {
399 0 0       0 $self->{neg} = shift if @_;
400 0         0 $self->{neg};
401             }
402             }
403              
404             sub visual {
405 24     24   42 my $self = shift;
406 24 100       59 if (ref $self->{data}) {
407 17         31 $self->{data}->visual;
408             }
409             else {
410             my $how = ref $self->{how} eq 'SCALAR' ?
411 7         19 ${ $self->{how} } :
412 7 50       29 $self->{how};
413             join "", "[", $how, ($self->{neg} ? '^' : ''),
414 7 100       64 $self->{type}, $how, "]";
415             }
416             }
417             }
418              
419              
420             {
421             package Regexp::Parser::anyof_close;
422             our @ISA = qw( Regexp::Parser::__object__ );
423              
424             sub new {
425 38     38   71 my ($class, $rx) = @_;
426             my $self = bless {
427             rx => $rx,
428 38         232 flags => $rx->{flags}[-1],
429             family => 'close',
430             type => 'anyof_close',
431             raw => ']',
432             omit => 1,
433             up => 1,
434             }, $class;
435 38         133 return $self;
436             }
437              
438             sub insert {
439 38     38   49 my $self = shift;
440 38         95 my $rx = $self->{rx};
441 38         46 $rx->{tree} = pop @{ $rx->{stack} };
  38         75  
442 38         68 return $self;
443             }
444             }
445              
446              
447             {
448             package Regexp::Parser::prop;
449             our @ISA = qw( Regexp::Parser::__object__ );
450              
451             sub new {
452 5     5   19 my ($class, $rx, $type, $neg) = @_;
453             my $self = bless {
454             rx => $rx,
455 5 100       59 flags => $rx->{flags}[-1],
456             family => 'prop',
457             type => $type,
458             data => '',
459             neg => ($neg ? 1 : 0),
460             }, $class;
461 5         33 return $self;
462             }
463              
464             sub type {
465 5     5   9 my $self = shift;
466 5         58 $self->{type};
467             }
468              
469             sub neg {
470 0     0   0 my $self = shift;
471 0 0       0 $self->{neg} = shift if @_;
472 0         0 $self->{neg};
473             }
474              
475             sub visual {
476 5     5   13 my $self = shift;
477 5 100       30 sprintf "\\%s{%s}", $self->{neg} ? 'P' : 'p', $self->type;
478             }
479             }
480              
481              
482             {
483             package Regexp::Parser::clump;
484             our @ISA = qw( Regexp::Parser::__object__ );
485              
486             sub new {
487 2     2   5 my ($class, $rx, $vis) = @_;
488             my $self = bless {
489             rx => $rx,
490 2         16 flags => $rx->{flags}[-1],
491             family => 'clump',
492             type => 'clump',
493             vis => $vis,
494             }, $class;
495             }
496             }
497              
498              
499             {
500             package Regexp::Parser::branch;
501             our @ISA = qw( Regexp::Parser::__object__ );
502              
503             sub new {
504 91     91   235 my ($class, $rx) = @_;
505             my $self = bless {
506             rx => $rx,
507 91         1176 flags => $rx->{flags}[-1],
508             data => [[]],
509             family => 'branch',
510             type => 'branch',
511             raw => '|',
512             branch => 1,
513             }, $class;
514             }
515              
516             sub qr {
517 3     3   4 my $self = shift;
518 3         4 join $self->raw, map join("", map $_->qr, @$_), @{ $self->{data} };
  3         8  
519             }
520              
521             sub visual {
522 73     73   182 my $self = shift;
523 73         179 join $self->raw, map join("", map $_->visual, @$_), @{ $self->{data} };
  73         322  
524             }
525              
526             sub merge {
527 0     0   0 my ($self) = @_;
528 0         0 my $tree = $self->{rx}{tree};
529 0 0       0 return unless @$tree;
530              
531 0 0       0 push @$tree, $self unless $tree->[-1] == $self;
532 0 0       0 return unless @$tree > 1;
533 0         0 my $prev = $tree->[-2];
534 0 0       0 return unless $prev->type eq $self->type;
535 0         0 push @{ $prev->{data} }, @{ $self->{data} };
  0         0  
  0         0  
536 0         0 pop @$tree;
537 0         0 return 1;
538             }
539              
540             sub walk {
541 20     20   73 my ($self, $ws, $d) = @_;
542 20 50       56 if ($d) {
543 20         66 my $br = $self->{rx}->object($self->type);
544 20         93 $br->omit(1);
545 20         34 for (reverse @{ $self->data }) {
  20         45  
546 30     30   220 unshift @$ws, $br, sub { -1 }, @$_, sub { +1 };
  30         80  
  30         86  
547             }
548 20         64 shift @$ws;
549             }
550             }
551              
552             sub insert {
553 55     55   120 my ($self, $tree) = @_;
554 55         123 my $rx = $self->{rx};
555 55         110 my $st = $rx->{stack};
556              
557             # this is a branch inside an IFTHEN
558 55 100 66     257 if (@$st and @{ $st->[-1] } and $st->[-1][-1]->type eq 'ifthen') {
  49 100 100     323  
      66        
      100        
559 18         75 my $ifthen = $st->[-1][-1];
560 18         33 my $cond = shift @{ $ifthen->{data} };
  18         57  
561 18         34 $ifthen->{data} = [ [ @{ $ifthen->{data} } ], $cond ];
  18         101  
562 18         68 $rx->{tree} = $ifthen->{data};
563             }
564              
565             # if this is the 2nd or 3rd (etc) branch...
566 31         166 elsif (@$st and @{ $st->[-1] } and $st->[-1][-1]->family eq $self->family) {
567 6         14 my $br = $st->[-1][-1];
568 6         18 $br->{data}[-1] = [ @$tree ];
569 6         11 for (@{ $br->{data}[-1] }) {
  6         47  
570 6 50 33     33 last unless $br->{zerolen} &&= $_->{zerolen};
571             }
572 6         11 push @{ $br->{data} }, [];
  6         29  
573 6         24 $rx->{tree} = $br->{data}[-1];
574             }
575              
576             # if this is the first branch
577             else {
578 31         97 $self->{data}[-1] = [ @$tree ];
579 31         52 push @{ $self->{data} }, [];
  31         84  
580 31         107 @$tree = $self;
581 31         74 $tree->[-1]{zerolen} = 1;
582 31         54 for (@{ $tree->[-1]{data}[0] }) {
  31         124  
583 31 50 33     187 last unless $tree->[-1]{zerolen} &&= $_->{zerolen};
584             }
585 31         63 push @$st, $tree;
586 31         98 $rx->{tree} = $self->{data}[-1];
587             }
588             }
589             }
590              
591              
592             {
593             package Regexp::Parser::exact;
594             our @ISA = qw( Regexp::Parser::__object__ );
595              
596             sub new {
597 513     513   1213 my ($class, $rx, $data, $vis) = @_;
598 513 100       1021 $vis = $data if not defined $vis;
599             my $self = bless {
600             rx => $rx,
601 513         2811 flags => $rx->{flags}[-1],
602             family => 'exact',
603             data => [$data],
604             vis => [$vis],
605             }, $class;
606 513         1918 return $self;
607             }
608              
609             sub visual {
610 445     445   878 my $self = shift;
611 445         596 join "", @{ $self->{vis} };
  445         2288  
612             }
613              
614             sub type {
615 509     509   806 my $self = shift;
616 509 100       1320 $self->{flags} & $self->{rx}->FLAG_i ? "exactf" : "exact";
617             }
618              
619             sub data {
620 1     1   3 my $self = shift;
621 1         3 join "", @{ $self->{data} };
  1         8  
622             }
623              
624             sub merge {
625 513     513   859 my ($self) = @_;
626 513         834 my $tree = $self->{rx}{tree};
627 513 50       919 return unless @$tree;
628              
629 513 50       1250 push @$tree, $self unless $tree->[-1] == $self;
630 513 100       1261 return unless @$tree > 1;
631 279         351 my $prev = $tree->[-2];
632 279 100       584 return unless $prev->type eq $self->type;
633            
634 190         259 push @{ $prev->{data} }, @{ $self->{data} };
  190         261  
  190         375  
635 190         255 push @{ $prev->{vis} }, @{ $self->{vis} };
  190         239  
  190         351  
636 190         269 pop @$tree;
637 190         351 return 1;
638             }
639             }
640              
641              
642             {
643             package Regexp::Parser::quant;
644             our @ISA = qw( Regexp::Parser::__object__ );
645              
646             sub new {
647 91     91   370 my ($class, $rx, $min, $max, $data) = @_;
648             my $self = bless {
649             rx => $rx,
650 91         480 flags => $rx->{flags}[-1],
651             family => 'quant',
652             data => $data,
653             min => $min,
654             max => $max,
655             }, $class;
656 91         451 return $self;
657             }
658              
659             sub min {
660 176     176   274 my $self = shift;
661 176         410 $self->{min};
662             }
663              
664             sub max {
665 176     176   228 my $self = shift;
666 176         452 $self->{max};
667             }
668              
669             sub type {
670 22     22   69 my $self = shift;
671 22         68 my ($min, $max) = ($self->min, $self->max);
672 22 100 66     144 if ($min == 0 and $max eq '') { 'star' }
  7 100 66     33  
673 6         25 elsif ($min == 1 and $max eq '') { 'plus' }
674 9         37 else { 'curly' }
675             }
676              
677             sub raw {
678 154     154   220 my $self = shift;
679 154         392 my ($min, $max) = ($self->min, $self->max);
680 154 100 100     835 if ($min == 0 and $max eq '') { '*' }
  49 100 66     240  
    100 66        
    100 100        
681 67         429 elsif ($min == 1 and $max eq '') { '+' }
682 7         29 elsif ($min == 0 and $max == 1) { '?' }
683 6         29 elsif ($max ne '' and $min == $max) { "{$min}" }
684 25         147 else { "{$min,$max}" }
685             }
686              
687             sub qr {
688 51     51   68 my $self = shift;
689 51         113 join "", $self->{data}->qr, $self->raw;
690             }
691              
692             sub visual {
693 103     103   180 my $self = shift;
694 103         386 join "", $self->{data}->visual, $self->raw;
695             }
696              
697             sub data {
698 0     0   0 my $self = shift;
699 0 0       0 if (@_) {
700 0         0 my $how = shift;
701 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
702 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
703             else {
704 0         0 my $t = $self->type;
705 0         0 Carp::croak("\$$t->data([+=], \@data)");
706             }
707             }
708 0         0 $self->{data};
709             }
710              
711             sub walk {
712 15     15   37 my ($self, $ws, $d) = @_;
713 15 100   11   107 unshift @$ws, sub { -1 }, $self->{data}, sub { +1 } if $d;
  11         31  
  11         63  
714             }
715              
716             sub insert {
717 91     91   147 my ($self, $tree) = @_;
718 91         163 my $rx = $self->{rx};
719              
720             # quantifiers must follow something
721 91 100 66     554 $rx->error($rx->RPe_EQUANT)
722             if @$tree == 0 or $tree->[-1]->family eq "flags";
723              
724             # quantifiers must NOT follow quantifiers
725 89 50       189 $rx->error($rx->RPe_NESTED)
726             if $tree->[-1]->family eq "quant";
727              
728             # on /abc+/, we extract the 'c' from the 'exact' node
729 89 50 66     162 if ($tree->[-1]->family eq "exact" and @{ $tree->[-1]->{data} } > 1) {
  37         96  
730 0         0 my $d = pop @{ $tree->[-1]->{data} };
  0         0  
731 0         0 my $v = pop @{ $tree->[-1]->{vis} };
  0         0  
732 0         0 my $q = $rx->object(exact => $d, $v);
733 0         0 $q->{flags} = $tree->[-1]->{flags};
734 0         0 $self->{data} = $q;
735 0         0 push @$tree, $self;
736             }
737             else {
738             # quantifier on (?{ ... }) is pointless;
739             # bounded quantifier (but not ?) on a
740             # zero-width assertion is unexpected
741 89 50 66     171 if (
    50 0        
      33        
      33        
      33        
742             ($tree->[-1]->family eq "assertion" and $tree->[-1]->type eq "eval") or
743             ($tree->[-1]->{zerolen} and !($self->{min} == 0 and $self->{max} == 1))
744             ) {
745 0         0 $rx->awarn($rx->RPe_ZQUANT);
746             }
747              
748             # unbounded quantifier on a zero-width
749             # assertion can match a null string a lot
750             elsif ($tree->[-1]->{zerolen} and $self->{max} eq '') {
751 0         0 $rx->awarn($rx->RPe_NULNUL, $tree->[-1]->visual . $self->raw);
752             }
753              
754 89         189 $self->{data} = $tree->[-1];
755 89         226 $tree->[-1] = $self;
756             }
757             }
758             }
759              
760              
761             {
762             # ( non-capturing
763             package Regexp::Parser::group;
764             our @ISA = qw( Regexp::Parser::__object__ );
765              
766             sub new {
767 48     48   132 my ($class, $rx, $on, $off, @data) = @_;
768             my $self = bless {
769             rx => $rx,
770 48         648 flags => $rx->{flags}[-1],
771             family => 'group',
772             type => 'group',
773             data => \@data,
774             on => $on,
775             off => $off,
776             down => 1,
777             }, $class;
778             }
779              
780             sub on {
781 6     6   7 my $self = shift;
782 6         10 $self->{on};
783             }
784              
785             sub off {
786 0     0   0 my $self = shift;
787 0         0 $self->{off};
788             }
789              
790             sub raw {
791 54     54   71 my $self = shift;
792 54 100       151 if ($self->{on} =~ /^\^/) {
793 4         16 return join "", "(?", $self->{on}, ":";
794             }
795             join "", "(?", $self->{on},
796 50 100       219 (length $self->{off} ? "-" : ""), $self->{off}, ":";
797             }
798              
799             sub qr {
800 6     6   6 my $self = shift;
801 6         12 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  6         17  
802             }
803              
804             sub visual {
805 48     48   113 my $self = shift;
806 48         108 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  48         238  
807             }
808              
809             sub data {
810 0     0   0 my $self = shift;
811 0 0       0 if (@_) {
812 0         0 my $how = shift;
813 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
814 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
815             else {
816 0         0 my $t = $self->type;
817 0         0 Carp::croak("\$$t->data([+=], \@data)");
818             }
819             }
820 0         0 $self->{data};
821             }
822              
823             sub walk {
824 1     1   4 my ($self, $ws, $d) = @_;
825 1         2 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  1         8  
826 1 50   1   7 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  1         4  
  1         15  
  1         3  
827             }
828              
829             sub insert {
830 48     48   109 my ($self, $tree) = @_;
831 48         106 my $rx = $self->{rx};
832 48         105 push @$tree, $self;
833 48         69 push @{ $rx->{stack} }, $tree;
  48         86  
834 48         121 $rx->{tree} = $self->{data};
835             }
836             }
837              
838              
839             {
840             # ( capturing
841             package Regexp::Parser::open;
842             our @ISA = qw( Regexp::Parser::__object__ );
843              
844             sub new {
845 60     60   160 my ($class, $rx, $nparen, @data) = @_;
846             my $self = bless {
847             rx => $rx,
848 60         596 flags => $rx->{flags}[-1],
849             family => 'open',
850             nparen => $nparen,
851             data => \@data,
852             raw => '(',
853             down => 1,
854             }, $class;
855 60         214 $self->{rx}{captures}[$nparen - 1] = $self;
856 60         371 return $self;
857             }
858              
859             sub type {
860 15     15   25 my $self = shift;
861 15         35 $self->family . $self->nparen;
862             }
863              
864             sub nparen {
865 80     80   2304 my $self = shift;
866 80         244 $self->{nparen};
867             }
868              
869             sub qr {
870 15     15   23 my $self = shift;
871 15         47 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  15         46  
872             }
873              
874             sub visual {
875 58     58   99 my $self = shift;
876 58         156 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  58         186  
877             }
878              
879             sub ender {
880 0     0   0 my $self = shift;
881 0         0 [ close => $self->nparen ];
882             }
883              
884             sub data {
885 0     0   0 my $self = shift;
886 0 0       0 if (@_) {
887 0         0 my $how = shift;
888 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
889 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
890             else {
891 0         0 my $t = $self->type;
892 0         0 Carp::croak("\$$t->data([+=], \@data)");
893             }
894             }
895 0         0 $self->{data};
896             }
897              
898             sub walk {
899 0     0   0 my ($self, $ws, $d) = @_;
900 0         0 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  0         0  
901 0 0   0   0 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  0         0  
  0         0  
  0         0  
902             }
903              
904             sub insert {
905 60     60   232 my ($self, $tree) = @_;
906 60         107 my $rx = $self->{rx};
907 60         141 push @$tree, $self;
908 60         93 push @{ $rx->{stack} }, $tree;
  60         203  
909 60         161 $rx->{tree} = $self->{data};
910             }
911             }
912              
913              
914             {
915             # ) closing
916             package Regexp::Parser::close;
917             our @ISA = qw( Regexp::Parser::__object__ );
918              
919             sub new {
920 167     167   403 my ($class, $rx, $nparen) = @_;
921             my $self = bless {
922             rx => $rx,
923 167         1072 flags => $rx->{flags}[-1],
924             family => 'close',
925             nparen => $nparen,
926             raw => ')',
927             omit => 1,
928             up => 1,
929             }, $class;
930 167         731 return $self;
931             }
932              
933             sub type {
934 0     0   0 my $self = shift;
935 0         0 $self->family . $self->nparen;
936             }
937              
938             sub nparen {
939 0     0   0 my $self = shift;
940 0         0 $self->{nparen};
941             }
942              
943             sub insert {
944 167     167   326 my ($self, $tree) = @_;
945 167         339 my $rx = $self->{rx};
946              
947             do {
948 192 50       275 $tree = pop @{ $rx->{stack} }
  192         913  
949             or $rx->error($rx->RPe_RPAREN)
950 167         259 } until $tree->[-1]->{down};
951              
952 167         343 $rx->{tree} = $tree;
953              
954 167 100 66     421 $self->{nparen} = $tree->[-1]->nparen
955             if $self->family eq 'close' and $tree->[-1]->can('nparen');
956              
957 167 100       425 if ($tree->[-1]->{ifthen}) {
958 18         37 my $ifthen = $tree->[-1];
959 18         49 my $br = $rx->object(branch =>);
960 18         37 my $cond;
961              
962 18 50       110 if (ref $ifthen->{data}[0] eq "ARRAY") {
963 18         35 (my($true), $cond) = splice @{ $ifthen->{data} }, 0, 2;
  18         56  
964 18         65 $br->{data} = [ $true, $ifthen->{data} ];
965             }
966             else {
967 0         0 $cond = shift @{ $ifthen->{data} };
  0         0  
968 0         0 $br->{data} = [ $ifthen->{data} ];
969             }
970              
971 18         46 $ifthen->{data} = [ $cond, $br ];
972             $ifthen->{zerolen} =
973 18         34 !grep !(grep $_->{zerolen}, @$_), @{ $ifthen->{data}[1]{data} };
  18         158  
974             }
975             else {
976             $tree->[-1]->{zerolen} ||=
977 149   66     540 !grep !$_->{zerolen}, @{ $tree->[-1]->{data} };
  123         609  
978             }
979              
980 167 50       506 push @$tree, $self unless $self->omit;
981             }
982             }
983              
984              
985             {
986             # ) for non-captures
987             package Regexp::Parser::tail;
988             our @ISA = qw( Regexp::Parser::__object__ );
989              
990             sub new {
991 11     11   58 my ($class, $rx) = @_;
992             my $self = bless {
993             rx => $rx,
994 11         110 flags => $rx->{flags}[-1],
995             family => 'close',
996             type => 'tail',
997             raw => ')',
998             omit => 1,
999             up => 1,
1000             }, $class;
1001 11         38 return $self;
1002             }
1003              
1004             sub insert {
1005 0     0   0 my ($self, $tree) = @_;
1006 0         0 my $rx = $self->{rx};
1007              
1008             do {
1009 0 0       0 $rx->{tree} = pop @{ $rx->{stack} }
  0         0  
1010             or $rx->error($rx->RPe_RPAREN)
1011 0         0 } until $tree->[-1]->{down};
1012              
1013 0 0 0     0 $self->{nparen} = $tree->[-1]->nparen
1014             if $self->family eq 'close' and $tree->[-1]->can('nparen');
1015              
1016 0 0       0 if ($tree->[-1]->{ifthen}) {
1017 0         0 my $ifthen = $tree->[-1];
1018 0         0 my $br = $rx->object(branch =>);
1019 0         0 my $cond;
1020              
1021 0 0       0 if (ref $ifthen->{data}[0] eq "ARRAY") {
1022 0         0 (my($true), $cond) = splice @{ $ifthen->{data} }, 0, 2;
  0         0  
1023 0         0 $br->{data} = [ $true, $ifthen->{data} ];
1024             }
1025             else {
1026 0         0 $cond = shift @{ $ifthen->{data} };
  0         0  
1027 0         0 $br->{data} = [ $ifthen->{data} ];
1028             }
1029              
1030 0         0 $ifthen->{data} = [ $cond, $br ];
1031             $ifthen->{zerolen} =
1032 0         0 !grep !(grep $_->{zerolen}, @$_), @{ $ifthen->{data}[1]{data} };
  0         0  
1033             }
1034             else {
1035             $tree->[-1]->{zerolen} ||=
1036 0   0     0 !grep !$_->{zerolen}, @{ $tree->[-1]->{data} };
  0         0  
1037             }
1038              
1039 0 0       0 push @$tree, $self unless $self->omit;
1040             }
1041             }
1042              
1043              
1044             {
1045             # \1 (backrefs)
1046             package Regexp::Parser::ref;
1047             our @ISA = qw( Regexp::Parser::__object__ );
1048              
1049             sub new {
1050 16     16   53 my ($class, $rx, $nparen, $vis) = @_;
1051             my $self = bless {
1052             rx => $rx,
1053 16 50       131 flags => $rx->{flags}[-1],
1054             family => 'ref',
1055             nparen => $nparen,
1056             ($vis ? (vis => $vis) : ()),
1057             }, $class;
1058 16         119 return $self;
1059             }
1060              
1061             sub type {
1062 0     0   0 my $self = shift;
1063 0 0       0 ($self->{flags} & $self->{rx}->FLAG_i ? 'reff' : 'ref') . $self->nparen;
1064             }
1065              
1066             sub nparen {
1067 0     0   0 my $self = shift;
1068 0         0 $self->{nparen};
1069             }
1070              
1071             sub visual {
1072 13     13   23 my $self = shift;
1073 13 50       61 exists $self->{vis} ? $self->{vis} : "\\$self->{nparen}";
1074             }
1075              
1076             sub qr {
1077 6     6   12 my $self = shift;
1078             # Always emit \N format for qr() regardless of visual form
1079 6         26 "\\$self->{nparen}";
1080             }
1081             }
1082              
1083              
1084             {
1085             # \g{name} named backreference (Perl 5.10+)
1086             package Regexp::Parser::gref;
1087             our @ISA = qw( Regexp::Parser::__object__ );
1088              
1089             sub new {
1090 0     0   0 my ($class, $rx, $name, $vis) = @_;
1091             my $self = bless {
1092             rx => $rx,
1093 0         0 flags => $rx->{flags}[-1],
1094             family => 'ref',
1095             type => 'gref',
1096             name => $name,
1097             vis => $vis,
1098             }, $class;
1099 0         0 return $self;
1100             }
1101              
1102             sub name {
1103 0     0   0 my $self = shift;
1104 0         0 $self->{name};
1105             }
1106              
1107             sub visual {
1108 0     0   0 my $self = shift;
1109 0         0 $self->{vis};
1110             }
1111              
1112             sub qr {
1113 0     0   0 my $self = shift;
1114 0         0 "\\g{$self->{name}}";
1115             }
1116             }
1117              
1118              
1119             {
1120             package Regexp::Parser::assertion;
1121             our @ISA = qw( Regexp::Parser::__object__ );
1122              
1123             push @Regexp::Parser::ifmatch::ISA, __PACKAGE__;
1124             push @Regexp::Parser::unlessm::ISA, __PACKAGE__;
1125             push @Regexp::Parser::suspend::ISA, __PACKAGE__;
1126             push @Regexp::Parser::ifthen::ISA, __PACKAGE__;
1127             push @Regexp::Parser::eval::ISA, __PACKAGE__;
1128             push @Regexp::Parser::logical::ISA, __PACKAGE__;
1129              
1130             sub qr {
1131 6     6   41 my $self = shift;
1132 6         13 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  6         20  
1133             }
1134              
1135             sub visual {
1136 36     36   72 my $self = shift;
1137 36         87 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  36         127  
1138             }
1139              
1140             sub data {
1141 0     0   0 my $self = shift;
1142 0 0       0 if (@_) {
1143 0         0 my $how = shift;
1144 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
1145 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
1146             else {
1147 0         0 my $t = $self->type;
1148 0         0 Carp::croak("\$$t->data([+=], \@data)");
1149             }
1150             }
1151 0         0 $self->{data};
1152             }
1153              
1154             sub walk {
1155 10     10   26 my ($self, $ws, $d) = @_;
1156 10         26 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  10         39  
1157 10 50   10   63 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  10         33  
  10         57  
  10         26  
1158             }
1159              
1160             sub insert {
1161 50     50   109 my ($self, $tree) = @_;
1162 50         143 my $rx = $self->{rx};
1163 50         108 push @$tree, $self;
1164 50         82 push @{ $rx->{stack} }, $tree;
  50         111  
1165 50         142 $rx->{tree} = $self->{data};
1166             }
1167             }
1168              
1169              
1170             {
1171             # (?=) (?<=)
1172             package Regexp::Parser::ifmatch;
1173              
1174             sub new {
1175 16     16   48 my ($class, $rx, $dir, @data) = @_;
1176             my $self = bless {
1177             rx => $rx,
1178 16         119 flags => $rx->{flags}[-1],
1179             family => 'assertion',
1180             type => 'ifmatch',
1181             dir => $dir,
1182             data => \@data,
1183             down => 1,
1184             zerolen => 1,
1185             }, $class;
1186 16         80 return $self;
1187             }
1188              
1189             sub dir {
1190 0     0   0 my $self = shift;
1191 0         0 $self->{dir};
1192             }
1193              
1194             sub raw {
1195 18     18   30 my $self = shift;
1196 18 100       81 join "", "(?", ($self->{dir} < 0 ? '<' : ''), "=";
1197             }
1198             }
1199              
1200              
1201             {
1202             # (?!) (?
1203             package Regexp::Parser::unlessm;
1204              
1205             sub new {
1206 16     16   39 my ($class, $rx, $dir, @data) = @_;
1207             my $self = bless {
1208             rx => $rx,
1209 16         123 flags => $rx->{flags}[-1],
1210             family => 'assertion',
1211             type => 'unlessm',
1212             dir => $dir,
1213             data => \@data,
1214             down => 1,
1215             zerolen => 1,
1216             }, $class;
1217 16         79 return $self;
1218             }
1219              
1220             sub dir {
1221 0     0   0 my $self = shift;
1222 0         0 $self->{dir};
1223             }
1224              
1225             sub raw {
1226 18     18   27 my $self = shift;
1227 18 100       86 join "", "(?", ($self->{dir} < 0 ? '<' : ''), "!";
1228             }
1229             }
1230              
1231              
1232             {
1233             # (?>)
1234             package Regexp::Parser::suspend;
1235              
1236             sub new {
1237 6     6   17 my ($class, $rx, @data) = @_;
1238             my $self = bless {
1239             rx => $rx,
1240 6         50 flags => $rx->{flags}[-1],
1241             family => 'assertion',
1242             type => 'suspend',
1243             data => \@data,
1244             down => 1,
1245             }, $class;
1246 6         39 return $self;
1247             }
1248              
1249             sub raw {
1250 6     6   12 my $self = shift;
1251 6         13 "(?>";
1252             }
1253             }
1254              
1255             {
1256             # (?(n)t|f)
1257             package Regexp::Parser::ifthen;
1258              
1259             sub new {
1260 18     18   54 my ($class, $rx, @data) = @_;
1261             my $self = bless {
1262             rx => $rx,
1263 18         185 flags => $rx->{flags}[-1],
1264             family => 'assertion',
1265             type => 'ifthen',
1266             data => [],
1267             down => 1,
1268             ifthen => 1,
1269             }, $class;
1270 18         134 return $self;
1271             }
1272              
1273             sub raw {
1274 18     18   36 my $self = shift;
1275 18         82 "(?";
1276             }
1277              
1278             sub qr {
1279 0     0   0 my $self = shift;
1280 0         0 join "", $self->raw, $self->{data}[0]->qr, $self->{data}[1]->qr, ")";
1281             }
1282              
1283             sub visual {
1284 18     18   55 my $self = shift;
1285 18         49 join "", $self->raw, $self->{data}[0]->visual, $self->{data}[1]->visual, ")";
1286             }
1287             }
1288              
1289              
1290             {
1291             # the N in (?(N)t|f) when N is a number
1292             package Regexp::Parser::groupp;
1293             our @ISA = qw( Regexp::Parser::__object__ );
1294              
1295             sub new {
1296 3     3   12 my ($class, $rx, $nparen) = @_;
1297             my $self = bless {
1298             rx => $rx,
1299 3         21 flags => $rx->{flags}[-1],
1300             family => 'groupp',
1301             nparen => $nparen,
1302             }, $class;
1303 3         18 return $self;
1304             }
1305              
1306             sub type {
1307 7     7   16 my $self = shift;
1308 7         30 $self->family . $self->nparen;
1309             }
1310              
1311             sub nparen {
1312 7     7   16 my $self = shift;
1313 7         72 $self->{nparen};
1314             }
1315              
1316             sub visual {
1317 4     4   12 my $self = shift;
1318 4         22 "($self->{nparen})";
1319             }
1320             }
1321              
1322              
1323             {
1324             # (?{ ... })
1325             package Regexp::Parser::eval;
1326              
1327             sub new {
1328 5     5   27 my ($class, $rx, $code) = @_;
1329             my $self = bless {
1330             rx => $rx,
1331 5         45 flags => $rx->{flags}[-1],
1332             family => 'assertion',
1333             type => 'eval',
1334             data => $code,
1335             zerolen => 1,
1336             }, $class;
1337 5         49 return $self;
1338             }
1339              
1340             sub visual {
1341 6     6   17 my $self = shift;
1342 6         32 "(?{$self->{data}})";
1343             }
1344              
1345             sub qr {
1346 0     0   0 my $self = shift;
1347 0         0 $self->visual;
1348             }
1349              
1350             sub insert {
1351 5     5   13 my ($self, $tree) = @_;
1352 5         15 push @$tree, $self;
1353             }
1354              
1355             sub walk {
1356 1     1   3 my $self = shift;
1357 1         3 return;
1358             }
1359             }
1360              
1361              
1362             {
1363             # (??{ ... })
1364             package Regexp::Parser::logical;
1365              
1366             sub new {
1367 2     2   11 my ($class, $rx, $code) = @_;
1368             my $self = bless {
1369             rx => $rx,
1370 2         19 flags => $rx->{flags}[-1],
1371             family => 'assertion',
1372             type => 'logical',
1373             data => $code,
1374             zerolen => 1,
1375             }, $class;
1376 2         54 return $self;
1377             }
1378              
1379             sub visual {
1380 2     2   8 my $self = shift;
1381 2         10 "(??{$self->{data}})";
1382             }
1383              
1384             sub qr {
1385 0     0   0 my $self = shift;
1386 0         0 $self->visual;
1387             }
1388              
1389             sub insert {
1390 2     2   8 my ($self, $tree) = @_;
1391 2         6 push @$tree, $self;
1392             }
1393              
1394             sub walk {
1395 0     0   0 my $self = shift;
1396 0         0 return;
1397             }
1398             }
1399              
1400              
1401             {
1402             package Regexp::Parser::flags;
1403             our @ISA = qw( Regexp::Parser::__object__ );
1404              
1405             sub new {
1406 10     10   22 my ($class, $rx, $on, $off) = @_;
1407             my $self = bless {
1408             rx => $rx,
1409 10         62 flags => $rx->{flags}[-1],
1410             family => 'flags',
1411             type => 'flags',
1412             on => $on,
1413             off => $off,
1414             zerolen => 1,
1415             }, $class;
1416 10         43 return $self;
1417             }
1418              
1419             sub on {
1420 0     0   0 my $self = shift;
1421 0         0 $self->{on};
1422             }
1423              
1424             sub off {
1425 0     0   0 my $self = shift;
1426 0         0 $self->{off};
1427             }
1428              
1429             sub visual {
1430 10     10   19 my $self = shift;
1431 10 100       29 if ($self->{on} =~ /^\^/) {
1432 2         6 return join "", "(?", $self->{on}, ")";
1433             }
1434             join "", "(?", $self->{on},
1435 8 100       45 (length $self->{off} ? "-" : ""), $self->{off}, ")";
1436             }
1437             }
1438              
1439              
1440             {
1441             package Regexp::Parser::minmod;
1442             our @ISA = qw( Regexp::Parser::__object__ );
1443              
1444             sub new {
1445 12     12   28 my ($class, $rx, $data) = @_;
1446             my $self = bless {
1447             rx => $rx,
1448 12         53 flags => $rx->{flags}[-1],
1449             family => 'minmod',
1450             type => 'minmod',
1451             raw => '?',
1452             data => $data,
1453             }, $class;
1454 12         33 return $self;
1455             }
1456              
1457             sub qr {
1458 11     11   24 my $self = shift;
1459 11         29 join "", $self->{data}->qr, $self->raw;
1460             }
1461              
1462             sub visual {
1463 15     15   33 my $self = shift;
1464 15         40 join "", $self->{data}->visual, $self->raw;
1465             }
1466              
1467             sub walk {
1468 4     4   13 my ($self, $ws, $d) = @_;
1469 4 100   3   33 unshift @$ws, sub { -1 }, $self->{data}, sub { +1 } if $d;
  3         10  
  3         10  
1470             }
1471              
1472             sub insert {
1473 12     12   19 my ($self, $tree) = @_;
1474 12         39 $self->{data} = $tree->[-1];
1475 12         18 $tree->[-1] = $self;
1476             }
1477             }
1478              
1479              
1480             {
1481             # \K (keep, zero-width assertion added in Perl 5.10)
1482             package Regexp::Parser::keep;
1483             our @ISA = qw( Regexp::Parser::__object__ );
1484              
1485             sub new {
1486 3     3   6 my ($class, $rx) = @_;
1487             my $self = bless {
1488             rx => $rx,
1489 3         16 flags => $rx->{flags}[-1],
1490             family => 'anchor',
1491             type => 'keep',
1492             vis => '\K',
1493             zerolen => 1,
1494             }, $class;
1495 3         10 return $self;
1496             }
1497             }
1498              
1499              
1500             {
1501             # \h \H (horizontal whitespace, added in Perl 5.10)
1502             package Regexp::Parser::hspace;
1503             our @ISA = qw( Regexp::Parser::__object__ );
1504              
1505             sub new {
1506 10     10   21 my ($class, $rx, $neg) = @_;
1507             my $self = bless {
1508             rx => $rx,
1509 10         32 flags => $rx->{flags}[-1],
1510             neg => $neg,
1511             }, $class;
1512 10         30 return $self;
1513             }
1514              
1515             sub neg {
1516 2     2   4 my $self = shift;
1517 2 50       6 $self->{neg} = shift if @_;
1518 2         8 $self->{neg};
1519             }
1520              
1521             sub type {
1522 2     2   3 my $self = shift;
1523 2 100       9 ($self->{neg} ? 'n' : '') . $self->family;
1524             }
1525              
1526 12     12   42 sub family { 'hspace' }
1527              
1528             sub visual {
1529 6     6   8 my $self = shift;
1530 6 100       25 $self->{neg} ? '\H' : '\h';
1531             }
1532             }
1533              
1534              
1535             {
1536             # \v \V (vertical whitespace, added in Perl 5.10)
1537             package Regexp::Parser::vspace;
1538             our @ISA = qw( Regexp::Parser::__object__ );
1539              
1540             sub new {
1541 6     6   12 my ($class, $rx, $neg) = @_;
1542             my $self = bless {
1543             rx => $rx,
1544 6         18 flags => $rx->{flags}[-1],
1545             neg => $neg,
1546             }, $class;
1547 6         20 return $self;
1548             }
1549              
1550             sub neg {
1551 2     2   4 my $self = shift;
1552 2 50       7 $self->{neg} = shift if @_;
1553 2         7 $self->{neg};
1554             }
1555              
1556             sub type {
1557 2     2   5 my $self = shift;
1558 2 100       8 ($self->{neg} ? 'n' : '') . $self->family;
1559             }
1560              
1561 4     4   26 sub family { 'vspace' }
1562              
1563             sub visual {
1564 3     3   4 my $self = shift;
1565 3 100       12 $self->{neg} ? '\V' : '\v';
1566             }
1567             }
1568              
1569              
1570             {
1571             # \R (generic linebreak, added in Perl 5.10)
1572             package Regexp::Parser::lnbreak;
1573             our @ISA = qw( Regexp::Parser::__object__ );
1574              
1575             sub new {
1576 4     4   14 my ($class, $rx) = @_;
1577             my $self = bless {
1578             rx => $rx,
1579 4         31 flags => $rx->{flags}[-1],
1580             family => 'lnbreak',
1581             type => 'lnbreak',
1582             vis => '\R',
1583             }, $class;
1584 4         22 return $self;
1585             }
1586             }
1587              
1588              
1589             {
1590             # (?...) named capture group (added in Perl 5.10)
1591             package Regexp::Parser::named_open;
1592             our @ISA = qw( Regexp::Parser::__object__ );
1593              
1594             sub new {
1595 9     9   19 my ($class, $rx, $nparen, $name, @data) = @_;
1596             my $self = bless {
1597             rx => $rx,
1598 9         82 flags => $rx->{flags}[-1],
1599             family => 'open',
1600             nparen => $nparen,
1601             name => $name,
1602             data => \@data,
1603             raw => "(?<$name>",
1604             down => 1,
1605             }, $class;
1606 9         27 $self->{rx}{captures}[$nparen - 1] = $self;
1607 9         40 return $self;
1608             }
1609              
1610             sub type {
1611 0     0   0 my $self = shift;
1612 0         0 'open' . $self->nparen;
1613             }
1614              
1615             sub nparen {
1616 10     10   15 my $self = shift;
1617 10         18 $self->{nparen};
1618             }
1619              
1620             sub name {
1621 1     1   2 my $self = shift;
1622 1         5 $self->{name};
1623             }
1624              
1625             sub qr {
1626 0     0   0 my $self = shift;
1627 0         0 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  0         0  
1628             }
1629              
1630             sub visual {
1631 7     7   10 my $self = shift;
1632 7         19 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  7         20  
1633             }
1634              
1635             sub ender {
1636 0     0   0 my $self = shift;
1637 0         0 [ close => $self->nparen ];
1638             }
1639              
1640             sub data {
1641 0     0   0 my $self = shift;
1642 0 0       0 if (@_) {
1643 0         0 my $how = shift;
1644 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
1645 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
1646             else {
1647 0         0 my $t = $self->type;
1648 0         0 Carp::croak("\$$t->data([+=], \@data)");
1649             }
1650             }
1651 0         0 $self->{data};
1652             }
1653              
1654             sub walk {
1655 0     0   0 my ($self, $ws, $d) = @_;
1656 0         0 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  0         0  
1657 0 0   0   0 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  0         0  
  0         0  
  0         0  
1658             }
1659              
1660             sub insert {
1661 9     9   96 my ($self, $tree) = @_;
1662 9         14 my $rx = $self->{rx};
1663 9         12 push @$tree, $self;
1664 9         11 push @{ $rx->{stack} }, $tree;
  9         30  
1665 9         56 $rx->{tree} = $self->{data};
1666             }
1667             }
1668              
1669              
1670             {
1671             # \k named backreference (added in Perl 5.10)
1672             package Regexp::Parser::named_ref;
1673             our @ISA = qw( Regexp::Parser::__object__ );
1674              
1675             sub new {
1676 4     4   14 my ($class, $rx, $name, $vis) = @_;
1677             my $self = bless {
1678             rx => $rx,
1679 4         21 flags => $rx->{flags}[-1],
1680             family => 'ref',
1681             name => $name,
1682             vis => $vis,
1683             }, $class;
1684 4         15 return $self;
1685             }
1686              
1687             sub type {
1688 0     0   0 my $self = shift;
1689 0 0       0 ($self->{flags} & $self->{rx}->FLAG_i ? 'named_reff' : 'named_ref');
1690             }
1691              
1692             sub name {
1693 1     1   2 my $self = shift;
1694 1         4 $self->{name};
1695             }
1696              
1697             sub visual {
1698 3     3   4 my $self = shift;
1699 3         8 $self->{vis};
1700             }
1701             }
1702              
1703              
1704             {
1705             # possessive quantifier modifier (added in Perl 5.10)
1706             package Regexp::Parser::possessive;
1707             our @ISA = qw( Regexp::Parser::__object__ );
1708              
1709             sub new {
1710 8     8   17 my ($class, $rx, $data) = @_;
1711             my $self = bless {
1712             rx => $rx,
1713 8         34 flags => $rx->{flags}[-1],
1714             family => 'possessive',
1715             type => 'possessive',
1716             raw => '+',
1717             data => $data,
1718             }, $class;
1719 8         20 return $self;
1720             }
1721              
1722             sub qr {
1723 0     0   0 my $self = shift;
1724 0         0 join "", $self->{data}->qr, $self->raw;
1725             }
1726              
1727             sub visual {
1728 7     7   8 my $self = shift;
1729 7         18 join "", $self->{data}->visual, $self->raw;
1730             }
1731              
1732             sub walk {
1733 0     0   0 my ($self, $ws, $d) = @_;
1734 0 0   0   0 unshift @$ws, sub { -1 }, $self->{data}, sub { +1 } if $d;
  0         0  
  0         0  
1735             }
1736              
1737             sub insert {
1738 8     8   11 my ($self, $tree) = @_;
1739 8         14 $self->{data} = $tree->[-1];
1740 8         9 $tree->[-1] = $self;
1741             }
1742             }
1743              
1744              
1745             1;
1746              
1747             __END__