File Coverage

blib/lib/Regexp/Parser/Objects.pm
Criterion Covered Total %
statement 510 753 67.7
branch 107 230 46.5
condition 42 72 58.3
subroutine 158 215 73.4
pod n/a
total 817 1270 64.3


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