File Coverage

blib/lib/Regexp/Parser/Objects.pm
Criterion Covered Total %
statement 508 751 67.6
branch 105 228 46.0
condition 42 72 58.3
subroutine 157 213 73.7
pod n/a
total 812 1264 64.2


line stmt bran cond sub pod time code
1 16     46   8538 use NEXT;
  16         113372  
  16         242426  
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 708     708   3302 my $self = shift;
19 708         4774 $self->{family};
20             }
21              
22             sub type {
23 212     212   333 my $self = shift;
24 212         786 $self->{type};
25             }
26              
27             sub qr {
28 106     106   138 my $self = shift;
29 106         215 $self->visual(@_);
30             }
31              
32             sub visual {
33 191     191   312 my $self = shift;
34 191 100       808 exists $self->{vis} ? $self->{vis} : '';
35             }
36              
37             sub raw {
38 215     215   342 my $self = shift;
39 215 50       681 exists $self->{raw} ? $self->{raw} : $self->visual(@_);
40             }
41              
42             sub data {
43 57     57   111 my $self = shift;
44 57         155 return $self->{data};
45             }
46              
47             sub ender {
48 11     11   22 my $self = shift;
49 11 50       36 unless ($self->{down}) {
50 0         0 Carp::carp("ender() ignored for ", $self->family, "/", $self->type);
51 0         0 return;
52             }
53 11         64 [ 'tail' ];
54             }
55              
56             sub walk {
57 66     66   113 my $self = shift;
58 66         131 return;
59             }
60              
61             sub omit {
62 1113     1113   1456 my $self = shift;
63 1113 100       2265 $self->{omit} = shift if @_;
64 1113         2681 $self->{omit};
65             }
66              
67             sub insert {
68 864     864   1702 my ($self, $tree) = @_;
69 864         1527 my $rx = $self->{rx};
70 864         1195 my $merged = 0;
71 864 50       1714 return if $self->omit;
72 864         1529 push @$tree, $self;
73 864         1869 $self->merge;
74             }
75              
76             sub merge {
77 242     242   422 my ($self) = @_;
78 242         505 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   87 my ($class, $rx, $type, $vis) = @_;
94 36 50       96 Carp::croak("anchor is an abstract class") if $class =~ /::anchor$/;
95              
96             my $self = bless {
97             rx => $rx,
98 36         225 flags => $rx->{flags}[-1],
99             family => 'anchor',
100             type => $type,
101             vis => $vis,
102             zerolen => 1,
103             }, $class;
104 36         146 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         81 flags => $rx->{flags}[-1],
119             family => 'reg_any',
120             type => $type,
121             vis => $vis,
122             }, $class;
123 9         40 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 21     21   50 my ($class, $rx, $neg) = @_;
135             my $self = bless {
136             rx => $rx,
137 21         187 flags => $rx->{flags}[-1],
138             neg => $neg,
139             }, $class;
140 21         97 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 38     38   167 sub family { 'alnum' }
150              
151             sub type {
152 2     2   3 my $self = shift;
153 2 50       8 ($self->{neg} ? 'n' : '') . $self->family;
154             }
155              
156             sub visual {
157 14     14   25 my $self = shift;
158 14 100       66 $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   34 my ($class, $rx, $neg) = @_;
170             my $self = bless {
171             rx => $rx,
172 16         73 flags => $rx->{flags}[-1],
173             neg => $neg,
174             }, $class;
175 16         58 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   100 sub family { 'space' }
190              
191             sub visual {
192 12     12   18 my $self = shift;
193 12 100       54 $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 22     22   83 my ($class, $rx, $neg) = @_;
205             my $self = bless {
206             rx => $rx,
207 22         104 flags => $rx->{flags}[-1],
208             neg => $neg,
209             }, $class;
210 22         93 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 56     56   231 sub family { 'digit' }
225              
226             sub visual {
227 30     30   63 my $self = shift;
228 30 100       108 $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 39     39   96 my ($class, $rx, $neg, @data) = @_;
239             my $self = bless {
240             rx => $rx,
241 39         298 flags => $rx->{flags}[-1],
242             family => 'anyof',
243             type => 'anyof',
244             neg => $neg,
245             data => \@data,
246             down => 1,
247             }, $class;
248 39         180 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 39     39   66 my $self = shift;
258 39         88 join "", $self->raw, map($_->visual, @{ $self->{data} }), "]";
  39         129  
259             }
260              
261             sub raw {
262 39     39   57 my $self = shift;
263 39 100       187 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 39     39   89 my ($self, $tree) = @_;
299 39         79 my $rx = $self->{rx};
300 39         215 push @$tree, $self;
301 39         61 push @{ $rx->{stack} }, $tree;
  39         73  
302 39         112 $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 111     111   307 my ($class, $rx, $data, $vis) = @_;
313 111 100       258 $vis = $data if not defined $vis;
314             my $self = bless {
315             rx => $rx,
316 111         790 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 9     9   24 my ($class, $rx, $lhs, $rhs) = @_;
332             my $self = bless {
333             rx => $rx,
334 9         78 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 9     9   15 my $self = shift;
348 9         39 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   115 my ($class, $rx, $type, $neg, $how) = @_;
359             my $self = bless {
360             rx => $rx,
361 48         204 flags => $rx->{flags}[-1],
362             family => 'anyof_class',
363             }, $class;
364              
365 48 100       107 if (ref $type) {
366 34         86 $self->{data} = $type;
367             }
368             else {
369 14         32 $self->{type} = $type;
370 14         24 $self->{data} = 'POSIX';
371 14         43 $self->{neg} = $neg;
372 14         32 $self->{how} = $how;
373             }
374              
375 48         193 return $self;
376             }
377              
378             sub type {
379 2     2   3 my $self = shift;
380 2 50       6 if (ref $self->{data}) {
381 2         6 $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   38 my $self = shift;
406 24 100       56 if (ref $self->{data}) {
407 17         42 $self->{data}->visual;
408             }
409             else {
410             my $how = ref $self->{how} eq 'SCALAR' ?
411 7         17 ${ $self->{how} } :
412 7 50       23 $self->{how};
413             join "", "[", $how, ($self->{neg} ? '^' : ''),
414 7 100       48 $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 39     39   94 my ($class, $rx) = @_;
426             my $self = bless {
427             rx => $rx,
428 39         277 flags => $rx->{flags}[-1],
429             family => 'close',
430             type => 'anyof_close',
431             raw => ']',
432             omit => 1,
433             up => 1,
434             }, $class;
435 39         165 return $self;
436             }
437              
438             sub insert {
439 39     39   64 my $self = shift;
440 39         84 my $rx = $self->{rx};
441 39         50 $rx->{tree} = pop @{ $rx->{stack} };
  39         106  
442 39         101 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   16 my ($class, $rx, $type, $neg) = @_;
453             my $self = bless {
454             rx => $rx,
455 5 100       63 flags => $rx->{flags}[-1],
456             family => 'prop',
457             type => $type,
458             data => '',
459             neg => ($neg ? 1 : 0),
460             }, $class;
461 5         32 return $self;
462             }
463              
464             sub type {
465 5     5   9 my $self = shift;
466 5         43 $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   10 my $self = shift;
477 5 100       28 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 101     101   255 my ($class, $rx) = @_;
505             my $self = bless {
506             rx => $rx,
507 101         1078 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   6 my $self = shift;
518 3         9 join $self->raw, map join("", map $_->qr, @$_), @{ $self->{data} };
  3         11  
519             }
520              
521             sub visual {
522 80     80   194 my $self = shift;
523 80         416 join $self->raw, map join("", map $_->visual, @$_), @{ $self->{data} };
  80         473  
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   52 my ($self, $ws, $d) = @_;
542 20 50       52 if ($d) {
543 20         67 my $br = $self->{rx}->object($self->type);
544 20         68 $br->omit(1);
545 20         28 for (reverse @{ $self->data }) {
  20         43  
546 30     30   222 unshift @$ws, $br, sub { -1 }, @$_, sub { +1 };
  30         64  
  30         70  
547             }
548 20         50 shift @$ws;
549             }
550             }
551              
552             sub insert {
553 65     65   136 my ($self, $tree) = @_;
554 65         136 my $rx = $self->{rx};
555 65         166 my $st = $rx->{stack};
556              
557             # this is a branch inside an IFTHEN
558 65 100 66     221 if (@$st and @{ $st->[-1] } and $st->[-1][-1]->type eq 'ifthen') {
  56 100 100     377  
      66        
      100        
559 18         35 my $ifthen = $st->[-1][-1];
560 18         27 my $cond = shift @{ $ifthen->{data} };
  18         43  
561 18         33 $ifthen->{data} = [ [ @{ $ifthen->{data} } ], $cond ];
  18         51  
562 18         63 $rx->{tree} = $ifthen->{data};
563             }
564              
565             # if this is the 2nd or 3rd (etc) branch...
566 38         184 elsif (@$st and @{ $st->[-1] } and $st->[-1][-1]->family eq $self->family) {
567 8         17 my $br = $st->[-1][-1];
568 8         27 $br->{data}[-1] = [ @$tree ];
569 8         17 for (@{ $br->{data}[-1] }) {
  8         27  
570 8 50 33     38 last unless $br->{zerolen} &&= $_->{zerolen};
571             }
572 8         15 push @{ $br->{data} }, [];
  8         22  
573 8         32 $rx->{tree} = $br->{data}[-1];
574             }
575              
576             # if this is the first branch
577             else {
578 39         349 $self->{data}[-1] = [ @$tree ];
579 39         67 push @{ $self->{data} }, [];
  39         112  
580 39         182 @$tree = $self;
581 39         105 $tree->[-1]{zerolen} = 1;
582 39         129 for (@{ $tree->[-1]{data}[0] }) {
  39         150  
583 39 50 33     239 last unless $tree->[-1]{zerolen} &&= $_->{zerolen};
584             }
585 39         74 push @$st, $tree;
586 39         119 $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 622     622   1430 my ($class, $rx, $data, $vis) = @_;
598 622 100       1365 $vis = $data if not defined $vis;
599             my $self = bless {
600             rx => $rx,
601 622         3635 flags => $rx->{flags}[-1],
602             family => 'exact',
603             data => [$data],
604             vis => [$vis],
605             }, $class;
606 622         2343 return $self;
607             }
608              
609             sub visual {
610 510     510   924 my $self = shift;
611 510         693 join "", @{ $self->{vis} };
  510         2627  
612             }
613              
614             sub type {
615 580     580   833 my $self = shift;
616 580 100       1676 $self->{flags} & $self->{rx}->FLAG_i ? "exactf" : "exact";
617             }
618              
619             sub data {
620 1     1   3 my $self = shift;
621 1         2 join "", @{ $self->{data} };
  1         8  
622             }
623              
624             sub merge {
625 622     622   1064 my ($self) = @_;
626 622         1019 my $tree = $self->{rx}{tree};
627 622 50       1422 return unless @$tree;
628              
629 622 50       1458 push @$tree, $self unless $tree->[-1] == $self;
630 622 100       1627 return unless @$tree > 1;
631 319         514 my $prev = $tree->[-2];
632 319 100       827 return unless $prev->type eq $self->type;
633            
634 221         346 push @{ $prev->{data} }, @{ $self->{data} };
  221         373  
  221         567  
635 221         307 push @{ $prev->{vis} }, @{ $self->{vis} };
  221         391  
  221         481  
636 221         357 pop @$tree;
637 221         481 return 1;
638             }
639             }
640              
641              
642             {
643             package Regexp::Parser::quant;
644             our @ISA = qw( Regexp::Parser::__object__ );
645              
646             sub new {
647 98     98   277 my ($class, $rx, $min, $max, $data) = @_;
648             my $self = bless {
649             rx => $rx,
650 98         540 flags => $rx->{flags}[-1],
651             family => 'quant',
652             data => $data,
653             min => $min,
654             max => $max,
655             }, $class;
656 98         330 return $self;
657             }
658              
659             sub min {
660 184     184   284 my $self = shift;
661 184         468 $self->{min};
662             }
663              
664             sub max {
665 184     184   3313 my $self = shift;
666 184         486 $self->{max};
667             }
668              
669             sub type {
670 23     23   45 my $self = shift;
671 23         67 my ($min, $max) = ($self->min, $self->max);
672 23 100 100     142 if ($min == 0 and $max eq '') { 'star' }
  7 100 66     32  
673 6         24 elsif ($min == 1 and $max eq '') { 'plus' }
674 10         41 else { 'curly' }
675             }
676              
677             sub raw {
678 161     161   230 my $self = shift;
679 161         305 my ($min, $max) = ($self->min, $self->max);
680 161 100 100     877 if ($min == 0 and $max eq '') { '*' }
  49 100 66     193  
    100 66        
    100 100        
681 72         452 elsif ($min == 1 and $max eq '') { '+' }
682 9         40 elsif ($min == 0 and $max == 1) { '?' }
683 6         33 elsif ($max ne '' and $min == $max) { "{$min}" }
684 25         100 else { "{$min,$max}" }
685             }
686              
687             sub qr {
688 51     51   69 my $self = shift;
689 51         99 join "", $self->{data}->qr, $self->raw;
690             }
691              
692             sub visual {
693 110     110   228 my $self = shift;
694 110         325 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   35 my ($self, $ws, $d) = @_;
713 15 100   11   116 unshift @$ws, sub { -1 }, $self->{data}, sub { +1 } if $d;
  11         33  
  11         34  
714             }
715              
716             sub insert {
717 98     98   178 my ($self, $tree) = @_;
718 98         181 my $rx = $self->{rx};
719              
720             # quantifiers must follow something
721 98 100 66     469 $rx->error($rx->RPe_EQUANT)
722             if @$tree == 0 or $tree->[-1]->family eq "flags";
723              
724             # quantifiers must NOT follow quantifiers
725 96 50       207 $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 96 50 66     174 if ($tree->[-1]->family eq "exact" and @{ $tree->[-1]->{data} } > 1) {
  37         118  
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 96 50 66     189 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 96         218 $self->{data} = $tree->[-1];
755 96         213 $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 54     54   185 my ($class, $rx, $on, $off, @data) = @_;
768             my $self = bless {
769             rx => $rx,
770 54         845 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   8 my $self = shift;
782 6         14 $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 60     60   100 my $self = shift;
792 60 100       212 if ($self->{on} =~ /^\^/) {
793 4         15 return join "", "(?", $self->{on}, ":";
794             }
795             join "", "(?", $self->{on},
796 56 100       262 (length $self->{off} ? "-" : ""), $self->{off}, ":";
797             }
798              
799             sub qr {
800 6     6   10 my $self = shift;
801 6         15 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  6         28  
802             }
803              
804             sub visual {
805 54     54   98 my $self = shift;
806 54         135 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  54         176  
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         3 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  1         9  
826 1 50   1   9 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  1         4  
  1         8  
  1         5  
827             }
828              
829             sub insert {
830 54     54   204 my ($self, $tree) = @_;
831 54         147 my $rx = $self->{rx};
832 54         135 push @$tree, $self;
833 54         78 push @{ $rx->{stack} }, $tree;
  54         120  
834 54         137 $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 83     83   209 my ($class, $rx, $nparen, @data) = @_;
846             my $self = bless {
847             rx => $rx,
848 83         671 flags => $rx->{flags}[-1],
849             family => 'open',
850             nparen => $nparen,
851             data => \@data,
852             raw => '(',
853             down => 1,
854             }, $class;
855 83         345 $self->{rx}{captures}[$nparen - 1] = $self;
856 83         385 return $self;
857             }
858              
859             sub type {
860 15     15   27 my $self = shift;
861 15         43 $self->family . $self->nparen;
862             }
863              
864             sub nparen {
865 103     103   3190 my $self = shift;
866 103         320 $self->{nparen};
867             }
868              
869             sub qr {
870 15     15   30 my $self = shift;
871 15         110 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  15         54  
872             }
873              
874             sub visual {
875 73     73   147 my $self = shift;
876 73         273 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  73         215  
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 83     83   158 my ($self, $tree) = @_;
906 83         238 my $rx = $self->{rx};
907 83         187 push @$tree, $self;
908 83         166 push @{ $rx->{stack} }, $tree;
  83         162  
909 83         194 $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 229     229   522 my ($class, $rx, $nparen) = @_;
921             my $self = bless {
922             rx => $rx,
923 229         2241 flags => $rx->{flags}[-1],
924             family => 'close',
925             nparen => $nparen,
926             raw => ')',
927             omit => 1,
928             up => 1,
929             }, $class;
930 229         849 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 229     229   487 my ($self, $tree) = @_;
945 229         442 my $rx = $self->{rx};
946              
947             do {
948 259 50       349 $tree = pop @{ $rx->{stack} }
  259         1141  
949             or $rx->error($rx->RPe_RPAREN)
950 229         480 } until $tree->[-1]->{down};
951              
952 229         417 $rx->{tree} = $tree;
953              
954 229 100 66     591 $self->{nparen} = $tree->[-1]->nparen
955             if $self->family eq 'close' and $tree->[-1]->can('nparen');
956              
957 229 100       557 if ($tree->[-1]->{ifthen}) {
958 18         34 my $ifthen = $tree->[-1];
959 18         49 my $br = $rx->object(branch =>);
960 18         34 my $cond;
961              
962 18 50       85 if (ref $ifthen->{data}[0] eq "ARRAY") {
963 18         31 (my($true), $cond) = splice @{ $ifthen->{data} }, 0, 2;
  18         57  
964 18         123 $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         66 $ifthen->{data} = [ $cond, $br ];
972             $ifthen->{zerolen} =
973 18         33 !grep !(grep $_->{zerolen}, @$_), @{ $ifthen->{data}[1]{data} };
  18         155  
974             }
975             else {
976             $tree->[-1]->{zerolen} ||=
977 211   66     644 !grep !$_->{zerolen}, @{ $tree->[-1]->{data} };
  173         841  
978             }
979              
980 229 50       561 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   29 my ($class, $rx) = @_;
992             my $self = bless {
993             rx => $rx,
994 11         136 flags => $rx->{flags}[-1],
995             family => 'close',
996             type => 'tail',
997             raw => ')',
998             omit => 1,
999             up => 1,
1000             }, $class;
1001 11         41 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   48 my ($class, $rx, $nparen, $vis) = @_;
1051             my $self = bless {
1052             rx => $rx,
1053 16 50       111 flags => $rx->{flags}[-1],
1054             family => 'ref',
1055             nparen => $nparen,
1056             ($vis ? (vis => $vis) : ()),
1057             }, $class;
1058 16         94 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   24 my $self = shift;
1073 13 50       85 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         25 "\\$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             push @Regexp::Parser::script_run::ISA, __PACKAGE__;
1130             push @Regexp::Parser::asr::ISA, __PACKAGE__;
1131              
1132             sub qr {
1133 6     6   36 my $self = shift;
1134 6         19 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  6         23  
1135             }
1136              
1137             sub visual {
1138 53     53   110 my $self = shift;
1139 53         224 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  53         232  
1140             }
1141              
1142             sub data {
1143 0     0   0 my $self = shift;
1144 0 0       0 if (@_) {
1145 0         0 my $how = shift;
1146 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
1147 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
1148             else {
1149 0         0 my $t = $self->type;
1150 0         0 Carp::croak("\$$t->data([+=], \@data)");
1151             }
1152             }
1153 0         0 $self->{data};
1154             }
1155              
1156             sub walk {
1157 10     10   33 my ($self, $ws, $d) = @_;
1158 10         25 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  10         49  
1159 10 50   10   86 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  10         29  
  10         75  
  10         30  
1160             }
1161              
1162             sub insert {
1163 67     67   174 my ($self, $tree) = @_;
1164 67         212 my $rx = $self->{rx};
1165 67         154 push @$tree, $self;
1166 67         137 push @{ $rx->{stack} }, $tree;
  67         177  
1167 67         212 $rx->{tree} = $self->{data};
1168             }
1169             }
1170              
1171              
1172             {
1173             # (?=) (?<=)
1174             package Regexp::Parser::ifmatch;
1175              
1176             sub new {
1177 22     22   81 my ($class, $rx, $dir, @data) = @_;
1178             my $self = bless {
1179             rx => $rx,
1180 22         230 flags => $rx->{flags}[-1],
1181             family => 'assertion',
1182             type => 'ifmatch',
1183             dir => $dir,
1184             data => \@data,
1185             down => 1,
1186             zerolen => 1,
1187             }, $class;
1188 22         175 return $self;
1189             }
1190              
1191             sub dir {
1192 0     0   0 my $self = shift;
1193 0         0 $self->{dir};
1194             }
1195              
1196             sub raw {
1197 24     24   51 my $self = shift;
1198 24 100       159 join "", "(?", ($self->{dir} < 0 ? '<' : ''), "=";
1199             }
1200             }
1201              
1202              
1203             {
1204             # (?!) (?
1205             package Regexp::Parser::unlessm;
1206              
1207             sub new {
1208 22     22   84 my ($class, $rx, $dir, @data) = @_;
1209             my $self = bless {
1210             rx => $rx,
1211 22         220 flags => $rx->{flags}[-1],
1212             family => 'assertion',
1213             type => 'unlessm',
1214             dir => $dir,
1215             data => \@data,
1216             down => 1,
1217             zerolen => 1,
1218             }, $class;
1219 22         193 return $self;
1220             }
1221              
1222             sub dir {
1223 0     0   0 my $self = shift;
1224 0         0 $self->{dir};
1225             }
1226              
1227             sub raw {
1228 24     24   72 my $self = shift;
1229 24 100       154 join "", "(?", ($self->{dir} < 0 ? '<' : ''), "!";
1230             }
1231             }
1232              
1233              
1234             {
1235             # (?>)
1236             package Regexp::Parser::suspend;
1237              
1238             sub new {
1239 7     7   24 my ($class, $rx, @data) = @_;
1240             my $self = bless {
1241             rx => $rx,
1242 7         62 flags => $rx->{flags}[-1],
1243             family => 'assertion',
1244             type => 'suspend',
1245             data => \@data,
1246             down => 1,
1247             }, $class;
1248 7         84 return $self;
1249             }
1250              
1251             sub raw {
1252 7     7   14 my $self = shift;
1253 7         17 "(?>";
1254             }
1255             }
1256              
1257             {
1258             # (?(n)t|f)
1259             package Regexp::Parser::ifthen;
1260              
1261             sub new {
1262 18     18   55 my ($class, $rx, @data) = @_;
1263             my $self = bless {
1264             rx => $rx,
1265 18         194 flags => $rx->{flags}[-1],
1266             family => 'assertion',
1267             type => 'ifthen',
1268             data => [],
1269             down => 1,
1270             ifthen => 1,
1271             }, $class;
1272 18         141 return $self;
1273             }
1274              
1275             sub raw {
1276 18     18   33 my $self = shift;
1277 18         142 "(?";
1278             }
1279              
1280             sub qr {
1281 0     0   0 my $self = shift;
1282 0         0 join "", $self->raw, $self->{data}[0]->qr, $self->{data}[1]->qr, ")";
1283             }
1284              
1285             sub visual {
1286 18     18   60 my $self = shift;
1287 18         51 join "", $self->raw, $self->{data}[0]->visual, $self->{data}[1]->visual, ")";
1288             }
1289             }
1290              
1291              
1292             {
1293             # the N in (?(N)t|f) when N is a number
1294             package Regexp::Parser::groupp;
1295             our @ISA = qw( Regexp::Parser::__object__ );
1296              
1297             sub new {
1298 3     3   9 my ($class, $rx, $nparen) = @_;
1299             my $self = bless {
1300             rx => $rx,
1301 3         33 flags => $rx->{flags}[-1],
1302             family => 'groupp',
1303             nparen => $nparen,
1304             }, $class;
1305 3         12 return $self;
1306             }
1307              
1308             sub type {
1309 7     7   12 my $self = shift;
1310 7         21 $self->family . $self->nparen;
1311             }
1312              
1313             sub nparen {
1314 7     7   10 my $self = shift;
1315 7         38 $self->{nparen};
1316             }
1317              
1318             sub visual {
1319 4     4   31 my $self = shift;
1320 4         40 "($self->{nparen})";
1321             }
1322             }
1323              
1324              
1325             {
1326             # (?{ ... })
1327             package Regexp::Parser::eval;
1328              
1329             sub new {
1330 5     5   39 my ($class, $rx, $code) = @_;
1331             my $self = bless {
1332             rx => $rx,
1333 5         42 flags => $rx->{flags}[-1],
1334             family => 'assertion',
1335             type => 'eval',
1336             data => $code,
1337             zerolen => 1,
1338             }, $class;
1339 5         36 return $self;
1340             }
1341              
1342             sub visual {
1343 6     6   14 my $self = shift;
1344 6         26 "(?{$self->{data}})";
1345             }
1346              
1347             sub qr {
1348 0     0   0 my $self = shift;
1349 0         0 $self->visual;
1350             }
1351              
1352             sub insert {
1353 5     5   15 my ($self, $tree) = @_;
1354 5         14 push @$tree, $self;
1355             }
1356              
1357             sub walk {
1358 1     1   3 my $self = shift;
1359 1         4 return;
1360             }
1361             }
1362              
1363              
1364             {
1365             # (??{ ... })
1366             package Regexp::Parser::logical;
1367              
1368             sub new {
1369 2     2   8 my ($class, $rx, $code) = @_;
1370             my $self = bless {
1371             rx => $rx,
1372 2         17 flags => $rx->{flags}[-1],
1373             family => 'assertion',
1374             type => 'logical',
1375             data => $code,
1376             zerolen => 1,
1377             }, $class;
1378 2         17 return $self;
1379             }
1380              
1381             sub visual {
1382 2     2   3 my $self = shift;
1383 2         10 "(??{$self->{data}})";
1384             }
1385              
1386             sub qr {
1387 0     0   0 my $self = shift;
1388 0         0 $self->visual;
1389             }
1390              
1391             sub insert {
1392 2     2   6 my ($self, $tree) = @_;
1393 2         6 push @$tree, $self;
1394             }
1395              
1396             sub walk {
1397 0     0   0 my $self = shift;
1398 0         0 return;
1399             }
1400             }
1401              
1402              
1403             {
1404             package Regexp::Parser::flags;
1405             our @ISA = qw( Regexp::Parser::__object__ );
1406              
1407             sub new {
1408 11     11   36 my ($class, $rx, $on, $off) = @_;
1409             my $self = bless {
1410             rx => $rx,
1411 11         124 flags => $rx->{flags}[-1],
1412             family => 'flags',
1413             type => 'flags',
1414             on => $on,
1415             off => $off,
1416             zerolen => 1,
1417             }, $class;
1418 11         80 return $self;
1419             }
1420              
1421             sub on {
1422 0     0   0 my $self = shift;
1423 0         0 $self->{on};
1424             }
1425              
1426             sub off {
1427 0     0   0 my $self = shift;
1428 0         0 $self->{off};
1429             }
1430              
1431             sub visual {
1432 11     11   28 my $self = shift;
1433 11 100       43 if ($self->{on} =~ /^\^/) {
1434 2         6 return join "", "(?", $self->{on}, ")";
1435             }
1436             join "", "(?", $self->{on},
1437 9 100       67 (length $self->{off} ? "-" : ""), $self->{off}, ")";
1438             }
1439             }
1440              
1441              
1442             {
1443             package Regexp::Parser::minmod;
1444             our @ISA = qw( Regexp::Parser::__object__ );
1445              
1446             sub new {
1447 12     12   43 my ($class, $rx, $data) = @_;
1448             my $self = bless {
1449             rx => $rx,
1450 12         53 flags => $rx->{flags}[-1],
1451             family => 'minmod',
1452             type => 'minmod',
1453             raw => '?',
1454             data => $data,
1455             }, $class;
1456 12         38 return $self;
1457             }
1458              
1459             sub qr {
1460 11     11   17 my $self = shift;
1461 11         22 join "", $self->{data}->qr, $self->raw;
1462             }
1463              
1464             sub visual {
1465 15     15   35 my $self = shift;
1466 15         39 join "", $self->{data}->visual, $self->raw;
1467             }
1468              
1469             sub walk {
1470 4     4   14 my ($self, $ws, $d) = @_;
1471 4 100   3   37 unshift @$ws, sub { -1 }, $self->{data}, sub { +1 } if $d;
  3         12  
  3         10  
1472             }
1473              
1474             sub insert {
1475 12     12   22 my ($self, $tree) = @_;
1476 12         28 $self->{data} = $tree->[-1];
1477 12         51 $tree->[-1] = $self;
1478             }
1479             }
1480              
1481              
1482             {
1483             # \K (keep, zero-width assertion added in Perl 5.10)
1484             package Regexp::Parser::keep;
1485             our @ISA = qw( Regexp::Parser::__object__ );
1486              
1487             sub new {
1488 3     3   10 my ($class, $rx) = @_;
1489             my $self = bless {
1490             rx => $rx,
1491 3         51 flags => $rx->{flags}[-1],
1492             family => 'anchor',
1493             type => 'keep',
1494             vis => '\K',
1495             zerolen => 1,
1496             }, $class;
1497 3         17 return $self;
1498             }
1499             }
1500              
1501              
1502             {
1503             # \h \H (horizontal whitespace, added in Perl 5.10)
1504             package Regexp::Parser::hspace;
1505             our @ISA = qw( Regexp::Parser::__object__ );
1506              
1507             sub new {
1508 10     10   46 my ($class, $rx, $neg) = @_;
1509             my $self = bless {
1510             rx => $rx,
1511 10         38 flags => $rx->{flags}[-1],
1512             neg => $neg,
1513             }, $class;
1514 10         39 return $self;
1515             }
1516              
1517             sub neg {
1518 2     2   4 my $self = shift;
1519 2 50       6 $self->{neg} = shift if @_;
1520 2         7 $self->{neg};
1521             }
1522              
1523             sub type {
1524 2     2   5 my $self = shift;
1525 2 100       6 ($self->{neg} ? 'n' : '') . $self->family;
1526             }
1527              
1528 12     12   56 sub family { 'hspace' }
1529              
1530             sub visual {
1531 6     6   11 my $self = shift;
1532 6 100       27 $self->{neg} ? '\H' : '\h';
1533             }
1534             }
1535              
1536              
1537             {
1538             # \v \V (vertical whitespace, added in Perl 5.10)
1539             package Regexp::Parser::vspace;
1540             our @ISA = qw( Regexp::Parser::__object__ );
1541              
1542             sub new {
1543 6     6   10 my ($class, $rx, $neg) = @_;
1544             my $self = bless {
1545             rx => $rx,
1546 6         19 flags => $rx->{flags}[-1],
1547             neg => $neg,
1548             }, $class;
1549 6         19 return $self;
1550             }
1551              
1552             sub neg {
1553 2     2   4 my $self = shift;
1554 2 50       6 $self->{neg} = shift if @_;
1555 2         6 $self->{neg};
1556             }
1557              
1558             sub type {
1559 2     2   4 my $self = shift;
1560 2 100       8 ($self->{neg} ? 'n' : '') . $self->family;
1561             }
1562              
1563 4     4   22 sub family { 'vspace' }
1564              
1565             sub visual {
1566 3     3   4 my $self = shift;
1567 3 100       13 $self->{neg} ? '\V' : '\v';
1568             }
1569             }
1570              
1571              
1572             {
1573             # \R (generic linebreak, added in Perl 5.10)
1574             package Regexp::Parser::lnbreak;
1575             our @ISA = qw( Regexp::Parser::__object__ );
1576              
1577             sub new {
1578 4     4   9 my ($class, $rx) = @_;
1579             my $self = bless {
1580             rx => $rx,
1581 4         26 flags => $rx->{flags}[-1],
1582             family => 'lnbreak',
1583             type => 'lnbreak',
1584             vis => '\R',
1585             }, $class;
1586 4         20 return $self;
1587             }
1588             }
1589              
1590              
1591             {
1592             # (?...) named capture group (added in Perl 5.10)
1593             package Regexp::Parser::named_open;
1594             our @ISA = qw( Regexp::Parser::__object__ );
1595              
1596             sub new {
1597 18     18   45 my ($class, $rx, $nparen, $name, @data) = @_;
1598             my $self = bless {
1599             rx => $rx,
1600 18         112 flags => $rx->{flags}[-1],
1601             family => 'open',
1602             nparen => $nparen,
1603             name => $name,
1604             data => \@data,
1605             raw => "(?<$name>",
1606             down => 1,
1607             }, $class;
1608 18         47 $self->{rx}{captures}[$nparen - 1] = $self;
1609 18         82 return $self;
1610             }
1611              
1612             sub type {
1613 0     0   0 my $self = shift;
1614 0         0 'open' . $self->nparen;
1615             }
1616              
1617             sub nparen {
1618 19     19   23 my $self = shift;
1619 19         30 $self->{nparen};
1620             }
1621              
1622             sub name {
1623 2     2   900 my $self = shift;
1624 2         10 $self->{name};
1625             }
1626              
1627             sub qr {
1628 0     0   0 my $self = shift;
1629 0         0 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  0         0  
1630             }
1631              
1632             sub visual {
1633 13     13   35 my $self = shift;
1634 13         30 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  13         34  
1635             }
1636              
1637             sub ender {
1638 0     0   0 my $self = shift;
1639 0         0 [ close => $self->nparen ];
1640             }
1641              
1642             sub data {
1643 0     0   0 my $self = shift;
1644 0 0       0 if (@_) {
1645 0         0 my $how = shift;
1646 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
1647 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
1648             else {
1649 0         0 my $t = $self->type;
1650 0         0 Carp::croak("\$$t->data([+=], \@data)");
1651             }
1652             }
1653 0         0 $self->{data};
1654             }
1655              
1656             sub walk {
1657 0     0   0 my ($self, $ws, $d) = @_;
1658 0         0 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  0         0  
1659 0 0   0   0 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  0         0  
  0         0  
  0         0  
1660             }
1661              
1662             sub insert {
1663 18     18   27 my ($self, $tree) = @_;
1664 18         22 my $rx = $self->{rx};
1665 18         43 push @$tree, $self;
1666 18         21 push @{ $rx->{stack} }, $tree;
  18         28  
1667 18         45 $rx->{tree} = $self->{data};
1668             }
1669             }
1670              
1671              
1672             {
1673             # \k named backreference (added in Perl 5.10)
1674             package Regexp::Parser::named_ref;
1675             our @ISA = qw( Regexp::Parser::__object__ );
1676              
1677             sub new {
1678 5     5   15 my ($class, $rx, $name, $vis) = @_;
1679             my $self = bless {
1680             rx => $rx,
1681 5         25 flags => $rx->{flags}[-1],
1682             family => 'ref',
1683             name => $name,
1684             vis => $vis,
1685             }, $class;
1686 5         19 return $self;
1687             }
1688              
1689             sub type {
1690 0     0   0 my $self = shift;
1691 0 0       0 ($self->{flags} & $self->{rx}->FLAG_i ? 'named_reff' : 'named_ref');
1692             }
1693              
1694             sub name {
1695 2     2   281 my $self = shift;
1696 2         8 $self->{name};
1697             }
1698              
1699             sub visual {
1700 4     4   7 my $self = shift;
1701 4         12 $self->{vis};
1702             }
1703             }
1704              
1705              
1706             {
1707             # possessive quantifier modifier (added in Perl 5.10)
1708             package Regexp::Parser::possessive;
1709             our @ISA = qw( Regexp::Parser::__object__ );
1710              
1711             sub new {
1712 8     8   14 my ($class, $rx, $data) = @_;
1713             my $self = bless {
1714             rx => $rx,
1715 8         31 flags => $rx->{flags}[-1],
1716             family => 'possessive',
1717             type => 'possessive',
1718             raw => '+',
1719             data => $data,
1720             }, $class;
1721 8         21 return $self;
1722             }
1723              
1724             sub qr {
1725 0     0   0 my $self = shift;
1726 0         0 join "", $self->{data}->qr, $self->raw;
1727             }
1728              
1729             sub visual {
1730 7     7   12 my $self = shift;
1731 7         16 join "", $self->{data}->visual, $self->raw;
1732             }
1733              
1734             sub walk {
1735 0     0   0 my ($self, $ws, $d) = @_;
1736 0 0   0   0 unshift @$ws, sub { -1 }, $self->{data}, sub { +1 } if $d;
  0         0  
  0         0  
1737             }
1738              
1739             sub insert {
1740 8     8   11 my ($self, $tree) = @_;
1741 8         13 $self->{data} = $tree->[-1];
1742 8         26 $tree->[-1] = $self;
1743             }
1744             }
1745              
1746              
1747             {
1748             # (?R) (?0) (?1) (?+1) (?-1) -- recursive subpatterns (Perl 5.10+)
1749             package Regexp::Parser::recurse;
1750             our @ISA = qw( Regexp::Parser::__object__ );
1751              
1752             sub new {
1753 21     21   66 my ($class, $rx, $num, $vis) = @_;
1754             my $self = bless {
1755             rx => $rx,
1756 21         123 flags => $rx->{flags}[-1],
1757             family => 'recurse',
1758             type => 'recurse',
1759             num => $num,
1760             vis => $vis,
1761             }, $class;
1762 21         83 return $self;
1763             }
1764              
1765             sub num {
1766 8     8   1554 my $self = shift;
1767 8         35 $self->{num};
1768             }
1769              
1770             sub visual {
1771 19     19   48 my $self = shift;
1772 19         53 $self->{vis};
1773             }
1774              
1775             sub qr {
1776 1     1   4 my $self = shift;
1777 1         5 $self->{vis};
1778             }
1779             }
1780              
1781              
1782             {
1783             # (?&name) -- named recursive subpattern (Perl 5.10+)
1784             package Regexp::Parser::named_recurse;
1785             our @ISA = qw( Regexp::Parser::__object__ );
1786              
1787             sub new {
1788 5     5   11 my ($class, $rx, $name, $vis) = @_;
1789             my $self = bless {
1790             rx => $rx,
1791 5         21 flags => $rx->{flags}[-1],
1792             family => 'recurse',
1793             type => 'named_recurse',
1794             name => $name,
1795             vis => $vis,
1796             }, $class;
1797 5         21 return $self;
1798             }
1799              
1800             sub name {
1801 2     2   275 my $self = shift;
1802 2         9 $self->{name};
1803             }
1804              
1805             sub visual {
1806 5     5   12 my $self = shift;
1807 5         24 $self->{vis};
1808             }
1809              
1810             sub qr {
1811 2     2   7 my $self = shift;
1812 2         11 "(?&$self->{name})";
1813             }
1814             }
1815              
1816              
1817             {
1818             # (*VERB) and (*VERB:arg) backtracking control verbs (Perl 5.10+)
1819             package Regexp::Parser::verb;
1820             our @ISA = qw( Regexp::Parser::__object__ );
1821              
1822             sub new {
1823 14     14   42 my ($class, $rx, $name, $arg) = @_;
1824             my $self = bless {
1825             rx => $rx,
1826 14         120 flags => $rx->{flags}[-1],
1827             family => 'verb',
1828             type => $name,
1829             name => $name,
1830             arg => $arg,
1831             }, $class;
1832 14         345 return $self;
1833             }
1834              
1835             sub name {
1836 1     1   3 my $self = shift;
1837 1         5 $self->{name};
1838             }
1839              
1840             sub arg {
1841 1     1   3 my $self = shift;
1842 1         4 $self->{arg};
1843             }
1844              
1845             sub visual {
1846 13     13   23 my $self = shift;
1847 13         34 my $v = "(*" . $self->{name};
1848 13 100 66     69 $v .= ":" . $self->{arg} if defined $self->{arg} && length $self->{arg};
1849 13         45 $v . ")";
1850             }
1851             }
1852              
1853              
1854             {
1855             # (?|...) branch reset group (Perl 5.10+)
1856             package Regexp::Parser::branch_reset;
1857             our @ISA = qw( Regexp::Parser::__object__ );
1858              
1859             sub new {
1860 7     7   21 my ($class, $rx, @data) = @_;
1861             my $self = bless {
1862             rx => $rx,
1863 7         58 flags => $rx->{flags}[-1],
1864             family => 'group',
1865             type => 'branch_reset',
1866             data => \@data,
1867             down => 1,
1868             }, $class;
1869 7         38 return $self;
1870             }
1871              
1872             sub raw {
1873 6     6   10 my $self = shift;
1874 6         34 "(?|";
1875             }
1876              
1877             sub qr {
1878 0     0   0 my $self = shift;
1879 0         0 join "", $self->raw, map($_->qr, @{ $self->{data} }), ")";
  0         0  
1880             }
1881              
1882             sub visual {
1883 6     6   9 my $self = shift;
1884 6         17 join "", $self->raw, map($_->visual, @{ $self->{data} }), ")";
  6         25  
1885             }
1886              
1887             sub data {
1888 0     0   0 my $self = shift;
1889 0 0       0 if (@_) {
1890 0         0 my $how = shift;
1891 0 0       0 if ($how eq '=') { $self->{data} = \@_ }
  0 0       0  
1892 0         0 elsif ($how eq '+') { push @{ $self->{data} }, @_ }
  0         0  
1893             else {
1894 0         0 my $t = $self->type;
1895 0         0 Carp::croak("\$$t->data([+=], \@data)");
1896             }
1897             }
1898 0         0 $self->{data};
1899             }
1900              
1901             sub walk {
1902 0     0   0 my ($self, $ws, $d) = @_;
1903 0         0 unshift @$ws, $self->{rx}->object(@{ $self->ender });
  0         0  
1904 0 0   0   0 unshift @$ws, sub { -1 }, @{ $self->{data} }, sub { +1 } if $d;
  0         0  
  0         0  
  0         0  
1905             }
1906              
1907             sub insert {
1908 7     7   32 my ($self, $tree) = @_;
1909 7         22 my $rx = $self->{rx};
1910 7         17 push @$tree, $self;
1911 7         12 push @{ $rx->{stack} }, $tree;
  7         16  
1912 7         36 $rx->{tree} = $self->{data};
1913             }
1914             }
1915              
1916              
1917             {
1918             # (*script_run:...) Script run (Perl 5.28+)
1919             package Regexp::Parser::script_run;
1920             our @ISA = qw( Regexp::Parser::assertion );
1921              
1922             sub new {
1923 2     2   27 my ($class, $rx, @data) = @_;
1924             my $self = bless {
1925             rx => $rx,
1926 2         24 flags => $rx->{flags}[-1],
1927             family => 'assertion',
1928             type => 'script_run',
1929             data => \@data,
1930             down => 1,
1931             }, $class;
1932 2         32 return $self;
1933             }
1934              
1935             sub raw {
1936 2     2   5 my $self = shift;
1937 2         7 "(*script_run:";
1938             }
1939             }
1940              
1941              
1942             {
1943             # (*atomic_script_run:...) / (*asr:...) Atomic script run (Perl 5.28+)
1944             package Regexp::Parser::asr;
1945             our @ISA = qw( Regexp::Parser::assertion );
1946              
1947             sub new {
1948 2     2   10 my ($class, $rx, @data) = @_;
1949             my $self = bless {
1950             rx => $rx,
1951 2         49 flags => $rx->{flags}[-1],
1952             family => 'assertion',
1953             type => 'asr',
1954             data => \@data,
1955             down => 1,
1956             }, $class;
1957 2         35 return $self;
1958             }
1959              
1960             sub raw {
1961 2     2   5 my $self = shift;
1962 2         7 "(*asr:";
1963             }
1964             }
1965             1;
1966              
1967             __END__